Class: Middleman::WebP::Converter

Inherits:
Object
  • Object
show all
Defined in:
lib/middleman-webp/converter.rb

Overview

Handles finding image assets and running them through the conversion using external cwebp and gif2webp commandline tools

Constant Summary collapse

SUFFIX_RE =
/(jpe?g|png|tiff?|gif)$/i

Instance Method Summary collapse

Constructor Details

#initialize(app, builder, options = {}) ⇒ Converter

Returns a new instance of Converter.



11
12
13
14
15
# File 'lib/middleman-webp/converter.rb', line 11

def initialize(app, builder, options = {})
  @app = app
  @options = Middleman::WebP::Options.new(options)
  @builder = builder
end

Instance Method Details

#change_percentage(src_size, dst_size) ⇒ Object

Calculate change percentage of converted file size

src - File instance of the source dst - File instance of the destination

Examples

change_percentage(100, 75)
# => '25 %'

Returns percentage as string.



82
83
84
85
86
# File 'lib/middleman-webp/converter.rb', line 82

def change_percentage(src_size, dst_size)
  return '0 %' if src_size == 0

  format('%g %%', format('%.2f', 100 - 100.0 * dst_size / src_size))
end

#convertObject



17
18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/middleman-webp/converter.rb', line 17

def convert
  @original_size = 0
  @converted_size = 0

  convert_images(image_files) do |src, dst|
    next reject_file(dst) if @options.allow_skip && dst.size >= src.size

    @original_size += src.size
    @converted_size += dst.size
    @builder.trigger :created, "#{dst.path} "\
      "(#{change_percentage(src.size, dst.size)} smaller)"
  end
  print_summary
end

#convert_images(paths, &_after_conversion) ⇒ Object



32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/middleman-webp/converter.rb', line 32

def convert_images(paths, &_after_conversion)
  paths.each do |p|
    begin
      dst = destination_path(p)
      exec_convert_tool(p, dst)
      yield (src_file = File.new(p)), (dest_file = File.new(dst.to_s))
    rescue StandardError => e
      @builder.trigger :error, "Converting #{p} failed", e.backtrace
    ensure
      src_file&.close
      dest_file&.close
    end
  end
end

#destination_path(src_path) ⇒ Object



88
89
90
91
92
93
94
95
# File 'lib/middleman-webp/converter.rb', line 88

def destination_path(src_path)
  dst_name = if @options.append_extension
               "#{src_path.basename}.webp"
             else
               src_path.basename.to_s.gsub(SUFFIX_RE, 'webp')
             end
  src_path.parent.join(dst_name)
end

#exec_convert_tool(src, dst) ⇒ Object



47
48
49
50
# File 'lib/middleman-webp/converter.rb', line 47

def exec_convert_tool(src, dst)
  cmd = "#{tool_for(src)} #{@options.for(src)} -quiet #{src} -o #{dst}"
  @builder.thor.run(cmd, verbose: @options.verbose, capture: true)
end

#image_filesObject



97
98
99
100
101
102
103
104
105
# File 'lib/middleman-webp/converter.rb', line 97

def image_files
  all = ::Middleman::Util.all_files_under(site_dir)
  images = all.select { |p| p.to_s =~ SUFFIX_RE }

  # Reject files matching possible ignore patterns
  @options.ignore.reduce(images) do |arr, matcher|
    arr.select { |path| !matcher.matches? path }
  end
end

#number_to_human_size(n) ⇒ Object

Output file size using most human friendly multiple of byte eg. MiB.

n - size in bytes

Examples

number_to_human_size(12345)
# => '12.06 KiB'

Returns string containing size and unit.



118
119
120
121
122
123
124
125
# File 'lib/middleman-webp/converter.rb', line 118

def number_to_human_size(n)
  return "#{n} B" if n <= 0

  units = %w(B KiB MiB GiB TiB PiB)
  exponent = (Math.log(n) / Math.log(1024)).to_i
  format("%g #{units[exponent]}",
         format('%.2f', n.to_f / 1024**exponent))
end


64
65
66
67
68
69
# File 'lib/middleman-webp/converter.rb', line 64

def print_summary
  savings = @original_size - @converted_size
  @builder.trigger :webp, '', 'Total conversion savings: '\
    "#{number_to_human_size(savings)} "\
    "(#{change_percentage(@original_size, @converted_size)})"
end

#reject_file(file) ⇒ Object



59
60
61
62
# File 'lib/middleman-webp/converter.rb', line 59

def reject_file(file)
  @builder.trigger :deleted, "#{file.path} skipped"
  File.unlink(file)
end

#tool_for(file) ⇒ Object

Internal: Return proper tool command based on file type

file - Filename



55
56
57
# File 'lib/middleman-webp/converter.rb', line 55

def tool_for(file)
  file.to_s =~ /gif$/i ? 'gif2webp' : 'cwebp'
end