Skip to content

Instantly share code, notes, and snippets.

@weibel
Created May 13, 2015 08:46
Show Gist options
  • Select an option

  • Save weibel/bffe877d83be7acfe3a2 to your computer and use it in GitHub Desktop.

Select an option

Save weibel/bffe877d83be7acfe3a2 to your computer and use it in GitHub Desktop.
OSX ImageOptimizer and pngquant ruby script to be run regularly by cron. Saves an image hash to prevent reprocessing of already processed images. Can be used for optimizing images in e.g. an iOS project.
module ImageOptimizer
module Optimizer
class Launch
def initialize(args)
@meta_manager = FileMeta::Manager.new(args[:db_name])
@png_optimizer = Optimizers::PNGOptimizer.new(args[:pngquant_quality_range])
end
# Use this for i.e. a rake task
def self.optimize_images
optim = ImageOptimizer::Optimizer::Launch.new({db_name: 'optimized_image_fingerprints.json',
pngquant_quality_range: '100-100'})
optim.optimize!
end
def optimize!
files = @png_optimizer.files_in_path.select { |file| !@meta_manager.same?(file) }
if (files.count > 0)
total_before_size = files_size(files)
optimize_alpha!(files)
optimize_compression!(files)
total_after_size = files_size(files)
p "Total gain: #{gain_percentage(total_before_size, total_after_size).round(2)}%, #{((total_before_size - total_after_size).to_f/1024/1024).round(2)}Mb" if total_before_size > 0
write_meta(files)
else
p "No changes, exiting"
end
end
def optimize_alpha!(files)
i = 1
count = files.count
files.each do |file|
before_size = File.size(file)
@png_optimizer.optimize_alpha!(file)
after_size = File.size(file)
p "Alpha Optimized #{i} of #{count}, gain: #{gain_percentage(before_size, after_size).round(2)}%, path:#{file}" if before_size > 0
i += 1
end
end
def optimize_compression!(files)
@png_optimizer.optimize_compression!(files)
end
def write_meta(files)
files.each { |file| @meta_manager.set_meta(file) }
@meta_manager.write_to_disk
end
def files_size(files)
total_before_size = 0
files.each { |file| total_before_size += File.size(file) }
total_before_size
end
def gain_percentage(before, after)
((1.0-((after.to_f)/(before.to_f)))*100.0)
end
end
end
module FileMeta
require 'digest'
require 'JSON'
class Manager
def initialize(json_filename)
@json_filename = json_filename
@paths = read_from_disk
end
def same?(path)
compute_meta(path) == get_meta(path)
end
def compute_meta(path)
sha256 = Digest::SHA256.file(path)
sha256.hexdigest
end
def set_meta(path)
@paths[path] = compute_meta(path)
end
def get_meta(path)
@paths[path]
end
def read_from_disk
if File.exist?(@json_filename)
@paths = JSON.parse(IO.read(@json_filename))
else
{}
end
end
def write_to_disk
if !File.exist?(@json_filename)
file = File.open(@json_filename, 'w')
else
file = File.open(@json_filename, 'r+')
end
JSON.dump(@paths, file)
end
end
end
module Optimizers
require 'find'
class BaseOptimizer
def initialize(file_types)
@file_types = file_types
end
def files_in_path
file_paths = []
Find.find(Dir.pwd) do |path|
@file_types.each do |type|
file_paths << path if path =~ /.*\.#{type}$/
end
end
file_paths
end
end
class PNGOptimizer < BaseOptimizer
def initialize(pngquant_quality_range = '0-100')
super(%w{png})
@pngquant_quality_range = pngquant_quality_range
end
def optimize_alpha!(path)
%x(pngquant --force --ext '.png' --speed 1 --skip-if-larger --nofs --quality #{@pngquant_quality_range} '#{path}')
end
def optimize_compression!(files)
%x(/Applications/ImageOptim.app/Contents/MacOS/ImageOptim #{files.map { |file| "'#{file}'" }.join(' ')})
end
end
# JPGOptimizer is left unimplemented
class JPGOptimizer < BaseOptimizer
def initialize
super(%w{jpg jpeg})
end
def optimize_file!(path)
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment