image_optim 0.21.0 → 0.22.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 +8 -8
- data/.rubocop.yml +3 -3
- data/.travis.yml +3 -1
- data/CHANGELOG.markdown +8 -0
- data/README.markdown +14 -13
- data/Vagrantfile +10 -3
- data/image_optim.gemspec +2 -2
- data/lib/image_optim.rb +3 -1
- data/lib/image_optim/bin_resolver/bin.rb +1 -0
- data/lib/image_optim/option_definition.rb +6 -0
- data/lib/image_optim/railtie.rb +10 -0
- data/lib/image_optim/runner/option_parser.rb +2 -2
- data/lib/image_optim/worker/optipng.rb +3 -1
- data/lib/image_optim/worker/pngquant.rb +12 -7
- data/lib/image_optim/worker/svgo.rb +16 -0
- data/script/update_worker_options_in_readme +2 -2
- data/spec/image_optim/handler_spec.rb +1 -3
- data/spec/image_optim/hash_helpers_spec.rb +1 -3
- data/spec/image_optim/option_definition_spec.rb +110 -0
- data/spec/image_optim/railtie_spec.rb +29 -3
- data/spec/image_optim/worker/optipng_spec.rb +58 -0
- data/spec/image_optim/worker/pngquant_spec.rb +27 -0
- data/spec/image_optim_spec.rb +1 -1
- data/spec/images/test.svg +1 -1
- data/spec/spec_helper.rb +9 -8
- metadata +10 -10
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
NGEwM2UzY2VlZmU0OWJmNzg2YTAyMDZlNWM1MzM5ZWVhNDAyOTg3Mw==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
YTE0YzA1YjQ2NzU3NDIxZjFjNzA4ZGVjOGFmNGY4YTgxMjhiODlhZA==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
YjI3M2JhYmExNTg2OTg2OGI1NWU5YWEwM2Y4MjNmOWRhNjcwM2EwZmFjOTQz
|
10
|
+
ZjI2MzBiZjcwZWIwMjQ0ZWUwOTFlODNjZjU0NThmMDhjYWUzMTE2ZTVmOGFm
|
11
|
+
NGM1ZWMzMjYyODZmZTUzZjk2NzljMTY1MDg1M2Y4NmZmNTMwZTY=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
NTQxYjc1MWI2OTgzNzNhOTliMGRjMjgwMTBlMDBjZDdjYmRlN2RjOTVhNTk0
|
14
|
+
YjE0NzczOWE0NzZjMWMzOGM4NWFlZTg0ZjAzZWQ3NTNjZGRhYTVkNjc2ZjUx
|
15
|
+
OWQ3ODZmZGE2MmMxMWM1YmU1NjI0NzljNDE4MjE4MDdjYzliOTU=
|
data/.rubocop.yml
CHANGED
@@ -20,9 +20,6 @@ Metrics/MethodLength:
|
|
20
20
|
Metrics/PerceivedComplexity:
|
21
21
|
Max: 8
|
22
22
|
|
23
|
-
Performance/ParallelAssignment:
|
24
|
-
Enabled: false
|
25
|
-
|
26
23
|
Style/AccessModifierIndentation:
|
27
24
|
EnforcedStyle: outdent
|
28
25
|
|
@@ -47,6 +44,9 @@ Style/IfUnlessModifier:
|
|
47
44
|
Style/IndentHash:
|
48
45
|
EnforcedStyle: consistent
|
49
46
|
|
47
|
+
Style/ParallelAssignment:
|
48
|
+
Enabled: false
|
49
|
+
|
50
50
|
Style/PercentLiteralDelimiters:
|
51
51
|
PreferredDelimiters:
|
52
52
|
'%w': '[]'
|
data/.travis.yml
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
sudo: false
|
1
2
|
language: ruby
|
2
3
|
rvm:
|
3
4
|
- 1.8.7
|
@@ -6,7 +7,6 @@ rvm:
|
|
6
7
|
- '2.0'
|
7
8
|
- '2.1'
|
8
9
|
- '2.2'
|
9
|
-
- jruby-18mode
|
10
10
|
- jruby-19mode
|
11
11
|
- ree
|
12
12
|
script:
|
@@ -36,6 +36,8 @@ matrix:
|
|
36
36
|
rvm: default
|
37
37
|
- env: RUBOCOP=true
|
38
38
|
rvm: default
|
39
|
+
allow_failures:
|
40
|
+
- rvm: jruby-19mode
|
39
41
|
addons:
|
40
42
|
code_climate:
|
41
43
|
repo_token:
|
data/CHANGELOG.markdown
CHANGED
@@ -2,6 +2,14 @@
|
|
2
2
|
|
3
3
|
## unreleased
|
4
4
|
|
5
|
+
## v0.22.0 (2015-11-21)
|
6
|
+
|
7
|
+
* Unify getting description of option default value using `default_description` [@toy](https://github.com/toy)
|
8
|
+
* Don't use `-strip` option for optipng when the bin version is less than 0.7 [#106](https://github.com/toy/image_optim/issues/106) [@toy](https://github.com/toy)
|
9
|
+
* Use quality `0..100` by default in lossy mode of pngquant worker [#77](https://github.com/toy/image_optim/issues/77) [@toy](https://github.com/toy)
|
10
|
+
* Add `:disable_plugins` and `:enable_plugins` options to `svgo` worker [#110](https://github.com/toy/image_optim/pull/110) [@tomhughes](https://github.com/tomhughes)
|
11
|
+
* Allow setting config in rails like `config.assets.image_optim.name = value` [#111](https://github.com/toy/image_optim/pull/111) [@toy](https://github.com/toy)
|
12
|
+
|
5
13
|
## v0.21.0 (2015-05-30)
|
6
14
|
|
7
15
|
* Use exifr 1.2.2 with fix for a bug [#85](https://github.com/toy/image_optim/issues/85) [@toy](https://github.com/toy)
|
data/README.markdown
CHANGED
@@ -277,50 +277,51 @@ Worker can be disabled by passing `false` instead of options hash or by setting
|
|
277
277
|
<!---<worker-options>-->
|
278
278
|
<!-- markdown for worker options is generated by `script/update_worker_options_in_readme` -->
|
279
279
|
|
280
|
-
### :
|
280
|
+
### advpng:
|
281
281
|
* `:level` — Compression level: `0` - don't compress, `1` - fast, `2` - normal, `3` - extra, `4` - extreme *(defaults to `4`)*
|
282
282
|
|
283
|
-
### :
|
283
|
+
### gifsicle:
|
284
284
|
* `: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)
|
285
285
|
* `:level` — Compression level: `1` - light and fast, `2` - normal, `3` - heavy (slower) *(defaults to `3`)*
|
286
286
|
* `:careful` — Avoid bugs with some software *(defaults to `false`)*
|
287
287
|
|
288
|
-
### :
|
288
|
+
### jhead:
|
289
289
|
Worker has no options
|
290
290
|
|
291
|
-
### :
|
291
|
+
### jpegoptim:
|
292
292
|
* `:strip` — List of extra markers to strip: `:comments`, `:exif`, `:iptc`, `:icc` or `:all` *(defaults to `:all`)*
|
293
293
|
* `:max_quality` — Maximum image quality factor `0`..`100`, ignored in default/lossless mode *(defaults to `100`)*
|
294
294
|
|
295
|
-
### :
|
295
|
+
### jpegrecompress:
|
296
296
|
* `:quality` — JPEG quality preset: `0` - low, `1` - medium, `2` - high, `3` - veryhigh *(defaults to `3`)*
|
297
297
|
|
298
|
-
### :
|
298
|
+
### jpegtran:
|
299
299
|
* `:copy_chunks` — Copy all chunks *(defaults to `false`)*
|
300
300
|
* `:progressive` — Create progressive JPEG file *(defaults to `true`)*
|
301
301
|
* `:jpegrescan` — Use jpegtran through jpegrescan, ignore progressive option *(defaults to `false`)*
|
302
302
|
|
303
|
-
### :
|
303
|
+
### optipng:
|
304
304
|
* `:level` — Optimization level preset: `0` is least, `7` is best *(defaults to `6`)*
|
305
305
|
* `:interlace` — Interlace: `true` - interlace on, `false` - interlace off, `nil` - as is in original image *(defaults to `false`)*
|
306
306
|
* `:strip` — Remove all auxiliary chunks *(defaults to `true`)*
|
307
307
|
|
308
|
-
### :
|
308
|
+
### pngcrush:
|
309
309
|
* `:chunks` — List of chunks to remove or `:alla` - all except tRNS/transparency or `:allb` - all except tRNS and gAMA/gamma *(defaults to `:alla`)*
|
310
310
|
* `:fix` — Fix otherwise fatal conditions such as bad CRCs *(defaults to `false`)*
|
311
311
|
* `:brute` — Brute force try all methods, very time-consuming and generally not worthwhile *(defaults to `false`)*
|
312
312
|
* `:blacken` — Blacken fully transparent pixels *(defaults to `true`)*
|
313
313
|
|
314
|
-
### :
|
314
|
+
### pngout:
|
315
315
|
* `:copy_chunks` — Copy optional chunks *(defaults to `false`)*
|
316
316
|
* `:strategy` — Strategy: `0` - xtreme, `1` - intense, `2` - longest Match, `3` - huffman Only, `4` - uncompressed *(defaults to `0`)*
|
317
317
|
|
318
|
-
### :
|
319
|
-
* `: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`)*
|
318
|
+
### pngquant:
|
319
|
+
* `: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)*
|
320
320
|
* `:speed` — speed/quality trade-off: `1` - slow, `3` - default, `11` - fast & rough *(defaults to `3`)*
|
321
321
|
|
322
|
-
### :
|
323
|
-
|
322
|
+
### svgo:
|
323
|
+
* `:disable_plugins` — List of plugins to disable *(defaults to `[]`)*
|
324
|
+
* `:enable_plugins` — List of plugins to enable *(defaults to `[]`)*
|
324
325
|
|
325
326
|
<!---</worker-options>-->
|
326
327
|
|
data/Vagrantfile
CHANGED
@@ -1,15 +1,22 @@
|
|
1
1
|
VAGRANTFILE_API_VERSION = '2'
|
2
2
|
|
3
3
|
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
|
4
|
-
config.vm.box = 'ubuntu/
|
4
|
+
config.vm.box = 'ubuntu/precise64'
|
5
5
|
|
6
6
|
config.vm.provision 'shell', :inline => <<-SH
|
7
7
|
set -e
|
8
8
|
|
9
9
|
cd /vagrant
|
10
10
|
|
11
|
-
echo '
|
12
|
-
apt-get
|
11
|
+
echo 'apt-get update...'
|
12
|
+
apt-get update > /dev/null
|
13
|
+
|
14
|
+
echo 'Install git, imagemagick, ruby1.9.1-dev...'
|
15
|
+
apt-get install -y git npm imagemagick ruby1.9.1-dev > /dev/null
|
16
|
+
|
17
|
+
echo 'Install node, npm...'
|
18
|
+
curl -sL https://deb.nodesource.com/setup | sudo bash - > /dev/null
|
19
|
+
sudo apt-get install -y nodejs > /dev/null
|
13
20
|
|
14
21
|
echo 'Update rubygems...'
|
15
22
|
REALLY_GEM_UPDATE_SYSTEM=x gem update --system > /dev/null
|
data/image_optim.gemspec
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = 'image_optim'
|
5
|
-
s.version = '0.
|
5
|
+
s.version = '0.22.0'
|
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']
|
@@ -24,6 +24,6 @@ Gem::Specification.new do |s|
|
|
24
24
|
s.add_development_dependency 'image_optim_pack', '~> 0.2'
|
25
25
|
s.add_development_dependency 'rspec', '~> 3.0'
|
26
26
|
if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('1.9.3')
|
27
|
-
s.add_development_dependency 'rubocop', '~> 0.
|
27
|
+
s.add_development_dependency 'rubocop', '~> 0.35'
|
28
28
|
end
|
29
29
|
end
|
data/lib/image_optim.rb
CHANGED
@@ -163,7 +163,9 @@ class ImageOptim
|
|
163
163
|
|
164
164
|
# Version of image_optim gem spec loaded
|
165
165
|
def self.version
|
166
|
-
Gem.loaded_specs['image_optim'].version.to_s
|
166
|
+
Gem.loaded_specs['image_optim'].version.to_s
|
167
|
+
rescue
|
168
|
+
'DEV'
|
167
169
|
end
|
168
170
|
|
169
171
|
# Full version of image_optim
|
@@ -36,6 +36,7 @@ class ImageOptim
|
|
36
36
|
[:gifsicle, is < '1.85', 'does not support removing extension blocks'],
|
37
37
|
[:pngcrush, is < '1.7.38', 'does not have blacken flag'],
|
38
38
|
[:pngquant, is < '2.1', 'may be lossy even with quality `100-`'],
|
39
|
+
[:optipng, is < '0.7', 'does not support -strip option'],
|
39
40
|
]
|
40
41
|
|
41
42
|
# Fail if version will not work properly
|
@@ -28,5 +28,11 @@ class ImageOptim
|
|
28
28
|
value
|
29
29
|
end
|
30
30
|
end
|
31
|
+
|
32
|
+
# Describe default value, returns string as is otherwise surrounds
|
33
|
+
# inspected value with backticks
|
34
|
+
def default_description
|
35
|
+
default.is_a?(String) ? default : "`#{default.inspect}`"
|
36
|
+
end
|
31
37
|
end
|
32
38
|
end
|
data/lib/image_optim/railtie.rb
CHANGED
@@ -3,6 +3,16 @@ require 'image_optim'
|
|
3
3
|
class ImageOptim
|
4
4
|
# Adds image_optim as preprocessor for gif, jpeg, png and svg images
|
5
5
|
class Railtie < Rails::Railtie
|
6
|
+
config.before_configuration do |app|
|
7
|
+
worker_names = ImageOptim::Worker.klasses.map(&:bin_sym)
|
8
|
+
app.config.assets.image_optim =
|
9
|
+
ActiveSupport::OrderedOptions.new do |hash, key|
|
10
|
+
if worker_names.include?(key.to_sym)
|
11
|
+
hash[key] = ActiveSupport::OrderedOptions.new
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
6
16
|
initializer 'image_optim.initializer' do |app|
|
7
17
|
register_preprocessor(app) if register_preprocessor?(app)
|
8
18
|
end
|
@@ -174,8 +174,8 @@ ImageOptim::Runner::OptionParser::DEFINE = proc do |op, options|
|
|
174
174
|
|
175
175
|
bin = klass.bin_sym
|
176
176
|
klass.option_definitions.each do |option_definition|
|
177
|
-
name = option_definition.name.to_s.
|
178
|
-
default = option_definition.
|
177
|
+
name = option_definition.name.to_s.tr('_', '-')
|
178
|
+
default = option_definition.default_description
|
179
179
|
type = option_definition.type
|
180
180
|
|
181
181
|
type, marking = case
|
@@ -37,7 +37,9 @@ class ImageOptim
|
|
37
37
|
#{dst}
|
38
38
|
]
|
39
39
|
args.unshift "-i#{interlace ? 1 : 0}" unless interlace.nil?
|
40
|
-
|
40
|
+
if resolve_bin!(:optipng).version >= '0.7'
|
41
|
+
args.unshift '-strip', 'all' if strip
|
42
|
+
end
|
41
43
|
execute(:optipng, *args) && optimized?(src, dst)
|
42
44
|
end
|
43
45
|
end
|
@@ -7,19 +7,24 @@ class ImageOptim
|
|
7
7
|
# http://pngquant.org/
|
8
8
|
class Pngquant < Worker
|
9
9
|
QUALITY_OPTION =
|
10
|
-
option(:quality, 100..100
|
11
|
-
|
12
|
-
|
13
|
-
|
10
|
+
option(:quality, '`100..100`, `0..100` in lossy mode',
|
11
|
+
NonNegativeIntegerRange, 'min..max - don\'t '\
|
12
|
+
'save below min, use less colors below max (both in range `0..100`; '\
|
13
|
+
'in yaml - `!ruby/range 0..100`), ignored in default/lossless '\
|
14
|
+
'mode') do |v, opt_def|
|
14
15
|
if allow_lossy
|
15
|
-
|
16
|
-
|
16
|
+
if v == opt_def.default
|
17
|
+
0..100
|
18
|
+
else
|
19
|
+
min = OptionHelpers.limit_with_range(v.begin, 0..100)
|
20
|
+
min..OptionHelpers.limit_with_range(v.end, min..100)
|
21
|
+
end
|
17
22
|
else
|
18
23
|
if v != opt_def.default
|
19
24
|
warn "#{self.class.bin_sym} #{opt_def.name} #{v} ignored " \
|
20
25
|
'in lossless mode'
|
21
26
|
end
|
22
|
-
|
27
|
+
100..100
|
23
28
|
end
|
24
29
|
end
|
25
30
|
|
@@ -4,11 +4,27 @@ class ImageOptim
|
|
4
4
|
class Worker
|
5
5
|
# https://github.com/svg/svgo
|
6
6
|
class Svgo < Worker
|
7
|
+
DISABLE_PLUGINS_OPTION =
|
8
|
+
option(:disable_plugins, [], 'List of plugins to disable') do |v|
|
9
|
+
Array(v).map(&:to_s)
|
10
|
+
end
|
11
|
+
|
12
|
+
ENABLE_PLUGINS_OPTION =
|
13
|
+
option(:enable_plugins, [], 'List of plugins to enable') do |v|
|
14
|
+
Array(v).map(&:to_s)
|
15
|
+
end
|
16
|
+
|
7
17
|
def optimize(src, dst)
|
8
18
|
args = %W[
|
9
19
|
--input #{src}
|
10
20
|
--output #{dst}
|
11
21
|
]
|
22
|
+
disable_plugins.each do |plugin_name|
|
23
|
+
args.unshift "--disable=#{plugin_name}"
|
24
|
+
end
|
25
|
+
enable_plugins.each do |plugin_name|
|
26
|
+
args.unshift "--enable=#{plugin_name}"
|
27
|
+
end
|
12
28
|
execute(:svgo, *args) && optimized?(src, dst)
|
13
29
|
end
|
14
30
|
end
|
@@ -12,14 +12,14 @@ GENERATED_NOTE = '<!-- markdown for worker options is generated by '\
|
|
12
12
|
"`#{Pathname($PROGRAM_NAME).cleanpath}` -->"
|
13
13
|
|
14
14
|
def write_worker_options(io, klass)
|
15
|
-
io.puts "###
|
15
|
+
io.puts "### #{klass.bin_sym}:"
|
16
16
|
if klass.option_definitions.empty?
|
17
17
|
io.puts 'Worker has no options'
|
18
18
|
else
|
19
19
|
klass.option_definitions.each do |option_definition|
|
20
20
|
line = "* `:#{option_definition.name}` — #{option_definition.description}"
|
21
21
|
unless line['(defaults']
|
22
|
-
line << " *(defaults to
|
22
|
+
line << " *(defaults to #{option_definition.default_description})*"
|
23
23
|
end
|
24
24
|
io.puts line
|
25
25
|
end
|
@@ -72,9 +72,7 @@ describe ImageOptim::Handler do
|
|
72
72
|
expect(handler).to receive(:cleanup)
|
73
73
|
expect(handler).to receive(:result).and_return(result)
|
74
74
|
|
75
|
-
expect(Handler.for(original)
|
76
|
-
h.process
|
77
|
-
end).to eq(result)
|
75
|
+
expect(Handler.for(original, &:process)).to eq(result)
|
78
76
|
end
|
79
77
|
|
80
78
|
it 'cleans up if exception is raised' do
|
@@ -0,0 +1,110 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'image_optim/option_definition'
|
3
|
+
|
4
|
+
describe ImageOptim::OptionDefinition do
|
5
|
+
describe 'initialization' do
|
6
|
+
context 'when type is not specified explicitly' do
|
7
|
+
subject{ described_class.new('abc', :def, 'desc') }
|
8
|
+
|
9
|
+
describe '#name' do
|
10
|
+
it{ expect(subject.name).to eq(:abc) }
|
11
|
+
end
|
12
|
+
|
13
|
+
describe '#default' do
|
14
|
+
it{ expect(subject.default).to eq(:def) }
|
15
|
+
end
|
16
|
+
|
17
|
+
describe '#type' do
|
18
|
+
it{ expect(subject.type).to eq(Symbol) }
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '#description' do
|
22
|
+
it{ expect(subject.description).to eq('desc') }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context 'when type is specified explicitly' do
|
27
|
+
subject{ described_class.new('abc', :def, Hash, 'desc') }
|
28
|
+
|
29
|
+
describe '#name' do
|
30
|
+
it{ expect(subject.name).to eq(:abc) }
|
31
|
+
end
|
32
|
+
|
33
|
+
describe '#default' do
|
34
|
+
it{ expect(subject.default).to eq(:def) }
|
35
|
+
end
|
36
|
+
|
37
|
+
describe '#type' do
|
38
|
+
it{ expect(subject.type).to eq(Hash) }
|
39
|
+
end
|
40
|
+
|
41
|
+
describe '#description' do
|
42
|
+
it{ expect(subject.description).to eq('desc') }
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe '#value' do
|
48
|
+
context 'when proc not given' do
|
49
|
+
subject{ described_class.new('abc', :def, 'desc') }
|
50
|
+
|
51
|
+
context 'when option not provided' do
|
52
|
+
it 'returns default' do
|
53
|
+
expect(subject.value(nil, {})).to eq(:def)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context 'when option is nil' do
|
58
|
+
it 'returns nil' do
|
59
|
+
expect(subject.value(nil, :abc => nil)).to eq(nil)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context 'when option is set' do
|
64
|
+
it 'returns value' do
|
65
|
+
expect(subject.value(nil, :abc => 123)).to eq(123)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
context 'when proc given' do
|
71
|
+
subject{ described_class.new('abc', :def, 'desc', &:inspect) }
|
72
|
+
|
73
|
+
context 'when option not provided' do
|
74
|
+
it 'returns default passed through proc' do
|
75
|
+
expect(subject.value(nil, {})).to eq(':def')
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
context 'when option is nil' do
|
80
|
+
it 'returns nil passed through proc' do
|
81
|
+
expect(subject.value(nil, :abc => nil)).to eq('nil')
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
context 'when option is set' do
|
86
|
+
it 'returns value passed through proc' do
|
87
|
+
expect(subject.value(nil, :abc => 123)).to eq('123')
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe '#default_description' do
|
94
|
+
context 'when default is not a string' do
|
95
|
+
subject{ described_class.new('abc', :def, 'desc') }
|
96
|
+
|
97
|
+
it 'returns inspected value in backticks' do
|
98
|
+
expect(subject.default_description).to eq('`:def`')
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
context 'when default is a string' do
|
103
|
+
subject{ described_class.new('abc', '`1`', 'desc') }
|
104
|
+
|
105
|
+
it 'returns it as is' do
|
106
|
+
expect(subject.default_description).to eq('`1`')
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -23,7 +23,6 @@ describe 'ImageOptim::Railtie' do
|
|
23
23
|
assets.paths = %w[spec/images]
|
24
24
|
|
25
25
|
assets.delete(:compress)
|
26
|
-
assets.delete(:image_optim)
|
27
26
|
end
|
28
27
|
|
29
28
|
yield config if block_given?
|
@@ -68,14 +67,14 @@ describe 'ImageOptim::Railtie' do
|
|
68
67
|
end
|
69
68
|
|
70
69
|
it 'initializes with empty hash if config.assets.image_optim is true' do
|
71
|
-
expect(ImageOptim).to receive(:new).with({})
|
70
|
+
expect(ImageOptim).to receive(:new).with({})
|
72
71
|
init_rails_app do |config|
|
73
72
|
config.assets.image_optim = true
|
74
73
|
end
|
75
74
|
end
|
76
75
|
|
77
76
|
it 'initializes with empty hash if config.assets.image_optim is nil' do
|
78
|
-
expect(ImageOptim).to receive(:new).with({})
|
77
|
+
expect(ImageOptim).to receive(:new).with({})
|
79
78
|
init_rails_app do |config|
|
80
79
|
config.assets.image_optim = nil
|
81
80
|
end
|
@@ -88,6 +87,33 @@ describe 'ImageOptim::Railtie' do
|
|
88
87
|
config.assets.image_optim = hash
|
89
88
|
end
|
90
89
|
end
|
90
|
+
|
91
|
+
it 'is possible to set individual options' do
|
92
|
+
hash = {:config_paths => 'config/image_optim.yml'}
|
93
|
+
expect(ImageOptim).to receive(:new).with(hash)
|
94
|
+
init_rails_app do |config|
|
95
|
+
config.assets.image_optim.config_paths = 'config/image_optim.yml'
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'is possible to set individual worker options' do
|
100
|
+
hash = {:advpng => {:level => 3}}
|
101
|
+
expect(ImageOptim).to receive(:new).with(hash)
|
102
|
+
init_rails_app do |config|
|
103
|
+
expect(config.assets.image_optim.advpng).to eq({})
|
104
|
+
config.assets.image_optim.advpng.level = 3
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'is not possible to set unknown worker options' do
|
109
|
+
expect(ImageOptim).to receive(:new).with({})
|
110
|
+
init_rails_app do |config|
|
111
|
+
expect(config.assets.image_optim.unknown).to eq(nil)
|
112
|
+
expect do
|
113
|
+
config.assets.image_optim.unknown.level = 3
|
114
|
+
end.to raise_error(NoMethodError)
|
115
|
+
end
|
116
|
+
end
|
91
117
|
end
|
92
118
|
end
|
93
119
|
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'image_optim/worker/optipng'
|
3
|
+
require 'image_optim/image_path'
|
4
|
+
|
5
|
+
describe ImageOptim::Worker::Optipng do
|
6
|
+
describe 'strip option' do
|
7
|
+
subject{ described_class.new(ImageOptim.new, options) }
|
8
|
+
|
9
|
+
let(:options){ {} }
|
10
|
+
let(:optipng_version){ '0.7' }
|
11
|
+
let(:src){ instance_double(ImageOptim::ImagePath, :copy => nil) }
|
12
|
+
let(:dst){ instance_double(ImageOptim::ImagePath) }
|
13
|
+
|
14
|
+
before do
|
15
|
+
optipng_bin = instance_double(ImageOptim::BinResolver::Bin)
|
16
|
+
allow(subject).to receive(:resolve_bin!).
|
17
|
+
with(:optipng).and_return(optipng_bin)
|
18
|
+
allow(optipng_bin).to receive(:version).
|
19
|
+
and_return(ImageOptim::BinResolver::SimpleVersion.new(optipng_version))
|
20
|
+
|
21
|
+
allow(subject).to receive(:optimized?)
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'by default' do
|
25
|
+
it 'should add -strip all to arguments' do
|
26
|
+
expect(subject).to receive(:execute) do |_bin, *args|
|
27
|
+
expect(args.join(' ')).to match(/(^| )-strip all($| )/)
|
28
|
+
end
|
29
|
+
|
30
|
+
subject.optimize(src, dst)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'when strip is disabled' do
|
35
|
+
let(:options){ {:strip => false} }
|
36
|
+
|
37
|
+
it 'should not add -strip all to arguments' do
|
38
|
+
expect(subject).to receive(:execute) do |_bin, *args|
|
39
|
+
expect(args.join(' ')).not_to match(/(^| )-strip all($| )/)
|
40
|
+
end
|
41
|
+
|
42
|
+
subject.optimize(src, dst)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context 'when optipng version is < 0.7' do
|
47
|
+
let(:optipng_version){ '0.6.999' }
|
48
|
+
|
49
|
+
it 'should not add -strip all to arguments' do
|
50
|
+
expect(subject).to receive(:execute) do |_bin, *args|
|
51
|
+
expect(args.join(' ')).not_to match(/(^| )-strip all($| )/)
|
52
|
+
end
|
53
|
+
|
54
|
+
subject.optimize(src, dst)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'image_optim/worker/pngquant'
|
3
|
+
|
4
|
+
describe ImageOptim::Worker::Pngquant do
|
5
|
+
describe 'quality option' do
|
6
|
+
describe 'default' do
|
7
|
+
subject{ described_class::QUALITY_OPTION.default }
|
8
|
+
|
9
|
+
it{ is_expected.to match(/100\.\.100.*0\.\.100/) }
|
10
|
+
end
|
11
|
+
|
12
|
+
describe 'value' do
|
13
|
+
let(:options){ {} }
|
14
|
+
subject{ described_class.new(ImageOptim.new, options).quality }
|
15
|
+
|
16
|
+
context 'by default' do
|
17
|
+
it{ is_expected.to eq(100..100) }
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'when lossy allowed by default' do
|
21
|
+
let(:options){ {:allow_lossy => true} }
|
22
|
+
|
23
|
+
it{ is_expected.to eq(0..100) }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/spec/image_optim_spec.rb
CHANGED
@@ -67,7 +67,7 @@ describe ImageOptim do
|
|
67
67
|
base_options = {:skip_missing_workers => false}
|
68
68
|
[
|
69
69
|
['lossless', base_options, 0],
|
70
|
-
['lossy', base_options.merge(:allow_lossy => true), 0.
|
70
|
+
['lossy', base_options.merge(:allow_lossy => true), 0.001],
|
71
71
|
].each do |type, options, max_difference|
|
72
72
|
image_optim = ImageOptim.new(options)
|
73
73
|
describe type do
|
data/spec/images/test.svg
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -14,35 +14,36 @@ end
|
|
14
14
|
def flatten_animation(image)
|
15
15
|
if image.format == :gif
|
16
16
|
flattened = image.temp_path
|
17
|
-
|
17
|
+
command = %W[
|
18
18
|
convert
|
19
19
|
#{image.to_s.shellescape}
|
20
20
|
-coalesce
|
21
21
|
-append
|
22
22
|
#{flattened.to_s.shellescape}
|
23
23
|
].join(' ')
|
24
|
-
expect(ImageOptim::Cmd.run(
|
24
|
+
expect(ImageOptim::Cmd.run(command)).to be_truthy
|
25
25
|
flattened
|
26
26
|
else
|
27
27
|
image
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
|
-
def
|
31
|
+
def mepp(image_a, image_b)
|
32
32
|
coalesce_a = flatten_animation(image_a)
|
33
33
|
coalesce_b = flatten_animation(image_b)
|
34
|
-
|
34
|
+
command = %W[
|
35
35
|
compare
|
36
|
-
-metric
|
36
|
+
-metric MEPP
|
37
37
|
-alpha Background
|
38
38
|
#{coalesce_a.to_s.shellescape}
|
39
39
|
#{coalesce_b.to_s.shellescape}
|
40
40
|
/dev/null
|
41
41
|
2>&1
|
42
42
|
].join(' ')
|
43
|
-
output = ImageOptim::Cmd.capture(
|
43
|
+
output = ImageOptim::Cmd.capture(command)
|
44
44
|
if [0, 1].include?($CHILD_STATUS.exitstatus)
|
45
|
-
|
45
|
+
num_r = '\d+(?:\.\d+(?:[eE][-+]?\d+)?)?'
|
46
|
+
output[/\((#{num_r}), #{num_r}\)/, 1].to_f
|
46
47
|
else
|
47
48
|
fail "compare #{image_a} with #{image_b} failed with `#{output}`"
|
48
49
|
end
|
@@ -54,7 +55,7 @@ end
|
|
54
55
|
|
55
56
|
RSpec::Matchers.define :be_similar_to do |expected, max_difference|
|
56
57
|
match do |actual|
|
57
|
-
@diff =
|
58
|
+
@diff = mepp(actual, expected)
|
58
59
|
@diff <= max_difference
|
59
60
|
end
|
60
61
|
failure_message do |actual|
|
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.
|
4
|
+
version: 0.22.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: 2015-
|
11
|
+
date: 2015-11-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: fspath
|
@@ -126,20 +126,14 @@ dependencies:
|
|
126
126
|
requirements:
|
127
127
|
- - ~>
|
128
128
|
- !ruby/object:Gem::Version
|
129
|
-
version: '0.
|
130
|
-
- - ! '!='
|
131
|
-
- !ruby/object:Gem::Version
|
132
|
-
version: 0.30.1
|
129
|
+
version: '0.35'
|
133
130
|
type: :development
|
134
131
|
prerelease: false
|
135
132
|
version_requirements: !ruby/object:Gem::Requirement
|
136
133
|
requirements:
|
137
134
|
- - ~>
|
138
135
|
- !ruby/object:Gem::Version
|
139
|
-
version: '0.
|
140
|
-
- - ! '!='
|
141
|
-
- !ruby/object:Gem::Version
|
142
|
-
version: 0.30.1
|
136
|
+
version: '0.35'
|
143
137
|
description:
|
144
138
|
email:
|
145
139
|
executables:
|
@@ -206,10 +200,13 @@ files:
|
|
206
200
|
- spec/image_optim/handler_spec.rb
|
207
201
|
- spec/image_optim/hash_helpers_spec.rb
|
208
202
|
- spec/image_optim/image_path_spec.rb
|
203
|
+
- spec/image_optim/option_definition_spec.rb
|
209
204
|
- spec/image_optim/railtie_spec.rb
|
210
205
|
- spec/image_optim/runner/glob_helpers_spec.rb
|
211
206
|
- spec/image_optim/runner/option_parser_spec.rb
|
212
207
|
- spec/image_optim/space_spec.rb
|
208
|
+
- spec/image_optim/worker/optipng_spec.rb
|
209
|
+
- spec/image_optim/worker/pngquant_spec.rb
|
213
210
|
- spec/image_optim/worker_spec.rb
|
214
211
|
- spec/image_optim_spec.rb
|
215
212
|
- spec/images/comparison.png
|
@@ -274,10 +271,13 @@ test_files:
|
|
274
271
|
- spec/image_optim/handler_spec.rb
|
275
272
|
- spec/image_optim/hash_helpers_spec.rb
|
276
273
|
- spec/image_optim/image_path_spec.rb
|
274
|
+
- spec/image_optim/option_definition_spec.rb
|
277
275
|
- spec/image_optim/railtie_spec.rb
|
278
276
|
- spec/image_optim/runner/glob_helpers_spec.rb
|
279
277
|
- spec/image_optim/runner/option_parser_spec.rb
|
280
278
|
- spec/image_optim/space_spec.rb
|
279
|
+
- spec/image_optim/worker/optipng_spec.rb
|
280
|
+
- spec/image_optim/worker/pngquant_spec.rb
|
281
281
|
- spec/image_optim/worker_spec.rb
|
282
282
|
- spec/image_optim_spec.rb
|
283
283
|
- spec/images/comparison.png
|