Class: ImageOptim

Inherits:
Object
  • Object
show all
Includes:
OptionHelpers
Defined in:
lib/image_optim.rb,
lib/image_optim/worker.rb,
lib/image_optim/image_path.rb,
lib/image_optim/worker/advpng.rb,
lib/image_optim/worker/pngout.rb,
lib/image_optim/option_helpers.rb,
lib/image_optim/worker/optipng.rb,
lib/image_optim/worker/gifsicle.rb,
lib/image_optim/worker/jpegtran.rb,
lib/image_optim/worker/pngcrush.rb,
lib/image_optim/worker/jpegoptim.rb

Defined Under Namespace

Modules: OptionHelpers Classes: BinNotFoundError, ConfigurationError, ImagePath, TrueFalseNil, Worker

Constant Summary collapse

VENDOR_PATH =
File.expand_path('../../vendor', __FILE__)

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from OptionHelpers

#assert_options_empty!, #get_option!, limit_with_range

Constructor Details

#initialize(options = {}) ⇒ ImageOptim

Initialize workers, specify options using worker underscored name:

pass false to disable worker

ImageOptim.new(:pngcrush => false)

or hash with options to worker

ImageOptim.new(:advpng => {:level => 3}, :optipng => {:level => 2})

use :threads to set number of parallel optimizers to run (passing true or nil determines number of processors, false disables parallel processing)

ImageOptim.new(:threads => 8)

use :nice to specify optimizers nice level (true or nil makes it 10, false makes it 0)

ImageOptim.new(:nice => 20)


45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/image_optim.rb', line 45

def initialize(options = {})
  @resolved_bins = {}
  @resolver_lock = Mutex.new

  nice = options.delete(:nice)
  @nice = case nice
  when true, nil
    10
  when false
    0
  else
    nice.to_i
  end

  threads = options.delete(:threads)
  threads = case threads
  when true, nil
    processor_count
  when false
    1
  else
    threads.to_i
  end
  @threads = OptionHelpers.limit_with_range(threads, 1..16)

  @verbose = !!options.delete(:verbose)

  @workers_by_format = {}
  Worker.klasses.each do |klass|
    case worker_options = options.delete(klass.bin_sym)
    when Hash
    when true, nil
      worker_options = {}
    when false
      next
    else
      raise ConfigurationError, "Got #{worker_options.inspect} for #{klass.name} options"
    end
    worker = klass.new(self, worker_options)
    worker.image_formats.each do |format|
      @workers_by_format[format] ||= []
      @workers_by_format[format] << worker
    end
  end
  @workers_by_format.each do |format, workers|
    workers.replace workers.sort_by(&:run_order) # There is no sort_by! in ruby 1.8
  end

  assert_options_empty!(options)
end

Instance Attribute Details

#niceObject (readonly)

Nice level



18
19
20
# File 'lib/image_optim.rb', line 18

def nice
  @nice
end

#resolve_dirObject (readonly)

Temp directory for symlinks to bins with path coming from ENV



165
166
167
# File 'lib/image_optim.rb', line 165

def resolve_dir
  @resolve_dir
end

#threadsObject (readonly)

Number of threads to run with



21
22
23
# File 'lib/image_optim.rb', line 21

def threads
  @threads
end

Class Method Details

.method_missing(method, *args, &block) ⇒ Object

Optimization methods with default options



146
147
148
149
150
151
152
# File 'lib/image_optim.rb', line 146

def self.method_missing(method, *args, &block)
  if method.to_s =~ /^optimize_images?\!?$/
    new.send(method, *args, &block)
  else
    super
  end
end

.versionObject

Version of image_optim gem spec loaded



155
156
157
# File 'lib/image_optim.rb', line 155

def self.version
  Gem.loaded_specs['image_optim'].version.to_s rescue 'DEV'
end

Instance Method Details

#env_pathObject

Join resolve_dir, default path and vendor path for PATH environment variable



193
194
195
# File 'lib/image_optim.rb', line 193

def env_path
  "#{resolve_dir}:#{ENV['PATH']}:#{VENDOR_PATH}"
end

#optimizable?(path) ⇒ Boolean

Are there workers for file at path?

Returns:

  • (Boolean)


160
161
162
# File 'lib/image_optim.rb', line 160

def optimizable?(path)
  !!workers_for_image(path)
end

#optimize_image(original) ⇒ Object

Optimize one file, return new path or nil if optimization failed



102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/image_optim.rb', line 102

def optimize_image(original)
  original = ImagePath.new(original)
  if workers = workers_for_image(original)
    result = nil
    ts = [original, original.temp_path]
    workers.each do |worker|
      if result && ts.length < 3
        ts << original.temp_path
      end
      if worker.optimize(*ts.last(2))
        result = ts.last
        if ts.length == 3
          ts[-2, 2] = ts[-1], ts[-2]
        end
      end
    end
    result
  end
end

#optimize_image!(original) ⇒ Object

Optimize one file in place, return optimization status



123
124
125
126
127
128
129
# File 'lib/image_optim.rb', line 123

def optimize_image!(original)
  original = ImagePath.new(original)
  if result = optimize_image(original)
    result.replace(original)
    true
  end
end

#optimize_images(paths, &block) ⇒ Object

Optimize multiple images if block given yields path and result for each image and returns array of yield results else return array of results



134
135
136
# File 'lib/image_optim.rb', line 134

def optimize_images(paths, &block)
  run_method_for(paths, :optimize_image, &block)
end

#optimize_images!(paths, &block) ⇒ Object

Optimize multiple images in place if block given yields path and result for each image and returns array of yield results else return array of results



141
142
143
# File 'lib/image_optim.rb', line 141

def optimize_images!(paths, &block)
  run_method_for(paths, :optimize_image!, &block)
end

#resolve_bin!(bin) ⇒ Object

Check existance of binary, create symlink if ENV contains path for key XXX_BIN where XXX is upper case bin name



168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# File 'lib/image_optim.rb', line 168

def resolve_bin!(bin)
  bin = bin.to_sym
  @resolved_bins.include?(bin) || @resolver_lock.synchronize do
    @resolved_bins.include?(bin) || begin
      if path = ENV["#{bin}_bin".upcase]
        unless @resolve_dir
          @resolve_dir = FSPath.temp_dir
          at_exit{ FileUtils.remove_entry_secure @resolve_dir }
        end
        symlink = @resolve_dir / bin
        symlink.make_symlink(File.expand_path(path))
        at_exit{ symlink.unlink }

        @resolved_bins[bin] = bin_accessible?(symlink)
      else
        @resolved_bins[bin] = bin_accessible?(bin)
      end
    end
  end
  @resolved_bins[bin] or raise BinNotFoundError, "`#{bin}` not found"
end

#verbose?Boolean

Verbose output?

Returns:

  • (Boolean)


24
25
26
# File 'lib/image_optim.rb', line 24

def verbose?
  @verbose
end

#workers_for_image(path) ⇒ Object

Get workers for image



97
98
99
# File 'lib/image_optim.rb', line 97

def workers_for_image(path)
  @workers_by_format[ImagePath.new(path).format]
end