Screenshot Prettifier (via ImageMagick)

Provoked by @JMichaelTX's question "What is ImageMagick", here an AppleScript that allows you to tweak your screenshots in several ways.



The script has a few dependencies:

  • ImageMagick
  • advpng (aka advancecomp)
  • pngquant

How to install these programs via Homebrew is explained in the header of the script.



You can run the script either as it is (e.g. from the Script menu or via LaunchBar etc.), or as a KM Macro.

Just select one or more screenshots (png files) in the Finder and run the script.


The standalone version:

IM-Screenshot-Prettifier.scpt.zip (29.8 KB)

The KM Macro:

Screenshot Prettifier.kmmacros (12.3 KB)

The script text:

use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

set theDefaults to current application's NSUserDefaults's alloc()'s initWithSuiteName:"net.dflect.IMScreenshotPrettifier"

theDefaults's registerDefaults:{binPath:"export PATH=/usr/local/bin;", options:"", shadowValue:"80x3+2+2", polaroidValue:"-.5", usmValueForResized:".8x.8+1+0.55", usmValueForUnchangedSize:".8x.8+1+0.5", usmValueForPolaroid:".8x.8+1+0.35", polaroidCaption:"-gravity center -font SF-UI-TextI -pointsize 20 -fill maroon -set caption 'Look at this nice image!'", option1:"", option2:"", nonPNGs:0, helpMsg:"You can choose one item from each group.

Polaroid applies USM by default, so do not combine it with USM.

Choose Polaroid… to set the angle. If you press Save & OK a Polaroid action will be executed with that angle. If you press Save & Relaunch you can run the Polaroid w/Caption action with that angle value."}

# Good values for Unsharp Mask: [radius x sigma + amount + threshold]
# usmValueForResized:".8x.8+1+0.55"
# usmValueForUnchangedSize:".8x.8+1+0.5"
# usmValueForPolaroid:".8x.8+1+0.35"

set binPath to binPath of theDefaults as text
set options to options of theDefaults as list
set shadowValue to shadowValue of theDefaults as text
set polaroidValue to polaroidValue of theDefaults as text
set usmValueForResized to usmValueForResized of theDefaults as text
set usmValueForUnchangedSize to usmValueForUnchangedSize of theDefaults as text
# I have added an “unsharp” to the Polaroid action by default because it seems to use “resize” to shrink the image (“resize” is more blurry than “scale”)
set usmValueForPolaroid to usmValueForPolaroid of theDefaults as text
set polaroidCaption to polaroidCaption of theDefaults as text
set option1 to option1 of theDefaults as text
set option2 to option2 of theDefaults as text
set nonPNGs to nonPNGs of theDefaults as integer
set helpMsg to helpMsg of theDefaults as text

global binPath, outNamePrettyQuant, outNamePretty, outNameQuant

# Collect files
tell application "Finder"
  set trgImages to selection as alias list
  repeat while (count of trgImages) < 1
    display alert "Please select one or more image files (PNG) in the Finder." as warning buttons {"Cancel", "Continue"}
    if the result's button returned is "Cancel" then error number -128
    set trgImages to selection as alias list
  end repeat
end tell

# Get options. We can choose one of the first group + Quantize.
set prevOptions to options
tell application (path to frontmost application as text)
  set options to choose from list {"Drop Shadow…", "Drop Shadow", "Polaroid…", "Polaroid", "Polaroid w/Caption…", "Torn Edges", "Torn Edges +Shadow", "Thick", "--------------", "Quantize", "--------------", "Resize to 50 %", "Resize to 70  %", "Resize to 75 %", "Resize to 80 %", "Resize to 85 %", "Resize to 90 %", "Shrink to 300 px Width", "Shrink to 350 px Width", "Shrink to 400 px Width", "USM for Original Size", "--------------", "Help"} with title "Options" with prompt "Hold down ⌘ to select one option of each group." OK button name "OK" cancel button name "Cancel" default items options multiple selections allowed yes empty selection allowed no
  if options is false then error number -128
end tell

# Customization for some options
if options contains "Drop Shadow…" then
  set shadowValue to the text returned of (display dialog "Set shadow parameters (e.g. 80x3+2+2):" default answer shadowValue)
  set shadowValue of theDefaults to shadowValue
  set item 1 of options to "Drop Shadow"
