image_optim 0.30.0 → 0.31.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
  SHA256:
3
- metadata.gz: 0fb8179d2e5c5236278611842ad5dbb3ab39fc1ff92bbd50ed9dae6ccd931bf5
4
- data.tar.gz: 83ab00c10f205a164ea66f51b6964d3fb4fa7d019c30e472496a0e21879242c0
3
+ metadata.gz: e80e82d67e3434476f0bdf332b14b6369601010aaeef7ab7b901515d0c03565c
4
+ data.tar.gz: 16f304385c879cf1afc0073d7d037fb548d6c260f57e2b94cdcdd974f3cd4b4e
5
5
  SHA512:
6
- metadata.gz: 901e787f11a9829b96dd40f0d8aff14d4f2ac691ff3eaa8486d2915fd020b2f6e0d7425b360cf3bdbc52018afd69508078b69dd4e7846a138d9d5e9ea3b613d7
7
- data.tar.gz: 8a21b871165184221bf9af9b9647f144a21e5da1ebe03680ac54b09edf955068f0364da1ee0d6d8dd9976bb96c76ff0cdcf49cb005f43fd5c5cdfe3f51cde39f
6
+ metadata.gz: b0395980a804453e3273f779c1217d5dd5b9b7c522e74964070b43f2b3ac433f9f39d5f997a3e9c6594f22d244752910eea1697ac2e570de34e6b0641555b9e8
7
+ data.tar.gz: 9de0bebe89071d3aa7bd506b02dc684b53d998dcfccab1debad72bdc244e6fbae6eb0ac2d5871359fe2ffa5cb9e7c5ae8a7dc98829e00e8abef49c017ac3b00c
@@ -0,0 +1,59 @@
1
+ name: check
2
+ on:
3
+ push:
4
+ pull_request:
5
+ schedule:
6
+ - cron: 45 4 * * 2
7
+ jobs:
8
+ check:
9
+ runs-on: ubuntu-latest
10
+ strategy:
11
+ matrix:
12
+ ruby:
13
+ - '2.0'
14
+ - '2.1'
15
+ - '2.2'
16
+ - '2.3'
17
+ - '2.4'
18
+ - '2.5'
19
+ - '2.6'
20
+ - '2.7'
21
+ - '3.0'
22
+ - jruby-9.2
23
+ fail-fast: false
24
+ steps:
25
+ - uses: actions/checkout@v2
26
+ - uses: ruby/setup-ruby@v1
27
+ with:
28
+ ruby-version: "${{ matrix.ruby }}"
29
+ bundler-cache: true
30
+ - run: sudo npm install -g svgo
31
+ - run: curl -L "https://www.jonof.id.au/files/kenutils/pngout-20200115-linux.tar.gz" | sudo tar -xz -C /usr/local/bin --strip-components 2 --wildcards '*/amd64/pngout'
32
+ - run: curl -L "https://github.com/shssoichiro/oxipng/releases/download/v4.0.3/oxipng-4.0.3-x86_64-unknown-linux-musl.tar.gz" | tar -xz -C /usr/local/bin --strip-components 1 --wildcards '*oxipng'
33
+ - run: bundle exec image_optim --info
34
+ - run: bundle exec rspec
35
+ coverage:
36
+ runs-on: ubuntu-latest
37
+ env:
38
+ CC_TEST_REPORTER_ID: b433c6540d220a2da0663670c9b260806bafdb3a43c6f22b2e81bfb1f87b12fe
39
+ steps:
40
+ - uses: actions/checkout@v2
41
+ - uses: ruby/setup-ruby@v1
42
+ with:
43
+ ruby-version: '3.0'
44
+ bundler-cache: true
45
+ - run: sudo npm install -g svgo
46
+ - run: curl -L "https://www.jonof.id.au/files/kenutils/pngout-20200115-linux.tar.gz" | sudo tar -xz -C /usr/local/bin --strip-components 2 --wildcards '*/amd64/pngout'
47
+ - run: curl -L "https://github.com/shssoichiro/oxipng/releases/download/v4.0.3/oxipng-4.0.3-x86_64-unknown-linux-musl.tar.gz" | tar -xz -C /usr/local/bin --strip-components 1 --wildcards '*oxipng'
48
+ - uses: paambaati/codeclimate-action@v2.7.5
49
+ with:
50
+ coverageCommand: bundle exec rspec
51
+ rubocop:
52
+ runs-on: ubuntu-latest
53
+ steps:
54
+ - uses: actions/checkout@v2
55
+ - uses: ruby/setup-ruby@v1
56
+ with:
57
+ ruby-version: '3.0'
58
+ bundler-cache: true
59
+ - run: bundle exec rubocop
data/CHANGELOG.markdown CHANGED
@@ -2,6 +2,11 @@
2
2
 
3
3
  ## unreleased
4
4
 
5
+ ## v0.31.0 (2021-10-03)
6
+
7
+ * Add support for Oxipng [#167](https://github.com/toy/image_optim/issues/167) [#190](https://github.com/toy/image_optim/pull/190) [@oblakeerickson](https://github.com/oblakeerickson)
8
+ * Fix `TypeError: can't convert ImageOptim::Timer into Float` with Ruby 3 [#194](https://github.com/toy/image_optim/pull/194) [@yahonda](https://github.com/yahonda)
9
+
5
10
  ## v0.30.0 (2021-05-11)
6
11
 
7
12
  * Add `timeout` option to restrict maximum time spent on every image [#21](https://github.com/toy/image_optim/issues/21) [#148](https://github.com/toy/image_optim/pull/148) [#149](https://github.com/toy/image_optim/pull/149) [#162](https://github.com/toy/image_optim/pull/162) [#184](https://github.com/toy/image_optim/pull/184) [#189](https://github.com/toy/image_optim/pull/189) [@tgxworld](https://github.com/tgxworld) [@oblakeerickson](https://github.com/oblakeerickson) [@toy](https://github.com/toy)
@@ -11,4 +11,4 @@
11
11
  * Rebase on master and squash commits to logical units
12
12
  * Push your branch: `git push origin awesome-changes`
13
13
  * Create pull request
14
- * Check if [travis is happy](https://travis-ci.org/toy/image_optim/pull_requests)
14
+ * Check if [github actions workflow is happy](https://github.com/toy/image_optim_pack/actions/workflows/check.yml)
data/Gemfile CHANGED
@@ -4,14 +4,8 @@ source 'https://rubygems.org'
4
4
 
5
5
  gemspec
6
6
 
7
- if ENV['CODECLIMATE']
7
+ if ENV['CC_TEST_REPORTER_ID']
8
8
  group :test do
9
9
  gem 'simplecov'
10
-
11
- gem 'codeclimate-test-reporter'
12
10
  end
13
11
  end
14
-
15
- if ENV['CHECK_RUBIES']
16
- gem 'travis_check_rubies', '~> 0.2'
17
- end
data/README.markdown CHANGED
@@ -1,10 +1,10 @@
1
- [![Gem Version](https://img.shields.io/gem/v/image_optim.svg?style=flat)](https://rubygems.org/gems/image_optim)
2
- [![Build Status](https://img.shields.io/travis/toy/image_optim/master.svg?style=flat)](https://travis-ci.org/toy/image_optim)
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
- [![Code Climate](https://img.shields.io/codeclimate/maintainability/toy/image_optim.svg?style=flat)](https://codeclimate.com/github/toy/image_optim)
5
- [![Code Climate Coverage](https://img.shields.io/codeclimate/c/toy/image_optim.svg?style=flat)](https://codeclimate.com/github/toy/image_optim)
6
- [![Depfu](https://badges.depfu.com/badges/221b4832fa96f613aa5401f7cb4030ac/overview.svg)](https://depfu.com/github/toy/image_optim)
7
- [![Inch CI](https://inch-ci.org/github/toy/image_optim.svg?branch=master&style=flat)](https://inch-ci.org/github/toy/image_optim)
1
+ [![Gem Version](https://img.shields.io/gem/v/image_optim?logo=rubygems)](https://rubygems.org/gems/image_optim)
2
+ [![Build Status](https://img.shields.io/github/workflow/status/toy/image_optim/check/master?logo=github)](https://github.com/toy/image_optim/actions/workflows/check.yml)
3
+ [![AppVeyor Status](https://img.shields.io/appveyor/build/toy/image-optim/master?label=windows&logo=appveyor)](https://ci.appveyor.com/project/toy/image-optim)
4
+ [![Code Climate](https://img.shields.io/codeclimate/maintainability/toy/image_optim?logo=codeclimate)](https://codeclimate.com/github/toy/image_optim)
5
+ [![Code Climate Coverage](https://img.shields.io/codeclimate/coverage/toy/image_optim?logo=codeclimate)](https://codeclimate.com/github/toy/image_optim)
6
+ [![Depfu](https://img.shields.io/depfu/toy/image_optim)](https://depfu.com/github/toy/image_optim)
7
+ [![Inch CI](https://inch-ci.org/github/toy/image_optim.svg?branch=master)](https://inch-ci.org/github/toy/image_optim)
8
8
 
9
9
  # image_optim
10
10
 
@@ -18,6 +18,7 @@ Command line tool and ruby interface to optimize (lossless compress, optionally
18
18
  * [jpeg-recompress](https://github.com/danielgtaylor/jpeg-archive#jpeg-recompress)
19
19
  * jpegtran from [Independent JPEG Group's JPEG library](http://www.ijg.org/)
20
20
  * [optipng](http://optipng.sourceforge.net/)
21
+ * [oxipng](https://github.com/shssoichiro/oxipng)
21
22
  * [pngcrush](http://pmt.sourceforge.net/pngcrush/)
22
23
  * [pngout](http://www.advsys.net/ken/util/pngout.htm)
23
24
  * [pngquant](http://pngquant.org/)
@@ -60,7 +61,7 @@ With version:
60
61
 
61
62
  <!---<update-version>-->
62
63
  ```ruby
63
- gem 'image_optim', '~> 0.30'
64
+ gem 'image_optim', '~> 0.31'
64
65
  ```
65
66
  <!---</update-version>-->
66
67
 
@@ -166,6 +167,14 @@ sudo port install advancecomp gifsicle jhead jpegoptim jpeg optipng pngcrush png
166
167
  brew install advancecomp gifsicle jhead jpegoptim jpeg optipng pngcrush pngquant jonof/kenutils/pngout
167
168
  ```
168
169
 
170
+ ### oxipng installation (optional)
171
+
172
+ Unless it is available in your chosen package manager, can be installed using cargo:
173
+
174
+ ```bash
175
+ cargo install oxipng
176
+ ```
177
+
169
178
  ### pngout installation (optional)
170
179
 
171
180
  If you installed the dependencies via brew, pngout should be installed already. Otherwise, you can install `pngout` by downloading and installing the [binary versions](http://www.jonof.id.au/kenutils).
data/image_optim.gemspec CHANGED
@@ -2,8 +2,8 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = 'image_optim'
5
- s.version = '0.30.0'
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)}
5
+ s.version = '0.31.0'
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, oxipng, pngcrush, pngout, pngquant, svgo)}
7
7
  s.homepage = "https://github.com/toy/#{s.name}"
8
8
  s.authors = ['Ivan Kuchin']
9
9
  s.license = 'MIT'
@@ -109,7 +109,7 @@ class ImageOptim
109
109
  case name
110
110
  when :advpng
111
111
  capture("#{escaped_path} --version 2> #{Path::NULL}")[/\bv(\d+(\.\d+)+|none)/, 1]
112
- when :gifsicle, :jpegoptim, :optipng
112
+ when :gifsicle, :jpegoptim, :optipng, :oxipng
113
113
  capture("#{escaped_path} --version 2> #{Path::NULL}")[/\d+(\.\d+)+/]
114
114
  when :svgo, :pngquant
115
115
  capture("#{escaped_path} --version 2>&1")[/\A\d+(\.\d+)+/]
@@ -17,7 +17,7 @@ class ImageOptim
17
17
  pid = Process.spawn(*args)
18
18
 
19
19
  waiter = Process.detach(pid)
20
- if waiter.join(timeout)
20
+ if waiter.join(timeout.to_f)
21
21
  status = waiter.value
22
22
 
23
23
  check_status!(status)
@@ -186,7 +186,7 @@ class ImageOptim
186
186
  {disable: true}
187
187
  else
188
188
  fail ConfigurationError, "Got #{worker_options.inspect} for "\
189
- "#{klass.name} options"
189
+ "#{klass.name} options"
190
190
  end
191
191
  end
192
192
 
@@ -38,7 +38,7 @@ class ImageOptim
38
38
  columns = terminal_columns - 1
39
39
  # 1 for distance between summary and description
40
40
  # 2 for additional indent
41
- wrapped_indent = summary_indent + ' ' * (summary_width + 1 + 2)
41
+ wrapped_indent = summary_indent + (' ' * (summary_width + 1 + 2))
42
42
  wrapped_width = columns - wrapped_indent.length
43
43
  # don't try to wrap if there is too little space for description
44
44
  return text if wrapped_width < 20
@@ -84,7 +84,7 @@ ImageOptim::Runner::OptionParser::DEFINE = proc do |op, options|
84
84
  ImageOptim::TrueFalseNil.add_to_option_parser(op)
85
85
  ImageOptim::NonNegativeIntegerRange.add_to_option_parser(op)
86
86
 
87
- op.banner = <<-TEXT.gsub(/^\s*\|/, '')
87
+ op.banner = <<-TEXT.gsub(/^\s*\|/, '') # rubocop:disable Layout/DotPosition
88
88
  |#{ImageOptim.full_version}
89
89
  |
90
90
  |Usage:
@@ -97,29 +97,29 @@ ImageOptim::Runner::OptionParser::DEFINE = proc do |op, options|
97
97
  TEXT
98
98
 
99
99
  op.on('--config-paths PATH1,PATH2', Array, 'Config paths to use instead of '\
100
- 'default ones') do |paths|
100
+ 'default ones') do |paths|
101
101
  options[:config_paths] = paths
102
102
  end
103
103
 
104
104
  op.separator nil
105
105
 
106
106
  op.on('-r', '-R', '--recursive', 'Recursively scan directories '\
107
- 'for images') do |recursive|
107
+ 'for images') do |recursive|
108
108
  options[:recursive] = recursive
109
109
  end
110
110
 
111
111
  op.on("--exclude-dir 'GLOB'", 'Glob for excluding directories '\
112
- '(defaults to .*)') do |glob|
112
+ '(defaults to .*)') do |glob|
113
113
  options[:exclude_dir_glob] = glob
114
114
  end
115
115
 
116
116
  op.on("--exclude-file 'GLOB'", 'Glob for excluding files '\
117
- '(defaults to .*)') do |glob|
117
+ '(defaults to .*)') do |glob|
118
118
  options[:exclude_file_glob] = glob
119
119
  end
120
120
 
121
121
  op.on("--exclude 'GLOB'", 'Set glob for excluding both directories and '\
122
- 'files') do |glob|
122
+ 'files') do |glob|
123
123
  options[:exclude_file_glob] = options[:exclude_dir_glob] = glob
124
124
  end
125
125
 
@@ -130,19 +130,19 @@ ImageOptim::Runner::OptionParser::DEFINE = proc do |op, options|
130
130
  end
131
131
 
132
132
  op.on('--[no-]threads N', Integer, 'Number of threads or disable '\
133
- '(defaults to number of processors)') do |threads|
133
+ '(defaults to number of processors)') do |threads|
134
134
  options[:threads] = threads
135
135
  end
136
136
 
137
137
  op.on('--[no-]nice N', Integer, 'Nice level, priority of all used tools '\
138
- 'with higher value meaning lower priority, in range -20..19, negative '\
139
- 'values can be set only if run by root user (defaults to 10)') do |nice|
138
+ 'with higher value meaning lower priority, in range -20..19, negative '\
139
+ 'values can be set only if run by root user (defaults to 10)') do |nice|
140
140
  options[:nice] = nice
141
141
  end
142
142
 
143
143
  op.on('--[no-]pack', 'Require image_optim_pack or disable it, '\
144
- 'by default image_optim_pack will be used if available, '\
145
- 'will turn on skip-missing-workers unless explicitly disabled') do |pack|
144
+ 'by default image_optim_pack will be used if available, '\
145
+ 'will turn on skip-missing-workers unless explicitly disabled') do |pack|
146
146
  options[:pack] = pack
147
147
  end
148
148
 
@@ -150,12 +150,12 @@ ImageOptim::Runner::OptionParser::DEFINE = proc do |op, options|
150
150
  op.separator ' Caching:'
151
151
 
152
152
  op.on('--cache-dir DIR', 'Cache optimized images '\
153
- 'into the specified directory') do |cache_dir|
153
+ 'into the specified directory') do |cache_dir|
154
154
  options[:cache_dir] = cache_dir
155
155
  end
156
156
 
157
157
  op.on('--cache-worker-digests', 'Cache worker digests '\
158
- '(updating workers invalidates cache)') do |cache_worker_digests|
158
+ '(updating workers invalidates cache)') do |cache_worker_digests|
159
159
  options[:cache_worker_digests] = cache_worker_digests
160
160
  end
161
161
 
@@ -163,7 +163,7 @@ ImageOptim::Runner::OptionParser::DEFINE = proc do |op, options|
163
163
  op.separator ' Disabling workers:'
164
164
 
165
165
  op.on('--[no-]skip-missing-workers', 'Skip workers with missing or '\
166
- 'problematic binaries') do |skip|
166
+ 'problematic binaries') do |skip|
167
167
  options[:skip_missing_workers] = skip
168
168
  end
169
169
 
@@ -178,7 +178,7 @@ ImageOptim::Runner::OptionParser::DEFINE = proc do |op, options|
178
178
  op.separator ' Worker options:'
179
179
 
180
180
  op.on('--allow-lossy', 'Allow lossy workers and '\
181
- 'optimizations') do |allow_lossy|
181
+ 'optimizations') do |allow_lossy|
182
182
  options[:allow_lossy] = allow_lossy
183
183
  end
184
184
 
@@ -230,8 +230,8 @@ ImageOptim::Runner::OptionParser::DEFINE = proc do |op, options|
230
230
  op.separator ' Common options:'
231
231
 
232
232
  op.on_tail('-v', '--verbose', 'Verbose output (show global and worker '\
233
- 'config, binary resolution log, information about each tool invocation, '\
234
- 'backtrace of exception)') do
233
+ 'config, binary resolution log, information about each tool invocation, '\
234
+ 'backtrace of exception)') do
235
235
  options[:verbose] = true
236
236
  end
237
237
 
@@ -38,7 +38,7 @@ class ImageOptim
38
38
  if size_a == size_b
39
39
  "------ #{Space::EMPTY_SPACE}"
40
40
  else
41
- percent = 100 - 100.0 * size_b / size_a
41
+ percent = 100 - (100.0 * size_b / size_a)
42
42
  space = Space.space(size_a - size_b)
43
43
  format('%5.2f%% %s', percent, space)
44
44
  end
@@ -9,11 +9,11 @@ class ImageOptim
9
9
  class Advpng < Worker
10
10
  LEVEL_OPTION =
11
11
  option(:level, 4, 'Compression level: '\
12
- '`0` - don\'t compress, '\
13
- '`1` - fast, '\
14
- '`2` - normal, '\
15
- '`3` - extra, '\
16
- '`4` - extreme') do |v|
12
+ '`0` - don\'t compress, '\
13
+ '`1` - fast, '\
14
+ '`2` - normal, '\
15
+ '`3` - extra, '\
16
+ '`4` - extreme') do |v|
17
17
  OptionHelpers.limit_with_range(v.to_i, 0..4)
18
18
  end
19
19
 
@@ -18,19 +18,19 @@ class ImageOptim
18
18
 
19
19
  INTERLACE_OPTION =
20
20
  option(:interlace, false, TrueFalseNil, 'Interlace: '\
21
- '`true` - interlace on, '\
22
- '`false` - interlace off, '\
23
- '`nil` - as is in original image '\
24
- '(defaults to running two instances, one with interlace off and '\
25
- 'one with on)') do |v|
21
+ '`true` - interlace on, '\
22
+ '`false` - interlace off, '\
23
+ '`nil` - as is in original image '\
24
+ '(defaults to running two instances, one with interlace off and '\
25
+ 'one with on)') do |v|
26
26
  TrueFalseNil.convert(v)
27
27
  end
28
28
 
29
29
  LEVEL_OPTION =
30
30
  option(:level, 3, 'Compression level: '\
31
- '`1` - light and fast, '\
32
- '`2` - normal, '\
33
- '`3` - heavy (slower)') do |v|
31
+ '`1` - light and fast, '\
32
+ '`2` - normal, '\
33
+ '`3` - heavy (slower)') do |v|
34
34
  OptionHelpers.limit_with_range(v.to_i, 1..3)
35
35
  end
36
36
 
@@ -12,13 +12,13 @@ class ImageOptim
12
12
 
13
13
  STRIP_OPTION =
14
14
  option(:strip, :all, Array, 'List of markers to strip: '\
15
- '`:com`, '\
16
- '`:exif`, '\
17
- '`:iptc`, '\
18
- '`:icc`, '\
19
- '`:xmp`, '\
20
- '`:none` or '\
21
- '`:all`') do |v|
15
+ '`:com`, '\
16
+ '`:exif`, '\
17
+ '`:iptc`, '\
18
+ '`:icc`, '\
19
+ '`:xmp`, '\
20
+ '`:none` or '\
21
+ '`:all`') do |v|
22
22
  values = Array(v).map(&:to_s)
23
23
  known_values = %w[com exif iptc icc xmp none all]
24
24
  unknown_values = values - known_values
@@ -30,13 +30,13 @@ class ImageOptim
30
30
 
31
31
  MAX_QUALITY_OPTION =
32
32
  option(:max_quality, 100, 'Maximum image quality factor '\
33
- '`0`..`100`, ignored in default/lossless mode') do |v, opt_def|
33
+ '`0`..`100`, ignored in default/lossless mode') do |v, opt_def|
34
34
  if allow_lossy
35
35
  OptionHelpers.limit_with_range(v.to_i, 0..100)
36
36
  else
37
37
  if v != opt_def.default
38
38
  warn "#{self.class.bin_sym} #{opt_def.name} #{v} ignored " \
39
- 'in lossless mode'
39
+ 'in lossless mode'
40
40
  end
41
41
  opt_def.default
42
42
  end
@@ -28,10 +28,10 @@ class ImageOptim
28
28
 
29
29
  METHOD_OPTION =
30
30
  option(:method, 'ssim', 'Comparison Metric: '\
31
- '`mpe` - Mean pixel error, '\
32
- '`ssim` - Structural similarity, '\
33
- '`ms-ssim` - Multi-scale structural similarity (slow!), '\
34
- '`smallfry` - Linear-weighted BBCQ-like (may be patented)') do |v, opt_def|
31
+ '`mpe` - Mean pixel error, '\
32
+ '`ssim` - Structural similarity, '\
33
+ '`ms-ssim` - Multi-scale structural similarity (slow!), '\
34
+ '`smallfry` - Linear-weighted BBCQ-like (may be patented)') do |v, opt_def|
35
35
  if %w[mpe ssim ms-ssim smallfry].include? v
36
36
  v
37
37
  else
@@ -17,7 +17,7 @@ class ImageOptim
17
17
 
18
18
  JPEGRESCAN_OPTION =
19
19
  option(:jpegrescan, true, 'Use jpegtran through jpegrescan, '\
20
- 'ignore progressive option'){ |v| !!v }
20
+ 'ignore progressive option'){ |v| !!v }
21
21
 
22
22
  def used_bins
23
23
  jpegrescan ? [:jpegtran, :jpegrescan] : [:jpegtran]
@@ -10,16 +10,16 @@ class ImageOptim
10
10
  class Optipng < Worker
11
11
  LEVEL_OPTION =
12
12
  option(:level, 6, 'Optimization level preset: '\
13
- '`0` is least, '\
14
- '`7` is best') do |v|
13
+ '`0` is least, '\
14
+ '`7` is best') do |v|
15
15
  OptionHelpers.limit_with_range(v.to_i, 0..7)
16
16
  end
17
17
 
18
18
  INTERLACE_OPTION =
19
19
  option(:interlace, false, TrueFalseNil, 'Interlace: '\
20
- '`true` - interlace on, '\
21
- '`false` - interlace off, '\
22
- '`nil` - as is in original image') do |v|
20
+ '`true` - interlace on, '\
21
+ '`false` - interlace off, '\
22
+ '`nil` - as is in original image') do |v|
23
23
  TrueFalseNil.convert(v)
24
24
  end
25
25
 
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'image_optim/worker'
4
+ require 'image_optim/option_helpers'
5
+ require 'image_optim/true_false_nil'
6
+
7
+ class ImageOptim
8
+ class Worker
9
+ # https://github.com/shssoichiro/oxipng
10
+ class Oxipng < Worker
11
+ LEVEL_OPTION =
12
+ option(:level, 3, 'Optimization level preset: '\
13
+ '`0` is least, '\
14
+ '`6` is best') do |v|
15
+ OptionHelpers.limit_with_range(v.to_i, 0..6)
16
+ end
17
+
18
+ INTERLACE_OPTION =
19
+ option(:interlace, false, TrueFalseNil, 'Interlace: '\
20
+ '`true` - interlace on, '\
21
+ '`false` - interlace off, '\
22
+ '`nil` - as is in original image') do |v|
23
+ TrueFalseNil.convert(v)
24
+ end
25
+
26
+ STRIP_OPTION =
27
+ option(:strip, true, 'Remove all auxiliary chunks'){ |v| !!v }
28
+
29
+ def run_order
30
+ -4
31
+ end
32
+
33
+ def optimize(src, dst, options = {})
34
+ src.copy(dst)
35
+ args = %W[
36
+ -o #{level}
37
+ --quiet
38
+ --
39
+ #{dst}
40
+ ]
41
+ args.unshift "-i#{interlace ? 1 : 0}" unless interlace.nil?
42
+ if strip
43
+ args.unshift '--strip', 'all'
44
+ end
45
+ execute(:oxipng, args, options) && optimized?(src, dst)
46
+ end
47
+
48
+ def optimized?(src, dst)
49
+ interlace ? dst.size? : super
50
+ end
51
+ end
52
+ end
53
+ end
@@ -8,18 +8,18 @@ class ImageOptim
8
8
  class Pngcrush < Worker
9
9
  CHUNKS_OPTION =
10
10
  option(:chunks, :alla, Array, 'List of chunks to remove or '\
11
- '`:alla` - all except tRNS/transparency or '\
12
- '`:allb` - all except tRNS and gAMA/gamma') do |v|
11
+ '`:alla` - all except tRNS/transparency or '\
12
+ '`:allb` - all except tRNS and gAMA/gamma') do |v|
13
13
  Array(v).map(&:to_s)
14
14
  end
15
15
 
16
16
  FIX_OPTION =
17
17
  option(:fix, false, 'Fix otherwise fatal conditions '\
18
- 'such as bad CRCs'){ |v| !!v }
18
+ 'such as bad CRCs'){ |v| !!v }
19
19
 
20
20
  BRUTE_OPTION =
21
21
  option(:brute, false, 'Brute force try all methods, '\
22
- 'very time-consuming and generally not worthwhile'){ |v| !!v }
22
+ 'very time-consuming and generally not worthwhile'){ |v| !!v }
23
23
 
24
24
  BLACKEN_OPTION =
25
25
  option(:blacken, true, 'Blacken fully transparent pixels'){ |v| !!v }
@@ -12,11 +12,11 @@ class ImageOptim
12
12
 
13
13
  STRATEGY_OPTION =
14
14
  option(:strategy, 0, 'Strategy: '\
15
- '`0` - xtreme, '\
16
- '`1` - intense, '\
17
- '`2` - longest Match, '\
18
- '`3` - huffman Only, '\
19
- '`4` - uncompressed') do |v|
15
+ '`0` - xtreme, '\
16
+ '`1` - intense, '\
17
+ '`2` - longest Match, '\
18
+ '`3` - huffman Only, '\
19
+ '`4` - uncompressed') do |v|
20
20
  OptionHelpers.limit_with_range(v.to_i, 0..4)
21
21
  end
22
22
 
@@ -19,9 +19,9 @@ class ImageOptim
19
19
  QUALITY_OPTION =
20
20
  option(:quality, '`100..100`, `0..100` in lossy mode',
21
21
  NonNegativeIntegerRange, 'min..max - don\'t '\
22
- 'save below min, use less colors below max (both in range `0..100`; '\
23
- 'in yaml - `!ruby/range 0..100`), ignored in default/lossless '\
24
- 'mode') do |v, opt_def|
22
+ 'save below min, use less colors below max (both in range `0..100`; '\
23
+ 'in yaml - `!ruby/range 0..100`), ignored in default/lossless '\
24
+ 'mode') do |v, opt_def|
25
25
  if allow_lossy
26
26
  if v == opt_def.default
27
27
  0..100
@@ -32,7 +32,7 @@ class ImageOptim
32
32
  else
33
33
  if v != opt_def.default
34
34
  warn "#{self.class.bin_sym} #{opt_def.name} #{v} ignored " \
35
- 'in lossless mode'
35
+ 'in lossless mode'
36
36
  end
37
37
  100..100
38
38
  end
@@ -40,9 +40,9 @@ class ImageOptim
40
40
 
41
41
  SPEED_OPTION =
42
42
  option(:speed, 3, 'speed/quality trade-off: '\
43
- '`1` - slow, '\
44
- '`3` - default, '\
45
- '`11` - fast & rough') do |v|
43
+ '`1` - slow, '\
44
+ '`3` - default, '\
45
+ '`11` - fast & rough') do |v|
46
46
  OptionHelpers.limit_with_range(v.to_i, 1..11)
47
47
  end
48
48
 
@@ -105,7 +105,7 @@ class ImageOptim
105
105
  return if unknown_options.empty?
106
106
 
107
107
  fail ConfigurationError, "unknown options #{unknown_options.inspect} "\
108
- "for #{self}"
108
+ "for #{self}"
109
109
  end
110
110
 
111
111
  # Forward bin resolving to image_optim
@@ -118,8 +118,8 @@ class ImageOptim
118
118
  def wrap_resolver_error_message(message)
119
119
  name = self.class.bin_sym
120
120
  "#{name} worker: #{message}; please provide proper binary or "\
121
- "disable this worker (--no-#{name} argument or "\
122
- "`:#{name} => false` through options)"
121
+ "disable this worker (--no-#{name} argument or "\
122
+ "`:#{name} => false` through options)"
123
123
  end
124
124
 
125
125
  # Run command setting priority and hiding output
data/lib/image_optim.rb CHANGED
@@ -14,7 +14,7 @@ require 'in_threads'
14
14
  require 'shellwords'
15
15
 
16
16
  %w[
17
- pngcrush pngout advpng optipng pngquant
17
+ pngcrush pngout advpng optipng pngquant oxipng
18
18
  jhead jpegoptim jpegrecompress jpegtran
19
19
  gifsicle
20
20
  svgo
@@ -29,7 +29,7 @@ end
29
29
  def write_marked(io)
30
30
  io.puts BEGIN_MARKER
31
31
  io.puts '<!-- markdown for worker options is generated by '\
32
- "`#{Pathname($PROGRAM_NAME).cleanpath}` -->"
32
+ "`#{Pathname($PROGRAM_NAME).cleanpath}` -->"
33
33
  io.puts
34
34
 
35
35
  ImageOptim::Worker.klasses.sort_by(&:name).each do |klass|
@@ -42,13 +42,14 @@ describe ImageOptim::CachePath do
42
42
  end
43
43
 
44
44
  it 'does not preserve mtime of destination file' do
45
- time = src.mtime
45
+ time = src.mtime - 1000
46
+ dst.utime(time, time)
46
47
 
47
- dst.utime(time - 1000, time - 1000)
48
+ time = dst.mtime
48
49
 
49
50
  src.replace(dst)
50
51
 
51
- expect(dst.mtime).to be >= time
52
+ expect(dst.mtime).to_not eq(time)
52
53
  end
53
54
 
54
55
  it 'changes inode of destination', skip: SkipConditions[:inodes_support] do
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'spec_helper'
4
4
  require 'image_optim/cmd'
5
+ require 'image_optim/timer'
5
6
 
6
7
  describe ImageOptim::Cmd do
7
8
  before do
@@ -48,6 +49,11 @@ describe ImageOptim::Cmd do
48
49
  expect(Cmd.run('sh -c "exit 66"', timeout: 1)).to eq(false)
49
50
  end
50
51
 
52
+ it 'returns process success status when timeout is instance of ImageOptim::Timer' do
53
+ timeout = ImageOptim::Timer.new(1.0)
54
+ expect(Cmd.run('sh -c "exit 0"', timeout: timeout)).to eq(true)
55
+ end
56
+
51
57
  it 'raises SignalException if process terminates after signal', skip: SkipConditions[:signals_support] do
52
58
  expect_int_exception do
53
59
  Cmd.run('kill -s INT $$', timeout: 1)
@@ -9,7 +9,7 @@ describe ImageOptim::Handler do
9
9
  end
10
10
 
11
11
  it 'uses original as source for first conversion '\
12
- 'and two temp files for further conversions' do
12
+ 'and two temp files for further conversions' do
13
13
  original = double(:original)
14
14
  allow(original).to receive(:respond_to?).with(:temp_path).and_return(true)
15
15
 
@@ -86,13 +86,14 @@ describe ImageOptim::Path do
86
86
  end
87
87
 
88
88
  it 'does not preserve mtime of destination file' do
89
- time = src.mtime
89
+ time = src.mtime - 1000
90
+ dst.utime(time, time)
90
91
 
91
- dst.utime(time - 1000, time - 1000)
92
+ time = dst.mtime
92
93
 
93
94
  src.replace(dst)
94
95
 
95
- expect(dst.mtime).to be >= time
96
+ expect(dst.mtime).to_not eq(time)
96
97
  end
97
98
 
98
99
  it 'changes inode of destination', skip: SkipConditions[:inodes_support] do
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'image_optim/worker/oxipng'
5
+ require 'image_optim/path'
6
+
7
+ describe ImageOptim::Worker::Oxipng do
8
+ describe 'strip option' do
9
+ subject{ described_class.new(ImageOptim.new, options) }
10
+
11
+ let(:options){ {} }
12
+ let(:src){ instance_double(ImageOptim::Path, copy: nil) }
13
+ let(:dst){ instance_double(ImageOptim::Path) }
14
+
15
+ before do
16
+ oxipng_bin = instance_double(ImageOptim::BinResolver::Bin)
17
+ allow(subject).to receive(:resolve_bin!).
18
+ with(:oxipng).and_return(oxipng_bin)
19
+
20
+ allow(subject).to receive(:optimized?)
21
+ end
22
+
23
+ context 'by default' do
24
+ it 'should add --strip all to arguments' do
25
+ expect(subject).to receive(:execute) do |_bin, *args|
26
+ expect(args.join(' ')).to match(/(^| )--strip all($| )/)
27
+ end
28
+
29
+ subject.optimize(src, dst)
30
+ end
31
+ end
32
+
33
+ context 'when strip is disabled' do
34
+ let(:options){ {strip: false} }
35
+
36
+ it 'should not add --strip all to arguments' do
37
+ expect(subject).to receive(:execute) do |_bin, *args|
38
+ expect(args.join(' ')).not_to match(/(^| )--strip all($| )/)
39
+ end
40
+
41
+ subject.optimize(src, dst)
42
+ end
43
+ end
44
+ end
45
+
46
+ describe '#optimized?' do
47
+ let(:src){ instance_double(ImageOptim::Path, src_options) }
48
+ let(:dst){ instance_double(ImageOptim::Path, dst_options) }
49
+ let(:src_options){ {size: 10} }
50
+ let(:dst_options){ {size?: 9} }
51
+ let(:instance){ described_class.new(ImageOptim.new, instance_options) }
52
+ let(:instance_options){ {} }
53
+
54
+ subject{ instance.optimized?(src, dst) }
55
+
56
+ context 'when interlace option is enabled' do
57
+ let(:instance_options){ {interlace: true} }
58
+
59
+ context 'when dst is empty' do
60
+ let(:dst_options){ {size?: nil} }
61
+ it{ is_expected.to be_falsy }
62
+ end
63
+
64
+ context 'when dst is not empty' do
65
+ let(:dst_options){ {size?: 20} }
66
+ it{ is_expected.to be_truthy }
67
+ end
68
+ end
69
+
70
+ context 'when interlace option is disabled' do
71
+ let(:instance_options){ {interlace: false} }
72
+
73
+ context 'when dst is empty' do
74
+ let(:dst_options){ {size?: nil} }
75
+ it{ is_expected.to be_falsy }
76
+ end
77
+
78
+ context 'when dst is greater than or equal to src' do
79
+ let(:dst_options){ {size?: 10} }
80
+ it{ is_expected.to be_falsy }
81
+ end
82
+
83
+ context 'when dst is less than src' do
84
+ let(:dst_options){ {size?: 9} }
85
+ it{ is_expected.to be_truthy }
86
+ end
87
+ end
88
+ end
89
+ end
@@ -253,7 +253,7 @@ describe ImageOptim do
253
253
 
254
254
  describe 'given block' do
255
255
  it 'optimizes images, yields path and result for each and '\
256
- 'returns array of yield results' do
256
+ 'returns array of yield results' do
257
257
  image_optim = ImageOptim.new
258
258
  results = test_images.map do |src|
259
259
  dst = double
@@ -17,7 +17,7 @@ IO.popen(%W[
17
17
  ].shelljoin, 'w') do |f|
18
18
  side.times do |a|
19
19
  side.times do |b|
20
- alpha = [0, 1, 0x7f, 0xff][(a / 8 + b / 8) % 4]
20
+ alpha = [0, 1, 0x7f, 0xff][((a / 8) + (b / 8)) % 4]
21
21
  f << [rand(256), rand(256), rand(256), alpha].pack('C*')
22
22
  end
23
23
  end
data/spec/spec_helper.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- if ENV['CODECLIMATE']
3
+ if ENV['CC_TEST_REPORTER_ID']
4
4
  require 'simplecov'
5
5
  SimpleCov.start
6
6
  end
@@ -71,7 +71,7 @@ RSpec::Matchers.define :be_similar_to do |expected, max_difference|
71
71
  end
72
72
  failure_message do |actual|
73
73
  "expected #{actual} to have at most #{max_difference} difference from "\
74
- "#{expected}, got normalized root-mean-square error of #{@diff}"
74
+ "#{expected}, got normalized root-mean-square error of #{@diff}"
75
75
  end
76
76
  end
77
77
 
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.30.0
4
+ version: 0.31.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: 2021-05-10 00:00:00.000000000 Z
11
+ date: 2021-10-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: fspath
@@ -168,10 +168,10 @@ extensions: []
168
168
  extra_rdoc_files: []
169
169
  files:
170
170
  - ".appveyor.yml"
171
+ - ".github/workflows/check.yml"
171
172
  - ".gitignore"
172
173
  - ".pre-commit-hooks.yaml"
173
174
  - ".rubocop.yml"
174
- - ".travis.yml"
175
175
  - CHANGELOG.markdown
176
176
  - CONTRIBUTING.markdown
177
177
  - Gemfile
@@ -216,6 +216,7 @@ files:
216
216
  - lib/image_optim/worker/jpegrecompress.rb
217
217
  - lib/image_optim/worker/jpegtran.rb
218
218
  - lib/image_optim/worker/optipng.rb
219
+ - lib/image_optim/worker/oxipng.rb
219
220
  - lib/image_optim/worker/pngcrush.rb
220
221
  - lib/image_optim/worker/pngout.rb
221
222
  - lib/image_optim/worker/pngquant.rb
@@ -246,6 +247,7 @@ files:
246
247
  - spec/image_optim/timer_spec.rb
247
248
  - spec/image_optim/worker/jpegrecompress_spec.rb
248
249
  - spec/image_optim/worker/optipng_spec.rb
250
+ - spec/image_optim/worker/oxipng_spec.rb
249
251
  - spec/image_optim/worker/pngquant_spec.rb
250
252
  - spec/image_optim/worker_spec.rb
251
253
  - spec/image_optim_spec.rb
@@ -284,7 +286,7 @@ licenses:
284
286
  metadata:
285
287
  bug_tracker_uri: https://github.com/toy/image_optim/issues
286
288
  changelog_uri: https://github.com/toy/image_optim/blob/master/CHANGELOG.markdown
287
- documentation_uri: https://www.rubydoc.info/gems/image_optim/0.30.0
289
+ documentation_uri: https://www.rubydoc.info/gems/image_optim/0.31.0
288
290
  source_code_uri: https://github.com/toy/image_optim
289
291
  post_install_message: |
290
292
  Rails image assets optimization is extracted into image_optim_rails gem
@@ -303,13 +305,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
303
305
  - !ruby/object:Gem::Version
304
306
  version: '0'
305
307
  requirements: []
306
- rubygems_version: 3.2.16
308
+ rubygems_version: 3.2.28
307
309
  signing_key:
308
310
  specification_version: 4
309
311
  summary: Command line tool and ruby interface to optimize (lossless compress, optionally
310
312
  lossy) jpeg, png, gif and svg images using external utilities (advpng, gifsicle,
311
- jhead, jpeg-recompress, jpegoptim, jpegrescan, jpegtran, optipng, pngcrush, pngout,
312
- pngquant, svgo)
313
+ jhead, jpeg-recompress, jpegoptim, jpegrescan, jpegtran, optipng, oxipng, pngcrush,
314
+ pngout, pngquant, svgo)
313
315
  test_files:
314
316
  - spec/image_optim/bin_resolver/comparable_condition_spec.rb
315
317
  - spec/image_optim/bin_resolver/simple_version_spec.rb
@@ -332,6 +334,7 @@ test_files:
332
334
  - spec/image_optim/timer_spec.rb
333
335
  - spec/image_optim/worker/jpegrecompress_spec.rb
334
336
  - spec/image_optim/worker/optipng_spec.rb
337
+ - spec/image_optim/worker/oxipng_spec.rb
335
338
  - spec/image_optim/worker/pngquant_spec.rb
336
339
  - spec/image_optim/worker_spec.rb
337
340
  - spec/image_optim_spec.rb
data/.travis.yml DELETED
@@ -1,48 +0,0 @@
1
- dist: xenial
2
- language: ruby
3
- cache:
4
- bundler: true
5
- directories:
6
- - $(npm root)
7
- - ~/bin
8
- rvm:
9
- - '1.9.3-p551'
10
- - '2.0.0-p648'
11
- - '2.1.10'
12
- - '2.2.10'
13
- - '2.3.8'
14
- - '2.4.10'
15
- - '2.5.9'
16
- - '2.6.7'
17
- - '2.7.3'
18
- - '3.0.1'
19
- - 'jruby-9.2.14.0'
20
- script:
21
- - bundle exec image_optim --info
22
- - bundle exec rspec
23
- before_install:
24
- - 'echo "gem: --no-ri --no-rdoc --no-document" > ~/.gemrc'
25
- - gem install rubygems-update || gem install rubygems-update --version '< 3'
26
- - update_rubygems
27
- - gem install bundler || gem install bundler --version '< 2'
28
- - nvm install stable
29
- - command -v svgo || npm install -g svgo
30
- - mkdir -p ~/bin
31
- - command -v pngout || curl -L "https://www.jonof.id.au/files/kenutils/pngout-20200115-linux.tar.gz" | tar -xz -C ~/bin --strip-components 2 --wildcards '*/amd64/pngout'
32
- matrix:
33
- include:
34
- - env: CODECLIMATE=1
35
- rvm: '2.4.10'
36
- after_success: bundle exec codeclimate-test-reporter
37
- - env: RUBOCOP=1
38
- rvm: '2.4.10'
39
- script: bundle exec rubocop
40
- before_install: gem update --system && gem install bundler
41
- - env: CHECK_RUBIES=1
42
- rvm: '2.4.10'
43
- script: bundle exec travis_check_rubies
44
- before_install: gem update --system && gem install bundler
45
- addons:
46
- code_climate:
47
- repo_token:
48
- secure: FDikT3JnOJHOAFSaKwVPB1VOphU0sSzAnzQ+YjSt9XFE+9uFQHth/j4rFoVoqALhCj+47trv6spwkbcSjGCVzm+87OI80GkLCCzNjDOz2W4sP9JWItVgS1VoWW+ioPxpLgpguTb3wutwKOUMEAf+40EX657ZiHumM7nNHrF+RCU=