image_optim 0.26.2 → 0.26.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +8 -2
- data/CHANGELOG.markdown +4 -0
- data/README.markdown +1 -1
- data/image_optim.gemspec +2 -2
- data/lib/image_optim.rb +3 -0
- data/lib/image_optim/bin_resolver.rb +3 -0
- data/lib/image_optim/bin_resolver/bin.rb +42 -19
- data/lib/image_optim/cache.rb +1 -0
- data/lib/image_optim/config.rb +4 -0
- data/lib/image_optim/handler.rb +2 -0
- data/lib/image_optim/runner.rb +1 -0
- data/lib/image_optim/runner/option_parser.rb +1 -0
- data/lib/image_optim/worker.rb +4 -0
- data/lib/image_optim/worker/class_methods.rb +1 -0
- data/lib/image_optim/worker/jhead.rb +1 -0
- data/lib/image_optim/worker/pngout.rb +1 -0
- data/script/worker_analysis +6 -0
- data/spec/image_optim/bin_resolver_spec.rb +2 -2
- data/spec/spec_helper.rb +1 -0
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ec91f27b4e53d23a3516908c5714011fb47bbc251e95ef9952acc62948d123af
|
4
|
+
data.tar.gz: 8b5a675e29709e03bf5ca0567ae742f8d4d7f3d7e90f89ac5ef8c1935c594555
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 847ee0b721a90d761ccfa4948c979e532dfd53d52f2e4c82e9df1e3301bcaba6a4217f98ae5cd5be2bcd7407339614710bd95ef381e9d422e778a4674ddeb81b
|
7
|
+
data.tar.gz: 7f5b009a16df3c671ebc9a8c934cb499fd7ac47a0a464d33130ab1197ffa4b9c1f2767467226124dbd78281bcffd7864c058d8f3ff9fe7b58addfd3b6411ace7
|
data/.rubocop.yml
CHANGED
@@ -30,6 +30,9 @@ Layout/IndentHash:
|
|
30
30
|
Layout/IndentHeredoc:
|
31
31
|
Enabled: false
|
32
32
|
|
33
|
+
Layout/RescueEnsureAlignment:
|
34
|
+
Enabled: false
|
35
|
+
|
33
36
|
Layout/SpaceBeforeBlockBraces:
|
34
37
|
EnforcedStyle: no_space
|
35
38
|
EnforcedStyleForEmptyBraces: no_space
|
@@ -51,7 +54,7 @@ Lint/UnneededSplatExpansion:
|
|
51
54
|
Enabled: false
|
52
55
|
|
53
56
|
Metrics/AbcSize:
|
54
|
-
Max:
|
57
|
+
Max: 33
|
55
58
|
|
56
59
|
Metrics/BlockLength:
|
57
60
|
Exclude:
|
@@ -63,7 +66,10 @@ Metrics/ClassLength:
|
|
63
66
|
Max: 150
|
64
67
|
|
65
68
|
Metrics/CyclomaticComplexity:
|
66
|
-
Max:
|
69
|
+
Max: 11
|
70
|
+
|
71
|
+
Metrics/LineLength:
|
72
|
+
Max: 120
|
67
73
|
|
68
74
|
Metrics/MethodLength:
|
69
75
|
Max: 25
|
data/CHANGELOG.markdown
CHANGED
@@ -2,6 +2,10 @@
|
|
2
2
|
|
3
3
|
## unreleased
|
4
4
|
|
5
|
+
## v0.26.3 (2018-10-13)
|
6
|
+
|
7
|
+
* Handle `vnone` version of `advpng` that was erroneously produced for `ubuntu` and `homebrew` [#165](https://github.com/toy/image_optim/issues/165) [@toy](https://github.com/toy)
|
8
|
+
|
5
9
|
## v0.26.2 (2018-08-15)
|
6
10
|
|
7
11
|
* Ignore segmentation fault for `pngout` <= `20150920` [#158](https://github.com/toy/image_optim/issues/158) [@toy](https://github.com/toy)
|
data/README.markdown
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
[![AppVeyor Status](https://img.shields.io/appveyor/ci/toy/image-optim/master.svg?style=flat&label=windows)](https://ci.appveyor.com/project/toy/image-optim)
|
4
4
|
[![Code Climate](https://img.shields.io/codeclimate/maintainability/toy/image_optim.svg?style=flat)](https://codeclimate.com/github/toy/image_optim)
|
5
5
|
[![Code Climate Coverage](https://img.shields.io/codeclimate/c/toy/image_optim.svg?style=flat)](https://codeclimate.com/github/toy/image_optim)
|
6
|
-
[![
|
6
|
+
[![Depfu](https://badges.depfu.com/badges/221b4832fa96f613aa5401f7cb4030ac/overview.svg)](https://depfu.com/github/toy/image_optim)
|
7
7
|
[![Inch CI](https://inch-ci.org/github/toy/image_optim.svg?branch=master&style=flat)](https://inch-ci.org/github/toy/image_optim)
|
8
8
|
|
9
9
|
# image_optim
|
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.26.
|
5
|
+
s.version = '0.26.3'
|
6
6
|
s.summary = %q{Command line tool and ruby interface to optimize (lossless compress, optionally lossy) jpeg, png, gif and svg images 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']
|
@@ -36,6 +36,6 @@ EOF
|
|
36
36
|
s.add_development_dependency 'image_optim_pack', '~> 0.2', '>= 0.2.2'
|
37
37
|
s.add_development_dependency 'rspec', '~> 3.0'
|
38
38
|
if RUBY_VERSION >= '2.2'
|
39
|
-
s.add_development_dependency 'rubocop', '~> 0.
|
39
|
+
s.add_development_dependency 'rubocop', '~> 0.59'
|
40
40
|
end
|
41
41
|
end
|
data/lib/image_optim.rb
CHANGED
@@ -118,6 +118,7 @@ class ImageOptim
|
|
118
118
|
end
|
119
119
|
|
120
120
|
return unless optimized
|
121
|
+
|
121
122
|
OptimizedPath.new(optimized, original)
|
122
123
|
end
|
123
124
|
|
@@ -126,6 +127,7 @@ class ImageOptim
|
|
126
127
|
def optimize_image!(original)
|
127
128
|
original = Path.convert(original)
|
128
129
|
return unless (result = optimize_image(original))
|
130
|
+
|
129
131
|
result.replace(original)
|
130
132
|
OptimizedPath.new(original, result.original_size)
|
131
133
|
end
|
@@ -134,6 +136,7 @@ class ImageOptim
|
|
134
136
|
def optimize_image_data(original_data)
|
135
137
|
format = ImageMeta.format_for_data(original_data)
|
136
138
|
return unless format
|
139
|
+
|
137
140
|
Path.temp_file %W[image_optim .#{format}] do |temp|
|
138
141
|
temp.binmode
|
139
142
|
temp.write(original_data)
|
@@ -97,6 +97,7 @@ class ImageOptim
|
|
97
97
|
# Double-checked locking
|
98
98
|
def resolving(name)
|
99
99
|
return if @bins.include?(name)
|
100
|
+
|
100
101
|
@lock.synchronize do
|
101
102
|
yield unless @bins.include?(name)
|
102
103
|
end
|
@@ -108,11 +109,13 @@ class ImageOptim
|
|
108
109
|
env_name = "#{name}_bin".upcase
|
109
110
|
path = ENV[env_name]
|
110
111
|
return unless path
|
112
|
+
|
111
113
|
path = File.expand_path(path)
|
112
114
|
desc = "`#{path}` specified in #{env_name}"
|
113
115
|
fail "#{desc} doesn\'t exist" unless File.exist?(path)
|
114
116
|
fail "#{desc} is not a file" unless File.file?(path)
|
115
117
|
fail "#{desc} is not executable" unless File.executable?(path)
|
118
|
+
|
116
119
|
if @image_optim.verbose
|
117
120
|
$stderr << "Custom path for #{name} specified in #{env_name}: #{path}\n"
|
118
121
|
end
|
@@ -23,6 +23,7 @@ class ImageOptim
|
|
23
23
|
|
24
24
|
def digest
|
25
25
|
return @digest if defined?(@digest)
|
26
|
+
|
26
27
|
@digest = File.exist?(@path) && Digest::SHA1.file(@path).hexdigest
|
27
28
|
end
|
28
29
|
|
@@ -32,20 +33,34 @@ class ImageOptim
|
|
32
33
|
|
33
34
|
is = ComparableCondition.is
|
34
35
|
|
35
|
-
FAIL_CHECKS =
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
36
|
+
FAIL_CHECKS = {
|
37
|
+
:pngcrush => [
|
38
|
+
[is.between?('1.7.60', '1.7.65'), 'is known to produce broken pngs'],
|
39
|
+
[is == '1.7.80', 'loses one color in indexed images'],
|
40
|
+
],
|
41
|
+
:pngquant => [
|
42
|
+
[is < '2.0', 'is not supported'],
|
43
|
+
],
|
44
|
+
}.freeze
|
45
|
+
|
46
|
+
WARN_CHECKS = {
|
47
|
+
:advpng => [
|
48
|
+
[is == 'none', 'is of unknown version'],
|
49
|
+
[is < '1.17', 'does not use zopfli'],
|
50
|
+
],
|
51
|
+
:gifsicle => [
|
52
|
+
[is < '1.85', 'does not support removing extension blocks'],
|
53
|
+
],
|
54
|
+
:pngcrush => [
|
55
|
+
[is < '1.7.38', 'does not have blacken flag'],
|
56
|
+
],
|
57
|
+
:pngquant => [
|
58
|
+
[is < '2.1', 'may be lossy even with quality `100-`'],
|
59
|
+
],
|
60
|
+
:optipng => [
|
61
|
+
[is < '0.7', 'does not support -strip option'],
|
62
|
+
],
|
63
|
+
}.freeze
|
49
64
|
|
50
65
|
# Fail if version will not work properly
|
51
66
|
def check_fail!
|
@@ -53,9 +68,11 @@ class ImageOptim
|
|
53
68
|
fail UnknownVersion, "could not get version of #{name} at #{path}"
|
54
69
|
end
|
55
70
|
|
56
|
-
|
57
|
-
|
71
|
+
return unless FAIL_CHECKS[name]
|
72
|
+
|
73
|
+
FAIL_CHECKS[name].each do |matcher, message|
|
58
74
|
next unless matcher.match(version)
|
75
|
+
|
59
76
|
fail BadVersion, "#{self} (#{matcher}) #{message}"
|
60
77
|
end
|
61
78
|
end
|
@@ -64,10 +81,14 @@ class ImageOptim
|
|
64
81
|
def check!
|
65
82
|
check_fail!
|
66
83
|
|
67
|
-
|
68
|
-
|
84
|
+
return unless WARN_CHECKS[name]
|
85
|
+
|
86
|
+
WARN_CHECKS[name].each do |matcher, message|
|
69
87
|
next unless matcher.match(version)
|
88
|
+
|
70
89
|
warn "WARN: #{self} (#{matcher}) #{message}"
|
90
|
+
|
91
|
+
break
|
71
92
|
end
|
72
93
|
end
|
73
94
|
|
@@ -82,7 +103,9 @@ class ImageOptim
|
|
82
103
|
# Getting version of bin, will fail for an unknown name
|
83
104
|
def version_string
|
84
105
|
case name
|
85
|
-
when :advpng
|
106
|
+
when :advpng
|
107
|
+
capture("#{escaped_path} --version 2> #{Path::NULL}")[/\bv(\d+(\.\d+)+|none)/, 1]
|
108
|
+
when :gifsicle, :jpegoptim, :optipng
|
86
109
|
capture("#{escaped_path} --version 2> #{Path::NULL}")[/\d+(\.\d+)+/]
|
87
110
|
when :svgo, :pngquant
|
88
111
|
capture("#{escaped_path} --version 2>&1")[/\d+(\.\d+)+/]
|
data/lib/image_optim/cache.rb
CHANGED
@@ -7,6 +7,7 @@ class ImageOptim
|
|
7
7
|
class Cache
|
8
8
|
def initialize(image_optim, workers_by_format)
|
9
9
|
return unless image_optim.cache_dir
|
10
|
+
|
10
11
|
@cache_dir = FSPath.new(image_optim.cache_dir)
|
11
12
|
@cache_worker_digests = image_optim.cache_worker_digests
|
12
13
|
@options_by_format = Hash[workers_by_format.map do |format, workers|
|
data/lib/image_optim/config.rb
CHANGED
@@ -32,10 +32,12 @@ class ImageOptim
|
|
32
32
|
return {}
|
33
33
|
end
|
34
34
|
return {} unless File.size?(full_path)
|
35
|
+
|
35
36
|
config = YAML.load_file(full_path)
|
36
37
|
unless config.is_a?(Hash)
|
37
38
|
fail "expected hash, got #{config.inspect}"
|
38
39
|
end
|
40
|
+
|
39
41
|
HashHelpers.deep_symbolise_keys(config)
|
40
42
|
rescue => e
|
41
43
|
warn "exception when reading #{full_path}: #{e}"
|
@@ -77,6 +79,7 @@ class ImageOptim
|
|
77
79
|
def assert_no_unused_options!
|
78
80
|
unknown_options = @options.reject{ |key, _value| @used.include?(key) }
|
79
81
|
return if unknown_options.empty?
|
82
|
+
|
80
83
|
fail ConfigurationError, "unknown options #{unknown_options.inspect}"
|
81
84
|
end
|
82
85
|
|
@@ -131,6 +134,7 @@ class ImageOptim
|
|
131
134
|
true
|
132
135
|
rescue LoadError => e
|
133
136
|
raise "Cannot load image_optim_pack: #{e}" if pack
|
137
|
+
|
134
138
|
false
|
135
139
|
end
|
136
140
|
|
data/lib/image_optim/handler.rb
CHANGED
@@ -39,6 +39,7 @@ class ImageOptim
|
|
39
39
|
@dst ||= @original.temp_path
|
40
40
|
|
41
41
|
return unless yield @src, @dst
|
42
|
+
|
42
43
|
@result = @dst
|
43
44
|
if @src == @original
|
44
45
|
@src, @dst = @dst, nil
|
@@ -50,6 +51,7 @@ class ImageOptim
|
|
50
51
|
# Remove extra temp files
|
51
52
|
def cleanup
|
52
53
|
return unless @dst
|
54
|
+
|
53
55
|
@dst.unlink
|
54
56
|
@dst = nil
|
55
57
|
end
|
data/lib/image_optim/runner.rb
CHANGED
data/lib/image_optim/worker.rb
CHANGED
@@ -23,6 +23,7 @@ class ImageOptim
|
|
23
23
|
unless image_optim.is_a?(ImageOptim)
|
24
24
|
fail ArgumentError, 'first parameter should be an ImageOptim instance'
|
25
25
|
end
|
26
|
+
|
26
27
|
@image_optim = image_optim
|
27
28
|
parse_options(options)
|
28
29
|
assert_no_unknown_options!(options)
|
@@ -49,6 +50,7 @@ class ImageOptim
|
|
49
50
|
unless format_from_name
|
50
51
|
fail "#{self.class}: can't guess applicable format from worker name"
|
51
52
|
end
|
53
|
+
|
52
54
|
[format_from_name.to_sym]
|
53
55
|
end
|
54
56
|
|
@@ -68,6 +70,7 @@ class ImageOptim
|
|
68
70
|
@image_optim.resolve_bin!(bin)
|
69
71
|
end
|
70
72
|
return if errors.empty?
|
73
|
+
|
71
74
|
fail BinResolver::Error, wrap_resolver_error_message(errors.join(', '))
|
72
75
|
end
|
73
76
|
|
@@ -98,6 +101,7 @@ class ImageOptim
|
|
98
101
|
known_keys = self.class.option_definitions.map(&:name)
|
99
102
|
unknown_options = options.reject{ |key, _value| known_keys.include?(key) }
|
100
103
|
return if unknown_options.empty?
|
104
|
+
|
101
105
|
fail ConfigurationError, "unknown options #{unknown_options.inspect} "\
|
102
106
|
"for #{self}"
|
103
107
|
end
|
data/script/worker_analysis
CHANGED
@@ -118,8 +118,10 @@ class Analyser
|
|
118
118
|
def get!(key, etag)
|
119
119
|
raw = DB[Marshal.dump(key)]
|
120
120
|
return unless raw
|
121
|
+
|
121
122
|
entry = Marshal.load(raw)
|
122
123
|
return unless entry[1] == etag
|
124
|
+
|
123
125
|
entry[0]
|
124
126
|
end
|
125
127
|
|
@@ -175,6 +177,7 @@ class Analyser
|
|
175
177
|
|
176
178
|
def options_string(options)
|
177
179
|
return '' if options.empty?
|
180
|
+
|
178
181
|
"(#{options.sort.map{ |k, v| "#{k}:#{v.inspect}" }.join(', ')})"
|
179
182
|
end
|
180
183
|
end
|
@@ -284,6 +287,7 @@ class Analyser
|
|
284
287
|
required_workers = workers.select(&:required)
|
285
288
|
with_progress(workers, last_result) do |worker|
|
286
289
|
next if required_workers.any?{ |w| w.run_order < worker.run_order }
|
290
|
+
|
287
291
|
worker_result, result_image = run_worker(src, worker)
|
288
292
|
|
289
293
|
steps = (last_result ? last_result.steps : []) + [worker_result]
|
@@ -329,6 +333,7 @@ class Analyser
|
|
329
333
|
unless $CHILD_STATUS.success?
|
330
334
|
fail "failed comparison of #{@path} with #{other}"
|
331
335
|
end
|
336
|
+
|
332
337
|
nrmse
|
333
338
|
end
|
334
339
|
end
|
@@ -482,6 +487,7 @@ class Analyser
|
|
482
487
|
ImageOptim::Worker.klasses.each do |klass|
|
483
488
|
worker_config = config.delete(klass.bin_sym)
|
484
489
|
next if worker_config == false
|
490
|
+
|
485
491
|
worker_config ||= {}
|
486
492
|
|
487
493
|
option_variants = worker_config.delete(:variants) || [{}]
|
@@ -278,9 +278,9 @@ describe ImageOptim::BinResolver do
|
|
278
278
|
bin = Bin.new(:advpng, '/bin/advpng')
|
279
279
|
|
280
280
|
expect(Bin).to receive(:new).and_return(bin)
|
281
|
-
allow(bin).to receive(:version).and_return(SimpleVersion.new('
|
281
|
+
allow(bin).to receive(:version).and_return(SimpleVersion.new('none'))
|
282
282
|
|
283
|
-
expect(bin).to receive(:warn).once.with(match(/
|
283
|
+
expect(bin).to receive(:warn).once.with(match(/is of unknown version/))
|
284
284
|
|
285
285
|
5.times do
|
286
286
|
resolver.resolve!(:pngcrush)
|
data/spec/spec_helper.rb
CHANGED
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.26.
|
4
|
+
version: 0.26.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ivan Kuchin
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-10-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: fspath
|
@@ -138,14 +138,14 @@ dependencies:
|
|
138
138
|
requirements:
|
139
139
|
- - "~>"
|
140
140
|
- !ruby/object:Gem::Version
|
141
|
-
version: '0.
|
141
|
+
version: '0.59'
|
142
142
|
type: :development
|
143
143
|
prerelease: false
|
144
144
|
version_requirements: !ruby/object:Gem::Requirement
|
145
145
|
requirements:
|
146
146
|
- - "~>"
|
147
147
|
- !ruby/object:Gem::Version
|
148
|
-
version: '0.
|
148
|
+
version: '0.59'
|
149
149
|
description:
|
150
150
|
email:
|
151
151
|
executables:
|
@@ -263,7 +263,7 @@ licenses:
|
|
263
263
|
metadata:
|
264
264
|
bug_tracker_uri: https://github.com/toy/image_optim/issues
|
265
265
|
changelog_uri: https://github.com/toy/image_optim/CHANGELOG.markdown
|
266
|
-
documentation_uri: https://www.rubydoc.info/gems/image_optim/0.26.
|
266
|
+
documentation_uri: https://www.rubydoc.info/gems/image_optim/0.26.3
|
267
267
|
source_code_uri: https://github.com/toy/image_optim
|
268
268
|
post_install_message: |
|
269
269
|
Rails image assets optimization is extracted into image_optim_rails gem
|