else if options contains "Polaroid…" then
  set theResult to (display dialog "Set polaroid angle (e.g. .9):" default answer polaroidValue buttons {"Cancel", "Save & Relaunch", "Save & OK"} default button "Save & OK")
  set polaroidValue to theResult's text returned
  set polaroidValue of theDefaults to polaroidValue
  set item 1 of options to "Polaroid"
  if the theResult's button returned is "Save & Relaunch" then
    set item 1 of options to "Polaroid w/Caption…"
    run me
  end if
end if


# Set options
if options contains "Drop Shadow" then
  # http://www.imagemagick.org/Usage/blur/#shadow
  set option1 to "\\( +clone -background black -shadow" & space & shadowValue & space & "\\) +swap -background none -layers merge +repage"
else if options contains "Polaroid" then
  # http://www.imagemagick.org/Usage/transform/#polaroid
  # Nice colors: *OldLace, linen, *WhiteSmoke, moccasin, AntiqueWhite, PapayaWhip
  set option1 to "-bordercolor WhiteSmoke -background gray30 -polaroid" & space & polaroidValue & space & "-unsharp" & space & usmValueForPolaroid
else if options contains "Polaroid w/Caption…" then
  set polaroidCaption to the text returned of (display dialog "Set caption:" default answer polaroidCaption)
  set polaroidCaption of theDefaults to polaroidCaption
  set option1 to "-bordercolor GhostWhite -background gray30" & space & polaroidCaption & space & "-polaroid" & space & polaroidValue & space & "-unsharp" & space & usmValueForPolaroid
else if options contains "Torn Edges" then
  # http://www.imagemagick.org/Usage/thumbnails/#torn
  set option1 to "\\( +clone -alpha extract -virtual-pixel black -spread 10 -blur 0x3 -threshold 50% -spread 1 -blur 0x.7 \\) -alpha off -compose Copy_Opacity -composite"
else if options contains "Torn Edges +Shadow" then
  set option1 to "\\( +clone -alpha extract -virtual-pixel black -spread 10 -blur 0x3 -threshold 50% -spread 1 -blur 0x.7 \\) -alpha off -compose Copy_Opacity -composite - | convert - \\( +clone -background black -shadow 50x2+2+2 \\) +swap -background none -layers merge +repage"
else if options contains "Thick" then
  # http://www.imagemagick.org/Usage/thumbnails/#thickness
  set option1 to "-alpha set \\( +clone -fill LightSteelBlue3 -colorize 100% -repage +0+1 \\) \\( +clone -repage +1+2 \\) \\( +clone -repage +1+3 \\) \\( +clone -repage +2+4 \\) \\( +clone -repage +2+5 \\) \\( +clone -repage +3+6 \\) \\( +clone -repage +3+7 \\) \\( +clone -repage +4+8 \\) \\( +clone -repage +4+9 \\) -background none -compose DstOver -mosaic"
end if

# These options are combinable with the first option (option1); should always be the last item in the list
if item -1 of options is "Help" then
  display alert "Hints:" message helpMsg
  set options to prevOptions
  run me
  error number -128
else
  tell item -1 of options
    if it contains "%" then
      set scaleValue to word -1
      set option2 to "-scale" & space & scaleValue & "%" & space & "-unsharp" & space & usmValueForResized
    else if it contains "width" then
      set scaleValue to word -3
      set option2 to "-scale" & space & scaleValue & "\\>" & space & "-unsharp" & space & usmValueForResized
    else if it contains "USM" then
      set option2 to "-unsharp" & space & usmValueForUnchangedSize
    end if
  end tell
end if
set options of theDefaults to options

# Main part
repeat with image in trgImages
  set image to POSIX path of image
  # Get path components
  set saveTID to AppleScript's text item delimiters
  set AppleScript's text item delimiters to {"."}
  set extension to text item -1 of image
  set head to (text items 1 through -2 of image) as text
  set AppleScript's text item delimiters to saveTID
  
  # Most of the stuff runs only on pngs
  if extension is "png" then
    if item 1 of options is "Quantize" and (count of options) is 1 then
      # For convenience, quantization only
      quantize(image, extension, head)
      # Advpng does never harm. If too slow set it to -z3 or -z2.
      advpng(outNameQuant)
    else if options contains "Quantize" then
      # One IM command + quantization (as stdin/stdout combo)
      combo(image, extension, head, option1, option2)
      advpng(outNamePrettyQuant)
    else
      # Only IM, without quantization
      prettify(image, extension, head, option1, option2)
      advpng(outNamePretty)
    end if
  else
    set nonPNGs to nonPNGs + 1
  end if
end repeat

display notification (((count of trgImages) - nonPNGs) as text) & " image(s) processed." with title "Screenshot Prettifier" sound name "Submarine"

if nonPNGs > 0 then
  display alert (nonPNGs as text) & " non-PNG files found. Only PNG files have been processed!" as warning buttons "OK"
end if


### Handlers #######################################################

# A pure IM command
on prettify(image, extension, head, option1, option2)
  set outNamePretty to head & "-pty." & extension
  do shell script binPath & space & "convert" & space & quoted form of image & space & ¬
    option1 & space & option2 & space & quoted form of outNamePretty
end prettify

# Pure Pngquant
on quantize(image, extension, head)
  set outNameQuant to head & "-fs8." & extension
  do shell script binPath & space & "pngquant --quality=70-95 --floyd --skip-if-larger --force --speed=1 --output" & ¬
    space & quoted form of outNameQuant & space & quoted form of image
end quantize

# Both combined (preferable, since no intermediate file writing)
on combo(image, extension, head, option1, option2)
  set outNamePrettyQuant to head & "-pty-fs8." & extension
  do shell script binPath & space & "convert" & space & quoted form of image & space & ¬
    option1 & space & option2 & space & "- | pngquant - --quality=70-95 --floyd --force --speed=1 --output" & ¬
    space & quoted form of outNamePrettyQuant
end combo

# Lossless advpng (doesn't read from stdin). -z3 (7zip lib) is pretty good _and_ fast.
on advpng(input)
  do shell script binPath & space & "advpng -z3" & space & quoted form of input
end advpng

# Not significantly better than advpng -z3
--on zopfli(input)
--  do shell script binPath & space & "zopflipng --lossy_transparent -y" & ¬
--      space & quoted form of input & space & quoted form of input
--end zopfli

Examples

The script allows you to quickly produce screenshots like this:

…with a decent shadow:

…with torn edges and a slight shadow:

… as polaroid with caption:

…and some more.


Feel free to modify the ImageMagick parameters in the script. They are far from being optimal and you have a lot of choices :wink:

Comments in the script are pointing you to sources of information.


Hint:

If you have a "Retina" screen and your image is more than 690px wide choose "Resize to 50%".

5 Likes

I would have preferred "inspired by". LOL :wink:

But thanks for another cool macro, Tom.

1 Like

I thought about that wording, but…honestly… I rather felt provoked to post it :wink:

I mean, who — except you — could ask a question like "What is ImageMagick?" :wink:

Hello,

This is quite an old thread but this macro still works!

I was using it on my Intel MBP with macOS Ventura without any problem. Now, since I moved to M2 it seems it's broken. I followed the installation guide, did Homebrew etcetera, but when I run the macro I see just this Options window.

After selecting my options it does nothing...

Does somebody here use this macro with Apple Silicon? Does it work? Or do you use another workflow for png quantization?

Edit: Don't know if this is relevant but I found out every brew command I typed in the Terminal results "command not found" error. Seems it has to do something with different path on Apple Silicon.

I ran two commands from this github post:

export PATH="/opt/homebrew/bin:$PATH"
echo 'export PATH="/opt/homebrew/bin:$PATH"' >> $HOME/.zshrc

Now, brew commands are working in Terminal. Still have no clue why Screenshot Prettifier is not.

Thank you!

That's completely meaningless to Keyboard Maestro – as the macOS shell environment and KM's shell environment are completely separate.

For that matter KM is actually not managing the shell environment in this macro, because the entirety of the macro is an AppleScript.

Note the path in this portion of the script:

theDefaults's registerDefaults:{binPath:"export PATH=/usr/local/bin;", options:"", shadowValue:"80x3+2+2", polaroidValue:"-.5", usmValueForResized:".8x.8+1+0.55", usmValueForUnchangedSize:".8x.8+1+0.5", usmValueForPolaroid:".8x.8+1+0.35", polaroidCaption:"-gravity center -font SF-UI-TextI -pointsize 20 -fill maroon -set caption 'Look at this nice image!'", option1:"", option2:"", nonPNGs:0, helpMsg:"You can choose one item from each group.

