image_optim 0.31.3 → 0.32.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/.github/dependabot.yml +8 -0
- data/.github/workflows/build-test-containers.yml +60 -0
- data/.github/workflows/check.yml +43 -26
- data/.github/workflows/rubocop.yml +2 -2
- data/.rubocop.yml +5 -0
- data/CHANGELOG.markdown +13 -0
- data/Dockerfile.test +46 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +1 -1
- data/README.markdown +29 -6
- data/image_optim.gemspec +15 -5
- data/lib/image_optim/benchmark_result.rb +24 -0
- data/lib/image_optim/bin_resolver.rb +1 -1
- data/lib/image_optim/config.rb +15 -6
- data/lib/image_optim/runner/option_parser.rb +60 -45
- data/lib/image_optim/runner.rb +69 -6
- data/lib/image_optim/table.rb +64 -0
- data/lib/image_optim/worker/svgo.rb +72 -7
- data/lib/image_optim.rb +22 -0
- data/script/update-rubygems-n-bundler +50 -0
- data/script/update_worker_options_in_readme +16 -3
- data/spec/image_optim/bin_resolver_spec.rb +3 -3
- data/spec/image_optim/cache_spec.rb +3 -1
- data/spec/image_optim/option_definition_spec.rb +1 -3
- data/spec/image_optim/runner/option_parser_spec.rb +10 -1
- data/spec/image_optim/true_false_nil_spec.rb +24 -0
- data/spec/image_optim/worker/svgo_spec.rb +96 -0
- data/spec/image_optim_spec.rb +19 -4
- data/spec/images/invisiblepixels/generate +3 -1
- data/spec/images/invisiblepixels/image.png +0 -0
- data/spec/spec_helper.rb +8 -8
- metadata +14 -9
- data/.github/workflows/codeql.yml +0 -30
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
require 'image_optim/worker/svgo'
|
|
5
|
+
|
|
6
|
+
describe ImageOptim::Worker::Svgo do
|
|
7
|
+
%i[
|
|
8
|
+
disable_plugins
|
|
9
|
+
enable_plugins
|
|
10
|
+
].each do |option|
|
|
11
|
+
describe "#{option} option" do
|
|
12
|
+
let(:subject){ described_class.new(ImageOptim.new, value).send(option) }
|
|
13
|
+
|
|
14
|
+
context 'default' do
|
|
15
|
+
let(:value){ {} }
|
|
16
|
+
|
|
17
|
+
it{ is_expected.to eq([]) }
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
context 'when passed single valid value' do
|
|
21
|
+
let(:value){ {option => :pluginName} }
|
|
22
|
+
|
|
23
|
+
it 'converts it to a string array' do
|
|
24
|
+
is_expected.to eq(%w[pluginName])
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
context 'when passed multiple valid values' do
|
|
29
|
+
let(:value){ {option => %i[pluginName anotherName]} }
|
|
30
|
+
|
|
31
|
+
it 'converts them to a string array' do
|
|
32
|
+
is_expected.to eq(%w[pluginName anotherName])
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
context 'when given invalid values' do
|
|
37
|
+
let(:value){ {option => %w[1abc pluginName alert() anotherName]} }
|
|
38
|
+
|
|
39
|
+
it 'warns and skips them' do
|
|
40
|
+
expect_any_instance_of(described_class).
|
|
41
|
+
to receive(:warn).with('Doesn\'t look like svgo plugin name: 1abc')
|
|
42
|
+
expect_any_instance_of(described_class).
|
|
43
|
+
to receive(:warn).with('Doesn\'t look like svgo plugin name: alert()')
|
|
44
|
+
is_expected.to eq(%w[pluginName anotherName])
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
describe 'precision option' do
|
|
51
|
+
describe 'default' do
|
|
52
|
+
subject{ described_class::PRECISION_OPTION.default }
|
|
53
|
+
|
|
54
|
+
it{ is_expected.to eq(3) }
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
describe 'value' do
|
|
58
|
+
let(:subject){ described_class.new(ImageOptim.new, options).precision }
|
|
59
|
+
|
|
60
|
+
context 'when lossy not allowed' do
|
|
61
|
+
context 'by default' do
|
|
62
|
+
let(:options){ {} }
|
|
63
|
+
|
|
64
|
+
it{ is_expected.to eq(3) }
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
context 'when value is passed through options' do
|
|
68
|
+
let(:options){ {precision: 5} }
|
|
69
|
+
|
|
70
|
+
it 'warns and keeps default' do
|
|
71
|
+
expect_any_instance_of(described_class).
|
|
72
|
+
to receive(:warn).with(%r{ignored in default/lossless mode})
|
|
73
|
+
is_expected.to eq(3)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
context 'when lossy allowed' do
|
|
79
|
+
context 'by default' do
|
|
80
|
+
let(:options){ {allow_lossy: true} }
|
|
81
|
+
|
|
82
|
+
it{ is_expected.to eq(3) }
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
context 'when value is passed through options' do
|
|
86
|
+
let(:options){ {allow_lossy: true, precision: 5} }
|
|
87
|
+
|
|
88
|
+
it 'sets the value without warning' do
|
|
89
|
+
expect_any_instance_of(described_class).not_to receive(:warn)
|
|
90
|
+
is_expected.to eq(5)
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
data/spec/image_optim_spec.rb
CHANGED
|
@@ -61,9 +61,10 @@ describe ImageOptim do
|
|
|
61
61
|
|
|
62
62
|
base_options = {skip_missing_workers: false}
|
|
63
63
|
[
|
|
64
|
-
|
|
65
|
-
['
|
|
66
|
-
|
|
64
|
+
# 120 comes from https://github.com/ImageMagick/ImageMagick/commit/8a7495a6d9
|
|
65
|
+
['lossless', base_options, 120],
|
|
66
|
+
['lossy', base_options.merge(allow_lossy: true), 30],
|
|
67
|
+
].each do |type, options, psnr_min|
|
|
67
68
|
it "does it #{type}" do
|
|
68
69
|
image_optim = ImageOptim.new(options)
|
|
69
70
|
copies = test_images.map{ |image| temp_copy(image) }
|
|
@@ -78,7 +79,7 @@ describe ImageOptim do
|
|
|
78
79
|
expect(optimized).not_to have_same_data_as(original)
|
|
79
80
|
|
|
80
81
|
compare_to = rotate_images.include?(original) ? rotated : original
|
|
81
|
-
expect(optimized).to be_similar_to(compare_to,
|
|
82
|
+
expect(optimized).to be_similar_to(compare_to, psnr_min)
|
|
82
83
|
end
|
|
83
84
|
end
|
|
84
85
|
end
|
|
@@ -268,6 +269,20 @@ describe ImageOptim do
|
|
|
268
269
|
end
|
|
269
270
|
end
|
|
270
271
|
|
|
272
|
+
describe 'benchmark_images' do
|
|
273
|
+
it 'does it' do
|
|
274
|
+
image_optim = ImageOptim.new
|
|
275
|
+
pairs = image_optim.benchmark_images(test_images)
|
|
276
|
+
test_images.zip(pairs).each do |original, (src, bm)|
|
|
277
|
+
expect(original).to equal(src)
|
|
278
|
+
expect(bm[0]).to be_a(ImageOptim::BenchmarkResult)
|
|
279
|
+
expect(bm[0].bytes).to be_a(Numeric)
|
|
280
|
+
expect(bm[0].elapsed).to be_a(Numeric)
|
|
281
|
+
expect(bm[0].worker).to be_a(String)
|
|
282
|
+
end
|
|
283
|
+
end
|
|
284
|
+
end
|
|
285
|
+
|
|
271
286
|
%w[
|
|
272
287
|
optimize_image
|
|
273
288
|
optimize_image!
|
|
@@ -7,6 +7,8 @@ require 'shellwords'
|
|
|
7
7
|
|
|
8
8
|
side = 64
|
|
9
9
|
|
|
10
|
+
colors = Array.new(256){ [rand(256), rand(256), rand(256)] }
|
|
11
|
+
|
|
10
12
|
IO.popen(%W[
|
|
11
13
|
convert
|
|
12
14
|
-depth 8
|
|
@@ -18,7 +20,7 @@ IO.popen(%W[
|
|
|
18
20
|
side.times do |a|
|
|
19
21
|
side.times do |b|
|
|
20
22
|
alpha = [0, 1, 0x7f, 0xff][((a / 8) + (b / 8)) % 4]
|
|
21
|
-
f << [
|
|
23
|
+
f << [*colors.sample, alpha].pack('C*')
|
|
22
24
|
end
|
|
23
25
|
end
|
|
24
26
|
end
|
|
Binary file
|
data/spec/spec_helper.rb
CHANGED
|
@@ -42,12 +42,12 @@ def flatten_animation(image)
|
|
|
42
42
|
end
|
|
43
43
|
end
|
|
44
44
|
|
|
45
|
-
def
|
|
45
|
+
def psnr(image_a, image_b)
|
|
46
46
|
coalesce_a = flatten_animation(image_a)
|
|
47
47
|
coalesce_b = flatten_animation(image_b)
|
|
48
48
|
output = ImageOptim::Cmd.capture((IMAGEMAGICK_PREFIX + %W[
|
|
49
49
|
compare
|
|
50
|
-
-metric
|
|
50
|
+
-metric PSNR
|
|
51
51
|
-alpha Background
|
|
52
52
|
#{coalesce_a.to_s.shellescape}
|
|
53
53
|
#{coalesce_b.to_s.shellescape}
|
|
@@ -59,21 +59,21 @@ def mepp(image_a, image_b)
|
|
|
59
59
|
end
|
|
60
60
|
|
|
61
61
|
num_r = '\d+(?:\.\d+(?:[eE][-+]?\d+)?)?'
|
|
62
|
-
output[/\(
|
|
62
|
+
num = output[/\A(#{num_r})/, 1].to_f
|
|
63
|
+
num == 0 ? Float::INFINITY : num
|
|
63
64
|
end
|
|
64
65
|
|
|
65
66
|
RSpec::Matchers.define :be_smaller_than do |expected|
|
|
66
67
|
match{ |actual| actual.size < expected.size }
|
|
67
68
|
end
|
|
68
69
|
|
|
69
|
-
RSpec::Matchers.define :be_similar_to do |expected,
|
|
70
|
+
RSpec::Matchers.define :be_similar_to do |expected, psnr_min|
|
|
70
71
|
match do |actual|
|
|
71
|
-
@diff =
|
|
72
|
-
@diff
|
|
72
|
+
@diff = psnr(actual, expected)
|
|
73
|
+
@diff >= psnr_min
|
|
73
74
|
end
|
|
74
75
|
failure_message do |actual|
|
|
75
|
-
"expected #{actual}
|
|
76
|
-
"#{expected}, got mean error per pixel of #{@diff}"
|
|
76
|
+
"expected peaks signal to noise ratio between #{actual} and #{expected} to be #{psnr_min}, got #{@diff}"
|
|
77
77
|
end
|
|
78
78
|
end
|
|
79
79
|
|
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: image_optim
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.32.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ivan Kuchin
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: fspath
|
|
@@ -166,27 +165,28 @@ dependencies:
|
|
|
166
165
|
- - "~>"
|
|
167
166
|
- !ruby/object:Gem::Version
|
|
168
167
|
version: '2.0'
|
|
169
|
-
description:
|
|
170
|
-
email:
|
|
171
168
|
executables:
|
|
172
169
|
- image_optim
|
|
173
170
|
extensions: []
|
|
174
171
|
extra_rdoc_files: []
|
|
175
172
|
files:
|
|
173
|
+
- ".github/dependabot.yml"
|
|
174
|
+
- ".github/workflows/build-test-containers.yml"
|
|
176
175
|
- ".github/workflows/check.yml"
|
|
177
|
-
- ".github/workflows/codeql.yml"
|
|
178
176
|
- ".github/workflows/rubocop.yml"
|
|
179
177
|
- ".gitignore"
|
|
180
178
|
- ".pre-commit-hooks.yaml"
|
|
181
179
|
- ".rubocop.yml"
|
|
182
180
|
- CHANGELOG.markdown
|
|
183
181
|
- CONTRIBUTING.markdown
|
|
182
|
+
- Dockerfile.test
|
|
184
183
|
- Gemfile
|
|
185
184
|
- LICENSE.txt
|
|
186
185
|
- README.markdown
|
|
187
186
|
- bin/image_optim
|
|
188
187
|
- image_optim.gemspec
|
|
189
188
|
- lib/image_optim.rb
|
|
189
|
+
- lib/image_optim/benchmark_result.rb
|
|
190
190
|
- lib/image_optim/bin_resolver.rb
|
|
191
191
|
- lib/image_optim/bin_resolver/bin.rb
|
|
192
192
|
- lib/image_optim/bin_resolver/comparable_condition.rb
|
|
@@ -211,6 +211,7 @@ files:
|
|
|
211
211
|
- lib/image_optim/runner/glob_helpers.rb
|
|
212
212
|
- lib/image_optim/runner/option_parser.rb
|
|
213
213
|
- lib/image_optim/space.rb
|
|
214
|
+
- lib/image_optim/table.rb
|
|
214
215
|
- lib/image_optim/timer.rb
|
|
215
216
|
- lib/image_optim/true_false_nil.rb
|
|
216
217
|
- lib/image_optim/worker.rb
|
|
@@ -230,6 +231,7 @@ files:
|
|
|
230
231
|
- script/template/jquery-2.1.3.min.js
|
|
231
232
|
- script/template/sortable-0.6.0.min.js
|
|
232
233
|
- script/template/worker_analysis.erb
|
|
234
|
+
- script/update-rubygems-n-bundler
|
|
233
235
|
- script/update_worker_options_in_readme
|
|
234
236
|
- script/worker_analysis
|
|
235
237
|
- spec/files/config_with_range.yaml
|
|
@@ -252,10 +254,12 @@ files:
|
|
|
252
254
|
- spec/image_optim/runner/option_parser_spec.rb
|
|
253
255
|
- spec/image_optim/space_spec.rb
|
|
254
256
|
- spec/image_optim/timer_spec.rb
|
|
257
|
+
- spec/image_optim/true_false_nil_spec.rb
|
|
255
258
|
- spec/image_optim/worker/jpegrecompress_spec.rb
|
|
256
259
|
- spec/image_optim/worker/optipng_spec.rb
|
|
257
260
|
- spec/image_optim/worker/oxipng_spec.rb
|
|
258
261
|
- spec/image_optim/worker/pngquant_spec.rb
|
|
262
|
+
- spec/image_optim/worker/svgo_spec.rb
|
|
259
263
|
- spec/image_optim/worker_spec.rb
|
|
260
264
|
- spec/image_optim_spec.rb
|
|
261
265
|
- spec/images/broken_jpeg
|
|
@@ -293,7 +297,7 @@ licenses:
|
|
|
293
297
|
metadata:
|
|
294
298
|
bug_tracker_uri: https://github.com/toy/image_optim/issues
|
|
295
299
|
changelog_uri: https://github.com/toy/image_optim/blob/master/CHANGELOG.markdown
|
|
296
|
-
documentation_uri: https://www.rubydoc.info/gems/image_optim/0.
|
|
300
|
+
documentation_uri: https://www.rubydoc.info/gems/image_optim/0.32.0
|
|
297
301
|
source_code_uri: https://github.com/toy/image_optim
|
|
298
302
|
post_install_message: |
|
|
299
303
|
Rails image assets optimization is extracted into image_optim_rails gem
|
|
@@ -312,8 +316,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
312
316
|
- !ruby/object:Gem::Version
|
|
313
317
|
version: '0'
|
|
314
318
|
requirements: []
|
|
315
|
-
rubygems_version:
|
|
316
|
-
signing_key:
|
|
319
|
+
rubygems_version: 4.0.3
|
|
317
320
|
specification_version: 4
|
|
318
321
|
summary: Command line tool and ruby interface to optimize (lossless compress, optionally
|
|
319
322
|
lossy) jpeg, png, gif and svg images using external utilities (advpng, gifsicle,
|
|
@@ -340,10 +343,12 @@ test_files:
|
|
|
340
343
|
- spec/image_optim/runner/option_parser_spec.rb
|
|
341
344
|
- spec/image_optim/space_spec.rb
|
|
342
345
|
- spec/image_optim/timer_spec.rb
|
|
346
|
+
- spec/image_optim/true_false_nil_spec.rb
|
|
343
347
|
- spec/image_optim/worker/jpegrecompress_spec.rb
|
|
344
348
|
- spec/image_optim/worker/optipng_spec.rb
|
|
345
349
|
- spec/image_optim/worker/oxipng_spec.rb
|
|
346
350
|
- spec/image_optim/worker/pngquant_spec.rb
|
|
351
|
+
- spec/image_optim/worker/svgo_spec.rb
|
|
347
352
|
- spec/image_optim/worker_spec.rb
|
|
348
353
|
- spec/image_optim_spec.rb
|
|
349
354
|
- spec/images/broken_jpeg
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
name: codeql
|
|
2
|
-
on:
|
|
3
|
-
push:
|
|
4
|
-
pull_request:
|
|
5
|
-
schedule:
|
|
6
|
-
- cron: '43 20 * * 0'
|
|
7
|
-
|
|
8
|
-
jobs:
|
|
9
|
-
analyze:
|
|
10
|
-
runs-on: ubuntu-latest
|
|
11
|
-
permissions:
|
|
12
|
-
actions: read
|
|
13
|
-
contents: read
|
|
14
|
-
security-events: write
|
|
15
|
-
|
|
16
|
-
strategy:
|
|
17
|
-
fail-fast: false
|
|
18
|
-
matrix:
|
|
19
|
-
language: [ 'ruby' ]
|
|
20
|
-
|
|
21
|
-
steps:
|
|
22
|
-
- uses: actions/checkout@v3
|
|
23
|
-
|
|
24
|
-
- uses: github/codeql-action/init@v1
|
|
25
|
-
with:
|
|
26
|
-
languages: ${{ matrix.language }}
|
|
27
|
-
|
|
28
|
-
- uses: github/codeql-action/autobuild@v1
|
|
29
|
-
|
|
30
|
-
- uses: github/codeql-action/analyze@v1
|