image_optim 0.12.1 → 0.13.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/README.markdown +2 -0
- data/bin/image_optim +2 -1
- data/image_optim.gemspec +1 -1
- data/lib/image_optim.rb +9 -2
- data/lib/image_optim/bin_resolver.rb +12 -3
- data/lib/image_optim/bin_resolver/comparable_condition.rb +44 -0
- data/lib/image_optim/bin_resolver/simple_version.rb +22 -0
- data/lib/image_optim/image_meta.rb +24 -0
- data/lib/image_optim/image_path.rb +4 -2
- data/script/update_worker_options_in_readme +23 -15
- data/spec/image_optim/bin_resolver/comparable_condition_spec.rb +38 -0
- data/spec/image_optim/bin_resolver/simple_version_spec.rb +34 -0
- data/spec/image_optim_spec.rb +67 -9
- metadata +9 -2
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
YjI2ZTQxODlhMzRlMzllZjk0YjhiNmU3YWZiNWYzMDA5NTM2Y2VhNw==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
MWM1N2Q3ZDlmYzQ1MzczMWQ3NjJhMjBlN2E5NGU0ZGIwODhhMDkwNQ==
|
7
7
|
!binary "U0hBNTEy":
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
OTM3MDE3NThhYmEzZjI3NTM2NWMxZDZhOWI2YTg0NDk0ZDk1NjM1NzMyMzhj
|
10
|
+
NTJjY2UzODhhZmY5MTRhZjRlYTBlYzYxZTY1NzgyMGFmMjY5ZjBhNWU3NDAx
|
11
|
+
MmJlZTEwYTY5MDMxMGI1MTI3YWU0N2NkMjdmOTNjNzYzNjE0NTE=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
N2IzNzVhNWFjNzFkOWUwYjg1MjUyYmM4YWJhNjgzYTlhMjgwZDQ0NTYwNWE0
|
14
|
+
MGMzYTA3YzMzOWZkMmZlYzk0YzliMWJhMDZkODZiN2JkMzc3MzIwZDQ4ZGE3
|
15
|
+
MDE1MGY4NWI5YTA5YWU5YmNhN2Y4MTc4YmExMjkzNDg0NTFmNDk=
|
data/README.markdown
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
Optimize (lossless compress) images (jpeg, png, gif, svg) using external utilities:
|
4
4
|
|
5
5
|
* [advpng](http://advancemame.sourceforge.net/doc-advpng.html) from [AdvanceCOMP](http://advancemame.sourceforge.net/comp-readme.html)
|
6
|
+
(will use [zopfli](https://code.google.com/p/zopfli/) on default/maximum level 4)
|
6
7
|
* [gifsicle](http://www.lcdf.org/gifsicle/)
|
7
8
|
* [jhead](http://www.sentex.net/~mwandel/jhead/)
|
8
9
|
* [jpegoptim](http://www.kokkonen.net/tjko/projects.html)
|
@@ -218,6 +219,7 @@ optipng:
|
|
218
219
|
Worker can be disabled by passing `false` instead of options hash.
|
219
220
|
|
220
221
|
<!---<worker-options>-->
|
222
|
+
<!-- worker options markdown is generated by `script/update_worker_options_in_readme` -->
|
221
223
|
|
222
224
|
### :pngcrush =>
|
223
225
|
* `:chunks` — List of chunks to remove or `:alla` - all except tRNS/transparency or `:allb` - all except tRNS and gAMA/gamma *(defaults to `:alla`)*
|
data/bin/image_optim
CHANGED
@@ -9,7 +9,7 @@ option_parser = OptionParser.new do |op|
|
|
9
9
|
op.accept(ImageOptim::TrueFalseNil, OptionParser.top.atype[TrueClass][0].merge('nil' => nil)){ |arg, val| val }
|
10
10
|
|
11
11
|
op.banner = <<-TEXT.gsub(/^\s*\|/, '')
|
12
|
-
|#{
|
12
|
+
|#{ImageOptim.full_version}
|
13
13
|
|
|
14
14
|
|Usege:
|
15
15
|
| #{op.program_name} [options] image_path …
|
@@ -103,6 +103,7 @@ begin
|
|
103
103
|
end
|
104
104
|
|
105
105
|
option_parser.parse!(args)
|
106
|
+
$stderr.puts ImageOptim.full_version if options[:verbose]
|
106
107
|
ImageOptim::Runner.run!(args, options) or exit 1
|
107
108
|
rescue OptionParser::ParseError => e
|
108
109
|
abort "#{e.to_s}\n\n#{option_parser.help}"
|
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.13.0'
|
6
6
|
s.summary = %q{Optimize (lossless compress) images (jpeg, png, gif, svg) using external utilities (advpng, gifsicle, jpegoptim, jpegtran, optipng, pngcrush, pngout, svgo)}
|
7
7
|
s.homepage = "http://github.com/toy/#{s.name}"
|
8
8
|
s.authors = ['Ivan Kuchin']
|
data/lib/image_optim.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'image_optim/bin_resolver'
|
2
2
|
require 'image_optim/config'
|
3
3
|
require 'image_optim/handler'
|
4
|
+
require 'image_optim/image_meta'
|
4
5
|
require 'image_optim/image_path'
|
5
6
|
require 'image_optim/worker'
|
6
7
|
require 'in_threads'
|
@@ -97,8 +98,9 @@ class ImageOptim
|
|
97
98
|
|
98
99
|
# Optimize image data, return new data or nil if optimization failed
|
99
100
|
def optimize_image_data(original_data)
|
100
|
-
|
101
|
-
|
101
|
+
image_meta = ImageMeta.for_data(original_data)
|
102
|
+
return unless image_meta && image_meta.format
|
103
|
+
ImagePath.temp_file %W[image_optim .#{image_meta.format}] do |temp|
|
102
104
|
temp.binmode
|
103
105
|
temp.write(original_data)
|
104
106
|
temp.close
|
@@ -144,6 +146,11 @@ class ImageOptim
|
|
144
146
|
Gem.loaded_specs['image_optim'].version.to_s rescue 'DEV'
|
145
147
|
end
|
146
148
|
|
149
|
+
# Full version of image_optim
|
150
|
+
def self.full_version
|
151
|
+
"image_optim v#{version}"
|
152
|
+
end
|
153
|
+
|
147
154
|
# Are there workers for file at path?
|
148
155
|
def optimizable?(path)
|
149
156
|
!!workers_for_image(path)
|
@@ -1,5 +1,7 @@
|
|
1
1
|
require 'thread'
|
2
2
|
require 'fspath'
|
3
|
+
require 'image_optim/bin_resolver/simple_version'
|
4
|
+
require 'image_optim/bin_resolver/comparable_condition'
|
3
5
|
|
4
6
|
class ImageOptim
|
5
7
|
class BinNotFoundError < StandardError; end
|
@@ -9,7 +11,8 @@ class ImageOptim
|
|
9
11
|
class Bin
|
10
12
|
attr_reader :name, :version
|
11
13
|
def initialize(name, version)
|
12
|
-
@name
|
14
|
+
@name = name
|
15
|
+
@version = version && SimpleVersion.new(version)
|
13
16
|
end
|
14
17
|
|
15
18
|
def to_s
|
@@ -94,11 +97,17 @@ class ImageOptim
|
|
94
97
|
end
|
95
98
|
|
96
99
|
def check!(bin)
|
100
|
+
is = ComparableCondition.is
|
97
101
|
case bin.name
|
98
102
|
when :pngcrush
|
99
103
|
case bin.version
|
100
|
-
when '1.7.60'
|
101
|
-
raise BadBinVersion, "`#{bin}` is known to produce broken pngs"
|
104
|
+
when c = is.between?('1.7.60', '1.7.65')
|
105
|
+
raise BadBinVersion, "`#{bin}` (#{c}) is known to produce broken pngs"
|
106
|
+
end
|
107
|
+
when :advpng
|
108
|
+
case bin.version
|
109
|
+
when c = is < '1.17'
|
110
|
+
warn "Note that `#{bin}` (#{c}) does not use zopfli"
|
102
111
|
end
|
103
112
|
end
|
104
113
|
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
class ImageOptim
|
2
|
+
class BinResolver
|
3
|
+
class ComparableCondition
|
4
|
+
class Builder
|
5
|
+
Comparable.instance_methods.each do |method|
|
6
|
+
define_method method do |*args|
|
7
|
+
ComparableCondition.new(method, *args)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.is
|
13
|
+
Builder.new
|
14
|
+
end
|
15
|
+
|
16
|
+
attr_reader :method, :args
|
17
|
+
def initialize(method, *args)
|
18
|
+
@method = method.to_sym
|
19
|
+
@args = args
|
20
|
+
|
21
|
+
case @method
|
22
|
+
when :between?
|
23
|
+
raise ArgumentError, "`between?' expects 2 arguments" unless args.length == 2
|
24
|
+
when :<, :<=, :==, :>, :>=
|
25
|
+
raise ArgumentError, "`#{method}' expects 1 argument" unless args.length == 1
|
26
|
+
else
|
27
|
+
raise ArgumentError, "Unknown method `#{method}'"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def ===(to_compare)
|
32
|
+
to_compare.send(@method, *@args)
|
33
|
+
end
|
34
|
+
|
35
|
+
def to_s
|
36
|
+
if @method == :between?
|
37
|
+
@args.join('..')
|
38
|
+
else
|
39
|
+
"#{@method} #{@args.first}"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class ImageOptim
|
2
|
+
class BinResolver
|
3
|
+
class SimpleVersion
|
4
|
+
include Comparable
|
5
|
+
|
6
|
+
attr_reader :parts
|
7
|
+
def initialize(str)
|
8
|
+
@str = String(str)
|
9
|
+
@parts = @str.split('.').map(&:to_i).reverse.drop_while(&:zero?).reverse
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_s
|
13
|
+
@str
|
14
|
+
end
|
15
|
+
|
16
|
+
def <=>(other)
|
17
|
+
other = self.class.new(other) unless other.is_a?(self.class)
|
18
|
+
parts <=> other.parts
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'image_size'
|
2
|
+
|
3
|
+
class ImageOptim
|
4
|
+
class ImageMeta
|
5
|
+
def self.for_path(path)
|
6
|
+
is = ImageSize.path(path)
|
7
|
+
new(is.format)
|
8
|
+
rescue => e
|
9
|
+
warn "#{e} (detecting format of image at #{path})"
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.for_data(data)
|
13
|
+
is = ImageSize.new(data)
|
14
|
+
new(is.format)
|
15
|
+
rescue => e
|
16
|
+
warn "#{e} (detecting format of image data)"
|
17
|
+
end
|
18
|
+
|
19
|
+
attr_reader :format
|
20
|
+
def initialize(format)
|
21
|
+
@format = format
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'fspath'
|
2
|
-
require '
|
2
|
+
require 'image_optim/image_meta'
|
3
3
|
|
4
4
|
class ImageOptim
|
5
5
|
class ImagePath < FSPath
|
@@ -49,7 +49,9 @@ class ImageOptim
|
|
49
49
|
|
50
50
|
# Get format using ImageSize
|
51
51
|
def format
|
52
|
-
|
52
|
+
if image_meta = ImageMeta.for_path(self)
|
53
|
+
image_meta.format
|
54
|
+
end
|
53
55
|
end
|
54
56
|
|
55
57
|
# Returns path if it is already an instance of this class otherwise new instance
|
@@ -8,28 +8,36 @@ require 'image_optim'
|
|
8
8
|
README_FILE = File.expand_path('../../README.markdown', __FILE__)
|
9
9
|
BEGIN_MARKER = '<!---<worker-options>-->'
|
10
10
|
END_MARKER = '<!---</worker-options>-->'
|
11
|
+
GENERATED_NOTE = "<!-- markdown for worker options is generated by `#{$0}` -->"
|
12
|
+
|
13
|
+
def update_worker_options(text)
|
14
|
+
text.clone.sub!(/#{Regexp.escape(BEGIN_MARKER)}.*#{Regexp.escape(END_MARKER)}/m) do
|
15
|
+
StringIO.open do |md|
|
16
|
+
md.puts BEGIN_MARKER
|
17
|
+
md.puts GENERATED_NOTE
|
18
|
+
md.puts
|
19
|
+
|
20
|
+
ImageOptim::Worker.klasses.each_with_index do |klass, i|
|
21
|
+
md.puts "### :#{klass.bin_sym} =>"
|
22
|
+
if klass.option_definitions.empty?
|
23
|
+
md.puts 'Worker has no options'
|
24
|
+
else
|
25
|
+
klass.option_definitions.each do |option_definition|
|
26
|
+
md.puts "* `:#{option_definition.name}` — #{option_definition.description} *(defaults to `#{option_definition.default.inspect}`)*"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
md.puts
|
30
|
+
end
|
11
31
|
|
12
|
-
|
13
|
-
io = StringIO.new
|
32
|
+
md.puts END_MARKER
|
14
33
|
|
15
|
-
|
16
|
-
io.puts "### :#{klass.bin_sym} =>"
|
17
|
-
if klass.option_definitions.empty?
|
18
|
-
io.puts 'Worker has no options'
|
19
|
-
else
|
20
|
-
klass.option_definitions.each do |option_definition|
|
21
|
-
io.puts "* `:#{option_definition.name}` — #{option_definition.description} *(defaults to `#{option_definition.default.inspect}`)*"
|
22
|
-
end
|
34
|
+
md.string.strip
|
23
35
|
end
|
24
|
-
io.puts
|
25
36
|
end
|
26
|
-
|
27
|
-
io.string
|
28
37
|
end
|
29
38
|
|
30
39
|
readme = File.read(README_FILE)
|
31
|
-
|
32
|
-
if readme.sub!(/#{Regexp.escape(BEGIN_MARKER)}.*#{Regexp.escape(END_MARKER)}/m, "#{BEGIN_MARKER}\n\n#{worker_options.strip}\n\n#{END_MARKER}")
|
40
|
+
if readme = update_worker_options(readme)
|
33
41
|
File.open(README_FILE, 'w') do |f|
|
34
42
|
f.write readme
|
35
43
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
$:.unshift File.expand_path('../../../../lib', __FILE__)
|
2
|
+
require 'rspec'
|
3
|
+
require 'image_optim/bin_resolver/comparable_condition'
|
4
|
+
|
5
|
+
describe ImageOptim::BinResolver::ComparableCondition do
|
6
|
+
is = ImageOptim::BinResolver::ComparableCondition.is
|
7
|
+
|
8
|
+
it "should build conditions" do
|
9
|
+
expect(is.between?(10, 20).method).to eq(:between?)
|
10
|
+
expect(is.between?(10, 20).args).to eq([10, 20])
|
11
|
+
|
12
|
+
expect((is >= 15).method).to eq(:>=)
|
13
|
+
expect((is >= 15).args).to eq([15])
|
14
|
+
|
15
|
+
expect((is < 30).method).to eq(:<)
|
16
|
+
expect((is < 30).args).to eq([30])
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should stringify conditions" do
|
20
|
+
expect(is.between?(10, 20).to_s).to eq('10..20')
|
21
|
+
expect((is >= 15).to_s).to eq('>= 15')
|
22
|
+
expect((is < 30).to_s).to eq('< 30')
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should match conditions" do
|
26
|
+
expect(is.between?(10, 20)).not_to be === 9
|
27
|
+
expect(is.between?(10, 20)).to be === 15
|
28
|
+
expect(is.between?(10, 20)).not_to be === 21
|
29
|
+
|
30
|
+
expect(is >= 15).not_to be === 14
|
31
|
+
expect(is >= 15).to be === 15
|
32
|
+
expect(is >= 15).to be === 16
|
33
|
+
|
34
|
+
expect(is < 30).to be === 29
|
35
|
+
expect(is < 30).not_to be === 30
|
36
|
+
expect(is < 30).not_to be === 31
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
$:.unshift File.expand_path('../../../../lib', __FILE__)
|
2
|
+
require 'rspec'
|
3
|
+
require 'image_optim/bin_resolver/simple_version'
|
4
|
+
|
5
|
+
describe ImageOptim::BinResolver::SimpleVersion do
|
6
|
+
def v(str)
|
7
|
+
ImageOptim::BinResolver::SimpleVersion.new(str)
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should compare versions" do
|
11
|
+
expect(v '1.17').to be > '0'
|
12
|
+
expect(v '1.17').to be > '0.1'
|
13
|
+
expect(v '1.17').to be > '0.9'
|
14
|
+
expect(v '1.17').to be > '1.9'
|
15
|
+
expect(v '1.17').to be < '1.17.1'
|
16
|
+
expect(v '1.17').to be < '1.99'
|
17
|
+
expect(v '1.17').to be < '2.1'
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should normalize versions" do
|
21
|
+
variations = %w[1 01 1.0 1.00 1.0.0 1.0.0.0]
|
22
|
+
variations.each do |a|
|
23
|
+
variations.each do |b|
|
24
|
+
expect(v a).to eq(b)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should convert objects" do
|
30
|
+
expect(v 1.17).to eq('1.17')
|
31
|
+
expect(v '1.17').to eq('1.17')
|
32
|
+
expect(v(v 1.17)).to eq('1.17')
|
33
|
+
end
|
34
|
+
end
|
data/spec/image_optim_spec.rb
CHANGED
@@ -44,6 +44,18 @@ describe ImageOptim do
|
|
44
44
|
ImageOptim::Config.stub(:global => {}, :local => {})
|
45
45
|
end
|
46
46
|
|
47
|
+
describe "worker" do
|
48
|
+
options = Hash[ImageOptim::Worker.klasses.map{ |klass| [klass.bin_sym, false] }]
|
49
|
+
ImageOptim::Worker.klasses.reject{ |k| k.new({}).image_formats.empty? }.each do |worker_klass|
|
50
|
+
describe worker_klass.bin_sym do
|
51
|
+
it "should optimize at least one test image" do
|
52
|
+
image_optim = ImageOptim.new(options.merge(worker_klass.bin_sym => true))
|
53
|
+
expect(TEST_IMAGES.any?{ |original| image_optim.optimize_image(original.temp_copy) }).to be_true
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
47
59
|
describe "isolated" do
|
48
60
|
describe "optimize" do
|
49
61
|
TEST_IMAGES.each do |original|
|
@@ -92,6 +104,7 @@ describe ImageOptim do
|
|
92
104
|
it "should optimize #{original}" do
|
93
105
|
image_optim = ImageOptim.new
|
94
106
|
optimized_data = image_optim.optimize_image_data(original.read)
|
107
|
+
optimized_data.should_not be_nil
|
95
108
|
optimized_data.should == image_optim.optimize_image(original.temp_copy).open('rb', &:read)
|
96
109
|
|
97
110
|
image_optim.optimize_image_data(optimized_data).should be_nil
|
@@ -139,6 +152,7 @@ describe ImageOptim do
|
|
139
152
|
it "should optimize datas" do
|
140
153
|
optimized_images_datas = ImageOptim.optimize_images_data(TEST_IMAGES.map(&:read))
|
141
154
|
TEST_IMAGES.zip(optimized_images_datas).each do |original, optimized_image_data|
|
155
|
+
optimized_image_data.should_not be_nil
|
142
156
|
optimized_image_data.should == ImageOptim.optimize_image(original.temp_copy).open('rb', &:read)
|
143
157
|
end
|
144
158
|
end
|
@@ -165,6 +179,27 @@ describe ImageOptim do
|
|
165
179
|
Tempfile.init_count.should == 0
|
166
180
|
copy.read.should == original.read
|
167
181
|
end
|
182
|
+
|
183
|
+
{
|
184
|
+
:png => "\211PNG\r\n\032\n",
|
185
|
+
:jpeg => "\377\330",
|
186
|
+
}.each do |type, data|
|
187
|
+
describe "broken #{type}" do
|
188
|
+
before do
|
189
|
+
ImageOptim::ImageMeta.should_receive(:warn)
|
190
|
+
end
|
191
|
+
|
192
|
+
it "should ignore path" do
|
193
|
+
path = FSPath.temp_file_path
|
194
|
+
path.write(data)
|
195
|
+
ImageOptim.optimize_image(path).should be_nil
|
196
|
+
end
|
197
|
+
|
198
|
+
it "should ignore data" do
|
199
|
+
ImageOptim.optimize_image_data(data).should be_nil
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
168
203
|
end
|
169
204
|
|
170
205
|
describe "optimize multiple" do
|
@@ -202,15 +237,38 @@ describe ImageOptim do
|
|
202
237
|
end
|
203
238
|
end
|
204
239
|
|
205
|
-
describe "
|
206
|
-
|
207
|
-
ImageOptim::ImagePath.new(__FILE__).dirname.glob('images/orient/?.jpg')
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
240
|
+
describe "losslessness" do
|
241
|
+
rotated = ImageOptim::ImagePath.new(__FILE__).dirname / 'images/orient/original.jpg'
|
242
|
+
rotate_images = ImageOptim::ImagePath.new(__FILE__).dirname.glob('images/orient/?.jpg')
|
243
|
+
|
244
|
+
def flatten_animation(image)
|
245
|
+
if image.format == :gif
|
246
|
+
flattened = image.temp_path
|
247
|
+
system("convert #{image.to_s.shellescape} -coalesce -append #{flattened.to_s.shellescape}").should be_true
|
248
|
+
flattened
|
249
|
+
else
|
250
|
+
image
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
def check_lossless_optimization(original, optimized)
|
255
|
+
optimized.should_not be_nil
|
256
|
+
original = flatten_animation(original)
|
257
|
+
optimized = flatten_animation(optimized)
|
258
|
+
nrmse = `compare -metric RMSE #{original.to_s.shellescape} #{optimized.to_s.shellescape} /dev/null 2>&1`[/\((\d+(\.\d+)?)\)/, 1]
|
259
|
+
nrmse.should_not be_nil
|
260
|
+
nrmse.to_f.should == 0
|
261
|
+
end
|
262
|
+
|
263
|
+
rotate_images.each do |image|
|
264
|
+
it "should rotate and optimize #{image} losslessly" do
|
265
|
+
check_lossless_optimization(rotated, ImageOptim.optimize_image(image))
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
(TEST_IMAGES - rotate_images).each do |image|
|
270
|
+
it "should optimize #{image} losslessly" do
|
271
|
+
check_lossless_optimization(image, ImageOptim.optimize_image(image))
|
214
272
|
end
|
215
273
|
end
|
216
274
|
end
|
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.13.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: 2014-
|
11
|
+
date: 2014-04-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: fspath
|
@@ -110,10 +110,13 @@ files:
|
|
110
110
|
- image_optim.gemspec
|
111
111
|
- lib/image_optim.rb
|
112
112
|
- lib/image_optim/bin_resolver.rb
|
113
|
+
- lib/image_optim/bin_resolver/comparable_condition.rb
|
114
|
+
- lib/image_optim/bin_resolver/simple_version.rb
|
113
115
|
- lib/image_optim/config.rb
|
114
116
|
- lib/image_optim/configuration_error.rb
|
115
117
|
- lib/image_optim/handler.rb
|
116
118
|
- lib/image_optim/hash_helpers.rb
|
119
|
+
- lib/image_optim/image_meta.rb
|
117
120
|
- lib/image_optim/image_path.rb
|
118
121
|
- lib/image_optim/option_definition.rb
|
119
122
|
- lib/image_optim/option_helpers.rb
|
@@ -131,6 +134,8 @@ files:
|
|
131
134
|
- lib/image_optim/worker/pngout.rb
|
132
135
|
- lib/image_optim/worker/svgo.rb
|
133
136
|
- script/update_worker_options_in_readme
|
137
|
+
- spec/image_optim/bin_resolver/comparable_condition_spec.rb
|
138
|
+
- spec/image_optim/bin_resolver/simple_version_spec.rb
|
134
139
|
- spec/image_optim/bin_resolver_spec.rb
|
135
140
|
- spec/image_optim/config_spec.rb
|
136
141
|
- spec/image_optim/handler_spec.rb
|
@@ -184,6 +189,8 @@ specification_version: 4
|
|
184
189
|
summary: Optimize (lossless compress) images (jpeg, png, gif, svg) using external
|
185
190
|
utilities (advpng, gifsicle, jpegoptim, jpegtran, optipng, pngcrush, pngout, svgo)
|
186
191
|
test_files:
|
192
|
+
- spec/image_optim/bin_resolver/comparable_condition_spec.rb
|
193
|
+
- spec/image_optim/bin_resolver/simple_version_spec.rb
|
187
194
|
- spec/image_optim/bin_resolver_spec.rb
|
188
195
|
- spec/image_optim/config_spec.rb
|
189
196
|
- spec/image_optim/handler_spec.rb
|