About time to post a new version of my trusty Screenshot Prettifier script:

IM-Screenshot-Prettifier-0.9.9.applescript.zip (9.3 KB)

As with the old version, it can be used standalone (Script menu) or from within KM. Target is the Finder selection (PNG).

Noteworthy changes:

  • Using oxipng now instead of advpng for optimization (compression).
  • Independent of the action, PPI resolution is now always set to 144 (no pixel change).
  • Pre- and postprocessing (PPI metadata & final optimization) as standalone option.
  • Option for faster (lower) compression. (Affects optimization, not quantization.)
  • Fixed a couple of things and tweaked parameters.
  • Added path detection, since Homebrew installs to a different path on ARM Macs (see also the Edit notes for v0.9.9 at the end of the post).

So the dependencies of this version are:

They can all be installed with Homebrew: brew install imagemagick, brew install pngquant, brew install oxipng

The standardization to 144ppi is done with sips, which comes with macOS. sips writes the ppi metadata to the pHYs chunk of the PNG.

The pHYs chunk must be preserved during optimization, which – to my knowledge – is not possible with advpng. Hence the switch to oxipng. (zopfli also can preserve the chunk, but oxipng turned out to be significantly faster at a comparable compression level. Besides that, it is actively developed.)

A note on optimization/quantization:

  • Optimization (via oxipng) uses lossless compression and does not affect image quality in any way. The script optimizes the PNG automatically at the end.
  • Quantization (via pngquant) is significantly more effective, but also reduces image quality, e.g. by reducing the number of colors. Quantization must be selected in the Options dialog and is not done automatically.

The script content (without header):

# Version: 0.9.9 (15)

use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

# To leave ppi unchanged, set `ppi` to ""

set theDefaults to current application's NSUserDefaults's alloc()'s initWithSuiteName:"net.dflect.IMScreenshotPrettifier"

# Path: The script should detect the ususal Homebrew path austomatically. If you get a path alert, please set the `binPath` default in the next line manually to your path(s). Example: "export PATH=/xxx/yyy/bin:$PATH;" (single path) or "export PATH=/xxx/yyy/bin:/xxx/zzz/bin:$PATH;" (multiple paths).
theDefaults's registerDefaults:{binPath:"", ppi:"144", options:"", shadowValue:"80x3+2+2", polaroidValue:"-.5", usmValueForResized:".8x.8+1+0.55", usmValueForUnchangedSize:".8x.8+1+0.5", usmValueForPolaroid:".8x.8+1+0.35", polaroidCaption:"-gravity center -font SF-UI-TextI -pointsize 20 -fill maroon -set caption 'CAPTION TEXT HERE'", option1:"", option2:"", compression:"-o max", onlyPPP:false, nonPNGs:0, helpMsg:"You can choose one item from each group.

Polaroid applies USM by default, so do not combine it with USM.

Choose 'Polaroid…' to set the angle. If you press 'Save & Run', a Polaroid action will be executed with that angle. If you press 'Save & Relaunch', the script relaunches and you can run the Polaroid w/Caption action with that angle value.

Values you set in dialogs apply to the current run and are saved as your new default also for the corresponding dialog-less actions.

Select 'Pre- & Postprocessing Only' to only set the PPI metadata and apply lossless compression. (Automatically included with any other action.)"}

# Good values for Unsharp Mask: [radius x sigma + amount + threshold]
# usmValueForResized:".8x.8+1+0.55"
# usmValueForUnchangedSize:".8x.8+1+0.5"
# usmValueForPolaroid:".8x.8+1+0.35"

set binPath to binPath of theDefaults as text
set ppi to ppi of theDefaults as text
set options to options of theDefaults as list
set shadowValue to shadowValue of theDefaults as text
set polaroidValue to polaroidValue of theDefaults as text
set usmValueForResized to usmValueForResized of theDefaults as text
set usmValueForUnchangedSize to usmValueForUnchangedSize of theDefaults as text
# I have added an “unsharp” to the Polaroid action by default because it seems to use “resize” to shrink the image (“resize” is more blurry than “scale”)
set usmValueForPolaroid to usmValueForPolaroid of theDefaults as text
set polaroidCaption to polaroidCaption of theDefaults as text
set option1 to option1 of theDefaults as text
set option2 to option2 of theDefaults as text
set compression to compression of theDefaults as text
set onlyPPP to onlyPPP of theDefaults as boolean
set nonPNGs to nonPNGs of theDefaults as integer
set helpMsg to helpMsg of theDefaults as text

global binPath, outName

# Homebrew path is different on ARM Macs
# Naively we assume that all required binaries are in the same path as `convert`
if binPath is "" then
	tell application "System Events"
		if exists file "/opt/homebrew/bin/convert" then -- ARM
			set binPath to "export PATH=/opt/homebrew/bin:$PATH;"
		else if exists file "/usr/local/bin/convert" then -- X86
			set binPath to "export PATH=/usr/local/bin:$PATH;"
		else
			display alert "ImageMagick not found! Expected to find Imagemagick's `convert` in \"/opt/homebrew/bin\" (ARM) or \"/usr/local/bin\" (X86), but nothing was found." & linefeed & linefeed & "Please set your path(s) manually in the script; see the comment around line 33." as warning
			error number -128
		end if
	end tell
	set binPath of theDefaults to binPath
end if

# Collect files
tell application "Finder"
	set trgImages to selection as alias list
	repeat while (count of trgImages) < 1
		display alert "Please select one or more image files (PNG) in the Finder." as warning buttons {"Cancel", "Continue"}
		if the result's button returned is "Cancel" then error number -128
		set trgImages to selection as alias list
	end repeat
end tell

# Get options. We can choose one of the first group + Quantize.
set prevOptions to options
tell application (path to frontmost application as text)
	set options to choose from list {"Drop Shadow…", "Drop Shadow", "Polaroid…", "Polaroid", "Polaroid w/Caption…", "Torn Edges", "Torn Edges +Shadow", "Thick", "--------------", "Quantize", "--------------", "Resize to 50 %", "Resize to 70  %", "Resize to 75 %", "Resize to 80 %", "Resize to 85 %", "Resize to 90 %", "Shrink to 300 px Width", "Shrink to 350 px Width", "Shrink to 400 px Width", "USM for Original Size", "--------------", "Faster Compression", "--------------", "Pre- & Postprocessing Only", "Help"} with title "Actions & Options" with prompt "⌘-Click for multiple selection (up to 1 per group)." OK button name "OK" cancel button name "Cancel" default items options multiple selections allowed yes empty selection allowed no
	if options is false then error number -128
end tell

# Customization for some options
if options contains "Drop Shadow…" then
	set shadowValue to the text returned of (display dialog "Set new shadow parameters (default: `80x3+2+2`):" default answer shadowValue buttons {"Cancel", "Save & Run"} default button "Save & Run")
	set shadowValue of theDefaults to shadowValue
	set item 1 of options to "Drop Shadow"
else if options contains "Polaroid…" then
	set theResult to (display dialog "Set new polaroid angle (default `-.5`):" default answer polaroidValue buttons {"Cancel", "Save & Relaunch", "Save & Run"} default button "Save & Run")
	set polaroidValue to theResult's text returned
	set polaroidValue of theDefaults to polaroidValue
	if the theResult's button returned is "Save & Relaunch" then
		set item 1 of options to "Polaroid w/Caption…"
		set options of theDefaults to options
		run me
		return
	else
		set item 1 of options to "Polaroid"
	end if
end if


# Set options
if options contains "Drop Shadow" then
	# http://www.imagemagick.org/Usage/blur/#shadow
	set option1 to "\\( +clone -background black -shadow" & space & shadowValue & space & "\\) +swap -background none -layers merge +repage"
else if options contains "Polaroid" then
	# http://www.imagemagick.org/Usage/transform/#polaroid
	# Nice colors: *OldLace, linen, *WhiteSmoke, moccasin, AntiqueWhite, PapayaWhip
	set option1 to "-bordercolor WhiteSmoke -background gray30 -polaroid" & space & polaroidValue & space & "-unsharp" & space & usmValueForPolaroid
else if options contains "Polaroid w/Caption…" then
	set polaroidCaption to the text returned of (display dialog "Set caption:" default answer polaroidCaption)
	set polaroidCaption of theDefaults to polaroidCaption
	set option1 to "-bordercolor GhostWhite -background gray30" & space & polaroidCaption & space & "-polaroid" & space & polaroidValue & space & "-unsharp" & space & usmValueForPolaroid
else if options contains "Torn Edges" then
	# http://www.imagemagick.org/Usage/thumbnails/#torn
	set option1 to "\\( +clone -alpha extract -virtual-pixel black -spread 10 -blur 0x3 -threshold 50% -spread 1 -blur 0x.7 \\) -alpha off -compose Copy_Opacity -composite"
else if options contains "Torn Edges +Shadow" then
	set option1 to "\\( +clone -alpha extract -virtual-pixel black -spread 10 -blur 0x3 -threshold 50% -spread 1 -blur 0x.7 \\) -alpha off -compose Copy_Opacity -composite - | convert - \\( +clone -background black -shadow 50x2+2+2 \\) +swap -background none -layers merge +repage"
else if options contains "Thick" then
	# http://www.imagemagick.org/Usage/thumbnails/#thickness
	set option1 to "-alpha set \\( +clone -fill LightSteelBlue3 -colorize 100% -repage +0+1 \\) \\( +clone -repage +1+2 \\) \\( +clone -repage +1+3 \\) \\( +clone -repage +2+4 \\) \\( +clone -repage +2+5 \\) \\( +clone -repage +3+6 \\) \\( +clone -repage +3+7 \\) \\( +clone -repage +4+8 \\) \\( +clone -repage +4+9 \\) -background none -compose DstOver -mosaic"
end if

set lastItem to -1
if item lastItem of options is "Help" then
	set options to prevOptions
	set theResult to display alert "Hints:" message helpMsg buttons {"Cancel", "Continue"} default button "Continue" cancel button "Cancel"
	delay 0.5
	run me
	return
else if item lastItem of options is "Pre- & Postprocessing Only" then
	set onlyPPP to true
	if (count of options) is 2 and item -2 of options is "Faster Compression" then
		# oxipng: our default is `-o max`; the empty string sets it to oxi's default (2 of 6)
		# `-q` if using zopfli
		set compression to ""
	end if
else
	# These options are combinable with the first option (option1); should always be the last item in the list
	if item lastItem of options is "Faster Compression" then
		# oxipng: our default is `-o max`; the empty string sets it to oxi's default (2 of 6)
		# `-q` if using zopfli
		set compression to ""
		set lastItem to -2
	end if
	tell item lastItem of options
		if it contains "%" then
			set scaleValue to word -1
			set option2 to "-scale" & space & scaleValue & "%" & space & "-unsharp" & space & usmValueForResized
		else if it contains "width" then
			set scaleValue to word -3
			set option2 to "-scale" & space & scaleValue & "\\>" & space & "-unsharp" & space & usmValueForResized
		else if it contains "USM" then
			set option2 to "-unsharp" & space & usmValueForUnchangedSize
		end if
	end tell
end if
set options of theDefaults to options

# Main part
repeat with image in trgImages
	set image to POSIX path of image
	set {head, extension} to splitPath(image)
	
	# Most of the stuff runs only on pngs
	if extension is "png" then
		preprocess(image, ppi)
		if onlyPPP then
			postprocess(image, compression)
		else
			if item 1 of options is "Quantize" and (count of options) is 1 then
				# For convenience, quantization only
				quantize(image, extension, head)
			else if options contains "Quantize" then
				# One IM command + quantization (as stdin/stdout combo)
				combo(image, extension, head, option1, option2)
			else
				# Only IM, without quantization
				prettify(image, extension, head, option1, option2)
			end if
			postprocess(outName, compression)
		end if
	else
		set nonPNGs to nonPNGs + 1
	end if
end repeat

display notification (((count of trgImages) - nonPNGs) as text) & " image(s) processed." with title "Screenshot Prettifier" sound name "Submarine"

if nonPNGs > 0 then
	display alert (nonPNGs as text) & " non-PNG files found. Only PNG files have been processed!" as warning buttons "OK"
end if


### Handlers #######################################################

# Get path components
on splitPath(path)
	set saveTID to AppleScript's text item delimiters
	set AppleScript's text item delimiters to {"."}
	set extension to text item -1 of path
	set head to (text items 1 through -2 of path) as text
	set AppleScript's text item delimiters to saveTID
	return {head, extension}
end splitPath

# A pure IM command
on prettify(image, extension, head, option1, option2)
	set outName to head & "-pty." & extension
	do shell script binPath & space & "convert" & space & quoted form of image & space & ¬
		option1 & space & option2 & space & quoted form of outName
end prettify

# Pure Pngquant
on quantize(image, extension, head)
	set outName to head & "-fs8." & extension
	do shell script binPath & space & "pngquant --floyd --skip-if-larger --force --speed=1 --output" & ¬
		space & quoted form of outName & space & quoted form of image
end quantize

# Both combined (preferable, since no intermediate file writing)
on combo(image, extension, head, option1, option2)
	set outName to head & "-pty-fs8." & extension
	do shell script binPath & space & "convert" & space & quoted form of image & space & ¬
		option1 & space & option2 & space & "- | pngquant - --floyd --force --speed=1 --output" & ¬
		space & quoted form of outName
end combo

on preprocess(input, ppi)
	if ppi is not "" then
		do shell script "sips -s dpiHeight" & space & ppi & space & "-s dpiWidth" & space & ppi & space & quoted form of input
	end if
end preprocess

on postprocess(input, compression)
	# zopfli: need to keep pHYs chunk for  ppi metadata; use `-q` for fast mode.
	--set {head, extension} to splitPath(input)
	--set outName to head & "-z." & extension
	-- do shell script binPath & space & "zopflipng --keepchunks=pHYs -y -q" & space & quoted form of input & space & quoted form of input
	# oxipng seems better currently; `-s` preserves the pHYs chunk:
	do shell script binPath & space & "oxipng" & space & compression & space & "-a -s" & space & quoted form of input
end postprocess

Edit 2024-03-18:

Version 0.9.9:

  • Added path detection for convert. This should make it compatible out of the box with both ARM and X86 Homebrew paths.
  • Path detection is only done if no path is set (usually the first run); if your bin path changes afterwards, delete the script's preferences file in ~/Library/Preferences and run it again (or set the path manually in the script, if your binaries are not in one of the two Homebrew standard paths; see comment around line 33 in the script).
2 Likes

Looks great. I believe I installed the dependencies but got this error running in AppleScript editor.

Is there any more setup to do?

" **error** "sh: convert: command not found" number 127"

at

**do shell script** binPath & space & "convert" & space & quoted form **of** image & space & ¬
option1 & space & option2 & space & quoted form **of** outName

convert is the ImageMagick command (a symlink to magick) and should be in /usr/local/bin, if installed via Homebrew.

In the Terminal, what does type -a convert return?

If it's in a different path, then you can adjust the path in the script's defaults, line 27, where it reads:

binPath:"export PATH=/usr/local/bin:$PATH;"

PS:

See also the post above, where @roskozmos reports a different Homebrew path. Possible that this path is used if you did a fresh Homebrew install recently.

Great, it's working!

Apparently on M1 macs the default path location for Homebrew is

binPath:"export PATH=/opt/homebrew/bin:$PATH;"

OK, I will add a path detection in the next version.

Amazing.

The features that would suit my needs (preparing images to add to my website or social media) but maybe not yours would be

  • Reduce width to (custom size).
    Or a way to add these options
  • Reduce quality to X%

Not expecting anything though! Great script

but maybe not yours

Yes, the scope of the script is to prettify screenshots for posting :wink:.

Reduce width to (custom size)

You have some "Resize to…" and "Shrink to…" options. I may add a Resize option with free user input though…

Reduce quality to X%

If you mean the quality setting of pngquant, in earlier versions I used the quality range parameter (e.g. --quality=70-95), but this turned out to be problematic because if pngquant cannot get a result within the range, it aborts. So it could work on one image, but not the next. I now use the default, which always works and seems to be pretty good anyway.

Free user input would also be possible here, but I doubt it would be of great use, because to make it really efficient you would have to try it for every image.

For your custom needs, I suggest to take the script as template (it contains many ImageMagick command lines, with or without user input) and replace them with the ones you actually need for your purpose.

Uploaded a new version with path detection. Updated download link and description in this post.

1 Like