image_optim 0.24.3 → 0.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 76bd58bfc7147d344de3180b31eaf30572fdb940
4
- data.tar.gz: 477c8fb36bab5dcd8abc0fa9714404453e19fc7a
3
+ metadata.gz: 0274d7bf579938c5c208f39fb85d60781d727566
4
+ data.tar.gz: e27be28692c75bc6456071311a3bed6fa3a8a216
5
5
  SHA512:
6
- metadata.gz: c4dbea61152a4b7ae6fb1dd97f2019dd474073863009b7af55000f9e7657e691c43dbc7e11917f477f674536aba80d4e7d9dff588c0026f5e516a215941a5f6c
7
- data.tar.gz: f120068d0b452500630247676dedbe475b8299127d3aa08e479308fea2731b7f3b06b63291858482d4f90ded3f9137975e11b9e66aa5abb0b067dd53e167e348
6
+ metadata.gz: e8b6ec09460fa0f07b11ab3930e4b55d52c6ab313caf1a04b55ad5244b20430686f1833a0e66e3501f3cbeb64893b7e35cc9fa75edcb3810b93fb8942d853a20
7
+ data.tar.gz: 7550e19b5a4ec5821e3b4603bab89d48f09fe6c24e65beb79130c5eda8fa2aa5f7e3e7fe08630bef0021ddcf3affc50964662db1e339d8e5b4c96c10ca08fea7
@@ -6,6 +6,33 @@ AllCops:
6
6
  Bundler/OrderedGems:
7
7
  Enabled: false
8
8
 
9
+ Layout/AccessModifierIndentation:
10
+ EnforcedStyle: outdent
11
+
12
+ Layout/CaseIndentation:
13
+ EnforcedStyle: end
14
+
15
+ Layout/DotPosition:
16
+ EnforcedStyle: trailing
17
+
18
+ Layout/IndentArray:
19
+ EnforcedStyle: consistent
20
+
21
+ Layout/IndentAssignment:
22
+ Enabled: false
23
+
24
+ Layout/IndentHash:
25
+ EnforcedStyle: consistent
26
+
27
+ Layout/IndentHeredoc:
28
+ Enabled: false
29
+
30
+ Layout/SpaceBeforeBlockBraces:
31
+ EnforcedStyle: no_space
32
+
33
+ Layout/SpaceInsideHashLiteralBraces:
34
+ EnforcedStyle: no_space
35
+
9
36
  Lint/AmbiguousBlockAssociation:
10
37
  Exclude:
11
38
  - spec/**/*_spec.rb
@@ -41,18 +68,9 @@ Security/MarshalLoad:
41
68
  Exclude:
42
69
  - 'script/worker_analysis'
43
70
 
44
- Style/AccessModifierIndentation:
45
- EnforcedStyle: outdent
46
-
47
71
  Style/Alias:
48
72
  EnforcedStyle: prefer_alias_method
49
73
 
50
- Style/CaseIndentation:
51
- EnforcedStyle: end
52
-
53
- Style/DotPosition:
54
- EnforcedStyle: trailing
55
-
56
74
  Style/DoubleNegation:
57
75
  Enabled: false
58
76
 
@@ -68,43 +86,20 @@ Style/HashSyntax:
68
86
  Style/IfUnlessModifier:
69
87
  MaxLineLength: 40
70
88
 
71
- Style/IndentArray:
72
- EnforcedStyle: consistent
73
-
74
- Style/IndentAssignment:
75
- Enabled: false
76
-
77
- Style/IndentHash:
78
- EnforcedStyle: consistent
79
-
80
- Style/IndentHeredoc:
81
- Enabled: false
82
-
83
89
  Style/ParallelAssignment:
84
90
  Enabled: false
85
91
 
86
- Style/PercentLiteralDelimiters:
87
- PreferredDelimiters:
88
- '%w': '[]'
89
- '%W': '[]'
90
-
91
92
  Style/Semicolon:
92
93
  AllowAsExpressionSeparator: true
93
94
 
94
95
  Style/SignalException:
95
96
  EnforcedStyle: semantic
96
97
 
97
- Style/SpaceBeforeBlockBraces:
98
- EnforcedStyle: no_space
99
-
100
- Style/SpaceInsideHashLiteralBraces:
101
- EnforcedStyle: no_space
98
+ Style/SymbolArray:
99
+ Enabled: false
102
100
 
103
101
  Style/TrailingCommaInArguments:
104
102
  EnforcedStyleForMultiline: no_comma
105
103
 
106
104
  Style/TrailingCommaInLiteral:
107
105
  EnforcedStyleForMultiline: comma
108
-
109
- Style/SymbolArray:
110
- Enabled: false
@@ -15,11 +15,14 @@ rvm:
15
15
  - '2.4.1'
16
16
  - 'jruby-1.7.26'
17
17
  - 'jruby-9.0.5.0'
18
- - 'jruby-9.1.5.0'
18
+ - 'jruby-9.1.9.0'
19
19
  script:
20
20
  - bundle exec image_optim --info
21
21
  - bundle exec rspec
22
22
  before_install:
23
+ - gem update --system
24
+ - gem update bundler
25
+ - nvm install stable
23
26
  - mkdir -p ~/bin
24
27
  - command -v svgo || npm install svgo
25
28
  - command -v pngout || curl -L "http://static.jonof.id.au/dl/kenutils/pngout-20130221-linux.tar.gz" | tar -xz -C ~/bin --strip-components 2 --wildcards '*/x86_64/pngout'
@@ -2,6 +2,11 @@
2
2
 
3
3
  ## unreleased
4
4
 
5
+ ## v0.25.0 (2017-07-06)
6
+
7
+ * Fix error `uninitialized constant EXIFR::JPEG` (breaking change in [exifr v1.3.0](https://github.com/remvee/exifr/commit/e073a22d06c39f2c1c0e77f5b5fe71545b25e967)) [#150](https://github.com/toy/image_optim/pull/150) [@abemedia](https://github.com/abemedia)
8
+ * Add option to `pngquant` worker to limit maximum number of colors to use [#144](https://github.com/toy/image_optim/issues/144) [@toy](https://github.com/toy)
9
+
5
10
  ## v0.24.3 (2017-05-04)
6
11
 
7
12
  * Set mode of cache files to `0666 & ~umask`, related to [#147](https://github.com/toy/image_optim/issues/147) [@toy](https://github.com/toy)
@@ -58,7 +58,7 @@ With version:
58
58
 
59
59
  <!---<update-version>-->
60
60
  ```ruby
61
- gem 'image_optim', '~> 0.24'
61
+ gem 'image_optim', '~> 0.25'
62
62
  ```
63
63
  <!---</update-version>-->
64
64
 
@@ -319,6 +319,7 @@ Worker has no options
319
319
 
320
320
  ### pngquant:
321
321
  * `:allow_lossy` — Allow quality option *(defaults to `false`)*
322
+ * `:max_colors` — Maximum number of colors to use *(defaults to `256`)*
322
323
  * `: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)*
323
324
  * `:speed` — speed/quality trade-off: `1` - slow, `3` - default, `11` - fast & rough *(defaults to `3`)*
324
325
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = 'image_optim'
5
- s.version = '0.24.3'
5
+ s.version = '0.25.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']
@@ -29,6 +29,6 @@ EOF
29
29
  s.add_development_dependency 'image_optim_pack', '~> 0.2', '>= 0.2.2'
30
30
  s.add_development_dependency 'rspec', '~> 3.0'
31
31
  if RUBY_VERSION >= '2.0'
32
- s.add_development_dependency 'rubocop', '~> 0.47'
32
+ s.add_development_dependency 'rubocop', '~> 0.49'
33
33
  end
34
34
  end
@@ -1,5 +1,5 @@
1
1
  require 'image_optim/worker'
2
- require 'exifr'
2
+ require 'exifr/jpeg'
3
3
 
4
4
  class ImageOptim
5
5
  class Worker
@@ -9,6 +9,11 @@ class ImageOptim
9
9
  ALLOW_LOSSY_OPTION =
10
10
  option(:allow_lossy, false, 'Allow quality option'){ |v| !!v }
11
11
 
12
+ MAX_COLORS_OPTION =
13
+ option(:max_colors, 256, 'Maximum number of colors to use') do |v|
14
+ OptionHelpers.limit_with_range(v.to_i, 2..256)
15
+ end
16
+
12
17
  QUALITY_OPTION =
13
18
  option(:quality, '`100..100`, `0..100` in lossy mode',
14
19
  NonNegativeIntegerRange, 'min..max - don\'t '\
@@ -49,6 +54,7 @@ class ImageOptim
49
54
  --speed=#{speed}
50
55
  --output=#{dst}
51
56
  --force
57
+ #{max_colors}
52
58
  --
53
59
  #{src}
54
60
  ]
@@ -133,8 +133,10 @@ class Analyser
133
133
 
134
134
  # Delegate to worker with short id
135
135
  class WorkerVariant < DelegateClass(ImageOptim::Worker)
136
- attr_reader :name, :id, :cons_id
136
+ attr_reader :name, :id, :cons_id, :required
137
137
  def initialize(klass, image_optim, options)
138
+ @required = options.delete(:required)
139
+ @run_order = options.delete(:run_order)
138
140
  allow_consecutive_on = Array(options.delete(:allow_consecutive_on))
139
141
  @image_optim = image_optim
140
142
  @name = klass.bin_sym.to_s + options_string(options)
@@ -143,6 +145,10 @@ class Analyser
143
145
  @cons_id = [klass, allow_consecutive_on.map{ |key| [key, send(key)] }]
144
146
  end
145
147
 
148
+ def run_order
149
+ @run_order || super
150
+ end
151
+
146
152
  def etag
147
153
  [
148
154
  id,
@@ -155,7 +161,8 @@ class Analyser
155
161
 
156
162
  def bin_versions
157
163
  @bin_versions ||= used_bins.map do |name|
158
- @image_optim.resolve_bin!(name).to_s
164
+ bin = @image_optim.resolve_bin!(name)
165
+ "#{bin.name} #{bin.version}"
159
166
  end
160
167
  end
161
168
 
@@ -189,7 +196,7 @@ class Analyser
189
196
 
190
197
  dst_size = success ? dst.size : nil
191
198
  digest = (success ? dst : src).digest
192
- cache = digest.sub(/../, '\0/') + ".#{src.image_format}"
199
+ cache = digest.sub(/../, '\0/')
193
200
  result = new(worker.id, success, time, src.size, dst_size, cache)
194
201
  if success
195
202
  path = result.path
@@ -274,7 +281,9 @@ class Analyser
274
281
  end
275
282
 
276
283
  def run_workers(src, workers, last_result = nil, &block)
284
+ required_workers = workers.select(&:required)
277
285
  with_progress(workers, last_result) do |worker|
286
+ next if required_workers.any?{ |w| w.run_order < worker.run_order }
278
287
  worker_result, result_image = run_worker(src, worker)
279
288
 
280
289
  steps = (last_result ? last_result.steps : []) + [worker_result]
@@ -306,19 +315,12 @@ class Analyser
306
315
  def difference_with(other)
307
316
  run_cache[:difference][other.digest] ||=
308
317
  Cache.get(:difference, [@path.digest, other.digest].sort, nil) do
309
- images = [flatten_animation(@path), flatten_animation(other)]
310
-
311
- alpha_presence = images.map do |image|
312
- Cmd.capture("identify -format '%A' #{image.to_s.shellescape}")
313
- end
314
- if alpha_presence.uniq.length == 2
315
- images.map!{ |image| underlay_noise(image) }
316
- end
318
+ images = for_compare(@path, other)
317
319
 
318
320
  nrmse = Cmd.capture(%W[
319
321
  convert
320
- #{images[0]} -auto-orient
321
- #{images[1]} -auto-orient
322
+ #{images[0].image_format}:#{images[0]} -auto-orient
323
+ #{images[1].image_format}:#{images[1]} -auto-orient
322
324
  -metric RMSE
323
325
  -compare
324
326
  -format %[distortion]
@@ -331,16 +333,33 @@ class Analyser
331
333
  end
332
334
  end
333
335
 
336
+ def for_compare(*images)
337
+ images.map!{ |image| flatten_animation(image) }
338
+
339
+ alpha_presence = images.map do |image|
340
+ !!Cmd.capture(%W[
341
+ identify
342
+ -format %A
343
+ #{image.image_format}:#{image.to_s.shellescape}
344
+ ].shelljoin)[/true/i]
345
+ end
346
+ if alpha_presence.uniq.length != 1
347
+ images.map!{ |image| underlay_noise(image) }
348
+ end
349
+
350
+ images
351
+ end
352
+
334
353
  def flatten_animation(image)
335
354
  run_cache[:flatten][image.digest] ||= begin
336
355
  if image.image_format == :gif
337
356
  flattened = image.temp_path
338
357
  Cmd.run(*%W[
339
358
  convert
340
- #{image}
359
+ #{image.image_format}:#{image}
341
360
  -coalesce
342
361
  -append
343
- #{flattened}
362
+ #{image.image_format}:#{flattened}
344
363
  ]) || fail("failed flattening of #{image}")
345
364
  flattened
346
365
  else
@@ -354,12 +373,12 @@ class Analyser
354
373
  with_noise = image.temp_path
355
374
  Cmd.run(*%W[
356
375
  convert
357
- #{image}
376
+ #{image.image_format}:#{image}
358
377
  +noise Random
359
- #{image}
378
+ #{image.image_format}:#{image}
360
379
  -flatten
361
380
  -alpha off
362
- #{with_noise}
381
+ #{image.image_format}:#{with_noise}
363
382
  ]) || fail("failed underlaying noise to #{image}")
364
383
  with_noise
365
384
  end
@@ -455,25 +474,24 @@ class Analyser
455
474
  end
456
475
  end
457
476
 
458
- def initialize(option_variants)
459
- option_variants = HashHelpers.deep_symbolise_keys(option_variants)
477
+ def initialize(config)
478
+ config = HashHelpers.deep_symbolise_keys(config)
460
479
  image_optim = ImageOptim.new
461
480
 
462
481
  @workers_by_format = Hash.new{ |h, k| h[k] = [] }
463
482
  ImageOptim::Worker.klasses.each do |klass|
464
- worker_options_config = option_variants.delete(klass.bin_sym) || {}
465
- allow_consecutive_on = worker_options_config.delete(:allow_consecutive_on)
466
- worker_option_variants = case worker_options_config
467
- when Array
468
- worker_options_config
469
- when Hash
470
- worker_options_config.variants
471
- else
472
- fail "Array or Hash expected, got #{worker_options_config}"
483
+ worker_config = config.delete(klass.bin_sym)
484
+ next if worker_config == false
485
+ worker_config ||= {}
486
+
487
+ option_variants = worker_config.delete(:variants) || [{}]
488
+ option_variants = case option_variants
489
+ when Array then option_variants
490
+ when Hash then option_variants.variants
491
+ else fail "Array or Hash expected, got #{option_variants}"
473
492
  end
474
- worker_option_variants.each do |options|
475
- options = HashHelpers.deep_symbolise_keys(options)
476
- options[:allow_consecutive_on] = allow_consecutive_on
493
+ option_variants.each do |options|
494
+ options = HashHelpers.deep_symbolise_keys(options).merge(worker_config)
477
495
  worker = WorkerVariant.new(klass, image_optim, options)
478
496
  worker.image_formats.each do |format|
479
497
  @workers_by_format[format] << worker
@@ -483,7 +501,7 @@ class Analyser
483
501
 
484
502
  log_workers_by_format
485
503
 
486
- fail "unknown variants: #{option_variants}" unless option_variants.empty?
504
+ fail "unknown variants: #{config}" unless config.empty?
487
505
  end
488
506
 
489
507
  def analyse(paths)
@@ -553,7 +571,30 @@ private
553
571
  end
554
572
  end
555
573
 
556
- def option_variants
574
+ abort <<-HELP if ARGV.empty?
575
+ Specify paths for analysis.
576
+
577
+ Example of `.analysis_variants.yml`:
578
+ jhead:
579
+ required: true # don't skip this worker
580
+ jpegtran: # 3 worker variants
581
+ variants:
582
+ - jpegrescan: true
583
+ - progressive: true
584
+ - progressive: false
585
+ optipng: # 6 worker variants by combining options
586
+ variants:
587
+ level: [6, 7]
588
+ interlace: [true, false, nil]
589
+ gifsicle: # allow variants with different interlace to run consecutively
590
+ variants:
591
+ allow_consecutive_on: interlace
592
+ interlace: [true, false]
593
+ careful: [true, false]
594
+ # other workers will be used with default options
595
+ HELP
596
+
597
+ Analyser.new(begin
557
598
  path = '.analysis_variants.yml'
558
599
  case h = YAML.load_file(path)
559
600
  when Hash then h
@@ -563,27 +604,4 @@ def option_variants
563
604
  rescue Errno::ENOENT => e
564
605
  warn e
565
606
  {}
566
- end
567
-
568
- analyser = Analyser.new(option_variants)
569
-
570
- if ARGV.empty?
571
- abort <<-HELP
572
- Specify paths for analysis.
573
-
574
- Example of `.analysis_variants.yml`:
575
- jpegtran: # 3 worker variants
576
- - jpegrescan: true
577
- - progressive: true
578
- - progressive: false
579
- optipng: # 6 worker variants by combining options
580
- level: [6, 7]
581
- interlace: [true, false, nil]
582
- gifsicle: # allow variants with different interlace to run consecutively
583
- allow_consecutive_on: interlace
584
- interlace: [true, false]
585
- careful: [true, false]
586
- # other workers will be used with default options
587
- HELP
588
- end
589
- analyser.analyse(ARGV)
607
+ end).analyse(ARGV)
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.24.3
4
+ version: 0.25.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: 2017-05-04 00:00:00.000000000 Z
11
+ date: 2017-07-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: fspath
@@ -132,14 +132,14 @@ dependencies:
132
132
  requirements:
133
133
  - - "~>"
134
134
  - !ruby/object:Gem::Version
135
- version: '0.47'
135
+ version: '0.49'
136
136
  type: :development
137
137
  prerelease: false
138
138
  version_requirements: !ruby/object:Gem::Requirement
139
139
  requirements:
140
140
  - - "~>"
141
141
  - !ruby/object:Gem::Version
142
- version: '0.47'
142
+ version: '0.49'
143
143
  description:
144
144
  email:
145
145
  executables: