Skip to content

Instantly share code, notes, and snippets.

@agates4
Last active August 3, 2021 20:13
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save agates4/54be4a8584ee5e80d02f6b601e7d3e6a to your computer and use it in GitHub Desktop.
Save agates4/54be4a8584ee5e80d02f6b601e7d3e6a to your computer and use it in GitHub Desktop.
Script to turn a given image into a beautiful screenshot with rounded corners, drop shadow, and whitespace
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<array>
<dict>
<key>Activate</key>
<string>Normal</string>
<key>CreationDate</key>
<real>622511872.68444896</real>
<key>Macros</key>
<array>
<dict>
<key>Actions</key>
<array>
<dict>
<key>Conditions</key>
<dict>
<key>ConditionList</key>
<array>
<dict>
<key>Button</key>
<integer>0</integer>
<key>ConditionType</key>
<string>MouseButton</string>
</dict>
</array>
<key>ConditionListMatch</key>
<string>All</string>
</dict>
<key>MacroActionType</key>
<string>PauseUntil</string>
<key>TimeOutAbortsMacro</key>
<true/>
</dict>
<dict>
<key>Conditions</key>
<dict>
<key>ConditionList</key>
<array>
<dict>
<key>Button</key>
<integer>0</integer>
<key>ConditionType</key>
<string>MouseButton</string>
<key>Pressed</key>
<false/>
</dict>
</array>
<key>ConditionListMatch</key>
<string>All</string>
</dict>
<key>MacroActionType</key>
<string>PauseUntil</string>
<key>TimeOutAbortsMacro</key>
<true/>
</dict>
<dict>
<key>MacroActionType</key>
<string>Pause</string>
<key>Time</key>
<string>0.2</string>
<key>TimeOutAbortsMacro</key>
<true/>
</dict>
<dict>
<key>Conditions</key>
<dict>
<key>ConditionList</key>
<array>
<dict>
<key>ClipboardConditionType</key>
<string>HasImage</string>
<key>ClipboardText</key>
<string></string>
<key>ConditionType</key>
<string>Clipboard</string>
</dict>
</array>
<key>ConditionListMatch</key>
<string>All</string>
</dict>
<key>ElseActions</key>
<array/>
<key>MacroActionType</key>
<string>IfThenElse</string>
<key>ThenActions</key>
<array>
<dict>
<key>Append</key>
<false/>
<key>Destination</key>
<string>/Users/personal/Workspace/drop-shadow/temp.png</string>
<key>Encoding</key>
<string>UTF8</string>
<key>Format</key>
<string>PNG</string>
<key>Format2</key>
<string>PNG</string>
<key>MacroActionType</key>
<string>WriteFile</string>
<key>Source</key>
<string>Clipboard</string>
</dict>
<dict>
<key>DisplayKind</key>
<string>Window</string>
<key>HonourFailureSettings</key>
<true/>
<key>IncludeStdErr</key>
<true/>
<key>MacroActionType</key>
<string>ExecuteShellScript</string>
<key>Path</key>
<string>~/Workspace/drop-shadow/drop-shadow.sh</string>
<key>Source</key>
<string>Nothing</string>
<key>Text</key>
<string>./Users/personal/Workspace/drop-shadow/drop-shadow.sh /Users/personal/Workspace/drop-shadow/temp.png</string>
<key>TimeOutAbortsMacro</key>
<true/>
<key>TrimResults</key>
<true/>
<key>TrimResultsNew</key>
<true/>
<key>UseText</key>
<true/>
</dict>
</array>
<key>TimeOutAbortsMacro</key>
<true/>
</dict>
</array>
<key>CreationDate</key>
<real>622511932.61007595</real>
<key>ModificationDate</key>
<real>623533929.95638096</real>
<key>Name</key>
<string>Apply shadow to screenshot</string>
<key>Triggers</key>
<array>
<dict>
<key>FireType</key>
<string>Pressed</string>
<key>KeyCode</key>
<integer>21</integer>
<key>MacroTriggerType</key>
<string>HotKey</string>
<key>Modifiers</key>
<integer>768</integer>
</dict>
</array>
<key>UID</key>
<string>5EFD8E79-1CE2-4B4E-95D6-A0156AF1379F</string>
</dict>
</array>
<key>Name</key>
<string>Global Macro Group</string>
<key>ToggleMacroUID</key>
<string>837A4569-414A-45B0-B086-D85B3AAE90D0</string>
<key>UID</key>
<string>55D3F2B4-0024-4857-9E8D-02CF4B05D3D2</string>
</dict>
</array>
</plist>
#!/usr/bin/env bash
# ---------------------------------
# set this script as an executable:
# chmod u+x drop-shadow.sh
# example usage:
# ./Users/personal/Workspace/drop-shadow/drop-shadow.sh /Users/personal/Workspace/drop-shadow/temp.png
# ---------------------------------
# we need a filename as an argument
if [ $# -eq 0 ]; then
echo "Needs the filename as the first argument"
exit -1
fi
# Required package
type /usr/local/bin/convert >/dev/null 2>&1 || { echo >&2 "The convert command must be available (from imagemagick)."; exit 1; }
# use our argument path as our input filename
input_filename="${1}"
# set our output directory for temp images
output_dir="/Users/personal/Workspace/drop-shadow/"
# https://stackoverflow.com/questions/965053/extract-filename-and-extension-in-bash#965072
filename=$(basename -- "${input_filename}")
extension="${filename##*.}"
filename="${filename%.*}"
# get the mean colorspace as a decimal
colorspace=$(/usr/local/bin/convert "${input_filename}" -colorspace gray -format "%[fx:100*mean]%%" info:)
colorspace=$(echo $colorspace|perl -pe 's{\d+\.\d+%}{$&/100}eg')
# chose shadow color based on colorspace of the image
chosen_shadow="#000"
[ "`echo "${colorspace} < 1.0" | bc`" -eq 1 ] && chosen_shadow="#B0B0B0"
[ "`echo "${colorspace} < 0.91" | bc`" -eq 1 ] && chosen_shadow="#AAA"
[ "`echo "${colorspace} < 0.6" | bc`" -eq 1 ] && chosen_shadow="#333"
[ "`echo "${colorspace} < 0.2" | bc`" -eq 1 ] && chosen_shadow="#222"
[ "`echo "${colorspace} < 0.1" | bc`" -eq 1 ] && chosen_shadow="#000"
# generate rounded corners for image
/usr/local/bin/convert "${input_filename}" \( +clone -alpha extract -draw 'fill black polygon 0,0 0,15 15,0 fill white circle 15,15 15,0' \( +clone -flip \) -compose Multiply -composite \( +clone -flop \) -compose Multiply -composite \) -alpha off -compose CopyOpacity -composite "${output_dir}${filename}_shadow.${extension}"
# generate shadow for image
/usr/local/bin/convert "${output_dir}${filename}_shadow.${extension}" \( +clone -background "${chosen_shadow}" -shadow 100x10+0+10 \) +swap -background none -layers merge +repage "${output_dir}${filename}_shadow.${extension}"
# generate whitespace for image
/usr/local/bin/convert "${output_dir}${filename}_shadow.${extension}" -bordercolor none -border 1 -gravity south -background none -splice 0x25 "${output_dir}${filename}_shadow.${extension}"
# copy generated image to clipboard
osascript -e "set the clipboard to (read (POSIX file \"${output_dir}${filename}_shadow.${extension}\") as JPEG picture)"
@agates4
Copy link
Author

agates4 commented Sep 23, 2020

Steps -

Configuring the script

This script does the transformations to the given image to make it look very nice.

  1. save the .sh file in a new folder of your choice
  2. update output_dir in the script to the new folder you created
  3. set the script as an executable with chmod +x drop-shadow.sh

Installing dependencies

first, you need to install brew
when you have brew, you can run the commands in step 1

  1. brew update && brew install imagemagick && brew cask install copyq (new version below doesn't require copyq)
  2. in your security/privacy accessibility settings make sure you click the + button and add copyq.app (new version below doesn't require copyq)

image

Configuring keyboard maestro

  1. install keyboard maestro
    (make sure you gave it full accessibility permissions just like with copyq)
  2. import the maestro script and update the folder paths to the right folder paths

congrats now when you take screenshots with command+shift+4 and select a portion of your screen, it will be a beautiful screenshot

@agates4
Copy link
Author

agates4 commented Sep 23, 2020

here's an example of what it looks like when I take a screenshot of a random section of my screen

image

@Namaskar-1F64F
Copy link

That's cool.

@gatesyp
Copy link

gatesyp commented Sep 23, 2020

That looks really nice , how do I install?

@agates4
Copy link
Author

agates4 commented Aug 3, 2021

updated with dynamically generated whitespace based on image dimensions
and don't need to install copyq - using normal copy tool prepackaged with OS X

#!/usr/bin/env bash

# ---------------------------------
# set this script as an executable:
# chmod u+x drop-shadow.sh

# example usage:
# ./Users/personal/Workspace/drop-shadow/drop-shadow.sh /Users/personal/Workspace/drop-shadow/temp.png
# ---------------------------------

# we need a filename as an argument
if [ $# -eq 0 ]; then
  echo "Needs the filename as the first argument"
  exit -1
fi

# Required package
type /usr/local/bin/convert >/dev/null 2>&1 || { echo >&2 "The convert command must be available (from imagemagick)."; exit 1; }

# use our argument path as our input filename
input_filename="${1}"

# set our output directory for temp images
output_dir="/Users/personal/Workspace/drop-shadow/"

# https://stackoverflow.com/questions/965053/extract-filename-and-extension-in-bash#965072
filename=$(basename -- "${input_filename}")
extension="${filename##*.}"
filename="${filename%.*}"

# get the mean colorspace as a decimal
colorspace=$(/usr/local/bin/convert "${input_filename}" -colorspace gray -format "%[fx:100*mean]%%" info:)
colorspace=$(echo $colorspace|perl -pe 's{\d+\.\d+%}{$&/100}eg')

# chose shadow color based on colorspace of the image
chosen_shadow="#000"
[ "`echo "${colorspace} < 1.0" | bc`" -eq 1 ] && chosen_shadow="#B0B0B0"
[ "`echo "${colorspace} < 0.91" | bc`" -eq 1 ] && chosen_shadow="#AAA"
[ "`echo "${colorspace} < 0.6" | bc`" -eq 1 ] && chosen_shadow="#333"
[ "`echo "${colorspace} < 0.2" | bc`" -eq 1 ] && chosen_shadow="#222"
[ "`echo "${colorspace} < 0.1" | bc`" -eq 1 ] && chosen_shadow="#000"

# generate rounded corners for image
/usr/local/bin/convert "${input_filename}" \( +clone  -alpha extract -draw 'fill black polygon 0,0 0,15 15,0 fill white circle 15,15 15,0' \( +clone -flip \) -compose Multiply -composite \( +clone -flop \) -compose Multiply -composite \) -alpha off -compose CopyOpacity -composite "${output_dir}${filename}_shadow.${extension}"

# calculating whitespace by dimension and our magic numbers
width=`/usr/local/bin/identify ${input_filename} | cut -f 3 -d " " | sed s/x.*//` # width
height=`/usr/local/bin/identify ${input_filename} | cut -f 3 -d " " | sed s/.*x//` # height
whitespace_bottom="$(echo "$width*0.042" | bc)"
whitespace_top="$(echo "$height*0.026" | bc)"
whitespace_sides="$(echo "$height*0.035" | bc)"

# generate shadow for image
/usr/local/bin/convert "${output_dir}${filename}_shadow.${extension}" \( +clone -background "${chosen_shadow}" -shadow 100x10+0+10 \) +swap -background none -layers merge +repage "${output_dir}${filename}_shadow.${extension}"

# generate whitespace for image
/usr/local/bin/convert "${output_dir}${filename}_shadow.${extension}" -bordercolor none -border 1 -gravity south -background none -splice "0x${whitespace_bottom}" "${output_dir}${filename}_shadow.${extension}"
/usr/local/bin/convert "${output_dir}${filename}_shadow.${extension}" -bordercolor none -border 1 -gravity north -background none -splice "0x${whitespace_top}" "${output_dir}${filename}_shadow.${extension}"
/usr/local/bin/convert "${output_dir}${filename}_shadow.${extension}" -bordercolor none -border 1 -gravity east -background none -splice "${whitespace_sides}x0" "${output_dir}${filename}_shadow.${extension}"
/usr/local/bin/convert "${output_dir}${filename}_shadow.${extension}" -bordercolor none -border 1 -gravity west -background none -splice "${whitespace_sides}x0" "${output_dir}${filename}_shadow.${extension}"

# copy generated image to clipboard
osascript -e "set the clipboard to (read (POSIX file \"${output_dir}${filename}_shadow.${extension}\") as JPEG picture)"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment