Skip to content

Instantly share code, notes, and snippets.

@jgclark
Forked from ttscoff/autooptim.rb
Last active September 11, 2020 23:33
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jgclark/2f82e4a27a6157d5608cfc122b26891f to your computer and use it in GitHub Desktop.
Save jgclark/2f82e4a27a6157d5608cfc122b26891f to your computer and use it in GitHub Desktop.
Script intended for use with Hazel to resize/optimize web images based on directives in image filenames. Extended from ttscoff's original.
#!/usr/bin/ruby
# From Brett Terpstra <https://gist.github.com/ttscoff/d11fd063d0047bb0d4d235d2279e2085>
# extended by Jonathan Clark 2.4.2018 to allow original to be kept
# extended further, 11.9.2020 to allow borders to be added (currently white and/or black)
# and published at https://gist.github.com/jgclark/2f82e4a27a6157d5608cfc122b26891f
#
# Example:
# > file1@2x%%ohc.png
# => Converts png to jpeg, creates 1x and 2x versions, optimizes both with jpegoptim
#
# Available directives:
#
# %%[ochdkbw]rXXX[xXXX]
# o => optimize image
# c => convert png to jpg
# h => create a half size image (remove @2x or add _sm)
# k => keep original
# rXXX[xXXX] => resize to max-width or WxH
# b => add black border (default 2 px)
# w => add white border (default 8 px).
# If both borders are present, they are added in order they appear.
# Borders are added after resize and conversion operations.
#
# Requires jpegoptim, pngcrush, and convert (ImageMagick)
require 'fileutils'
ARGV.each do |arg|
input = File.expand_path(arg)
Process.exit 1 unless File.exist?(input)
extension = File.extname(input)
filename = File.basename(input, extension)
folder = File.dirname(input)
keep = false
next unless filename =~ /%%/
targets = []
m = filename.match(/%%([hcor\dxkbw]+)$/)
next if m.nil?
directives = m[1]
filename.sub!(/%%[hcor\dxkbw]+$/, '')
# Convert png -> jpg
if directives =~ /c/ && extension =~ /\.png/i
target = File.join(folder, filename + '.jpg')
print "Converting #{input} -> #{target}... "
res = system %(/usr/local/bin/convert "#{input}" -background white -flatten -alpha off "#{target}" &> /dev/null)
if res
puts 'OK'
FileUtils.mv input, File.expand_path('~/.Trash'), force: true unless keep
extension = '.jpg'
input = target
targets.push(target)
else
puts 'ERROR'
Process.exit 1
end
else
target = File.join(folder, filename + extension)
FileUtils.cp input, File.expand_path('~/.Trash') unless keep
FileUtils.mv input, target, force: true
input = target
targets.push(target)
end
if directives =~ /k/
keep = true
puts 'Will keep original'
end
# resize to max-width or WxH
if directives =~ /r(\d+(x(\d+))?)/
width = Regexp.last_match(1)
dim = Regexp.last_match(2).nil? ? "#{width}x#{width}" : "#{width}x#{Regexp.last_match(3)}"
if filename =~ /@2x$/ && directives =~ /h/
size = (width.to_i / 2).to_s
puts "#{width} / 2 = #{size}"
else
size = width.to_s
puts "Fullsize = #{size}"
end
filename.sub!(/(@2x)?$/, "-#{size}\\1")
resized = File.join(folder, filename + extension)
print "Resizing #{input} to #{dim} -> #{resized}... "
res = system %(/usr/local/bin/convert "#{input}" -adaptive-resize #{dim} "#{resized}" &> /dev/null)
if res
puts 'OK'
unless keep
FileUtils.mv input, File.expand_path('~/.Trash'), force: true
targets.delete(input)
end
targets.push(resized)
input = resized
else
puts 'ERROR'
Process.exit 1
end
end
# create a half size image (remove @2x or add _sm)
if directives =~ /h/
halfsize = if filename =~ /@2x$/
File.join(folder, filename.sub(/@2x$/, '') + extension)
else
File.join(folder, filename + '_sm' + extension)
end
print "Halving #{input} -> #{halfsize}... "
puts %(/usr/local/bin/convert "#{input}" -adaptive-resize 50% "#{halfsize}" &> /dev/null)
res = system %(/usr/local/bin/convert "#{input}" -adaptive-resize 50% "#{halfsize}" &> /dev/null)
if res
puts 'OK'
targets.push(halfsize)
else
puts 'ERROR'
Process.exit 1
end
end
# Add border(s)
if directives =~ /[wb]/
temp = File.join(folder, filename + '_temp' + extension)
if directives =~ /wb/
puts 'Adding white then black borders ...'
bordered = File.join(folder, filename + '_borderwb' + extension)
# it seems these can't both be done as one operation
res = system %(/usr/local/bin/convert "#{input}" -bordercolor white -border 8 "#{temp}" &> /dev/null)
unless res
puts 'ERROR'
Process.exit 1
end
res = system %(/usr/local/bin/convert "#{temp}" -bordercolor black -border 2 "#{bordered}" &> /dev/null)
elsif directives =~ /bw/
puts 'Adding black then white borders ...'
bordered = File.join(folder, filename + '_borderbw' + extension)
# it seems these can't both be done as one operation
res = system %(/usr/local/bin/convert "#{input}" -bordercolor black -border 2 "#{temp}" &> /dev/null)
unless res
puts 'ERROR'
Process.exit 1
end
res = system %(/usr/local/bin/convert "#{temp}" -bordercolor white -border 8 "#{bordered}" &> /dev/null)
elsif directives =~ /w/ && directives !~ /b/
puts 'Adding white border ...'
bordered = File.join(folder, filename + '_borderw' + extension)
res = system %(/usr/local/bin/convert "#{input}" -bordercolor white -border 8 "#{bordered}" &> /dev/null)
elsif directives =~ /b/ && directives !~ /w/
puts 'Adding black border ...'
bordered = File.join(folder, filename + '_borderb' + extension)
res = system %(/usr/local/bin/convert "#{input}" -bordercolor black -border 2 "#{bordered}" &> /dev/null)
end
if !res
puts 'ERROR'
Process.exit 1
else
puts 'OK'
targets.push(bordered)
# delete temporary file
FileUtils.mv temp, File.expand_path('~/.Trash'), force: true
unless keep
FileUtils.mv input, File.expand_path('~/.Trash'), force: true
targets.delete(input)
end
end
end
# Optimise target
next unless directives =~ /o/
targets.each do |target|
print "Optimizing #{target}... "
if target =~ /\.jpe?g$/i && File.exist?('/usr/local/bin/jpegoptim')
res = system %(/usr/local/bin/jpegoptim -fopt --strip-all -m80 -T10 "#{target}" &> /dev/null)
elsif target =~ /.png$/i && File.exist?('/usr/local/bin/pngcrush')
res = system %(/usr/local/bin/pngcrush -q -ow "#{target}" &> /dev/null)
end
puts res ? 'OK' : 'ERROR'
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment