image_optim 0.21.0 → 0.22.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- MzU4OTIxMDYxM2E3MjAyOTk3NGEzOTg1MjY0NzY0OGE2YTVkZGNiMA==
4
+ NGEwM2UzY2VlZmU0OWJmNzg2YTAyMDZlNWM1MzM5ZWVhNDAyOTg3Mw==
5
5
  data.tar.gz: !binary |-
6
- M2E0MzhmYWQ2MGJjMDIzOWJkMDg3ODNhZDg5NmVjMTNhODRiMDMxMg==
6
+ YTE0YzA1YjQ2NzU3NDIxZjFjNzA4ZGVjOGFmNGY4YTgxMjhiODlhZA==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- NWI2M2EyYzdjOTVmYjVlNmY3YjQ5ZTc4ZTg1NGFmNTBmODQ2NzI5MDBjZjEy
10
- MDlkMDI4NTNmNWYyMDAyOTcyN2ZhMWY4ZDA3ZjZlNGQwMmQ5MGY2ODdjMWRh
11
- ODM1MWVlMTkyM2EyMWQ2NjEzMGMwOWZhNWIwNDZjNDg1MjZjMmM=
9
+ YjI3M2JhYmExNTg2OTg2OGI1NWU5YWEwM2Y4MjNmOWRhNjcwM2EwZmFjOTQz
10
+ ZjI2MzBiZjcwZWIwMjQ0ZWUwOTFlODNjZjU0NThmMDhjYWUzMTE2ZTVmOGFm
11
+ NGM1ZWMzMjYyODZmZTUzZjk2NzljMTY1MDg1M2Y4NmZmNTMwZTY=
12
12
  data.tar.gz: !binary |-
13
- MmExY2E0YzJlODkwM2EwOTdiODI3ZTU4ZjU4ODNmNmQ4ZDQ1ZWQwZDczMDc3
14
- YThiMTdlNGI5ODc3M2NiODkzMDRkMDU0MGUyOWUzZWRiZDcwMDYyM2U5NTQ3
15
- NzZmNzc0NzhiOGE0ZTFhMmFlMGU1ODA4YjUzYzQxYzc0YTViYTg=
13
+ NTQxYjc1MWI2OTgzNzNhOTliMGRjMjgwMTBlMDBjZDdjYmRlN2RjOTVhNTk0
14
+ YjE0NzczOWE0NzZjMWMzOGM4NWFlZTg0ZjAzZWQ3NTNjZGRhYTVkNjc2ZjUx
15
+ OWQ3ODZmZGE2MmMxMWM1YmU1NjI0NzljNDE4MjE4MDdjYzliOTU=
@@ -20,9 +20,6 @@ Metrics/MethodLength:
20
20
  Metrics/PerceivedComplexity:
21
21
  Max: 8
22
22
 
23
- Performance/ParallelAssignment:
24
- Enabled: false
25
-
26
23
  Style/AccessModifierIndentation:
27
24
  EnforcedStyle: outdent
28
25
 
@@ -47,6 +44,9 @@ Style/IfUnlessModifier:
47
44
  Style/IndentHash:
48
45
  EnforcedStyle: consistent
49
46
 
47
+ Style/ParallelAssignment:
48
+ Enabled: false
49
+
50
50
  Style/PercentLiteralDelimiters:
51
51
  PreferredDelimiters:
52
52
  '%w': '[]'
@@ -1,3 +1,4 @@
1
+ sudo: false
1
2
  language: ruby
2
3
  rvm:
3
4
  - 1.8.7
@@ -6,7 +7,6 @@ rvm:
6
7
  - '2.0'
7
8
  - '2.1'
8
9
  - '2.2'
9
- - jruby-18mode
10
10
  - jruby-19mode
11
11
  - ree
12
12
  script:
@@ -36,6 +36,8 @@ matrix:
36
36
  rvm: default
37
37
  - env: RUBOCOP=true
38
38
  rvm: default
39
+ allow_failures:
40
+ - rvm: jruby-19mode
39
41
  addons:
40
42
  code_climate:
41
43
  repo_token:
@@ -2,6 +2,14 @@
2
2
 
3
3
  ## unreleased
4
4
 
5
+ ## v0.22.0 (2015-11-21)
6
+
7
+ * Unify getting description of option default value using `default_description` [@toy](https://github.com/toy)
8
+ * Don't use `-strip` option for optipng when the bin version is less than 0.7 [#106](https://github.com/toy/image_optim/issues/106) [@toy](https://github.com/toy)
9
+ * Use quality `0..100` by default in lossy mode of pngquant worker [#77](https://github.com/toy/image_optim/issues/77) [@toy](https://github.com/toy)
10
+ * Add `:disable_plugins` and `:enable_plugins` options to `svgo` worker [#110](https://github.com/toy/image_optim/pull/110) [@tomhughes](https://github.com/tomhughes)
11
+ * Allow setting config in rails like `config.assets.image_optim.name = value` [#111](https://github.com/toy/image_optim/pull/111) [@toy](https://github.com/toy)
12
+
5
13
  ## v0.21.0 (2015-05-30)
6
14
 
7
15
  * Use exifr 1.2.2 with fix for a bug [#85](https://github.com/toy/image_optim/issues/85) [@toy](https://github.com/toy)
@@ -277,50 +277,51 @@ Worker can be disabled by passing `false` instead of options hash or by setting
277
277
  <!---<worker-options>-->
278
278
  <!-- markdown for worker options is generated by `script/update_worker_options_in_readme` -->
279
279
 
280
- ### :advpng =>
280
+ ### advpng:
281
281
  * `:level` — Compression level: `0` - don't compress, `1` - fast, `2` - normal, `3` - extra, `4` - extreme *(defaults to `4`)*
282
282
 
283
- ### :gifsicle =>
283
+ ### gifsicle:
284
284
  * `:interlace` — Interlace: `true` - interlace on, `false` - interlace off, `nil` - as is in original image (defaults to running two instances, one with interlace off and one with on)
285
285
  * `:level` — Compression level: `1` - light and fast, `2` - normal, `3` - heavy (slower) *(defaults to `3`)*
286
286
  * `:careful` — Avoid bugs with some software *(defaults to `false`)*
287
287
 
288
- ### :jhead =>
288
+ ### jhead:
289
289
  Worker has no options
290
290
 
291
- ### :jpegoptim =>
291
+ ### jpegoptim:
292
292
  * `:strip` — List of extra markers to strip: `:comments`, `:exif`, `:iptc`, `:icc` or `:all` *(defaults to `:all`)*
293
293
  * `:max_quality` — Maximum image quality factor `0`..`100`, ignored in default/lossless mode *(defaults to `100`)*
294
294
 
295
- ### :jpegrecompress =>
295
+ ### jpegrecompress:
296
296
  * `:quality` — JPEG quality preset: `0` - low, `1` - medium, `2` - high, `3` - veryhigh *(defaults to `3`)*
297
297
 
298
- ### :jpegtran =>
298
+ ### jpegtran:
299
299
  * `:copy_chunks` — Copy all chunks *(defaults to `false`)*
300
300
  * `:progressive` — Create progressive JPEG file *(defaults to `true`)*
301
301
  * `:jpegrescan` — Use jpegtran through jpegrescan, ignore progressive option *(defaults to `false`)*
302
302
 
303
- ### :optipng =>
303
+ ### optipng:
304
304
  * `:level` — Optimization level preset: `0` is least, `7` is best *(defaults to `6`)*
305
305
  * `:interlace` — Interlace: `true` - interlace on, `false` - interlace off, `nil` - as is in original image *(defaults to `false`)*
306
306
  * `:strip` — Remove all auxiliary chunks *(defaults to `true`)*
307
307
 
308
- ### :pngcrush =>
308
+ ### pngcrush:
309
309
  * `:chunks` — List of chunks to remove or `:alla` - all except tRNS/transparency or `:allb` - all except tRNS and gAMA/gamma *(defaults to `:alla`)*
310
310
  * `:fix` — Fix otherwise fatal conditions such as bad CRCs *(defaults to `false`)*
311
311
  * `:brute` — Brute force try all methods, very time-consuming and generally not worthwhile *(defaults to `false`)*
312
312
  * `:blacken` — Blacken fully transparent pixels *(defaults to `true`)*
313
313
 
314
- ### :pngout =>
314
+ ### pngout:
315
315
  * `:copy_chunks` — Copy optional chunks *(defaults to `false`)*
316
316
  * `:strategy` — Strategy: `0` - xtreme, `1` - intense, `2` - longest Match, `3` - huffman Only, `4` - uncompressed *(defaults to `0`)*
317
317
 
318
- ### :pngquant =>
319
- * `:quality` — min..max - don't save below min, use less colors below max (both in range `0..100`; in yaml - `!ruby/range 0..100`), ignored in default/lossless mode *(defaults to `100..100`)*
318
+ ### pngquant:
319
+ * `:quality` — min..max - don't save below min, use less colors below max (both in range `0..100`; in yaml - `!ruby/range 0..100`), ignored in default/lossless mode *(defaults to `100..100`, `0..100` in lossy mode)*
320
320
  * `:speed` — speed/quality trade-off: `1` - slow, `3` - default, `11` - fast & rough *(defaults to `3`)*
321
321
 
322
- ### :svgo =>
323
- Worker has no options
322
+ ### svgo:
323
+ * `:disable_plugins` List of plugins to disable *(defaults to `[]`)*
324
+ * `:enable_plugins` — List of plugins to enable *(defaults to `[]`)*
324
325
 
325
326
  <!---</worker-options>-->
326
327
 
@@ -1,15 +1,22 @@
1
1
  VAGRANTFILE_API_VERSION = '2'
2
2
 
3
3
  Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
4
- config.vm.box = 'ubuntu/trusty64'
4
+ config.vm.box = 'ubuntu/precise64'
5
5
 
6
6
  config.vm.provision 'shell', :inline => <<-SH
7
7
  set -e
8
8
 
9
9
  cd /vagrant
10
10
 
11
- echo 'Install git, node, npm, imagemagick...'
12
- apt-get install -y git npm nodejs-legacy imagemagick > /dev/null
11
+ echo 'apt-get update...'
12
+ apt-get update > /dev/null
13
+
14
+ echo 'Install git, imagemagick, ruby1.9.1-dev...'
15
+ apt-get install -y git npm imagemagick ruby1.9.1-dev > /dev/null
16
+
17
+ echo 'Install node, npm...'
18
+ curl -sL https://deb.nodesource.com/setup | sudo bash - > /dev/null
19
+ sudo apt-get install -y nodejs > /dev/null
13
20
 
14
21
  echo 'Update rubygems...'
15
22
  REALLY_GEM_UPDATE_SYSTEM=x gem update --system > /dev/null
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = 'image_optim'
5
- s.version = '0.21.0'
5
+ s.version = '0.22.0'
6
6
  s.summary = %q{Optimize (lossless compress, optionally lossy) images (jpeg, png, gif, svg) using external utilities (advpng, gifsicle, jhead, jpeg-recompress, jpegoptim, jpegrescan, jpegtran, optipng, pngcrush, pngout, pngquant, svgo)}
7
7
  s.homepage = "http://github.com/toy/#{s.name}"
8
8
  s.authors = ['Ivan Kuchin']
@@ -24,6 +24,6 @@ Gem::Specification.new do |s|
24
24
  s.add_development_dependency 'image_optim_pack', '~> 0.2'
25
25
  s.add_development_dependency 'rspec', '~> 3.0'
26
26
  if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('1.9.3')
27
- s.add_development_dependency 'rubocop', '~> 0.27', '!= 0.30.1'
27
+ s.add_development_dependency 'rubocop', '~> 0.35'
28
28
  end
29
29
  end
@@ -163,7 +163,9 @@ class ImageOptim
163
163
 
164
164
  # Version of image_optim gem spec loaded
165
165
  def self.version
166
- Gem.loaded_specs['image_optim'].version.to_s rescue 'DEV'
166
+ Gem.loaded_specs['image_optim'].version.to_s
167
+ rescue
168
+ 'DEV'
167
169
  end
168
170
 
169
171
  # Full version of image_optim
@@ -36,6 +36,7 @@ class ImageOptim
36
36
  [:gifsicle, is < '1.85', 'does not support removing extension blocks'],
37
37
  [:pngcrush, is < '1.7.38', 'does not have blacken flag'],
38
38
  [:pngquant, is < '2.1', 'may be lossy even with quality `100-`'],
39
+ [:optipng, is < '0.7', 'does not support -strip option'],
39
40
  ]
40
41
 
41
42
  # Fail if version will not work properly
@@ -28,5 +28,11 @@ class ImageOptim
28
28
  value
29
29
  end
30
30
  end
31
+
32
+ # Describe default value, returns string as is otherwise surrounds
33
+ # inspected value with backticks
34
+ def default_description
35
+ default.is_a?(String) ? default : "`#{default.inspect}`"
36
+ end
31
37
  end
32
38
  end
@@ -3,6 +3,16 @@ require 'image_optim'
3
3
  class ImageOptim
4
4
  # Adds image_optim as preprocessor for gif, jpeg, png and svg images
5
5
  class Railtie < Rails::Railtie
6
+ config.before_configuration do |app|
7
+ worker_names = ImageOptim::Worker.klasses.map(&:bin_sym)
8
+ app.config.assets.image_optim =
9
+ ActiveSupport::OrderedOptions.new do |hash, key|
10
+ if worker_names.include?(key.to_sym)
11
+ hash[key] = ActiveSupport::OrderedOptions.new
12
+ end
13
+ end
14
+ end
15
+
6
16
  initializer 'image_optim.initializer' do |app|
7
17
  register_preprocessor(app) if register_preprocessor?(app)
8
18
  end
@@ -174,8 +174,8 @@ ImageOptim::Runner::OptionParser::DEFINE = proc do |op, options|
174
174
 
175
175
  bin = klass.bin_sym
176
176
  klass.option_definitions.each do |option_definition|
177
- name = option_definition.name.to_s.gsub('_', '-')
178
- default = option_definition.default
177
+ name = option_definition.name.to_s.tr('_', '-')
178
+ default = option_definition.default_description
179
179
  type = option_definition.type
180
180
 
181
181
  type, marking = case
@@ -37,7 +37,9 @@ class ImageOptim
37
37
  #{dst}
38
38
  ]
39
39
  args.unshift "-i#{interlace ? 1 : 0}" unless interlace.nil?
40
- args.unshift '-strip', 'all' if strip
40
+ if resolve_bin!(:optipng).version >= '0.7'
41
+ args.unshift '-strip', 'all' if strip
42
+ end
41
43
  execute(:optipng, *args) && optimized?(src, dst)
42
44
  end
43
45
  end
@@ -7,19 +7,24 @@ class ImageOptim
7
7
  # http://pngquant.org/
8
8
  class Pngquant < Worker
9
9
  QUALITY_OPTION =
10
- option(:quality, 100..100, NonNegativeIntegerRange, 'min..max - don\'t '\
11
- 'save below min, use less colors below max (both in range `0..100`; '\
12
- 'in yaml - `!ruby/range 0..100`), ignored in default/lossless '\
13
- 'mode') do |v, opt_def|
10
+ option(:quality, '`100..100`, `0..100` in lossy mode',
11
+ NonNegativeIntegerRange, 'min..max - don\'t '\
12
+ 'save below min, use less colors below max (both in range `0..100`; '\
13
+ 'in yaml - `!ruby/range 0..100`), ignored in default/lossless '\
14
+ 'mode') do |v, opt_def|
14
15
  if allow_lossy
15
- min = OptionHelpers.limit_with_range(v.begin, 0..100)
16
- min..OptionHelpers.limit_with_range(v.end, min..100)
16
+ if v == opt_def.default
17
+ 0..100
18
+ else
19
+ min = OptionHelpers.limit_with_range(v.begin, 0..100)
20
+ min..OptionHelpers.limit_with_range(v.end, min..100)
21
+ end
17
22
  else
18
23
  if v != opt_def.default
19
24
  warn "#{self.class.bin_sym} #{opt_def.name} #{v} ignored " \
20
25
  'in lossless mode'
21
26
  end
22
- opt_def.default
27
+ 100..100
23
28
  end
24
29
  end
25
30
 
@@ -4,11 +4,27 @@ class ImageOptim
4
4
  class Worker
5
5
  # https://github.com/svg/svgo
6
6
  class Svgo < Worker
7
+ DISABLE_PLUGINS_OPTION =
8
+ option(:disable_plugins, [], 'List of plugins to disable') do |v|
9
+ Array(v).map(&:to_s)
10
+ end
11
+
12
+ ENABLE_PLUGINS_OPTION =
13
+ option(:enable_plugins, [], 'List of plugins to enable') do |v|
14
+ Array(v).map(&:to_s)
15
+ end
16
+
7
17
  def optimize(src, dst)
8
18
  args = %W[
9
19
  --input #{src}
10
20
  --output #{dst}
11
21
  ]
22
+ disable_plugins.each do |plugin_name|
23
+ args.unshift "--disable=#{plugin_name}"
24
+ end
25
+ enable_plugins.each do |plugin_name|
26
+ args.unshift "--enable=#{plugin_name}"
27
+ end
12
28
  execute(:svgo, *args) && optimized?(src, dst)
13
29
  end
14
30
  end
@@ -12,14 +12,14 @@ GENERATED_NOTE = '<!-- markdown for worker options is generated by '\
12
12
  "`#{Pathname($PROGRAM_NAME).cleanpath}` -->"
13
13
 
14
14
  def write_worker_options(io, klass)
15
- io.puts "### :#{klass.bin_sym} =>"
15
+ io.puts "### #{klass.bin_sym}:"
16
16
  if klass.option_definitions.empty?
17
17
  io.puts 'Worker has no options'
18
18
  else
19
19
  klass.option_definitions.each do |option_definition|
20
20
  line = "* `:#{option_definition.name}` — #{option_definition.description}"
21
21
  unless line['(defaults']
22
- line << " *(defaults to `#{option_definition.default.inspect}`)*"
22
+ line << " *(defaults to #{option_definition.default_description})*"
23
23
  end
24
24
  io.puts line
25
25
  end
@@ -72,9 +72,7 @@ describe ImageOptim::Handler do
72
72
  expect(handler).to receive(:cleanup)
73
73
  expect(handler).to receive(:result).and_return(result)
74
74
 
75
- expect(Handler.for(original) do |h|
76
- h.process
77
- end).to eq(result)
75
+ expect(Handler.for(original, &:process)).to eq(result)
78
76
  end
79
77
 
80
78
  it 'cleans up if exception is raised' do
@@ -40,9 +40,7 @@ describe ImageOptim::HashHelpers do
40
40
  :b => 1,
41
41
  :c => {
42
42
  :d => 2,
43
- :e => {
44
- :f => true,
45
- },
43
+ :e => {:f => true},
46
44
  },
47
45
  },
48
46
  :y => 10,
@@ -0,0 +1,110 @@
1
+ require 'spec_helper'
2
+ require 'image_optim/option_definition'
3
+
4
+ describe ImageOptim::OptionDefinition do
5
+ describe 'initialization' do
6
+ context 'when type is not specified explicitly' do
7
+ subject{ described_class.new('abc', :def, 'desc') }
8
+
9
+ describe '#name' do
10
+ it{ expect(subject.name).to eq(:abc) }
11
+ end
12
+
13
+ describe '#default' do
14
+ it{ expect(subject.default).to eq(:def) }
15
+ end
16
+
17
+ describe '#type' do
18
+ it{ expect(subject.type).to eq(Symbol) }
19
+ end
20
+
21
+ describe '#description' do
22
+ it{ expect(subject.description).to eq('desc') }
23
+ end
24
+ end
25
+
26
+ context 'when type is specified explicitly' do
27
+ subject{ described_class.new('abc', :def, Hash, 'desc') }
28
+
29
+ describe '#name' do
30
+ it{ expect(subject.name).to eq(:abc) }
31
+ end
32
+
33
+ describe '#default' do
34
+ it{ expect(subject.default).to eq(:def) }
35
+ end
36
+
37
+ describe '#type' do
38
+ it{ expect(subject.type).to eq(Hash) }
39
+ end
40
+
41
+ describe '#description' do
42
+ it{ expect(subject.description).to eq('desc') }
43
+ end
44
+ end
45
+ end
46
+
47
+ describe '#value' do
48
+ context 'when proc not given' do
49
+ subject{ described_class.new('abc', :def, 'desc') }
50
+
51
+ context 'when option not provided' do
52
+ it 'returns default' do
53
+ expect(subject.value(nil, {})).to eq(:def)
54
+ end
55
+ end
56
+
57
+ context 'when option is nil' do
58
+ it 'returns nil' do
59
+ expect(subject.value(nil, :abc => nil)).to eq(nil)
60
+ end
61
+ end
62
+
63
+ context 'when option is set' do
64
+ it 'returns value' do
65
+ expect(subject.value(nil, :abc => 123)).to eq(123)
66
+ end
67
+ end
68
+ end
69
+
70
+ context 'when proc given' do
71
+ subject{ described_class.new('abc', :def, 'desc', &:inspect) }
72
+
73
+ context 'when option not provided' do
74
+ it 'returns default passed through proc' do
75
+ expect(subject.value(nil, {})).to eq(':def')
76
+ end
77
+ end
78
+
79
+ context 'when option is nil' do
80
+ it 'returns nil passed through proc' do
81
+ expect(subject.value(nil, :abc => nil)).to eq('nil')
82
+ end
83
+ end
84
+
85
+ context 'when option is set' do
86
+ it 'returns value passed through proc' do
87
+ expect(subject.value(nil, :abc => 123)).to eq('123')
88
+ end
89
+ end
90
+ end
91
+ end
92
+
93
+ describe '#default_description' do
94
+ context 'when default is not a string' do
95
+ subject{ described_class.new('abc', :def, 'desc') }
96
+
97
+ it 'returns inspected value in backticks' do
98
+ expect(subject.default_description).to eq('`:def`')
99
+ end
100
+ end
101
+
102
+ context 'when default is a string' do
103
+ subject{ described_class.new('abc', '`1`', 'desc') }
104
+
105
+ it 'returns it as is' do
106
+ expect(subject.default_description).to eq('`1`')
107
+ end
108
+ end
109
+ end
110
+ end
@@ -23,7 +23,6 @@ describe 'ImageOptim::Railtie' do
23
23
  assets.paths = %w[spec/images]
24
24
 
25
25
  assets.delete(:compress)
26
- assets.delete(:image_optim)
27
26
  end
28
27
 
29
28
  yield config if block_given?
@@ -68,14 +67,14 @@ describe 'ImageOptim::Railtie' do
68
67
  end
69
68
 
70
69
  it 'initializes with empty hash if config.assets.image_optim is true' do
71
- expect(ImageOptim).to receive(:new).with({}).and_call_original
70
+ expect(ImageOptim).to receive(:new).with({})
72
71
  init_rails_app do |config|
73
72
  config.assets.image_optim = true
74
73
  end
75
74
  end
76
75
 
77
76
  it 'initializes with empty hash if config.assets.image_optim is nil' do
78
- expect(ImageOptim).to receive(:new).with({}).and_call_original
77
+ expect(ImageOptim).to receive(:new).with({})
79
78
  init_rails_app do |config|
80
79
  config.assets.image_optim = nil
81
80
  end
@@ -88,6 +87,33 @@ describe 'ImageOptim::Railtie' do
88
87
  config.assets.image_optim = hash
89
88
  end
90
89
  end
90
+
91
+ it 'is possible to set individual options' do
92
+ hash = {:config_paths => 'config/image_optim.yml'}
93
+ expect(ImageOptim).to receive(:new).with(hash)
94
+ init_rails_app do |config|
95
+ config.assets.image_optim.config_paths = 'config/image_optim.yml'
96
+ end
97
+ end
98
+
99
+ it 'is possible to set individual worker options' do
100
+ hash = {:advpng => {:level => 3}}
101
+ expect(ImageOptim).to receive(:new).with(hash)
102
+ init_rails_app do |config|
103
+ expect(config.assets.image_optim.advpng).to eq({})
104
+ config.assets.image_optim.advpng.level = 3
105
+ end
106
+ end
107
+
108
+ it 'is not possible to set unknown worker options' do
109
+ expect(ImageOptim).to receive(:new).with({})
110
+ init_rails_app do |config|
111
+ expect(config.assets.image_optim.unknown).to eq(nil)
112
+ expect do
113
+ config.assets.image_optim.unknown.level = 3
114
+ end.to raise_error(NoMethodError)
115
+ end
116
+ end
91
117
  end
92
118
  end
93
119
 
@@ -0,0 +1,58 @@
1
+ require 'spec_helper'
2
+ require 'image_optim/worker/optipng'
3
+ require 'image_optim/image_path'
4
+
5
+ describe ImageOptim::Worker::Optipng do
6
+ describe 'strip option' do
7
+ subject{ described_class.new(ImageOptim.new, options) }
8
+
9
+ let(:options){ {} }
10
+ let(:optipng_version){ '0.7' }
11
+ let(:src){ instance_double(ImageOptim::ImagePath, :copy => nil) }
12
+ let(:dst){ instance_double(ImageOptim::ImagePath) }
13
+
14
+ before do
15
+ optipng_bin = instance_double(ImageOptim::BinResolver::Bin)
16
+ allow(subject).to receive(:resolve_bin!).
17
+ with(:optipng).and_return(optipng_bin)
18
+ allow(optipng_bin).to receive(:version).
19
+ and_return(ImageOptim::BinResolver::SimpleVersion.new(optipng_version))
20
+
21
+ allow(subject).to receive(:optimized?)
22
+ end
23
+
24
+ context 'by default' do
25
+ it 'should add -strip all to arguments' do
26
+ expect(subject).to receive(:execute) do |_bin, *args|
27
+ expect(args.join(' ')).to match(/(^| )-strip all($| )/)
28
+ end
29
+
30
+ subject.optimize(src, dst)
31
+ end
32
+ end
33
+
34
+ context 'when strip is disabled' do
35
+ let(:options){ {:strip => false} }
36
+
37
+ it 'should not add -strip all to arguments' do
38
+ expect(subject).to receive(:execute) do |_bin, *args|
39
+ expect(args.join(' ')).not_to match(/(^| )-strip all($| )/)
40
+ end
41
+
42
+ subject.optimize(src, dst)
43
+ end
44
+ end
45
+
46
+ context 'when optipng version is < 0.7' do
47
+ let(:optipng_version){ '0.6.999' }
48
+
49
+ it 'should not add -strip all to arguments' do
50
+ expect(subject).to receive(:execute) do |_bin, *args|
51
+ expect(args.join(' ')).not_to match(/(^| )-strip all($| )/)
52
+ end
53
+
54
+ subject.optimize(src, dst)
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+ require 'image_optim/worker/pngquant'
3
+
4
+ describe ImageOptim::Worker::Pngquant do
5
+ describe 'quality option' do
6
+ describe 'default' do
7
+ subject{ described_class::QUALITY_OPTION.default }
8
+
9
+ it{ is_expected.to match(/100\.\.100.*0\.\.100/) }
10
+ end
11
+
12
+ describe 'value' do
13
+ let(:options){ {} }
14
+ subject{ described_class.new(ImageOptim.new, options).quality }
15
+
16
+ context 'by default' do
17
+ it{ is_expected.to eq(100..100) }
18
+ end
19
+
20
+ context 'when lossy allowed by default' do
21
+ let(:options){ {:allow_lossy => true} }
22
+
23
+ it{ is_expected.to eq(0..100) }
24
+ end
25
+ end
26
+ end
27
+ end
@@ -67,7 +67,7 @@ describe ImageOptim do
67
67
  base_options = {:skip_missing_workers => false}
68
68
  [
69
69
  ['lossless', base_options, 0],
70
- ['lossy', base_options.merge(:allow_lossy => true), 0.01],
70
+ ['lossy', base_options.merge(:allow_lossy => true), 0.001],
71
71
  ].each do |type, options, max_difference|
72
72
  image_optim = ImageOptim.new(options)
73
73
  describe type do
@@ -1,3 +1,3 @@
1
- <svg width="1in" height="100" xmlns="http://www.w3.org/2000/svg">
1
+ <svg width="90.000" height="100.000" xmlns="http://www.w3.org/2000/svg">
2
2
  <circle cx="36" cy="50" r="30" stroke="black" stroke-width="10" fill="red" />
3
3
  </svg>
@@ -14,35 +14,36 @@ end
14
14
  def flatten_animation(image)
15
15
  if image.format == :gif
16
16
  flattened = image.temp_path
17
- flatten_command = %W[
17
+ command = %W[
18
18
  convert
19
19
  #{image.to_s.shellescape}
20
20
  -coalesce
21
21
  -append
22
22
  #{flattened.to_s.shellescape}
23
23
  ].join(' ')
24
- expect(ImageOptim::Cmd.run(flatten_command)).to be_truthy
24
+ expect(ImageOptim::Cmd.run(command)).to be_truthy
25
25
  flattened
26
26
  else
27
27
  image
28
28
  end
29
29
  end
30
30
 
31
- def nrmse(image_a, image_b)
31
+ def mepp(image_a, image_b)
32
32
  coalesce_a = flatten_animation(image_a)
33
33
  coalesce_b = flatten_animation(image_b)
34
- nrmse_command = %W[
34
+ command = %W[
35
35
  compare
36
- -metric RMSE
36
+ -metric MEPP
37
37
  -alpha Background
38
38
  #{coalesce_a.to_s.shellescape}
39
39
  #{coalesce_b.to_s.shellescape}
40
40
  /dev/null
41
41
  2>&1
42
42
  ].join(' ')
43
- output = ImageOptim::Cmd.capture(nrmse_command)
43
+ output = ImageOptim::Cmd.capture(command)
44
44
  if [0, 1].include?($CHILD_STATUS.exitstatus)
45
- output[/\((\d+(\.\d+)?)\)/, 1].to_f
45
+ num_r = '\d+(?:\.\d+(?:[eE][-+]?\d+)?)?'
46
+ output[/\((#{num_r}), #{num_r}\)/, 1].to_f
46
47
  else
47
48
  fail "compare #{image_a} with #{image_b} failed with `#{output}`"
48
49
  end
@@ -54,7 +55,7 @@ end
54
55
 
55
56
  RSpec::Matchers.define :be_similar_to do |expected, max_difference|
56
57
  match do |actual|
57
- @diff = nrmse(actual, expected)
58
+ @diff = mepp(actual, expected)
58
59
  @diff <= max_difference
59
60
  end
60
61
  failure_message do |actual|
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: image_optim
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.21.0
4
+ version: 0.22.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ivan Kuchin
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-05-30 00:00:00.000000000 Z
11
+ date: 2015-11-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: fspath
@@ -126,20 +126,14 @@ dependencies:
126
126
  requirements:
127
127
  - - ~>
128
128
  - !ruby/object:Gem::Version
129
- version: '0.27'
130
- - - ! '!='
131
- - !ruby/object:Gem::Version
132
- version: 0.30.1
129
+ version: '0.35'
133
130
  type: :development
134
131
  prerelease: false
135
132
  version_requirements: !ruby/object:Gem::Requirement
136
133
  requirements:
137
134
  - - ~>
138
135
  - !ruby/object:Gem::Version
139
- version: '0.27'
140
- - - ! '!='
141
- - !ruby/object:Gem::Version
142
- version: 0.30.1
136
+ version: '0.35'
143
137
  description:
144
138
  email:
145
139
  executables:
@@ -206,10 +200,13 @@ files:
206
200
  - spec/image_optim/handler_spec.rb
207
201
  - spec/image_optim/hash_helpers_spec.rb
208
202
  - spec/image_optim/image_path_spec.rb
203
+ - spec/image_optim/option_definition_spec.rb
209
204
  - spec/image_optim/railtie_spec.rb
210
205
  - spec/image_optim/runner/glob_helpers_spec.rb
211
206
  - spec/image_optim/runner/option_parser_spec.rb
212
207
  - spec/image_optim/space_spec.rb
208
+ - spec/image_optim/worker/optipng_spec.rb
209
+ - spec/image_optim/worker/pngquant_spec.rb
213
210
  - spec/image_optim/worker_spec.rb
214
211
  - spec/image_optim_spec.rb
215
212
  - spec/images/comparison.png
@@ -274,10 +271,13 @@ test_files:
274
271
  - spec/image_optim/handler_spec.rb
275
272
  - spec/image_optim/hash_helpers_spec.rb
276
273
  - spec/image_optim/image_path_spec.rb
274
+ - spec/image_optim/option_definition_spec.rb
277
275
  - spec/image_optim/railtie_spec.rb
278
276
  - spec/image_optim/runner/glob_helpers_spec.rb
279
277
  - spec/image_optim/runner/option_parser_spec.rb
280
278
  - spec/image_optim/space_spec.rb
279
+ - spec/image_optim/worker/optipng_spec.rb
280
+ - spec/image_optim/worker/pngquant_spec.rb
281
281
  - spec/image_optim/worker_spec.rb
282
282
  - spec/image_optim_spec.rb
283
283
  - spec/images/comparison.png