Created
May 13, 2015 08:46
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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