discourse_image_optim 0.24.5 → 0.26.1
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 +5 -5
- data/.gitignore +0 -1
- data/.rubocop.yml +38 -34
- data/.travis.yml +11 -9
- data/CHANGELOG.markdown +21 -3
- data/Gemfile +0 -1
- data/README.markdown +61 -50
- data/bin/image_optim +1 -1
- data/image_optim.gemspec +3 -3
- data/lib/image_optim/bin_resolver/bin.rb +1 -0
- data/lib/image_optim/runner/option_parser.rb +3 -1
- data/lib/image_optim/worker/jhead.rb +1 -1
- data/lib/image_optim/worker/jpegtran.rb +1 -1
- data/lib/image_optim/worker/pngquant.rb +6 -0
- data/lib/image_optim/worker.rb +2 -1
- data/script/worker_analysis +76 -58
- data/vendor/jpegrescan +49 -19
- data/vendor/jpegrescan.bat +6 -0
- metadata +6 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: d4cc5e84e0c8dff3c8fd0af654608b8ee958b3283463f7f945076964ae9d3eae
|
|
4
|
+
data.tar.gz: ca77fd28eac0fb79493ed19600eaae18fdb7ea244f9025fdc909e7791a32133e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fcbd37ef3c8899889ebcf1912f0200f7bab98399779e32658b39d55af99da87f452dfec263e91d15a177e1700d566705891f455191758ebc23f9c68d47b96cfa
|
|
7
|
+
data.tar.gz: 0b1379b801324ee93c546c4672abec97385cd7e5c50624e8657c9049d4f4e06135d167783d46901385209aab8b0ae364dfaf40887a67f8931c8a3b6f36255352
|
data/.gitignore
CHANGED
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
|
|
@@ -13,6 +40,9 @@ Lint/AmbiguousBlockAssociation:
|
|
|
13
40
|
Lint/EndAlignment:
|
|
14
41
|
EnforcedStyleAlignWith: variable
|
|
15
42
|
|
|
43
|
+
Lint/NestedPercentLiteral:
|
|
44
|
+
Enabled: false
|
|
45
|
+
|
|
16
46
|
Lint/UnneededSplatExpansion:
|
|
17
47
|
Enabled: false
|
|
18
48
|
|
|
@@ -41,18 +71,9 @@ Security/MarshalLoad:
|
|
|
41
71
|
Exclude:
|
|
42
72
|
- 'script/worker_analysis'
|
|
43
73
|
|
|
44
|
-
Style/AccessModifierIndentation:
|
|
45
|
-
EnforcedStyle: outdent
|
|
46
|
-
|
|
47
74
|
Style/Alias:
|
|
48
75
|
EnforcedStyle: prefer_alias_method
|
|
49
76
|
|
|
50
|
-
Style/CaseIndentation:
|
|
51
|
-
EnforcedStyle: end
|
|
52
|
-
|
|
53
|
-
Style/DotPosition:
|
|
54
|
-
EnforcedStyle: trailing
|
|
55
|
-
|
|
56
77
|
Style/DoubleNegation:
|
|
57
78
|
Enabled: false
|
|
58
79
|
|
|
@@ -60,33 +81,22 @@ Style/EmptyCaseCondition:
|
|
|
60
81
|
Enabled: false
|
|
61
82
|
|
|
62
83
|
Style/Encoding:
|
|
63
|
-
|
|
84
|
+
Enabled: false
|
|
85
|
+
|
|
86
|
+
Style/FormatStringToken:
|
|
87
|
+
Enabled: false
|
|
64
88
|
|
|
65
89
|
Style/HashSyntax:
|
|
66
90
|
EnforcedStyle: hash_rockets
|
|
67
91
|
|
|
68
92
|
Style/IfUnlessModifier:
|
|
69
|
-
MaxLineLength: 40
|
|
70
|
-
|
|
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
93
|
Enabled: false
|
|
82
94
|
|
|
83
95
|
Style/ParallelAssignment:
|
|
84
96
|
Enabled: false
|
|
85
97
|
|
|
86
|
-
Style/
|
|
87
|
-
|
|
88
|
-
'%w': '[]'
|
|
89
|
-
'%W': '[]'
|
|
98
|
+
Style/RescueStandardError:
|
|
99
|
+
EnforcedStyle: implicit
|
|
90
100
|
|
|
91
101
|
Style/Semicolon:
|
|
92
102
|
AllowAsExpressionSeparator: true
|
|
@@ -94,17 +104,11 @@ Style/Semicolon:
|
|
|
94
104
|
Style/SignalException:
|
|
95
105
|
EnforcedStyle: semantic
|
|
96
106
|
|
|
97
|
-
Style/
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
Style/SpaceInsideHashLiteralBraces:
|
|
101
|
-
EnforcedStyle: no_space
|
|
107
|
+
Style/SymbolArray:
|
|
108
|
+
Enabled: false
|
|
102
109
|
|
|
103
110
|
Style/TrailingCommaInArguments:
|
|
104
111
|
EnforcedStyleForMultiline: no_comma
|
|
105
112
|
|
|
106
113
|
Style/TrailingCommaInLiteral:
|
|
107
114
|
EnforcedStyleForMultiline: comma
|
|
108
|
-
|
|
109
|
-
Style/SymbolArray:
|
|
110
|
-
Enabled: false
|
data/.travis.yml
CHANGED
|
@@ -10,30 +10,32 @@ rvm:
|
|
|
10
10
|
- '1.9.3-p551'
|
|
11
11
|
- '2.0.0-p648'
|
|
12
12
|
- '2.1.10'
|
|
13
|
-
- '2.2.
|
|
14
|
-
- '2.3.
|
|
15
|
-
- '2.4.
|
|
16
|
-
- 'jruby-1.7.26'
|
|
13
|
+
- '2.2.8'
|
|
14
|
+
- '2.3.5'
|
|
15
|
+
- '2.4.2'
|
|
17
16
|
- 'jruby-9.0.5.0'
|
|
18
|
-
- 'jruby-9.1.
|
|
17
|
+
- 'jruby-9.1.9.0'
|
|
19
18
|
script:
|
|
20
19
|
- bundle exec image_optim --info
|
|
21
20
|
- bundle exec rspec
|
|
22
21
|
before_install:
|
|
22
|
+
- gem update --system
|
|
23
|
+
- gem update bundler
|
|
24
|
+
- nvm install stable
|
|
23
25
|
- mkdir -p ~/bin
|
|
24
|
-
- command -v svgo || npm install svgo
|
|
26
|
+
- command -v svgo || npm install -g svgo
|
|
25
27
|
- 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'
|
|
26
28
|
matrix:
|
|
27
29
|
include:
|
|
28
30
|
- env: CODECLIMATE=✓
|
|
29
|
-
rvm: '2.4.
|
|
31
|
+
rvm: '2.4.2'
|
|
30
32
|
after_success: bundle exec codeclimate-test-reporter
|
|
31
33
|
- env: RUBOCOP=✓
|
|
32
|
-
rvm: '2.4.
|
|
34
|
+
rvm: '2.4.2'
|
|
33
35
|
script: bundle exec rubocop
|
|
34
36
|
before_install:
|
|
35
37
|
- env: CHECK_RUBIES=✓
|
|
36
|
-
rvm: '2.4.
|
|
38
|
+
rvm: '2.4.2'
|
|
37
39
|
script: bundle exec travis_check_rubies
|
|
38
40
|
before_install:
|
|
39
41
|
addons:
|
data/CHANGELOG.markdown
CHANGED
|
@@ -2,8 +2,26 @@
|
|
|
2
2
|
|
|
3
3
|
## unreleased
|
|
4
4
|
|
|
5
|
+
## v0.26.1 (2017-12-14)
|
|
6
|
+
|
|
7
|
+
* Require `'date'` which is used in parsing pngout version [toy/image_optim_pack#14](https://github.com/toy/image_optim_pack/issues/14) [@toy](https://github.com/toy)
|
|
8
|
+
|
|
5
9
|
* Add `timeout` option to workers [#21](https://github.com/toy/image_optim/issues/21)
|
|
6
|
-
[@tgxworld](http://github.com/tgxworld)
|
|
10
|
+
[@tgxworld](http://github.com/tgxworld)
|
|
11
|
+
|
|
12
|
+
## v0.26.0 (2017-11-13)
|
|
13
|
+
|
|
14
|
+
* Enable `jpegrescan` by default after removing its dependency on `File::Slurp` and fixing for windows [#153](https://github.com/toy/image_optim/issues/153) [@toy](https://github.com/toy)
|
|
15
|
+
* Extend description of `--verbose` flag [#152](https://github.com/toy/image_optim/issues/152) [@toy](https://github.com/toy)
|
|
16
|
+
|
|
17
|
+
## v0.25.0 (2017-07-06)
|
|
18
|
+
|
|
19
|
+
* 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)
|
|
20
|
+
* 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)
|
|
21
|
+
|
|
22
|
+
## v0.24.3 (2017-05-04)
|
|
23
|
+
|
|
24
|
+
* Set mode of cache files to `0666 & ~umask`, related to [#147](https://github.com/toy/image_optim/issues/147) [@toy](https://github.com/toy)
|
|
7
25
|
|
|
8
26
|
## v0.24.2 (2017-02-18)
|
|
9
27
|
|
|
@@ -18,7 +36,7 @@
|
|
|
18
36
|
|
|
19
37
|
## v0.24.0 (2016-08-14)
|
|
20
38
|
|
|
21
|
-
* Rails image assets optimization is extracted into [
|
|
39
|
+
* Rails image assets optimization is extracted into [image_optim_rails gem](https://github.com/toy/image_optim_rails) [#127](https://github.com/toy/image_optim/issues/127) [@toy](https://github.com/toy)
|
|
22
40
|
* Add proper handling of `ImageOptim.respond_to?` [@toy](https://github.com/toy)
|
|
23
41
|
* Fix an issue not working OptiPNG `interlace` option [#136](https://github.com/toy/image_optim/pull/136) [@mrk21](https://github.com/mrk21)
|
|
24
42
|
* Minimize number of file system calls in default implementation of `optimized?` [#137](https://github.com/toy/image_optim/issues/137) [@toy](https://github.com/toy)
|
|
@@ -265,7 +283,7 @@
|
|
|
265
283
|
|
|
266
284
|
* Warn if directly added files are not images or are not optimizable [@toy](https://github.com/toy)
|
|
267
285
|
* Recursively scan directories for images [#4](https://github.com/toy/image_optim/issues/4) [@toy](https://github.com/toy)
|
|
268
|
-
* Typo in bin/image_optim
|
|
286
|
+
* Typo in bin/image_optim [#3](https://github.com/toy/image_optim/issues/3) [@fabiomcosta](https://github.com/fabiomcosta)
|
|
269
287
|
|
|
270
288
|
## v0.5.1 (2012-08-07)
|
|
271
289
|
|
data/Gemfile
CHANGED
data/README.markdown
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
Optimize (lossless compress, optionally lossy) images (jpeg, png, gif, svg) using external utilities:
|
|
12
12
|
|
|
13
13
|
* [advpng](http://advancemame.sourceforge.net/doc-advpng.html) from [AdvanceCOMP](http://advancemame.sourceforge.net/comp-readme.html)
|
|
14
|
-
(will use [zopfli](https://code.google.com/p/zopfli/) on default/maximum level 4)
|
|
14
|
+
(will use [zopfli](https://code.google.com/p/zopfli/) on default/maximum level 4)
|
|
15
15
|
* [gifsicle](http://www.lcdf.org/gifsicle/)
|
|
16
16
|
* [jhead](http://www.sentex.net/~mwandel/jhead/)
|
|
17
17
|
* [jpegoptim](http://www.kokkonen.net/tjko/projects.html)
|
|
@@ -57,9 +57,11 @@ gem 'image_optim_pack'
|
|
|
57
57
|
With version:
|
|
58
58
|
|
|
59
59
|
<!---<update-version>-->
|
|
60
|
+
|
|
60
61
|
```ruby
|
|
61
|
-
gem 'image_optim', '~> 0.
|
|
62
|
+
gem 'image_optim', '~> 0.26'
|
|
62
63
|
```
|
|
64
|
+
|
|
63
65
|
<!---</update-version>-->
|
|
64
66
|
|
|
65
67
|
If you want to check latest changes:
|
|
@@ -241,7 +243,7 @@ image_optim.optimize_images_data(datas)
|
|
|
241
243
|
|
|
242
244
|
### From rails
|
|
243
245
|
|
|
244
|
-
Rails image assets optimization is extracted into [
|
|
246
|
+
Rails image assets optimization is extracted into [image_optim_rails gem](https://github.com/toy/image_optim_rails).
|
|
245
247
|
|
|
246
248
|
## Configuration
|
|
247
249
|
|
|
@@ -263,79 +265,92 @@ optipng:
|
|
|
263
265
|
|
|
264
266
|
## Options
|
|
265
267
|
|
|
266
|
-
* `:nice` — Nice level, priority of all used tools with higher value meaning lower priority, in range `-20..19`, negative values can be set only if run by root user
|
|
267
|
-
* `:threads` — Number of threads or disable
|
|
268
|
-
* `:verbose` — Verbose output
|
|
269
|
-
* `:pack` — Require
|
|
270
|
-
* `:skip_missing_workers` — Skip workers with missing or problematic binaries
|
|
271
|
-
* `:allow_lossy` — Allow lossy workers and optimizations
|
|
268
|
+
* `:nice` — Nice level, priority of all used tools with higher value meaning lower priority, in range `-20..19`, negative values can be set only if run by root user _(defaults to `10`)_
|
|
269
|
+
* `:threads` — Number of threads or disable _(defaults to number of processors)_
|
|
270
|
+
* `:verbose` — Verbose output _(defaults to `false`)_
|
|
271
|
+
* `:pack` — Require image_optim_pack or disable it, by default image_optim_pack will be used if available, will turn on `:skip-missing-workers` unless explicitly disabled _(defaults to `nil`)_
|
|
272
|
+
* `:skip_missing_workers` — Skip workers with missing or problematic binaries _(defaults to `false`)_
|
|
273
|
+
* `:allow_lossy` — Allow lossy workers and optimizations _(defaults to `false`)_
|
|
272
274
|
* `:cache_dir` — Configure cache directory
|
|
273
275
|
* `:cache_worker_digests` - Also cache worker digests along with original file digest and worker options: updating workers invalidates cache
|
|
274
|
-
* `:timeout` — Number of seconds before workers are timed out. Must be greater than 0 to enable timeout.
|
|
276
|
+
* `:timeout` — Number of seconds before workers are timed out. Must be greater than 0 to enable timeout. _(defaults to `0`)_
|
|
275
277
|
|
|
276
278
|
Worker can be disabled by passing `false` instead of options hash or by setting option `:disable` to `true`.
|
|
277
279
|
|
|
278
280
|
<!---<worker-options>-->
|
|
281
|
+
|
|
279
282
|
<!-- markdown for worker options is generated by `script/update_worker_options_in_readme` -->
|
|
280
283
|
|
|
281
284
|
### advpng:
|
|
282
|
-
|
|
283
|
-
* `:
|
|
285
|
+
|
|
286
|
+
* `:level` — Compression level: `0` - don't compress, `1` - fast, `2` - normal, `3` - extra, `4` - extreme _(defaults to `4`)_
|
|
287
|
+
* `:timeout` — Number of seconds before worker is timed out. Must be greater than 0 to enable timeout. _(defaults to `0`)_
|
|
284
288
|
|
|
285
289
|
### gifsicle:
|
|
290
|
+
|
|
286
291
|
* `: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)
|
|
287
|
-
* `:level` — Compression level: `1` - light and fast, `2` - normal, `3` - heavy (slower)
|
|
288
|
-
* `:careful` — Avoid bugs with some software
|
|
289
|
-
* `:timeout` — Number of seconds before worker is timed out. Must be greater than 0 to enable timeout.
|
|
292
|
+
* `:level` — Compression level: `1` - light and fast, `2` - normal, `3` - heavy (slower) _(defaults to `3`)_
|
|
293
|
+
* `:careful` — Avoid bugs with some software _(defaults to `false`)_
|
|
294
|
+
* `:timeout` — Number of seconds before worker is timed out. Must be greater than 0 to enable timeout. _(defaults to `0`)_
|
|
290
295
|
|
|
291
296
|
### jhead:
|
|
292
|
-
|
|
297
|
+
|
|
298
|
+
* `:timeout` — Number of seconds before worker is timed out. Must be greater than 0 to enable timeout. _(defaults to `0`)_
|
|
293
299
|
|
|
294
300
|
### jpegoptim:
|
|
295
|
-
|
|
296
|
-
* `:
|
|
297
|
-
* `:
|
|
298
|
-
* `:
|
|
301
|
+
|
|
302
|
+
* `:allow_lossy` — Allow limiting maximum quality _(defaults to `false`)_
|
|
303
|
+
* `:strip` — List of extra markers to strip: `:comments`, `:exif`, `:iptc`, `:icc` or `:all` _(defaults to `:all`)_
|
|
304
|
+
* `:max_quality` — Maximum image quality factor `0`..`100`, ignored in default/lossless mode _(defaults to `100`)_
|
|
305
|
+
* `:timeout` — Number of seconds before worker is timed out. Must be greater than 0 to enable timeout. _(defaults to `0`)_
|
|
299
306
|
|
|
300
307
|
### jpegrecompress:
|
|
301
|
-
|
|
302
|
-
* `:
|
|
303
|
-
* `:
|
|
308
|
+
|
|
309
|
+
* `:allow_lossy` — Allow worker, it is always lossy _(defaults to `false`)_
|
|
310
|
+
* `:quality` — JPEG quality preset: `0` - low, `1` - medium, `2` - high, `3` - veryhigh _(defaults to `3`)_
|
|
311
|
+
* `:timeout` — Number of seconds before worker is timed out. Must be greater than 0 to enable timeout. _(defaults to `0`)_
|
|
304
312
|
|
|
305
313
|
### jpegtran:
|
|
306
|
-
|
|
307
|
-
* `:
|
|
308
|
-
* `:
|
|
309
|
-
* `:
|
|
314
|
+
|
|
315
|
+
* `:copy_chunks` — Copy all chunks _(defaults to `false`)_
|
|
316
|
+
* `:progressive` — Create progressive JPEG file _(defaults to `true`)_
|
|
317
|
+
* `:jpegrescan` — Use jpegtran through jpegrescan, ignore progressive option _(defaults to `false`)_
|
|
318
|
+
* `:timeout` — Number of seconds before worker is timed out. Must be greater than 0 to enable timeout. _(defaults to `0`)_
|
|
310
319
|
|
|
311
320
|
### optipng:
|
|
312
|
-
|
|
313
|
-
* `:
|
|
314
|
-
* `:
|
|
315
|
-
* `:
|
|
321
|
+
|
|
322
|
+
* `:level` — Optimization level preset: `0` is least, `7` is best _(defaults to `6`)_
|
|
323
|
+
* `:interlace` — Interlace: `true` - interlace on, `false` - interlace off, `nil` - as is in original image _(defaults to `false`)_
|
|
324
|
+
* `:strip` — Remove all auxiliary chunks _(defaults to `true`)_
|
|
325
|
+
* `:timeout` — Number of seconds before worker is timed out. Must be greater than 0 to enable timeout. _(defaults to `0`)_
|
|
316
326
|
|
|
317
327
|
### pngcrush:
|
|
318
|
-
|
|
319
|
-
* `:
|
|
320
|
-
* `:
|
|
321
|
-
* `:
|
|
322
|
-
* `:
|
|
328
|
+
|
|
329
|
+
* `:chunks` — List of chunks to remove or `:alla` - all except tRNS/transparency or `:allb` - all except tRNS and gAMA/gamma _(defaults to `:alla`)_
|
|
330
|
+
* `:fix` — Fix otherwise fatal conditions such as bad CRCs _(defaults to `false`)_
|
|
331
|
+
* `:brute` — Brute force try all methods, very time-consuming and generally not worthwhile _(defaults to `false`)_
|
|
332
|
+
* `:blacken` — Blacken fully transparent pixels _(defaults to `true`)_
|
|
333
|
+
* `:timeout` — Number of seconds before worker is timed out. Must be greater than 0 to enable timeout. _(defaults to `0`)_
|
|
323
334
|
|
|
324
335
|
### pngout:
|
|
325
|
-
|
|
326
|
-
* `:
|
|
327
|
-
* `:
|
|
336
|
+
|
|
337
|
+
* `:copy_chunks` — Copy optional chunks _(defaults to `false`)_
|
|
338
|
+
* `:strategy` — Strategy: `0` - xtreme, `1` - intense, `2` - longest Match, `3` - huffman Only, `4` - uncompressed _(defaults to `0`)_
|
|
339
|
+
* `:timeout` — Number of seconds before worker is timed out. Must be greater than 0 to enable timeout. _(defaults to `0`)_
|
|
328
340
|
|
|
329
341
|
### pngquant:
|
|
330
|
-
|
|
331
|
-
* `:
|
|
332
|
-
* `:
|
|
333
|
-
* `:
|
|
342
|
+
|
|
343
|
+
* `:allow_lossy` — Allow quality option _(defaults to `false`)_
|
|
344
|
+
* `:max_colors` — Maximum number of colors to use _(defaults to `256`)_
|
|
345
|
+
* `: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)_
|
|
346
|
+
* `:speed` — speed/quality trade-off: `1` - slow, `3` - default, `11` - fast & rough _(defaults to `3`)_
|
|
347
|
+
* `:timeout` — Number of seconds before worker is timed out. Must be greater than 0 to enable timeout. _(defaults to `0`)_
|
|
334
348
|
|
|
335
349
|
### svgo:
|
|
336
|
-
|
|
337
|
-
* `:
|
|
338
|
-
* `:
|
|
350
|
+
|
|
351
|
+
* `:disable_plugins` — List of plugins to disable _(defaults to `[]`)_
|
|
352
|
+
* `:enable_plugins` — List of plugins to enable _(defaults to `[]`)_
|
|
353
|
+
* `:timeout` — Number of seconds before worker is timed out. Must be greater than 0 to enable timeout. _(defaults to `0`)_
|
|
339
354
|
|
|
340
355
|
<!---</worker-options>-->
|
|
341
356
|
|
|
@@ -345,10 +360,6 @@ Worker can be disabled by passing `false` instead of options hash or by setting
|
|
|
345
360
|
|
|
346
361
|
If you would like to contribute - that is great and you are very welcome. Please check few notes in file [CONTRIBUTING.markdown](CONTRIBUTING.markdown).
|
|
347
362
|
|
|
348
|
-
Financial contributions can be made via [gratipay](https://gratipay.com/toy/).
|
|
349
|
-
|
|
350
|
-
[](https://gratipay.com/toy/)
|
|
351
|
-
|
|
352
363
|
## ChangeLog
|
|
353
364
|
|
|
354
365
|
In separate file [CHANGELOG.markdown](CHANGELOG.markdown).
|
data/bin/image_optim
CHANGED
data/image_optim.gemspec
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Gem::Specification.new do |s|
|
|
4
4
|
s.name = 'discourse_image_optim'
|
|
5
|
-
s.version = '0.
|
|
5
|
+
s.version = '0.26.1'
|
|
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']
|
|
@@ -28,7 +28,7 @@ EOF
|
|
|
28
28
|
|
|
29
29
|
s.add_development_dependency 'image_optim_pack', '~> 0.2', '>= 0.2.2'
|
|
30
30
|
s.add_development_dependency 'rspec', '~> 3.0'
|
|
31
|
-
if RUBY_VERSION >= '2.
|
|
32
|
-
s.add_development_dependency 'rubocop', '~> 0.
|
|
31
|
+
if RUBY_VERSION >= '2.1'
|
|
32
|
+
s.add_development_dependency 'rubocop', '~> 0.52'
|
|
33
33
|
end
|
|
34
34
|
end
|
|
@@ -225,7 +225,9 @@ ImageOptim::Runner::OptionParser::DEFINE = proc do |op, options|
|
|
|
225
225
|
op.separator nil
|
|
226
226
|
op.separator ' Common options:'
|
|
227
227
|
|
|
228
|
-
op.on_tail('-v', '--verbose', 'Verbose output'
|
|
228
|
+
op.on_tail('-v', '--verbose', 'Verbose output (show global and worker '\
|
|
229
|
+
'config, binary resolution log, information about each tool invocation, '\
|
|
230
|
+
'backtrace of exception)') do
|
|
229
231
|
options[:verbose] = true
|
|
230
232
|
end
|
|
231
233
|
|
|
@@ -14,7 +14,7 @@ class ImageOptim
|
|
|
14
14
|
option(:progressive, true, 'Create progressive JPEG file'){ |v| !!v }
|
|
15
15
|
|
|
16
16
|
JPEGRESCAN_OPTION =
|
|
17
|
-
option(:jpegrescan,
|
|
17
|
+
option(:jpegrescan, true, 'Use jpegtran through jpegrescan, '\
|
|
18
18
|
'ignore progressive option'){ |v| !!v }
|
|
19
19
|
|
|
20
20
|
TIMEOUT_OPTION = timeout_option
|
|
@@ -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 '\
|
|
@@ -51,6 +56,7 @@ class ImageOptim
|
|
|
51
56
|
--speed=#{speed}
|
|
52
57
|
--output=#{dst}
|
|
53
58
|
--force
|
|
59
|
+
#{max_colors}
|
|
54
60
|
--
|
|
55
61
|
#{src}
|
|
56
62
|
]
|
data/lib/image_optim/worker.rb
CHANGED
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)
|
data/vendor/jpegrescan
CHANGED
|
@@ -1,11 +1,19 @@
|
|
|
1
|
-
#!/usr/bin/perl
|
|
1
|
+
#!/usr/bin/env perl
|
|
2
2
|
# jpegrescan by Loren Merritt
|
|
3
3
|
# Last updated: 2008-11-29 / 2013-03-19
|
|
4
4
|
# This code is public domain.
|
|
5
5
|
|
|
6
|
-
use
|
|
6
|
+
use warnings;
|
|
7
7
|
use File::Temp qw/ tempfile /;
|
|
8
8
|
|
|
9
|
+
%switches = ();
|
|
10
|
+
while (@ARGV && $ARGV[0] =~ /^-.+/) {
|
|
11
|
+
for (shift @ARGV) {
|
|
12
|
+
m/^--$/ && last;
|
|
13
|
+
m/^-([svq])$/ && do { $switches{$1} = 1; next; };
|
|
14
|
+
die "Unknown switch: $_";
|
|
15
|
+
}
|
|
16
|
+
}
|
|
9
17
|
@ARGV==2 or die "usage: jpegrescan in.jpg out.jpg
|
|
10
18
|
tries various progressive scan orders
|
|
11
19
|
switches:
|
|
@@ -15,26 +23,49 @@ switches:
|
|
|
15
23
|
";
|
|
16
24
|
$fin = $ARGV[0];
|
|
17
25
|
$fout = $ARGV[1];
|
|
18
|
-
(undef, $
|
|
19
|
-
$
|
|
20
|
-
$
|
|
21
|
-
$
|
|
22
|
-
|
|
23
|
-
|
|
26
|
+
(undef, $meta_tmp) = tempfile(SUFFIX => ".scan");
|
|
27
|
+
(undef, $baseline_tmp) = tempfile(SUFFIX => ".jpg");
|
|
28
|
+
$output_tmp = $fout;
|
|
29
|
+
$verbose = $switches{'v'};
|
|
30
|
+
$quiet = $switches{'q'};
|
|
31
|
+
@strip = $switches{'s'} ? ("-copy","none") : ("-copy","all");
|
|
24
32
|
undef $/;
|
|
25
33
|
$|=1;
|
|
26
34
|
|
|
35
|
+
sub read_file {
|
|
36
|
+
my ($path) = @_;
|
|
37
|
+
my $data;
|
|
38
|
+
|
|
39
|
+
open my $fh, '<', $path
|
|
40
|
+
or die "Could not open file $path: $!\n";
|
|
41
|
+
binmode $fh;
|
|
42
|
+
$data = <$fh>;
|
|
43
|
+
close $fh
|
|
44
|
+
or die "Could not close $path: $!\n";
|
|
45
|
+
|
|
46
|
+
return $data;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
sub write_file {
|
|
50
|
+
my ($path, $data) = @_;
|
|
51
|
+
|
|
52
|
+
open my $fh, '>', $path
|
|
53
|
+
or die "Could not open file $path: $!\n";
|
|
54
|
+
binmode $fh;
|
|
55
|
+
print $fh $data;
|
|
56
|
+
close $fh
|
|
57
|
+
or die "Could not close $path: $!\n";
|
|
58
|
+
}
|
|
59
|
+
|
|
27
60
|
# convert the input to baseline, just to make all the other conversions faster
|
|
28
61
|
# FIXME there's still a bunch of redundant computation in separate calls to jpegtran
|
|
29
62
|
open $OLDERR, ">&", STDERR;
|
|
30
|
-
open STDERR, ">", $
|
|
31
|
-
|
|
32
|
-
write_file($jtmp, <TRAN>);
|
|
33
|
-
close TRAN;
|
|
63
|
+
open STDERR, ">", $meta_tmp;
|
|
64
|
+
system("jpegtran", "-v", @strip, "-optimize", "-outfile", $baseline_tmp, $fin) == 0 or die;
|
|
34
65
|
open STDERR, ">&", $OLDERR;
|
|
35
66
|
|
|
36
|
-
$type = read_file($
|
|
37
|
-
$type =~ /components=(\d+)/ or die;
|
|
67
|
+
$type = read_file($meta_tmp);
|
|
68
|
+
$type =~ /components=(\d+)/ or die "Could not find components=\d+ in $type";
|
|
38
69
|
$rgb = $1==3 ? 1 : $1==1 ? 0 : die "not RGB nor gray\n";
|
|
39
70
|
|
|
40
71
|
# FIXME optimize order for either progressive transfer or decoding speed
|
|
@@ -55,10 +86,9 @@ sub canonize {
|
|
|
55
86
|
sub try {
|
|
56
87
|
my $txt = canonize(shift);
|
|
57
88
|
return $memo{$txt} if $memo{$txt};
|
|
58
|
-
write_file($
|
|
59
|
-
|
|
60
|
-
$data =
|
|
61
|
-
close TRAN;
|
|
89
|
+
write_file($meta_tmp, $txt);
|
|
90
|
+
system("jpegtran", @strip, "-scans", $meta_tmp, "-outfile", $output_tmp, $baseline_tmp) == 0 or die;
|
|
91
|
+
$data = read_file($output_tmp);
|
|
62
92
|
my $s = length $data;
|
|
63
93
|
$s or die;
|
|
64
94
|
$memo{$txt} = $s;
|
|
@@ -140,4 +170,4 @@ $old_size = -s $fin;
|
|
|
140
170
|
if($size < $old_size) {
|
|
141
171
|
write_file($fout, $data);
|
|
142
172
|
}
|
|
143
|
-
unlink $
|
|
173
|
+
unlink $meta_tmp, $baseline_tmp;
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: discourse_image_optim
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.26.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ivan Kuchin
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2018-07-03 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.52'
|
|
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.52'
|
|
143
143
|
description:
|
|
144
144
|
email:
|
|
145
145
|
executables:
|
|
@@ -250,6 +250,7 @@ files:
|
|
|
250
250
|
- spec/images/vergroessert.jpg
|
|
251
251
|
- spec/spec_helper.rb
|
|
252
252
|
- vendor/jpegrescan
|
|
253
|
+
- vendor/jpegrescan.bat
|
|
253
254
|
homepage: http://github.com/toy/discourse_image_optim
|
|
254
255
|
licenses:
|
|
255
256
|
- MIT
|
|
@@ -272,7 +273,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
272
273
|
version: '0'
|
|
273
274
|
requirements: []
|
|
274
275
|
rubyforge_project: discourse_image_optim
|
|
275
|
-
rubygems_version: 2.6
|
|
276
|
+
rubygems_version: 2.7.6
|
|
276
277
|
signing_key:
|
|
277
278
|
specification_version: 4
|
|
278
279
|
summary: Optimize (lossless compress, optionally lossy) images (jpeg, png, gif, svg)
|