module Middleman module WebP class Converter def initialize(app, builder) @app = app @builder = builder end def convert @total = 0 convert_images(image_files) do |src, dst| next reject_file(dst) if dst.size >= src.size @total += (src.size - dst.size) @builder.say_status :webp, "#{dst.path} (#{change_percentage(src,dst)} smaller)" end @builder.say_status(:webp, "Total conversion savings: #{number_to_human_size(@total)}", :blue) end def convert_images(paths, &after_conversion) paths.each do |p| dst = destination_path(p) if p.to_s =~ /gif$/i run_gif2webp(p, dst) else run_cwebp(p, dst) end yield File.new(p), File.new(dst) end end def run_cwebp(src, dst) system("cwebp -quiet #{src} -o #{dst}") end def run_gif2webp(src, dst) system("gif2webp -quiet #{src} -o #{dst}") end def reject_file(file) @builder.say_status :webp, "#{file.path} skipped", :yellow File.unlink(file) end # Calculate change percentage of converted file size # # src - File instance of the source # dst - File instance of the destination def change_percentage(src, dst) "%.2f%%" % [100 - 100.0 * dst.size / src.size] end def destination_path(src_path) dst_name = src_path.basename.to_s.gsub(/(jpe?g|png|tiff?|gif)$/, "webp") src_path.parent.join(dst_name) end def image_files all = ::Middleman::Util.all_files_under(@app.inst.build_dir) all.select {|p| p.to_s =~ /(jpe?g|png|tiff?|gif)$/i } end def number_to_human_size(n) units = %w{B KiB MiB GiB TiB PiB} exponent = (Math.log(n) / Math.log(1024)).to_i "%g #{units[exponent]}" % ("%.2f" % (n.to_f / 1024**exponent)) end end end end