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 +4 -4
- data/.rubocop.yml +29 -34
- data/.travis.yml +4 -1
- data/CHANGELOG.markdown +5 -0
- data/README.markdown +2 -1
- data/image_optim.gemspec +2 -2
- data/lib/image_optim/worker/jhead.rb +1 -1
- data/lib/image_optim/worker/pngquant.rb +6 -0
- data/script/worker_analysis +76 -58
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0274d7bf579938c5c208f39fb85d60781d727566
|
4
|
+
data.tar.gz: e27be28692c75bc6456071311a3bed6fa3a8a216
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e8b6ec09460fa0f07b11ab3930e4b55d52c6ab313caf1a04b55ad5244b20430686f1833a0e66e3501f3cbeb64893b7e35cc9fa75edcb3810b93fb8942d853a20
|
7
|
+
data.tar.gz: 7550e19b5a4ec5821e3b4603bab89d48f09fe6c24e65beb79130c5eda8fa2aa5f7e3e7fe08630bef0021ddcf3affc50964662db1e339d8e5b4c96c10ca08fea7
|
data/.rubocop.yml
CHANGED
@@ -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/
|
98
|
-
|
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
|
data/.travis.yml
CHANGED
@@ -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.
|
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'
|
data/CHANGELOG.markdown
CHANGED
@@ -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)
|
data/README.markdown
CHANGED
@@ -58,7 +58,7 @@ With version:
|
|
58
58
|
|
59
59
|
<!---<update-version>-->
|
60
60
|
```ruby
|
61
|
-
gem 'image_optim', '~> 0.
|
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
|
|
data/image_optim.gemspec
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = 'image_optim'
|
5
|
-
s.version = '0.
|
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.
|
32
|
+
s.add_development_dependency 'rubocop', '~> 0.49'
|
33
33
|
end
|
34
34
|
end
|
@@ -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
|
]
|
data/script/worker_analysis
CHANGED
@@ -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)
|
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/')
|
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 =
|
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(
|
459
|
-
|
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
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
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
|
-
|
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: #{
|
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
|
-
|
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.
|
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-
|
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.
|
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.
|
142
|
+
version: '0.49'
|
143
143
|
description:
|
144
144
|
email:
|
145
145
|
executables:
|