image_optim 0.30.0 → 0.31.0

Sign up to get free protection for your applications and to get access to all the features.
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=