image_optim_pack 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/.gitignore +7 -0
- data/.rubocop.yml +51 -0
- data/.travis.yml +22 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +27 -0
- data/Makefile +312 -0
- data/README.markdown +77 -0
- data/Vagrantfile +13 -0
- data/acknowledgements/7z.txt +56 -0
- data/acknowledgements/advancecomp.txt +674 -0
- data/acknowledgements/bmp2png.txt +8 -0
- data/acknowledgements/cexcept.txt +8 -0
- data/acknowledgements/gifread.txt +14 -0
- data/acknowledgements/gifsicle.txt +343 -0
- data/acknowledgements/jhead.txt +12 -0
- data/acknowledgements/jpegoptim.txt +339 -0
- data/acknowledgements/libjpeg.txt +64 -0
- data/acknowledgements/libpng.txt +90 -0
- data/acknowledgements/optipng-authors.txt +26 -0
- data/acknowledgements/optipng.txt +21 -0
- data/acknowledgements/pngcrush.txt +35 -0
- data/acknowledgements/pngquant.txt +56 -0
- data/acknowledgements/zlib.txt +34 -0
- data/acknowledgements/zopfli-contributors.txt +6 -0
- data/acknowledgements/zopfli.txt +201 -0
- data/image_optim_pack.gemspec +26 -0
- data/lib/image_optim/pack.rb +110 -0
- data/lib/image_optim_pack.rb +1 -0
- data/script/livecheck +72 -0
- data/script/run +26 -0
- data/script/update_versions +17 -0
- data/script/vm_init +30 -0
- data/spec/image_optim/pack_spec.rb +114 -0
- data/spec/image_optim_spec.rb +109 -0
- data/spec/spec_helper.rb +0 -0
- data/vendor/darwin/i386/advpng +0 -0
- data/vendor/darwin/i386/gifsicle +0 -0
- data/vendor/darwin/i386/jhead +0 -0
- data/vendor/darwin/i386/jpegoptim +0 -0
- data/vendor/darwin/i386/jpegtran +0 -0
- data/vendor/darwin/i386/libjpeg.dylib +0 -0
- data/vendor/darwin/i386/libpng.dylib +0 -0
- data/vendor/darwin/i386/libz.dylib +0 -0
- data/vendor/darwin/i386/optipng +0 -0
- data/vendor/darwin/i386/pngcrush +0 -0
- data/vendor/darwin/i386/pngquant +0 -0
- data/vendor/darwin/x86_64/advpng +0 -0
- data/vendor/darwin/x86_64/gifsicle +0 -0
- data/vendor/darwin/x86_64/jhead +0 -0
- data/vendor/darwin/x86_64/jpegoptim +0 -0
- data/vendor/darwin/x86_64/jpegtran +0 -0
- data/vendor/darwin/x86_64/libjpeg.dylib +0 -0
- data/vendor/darwin/x86_64/libpng.dylib +0 -0
- data/vendor/darwin/x86_64/libz.dylib +0 -0
- data/vendor/darwin/x86_64/optipng +0 -0
- data/vendor/darwin/x86_64/pngcrush +0 -0
- data/vendor/darwin/x86_64/pngquant +0 -0
- data/vendor/linux/i686/advpng +0 -0
- data/vendor/linux/i686/gifsicle +0 -0
- data/vendor/linux/i686/jhead +0 -0
- data/vendor/linux/i686/jpegoptim +0 -0
- data/vendor/linux/i686/jpegtran +0 -0
- data/vendor/linux/i686/libjpeg.so +0 -0
- data/vendor/linux/i686/libpng.so +0 -0
- data/vendor/linux/i686/libz.so +0 -0
- data/vendor/linux/i686/optipng +0 -0
- data/vendor/linux/i686/pngcrush +0 -0
- data/vendor/linux/i686/pngquant +0 -0
- data/vendor/linux/x86_64/advpng +0 -0
- data/vendor/linux/x86_64/gifsicle +0 -0
- data/vendor/linux/x86_64/jhead +0 -0
- data/vendor/linux/x86_64/jpegoptim +0 -0
- data/vendor/linux/x86_64/jpegtran +0 -0
- data/vendor/linux/x86_64/libjpeg.so +0 -0
- data/vendor/linux/x86_64/libpng.so +0 -0
- data/vendor/linux/x86_64/libz.so +0 -0
- data/vendor/linux/x86_64/optipng +0 -0
- data/vendor/linux/x86_64/pngcrush +0 -0
- data/vendor/linux/x86_64/pngquant +0 -0
- metadata +196 -0
@@ -0,0 +1,26 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = 'image_optim_pack'
|
5
|
+
s.version = '0.1.0'
|
6
|
+
s.summary = %q{Precompiled binaries for image_optim: advpng, gifsicle, jhead, jpegoptim, jpegtran, optipng, pngcrush, pngquant}
|
7
|
+
s.homepage = "http://github.com/toy/#{s.name}"
|
8
|
+
s.authors = ['Ivan Kuchin']
|
9
|
+
s.license = 'MIT'
|
10
|
+
|
11
|
+
s.rubyforge_project = s.name
|
12
|
+
|
13
|
+
s.files = `git ls-files`.split("\n")
|
14
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
15
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
16
|
+
s.require_paths = %w[lib]
|
17
|
+
|
18
|
+
s.add_dependency 'image_optim', '~> 0.18'
|
19
|
+
s.add_dependency 'fspath', '~> 2.1'
|
20
|
+
|
21
|
+
s.add_development_dependency 'versionomy', '~> 0.4.4'
|
22
|
+
s.add_development_dependency 'rspec', '~> 3.0'
|
23
|
+
if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('1.9.3')
|
24
|
+
s.add_development_dependency 'rubocop', '~> 0.26.0'
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
require 'fspath'
|
2
|
+
require 'image_optim/bin_resolver/bin'
|
3
|
+
|
4
|
+
class ImageOptim
|
5
|
+
# Handle selection of directory with binaries most suitable for current
|
6
|
+
# operating system and architecture
|
7
|
+
module Pack
|
8
|
+
# Path to binary, last two parts are expect to be os/arch
|
9
|
+
class Path
|
10
|
+
# Path provided to initialize as FSPath
|
11
|
+
attr_reader :path
|
12
|
+
|
13
|
+
# Intended os
|
14
|
+
attr_reader :os
|
15
|
+
|
16
|
+
# Inteded architecture
|
17
|
+
attr_reader :arch
|
18
|
+
|
19
|
+
# Receive path, use last part for arch and last but one part for os
|
20
|
+
def initialize(path)
|
21
|
+
@path = FSPath(path)
|
22
|
+
@os = @path.dirname.basename.to_s
|
23
|
+
@arch = @path.basename.to_s
|
24
|
+
end
|
25
|
+
|
26
|
+
# Return path converted to string
|
27
|
+
def to_s
|
28
|
+
path.to_s
|
29
|
+
end
|
30
|
+
|
31
|
+
# Cached array of BinResolver::Bin instances for each bin
|
32
|
+
def bins
|
33
|
+
@bins ||= bin_paths.map do |bin_path|
|
34
|
+
BinResolver::Bin.new(bin_path.basename.to_s, bin_path.to_s)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Return true if all bins can execute and return version
|
39
|
+
def all_bins_working?
|
40
|
+
bins.all?(&:version)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Return true if all bins can't execute and return version
|
44
|
+
def all_bins_failing?
|
45
|
+
bins.none?(&:version)
|
46
|
+
end
|
47
|
+
|
48
|
+
# List of bins which can execute and return version
|
49
|
+
def working_bins
|
50
|
+
bins.select(&:version)
|
51
|
+
end
|
52
|
+
|
53
|
+
# List of bins which can't execute and return version
|
54
|
+
def failing_bins
|
55
|
+
bins.reject(&:version)
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
# All children except those starting with 'lib'
|
61
|
+
def bin_paths
|
62
|
+
path.children.reject{ |child| child.basename.to_s =~ /^lib/ }
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# downcased `uname -s`
|
67
|
+
OS = `uname -s`.strip.downcase
|
68
|
+
|
69
|
+
# downcased `uname -m`
|
70
|
+
ARCH = `uname -m`.strip.downcase
|
71
|
+
|
72
|
+
# Path to vendor at root of image_optim_pack
|
73
|
+
VENDOR_PATH = FSPath('../../../vendor').expand_path(__FILE__)
|
74
|
+
|
75
|
+
# List of paths
|
76
|
+
PATHS = VENDOR_PATH.glob('*/*').map{ |path| Path.new(path) }
|
77
|
+
|
78
|
+
class << self
|
79
|
+
# Return path to directory with binaries
|
80
|
+
# Yields debug messages if block given
|
81
|
+
def path
|
82
|
+
ordered_by_os_arch_match.find do |path|
|
83
|
+
yield "image_optim_pack: #{debug_message(path)}" if block_given?
|
84
|
+
path.all_bins_working?
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
# Order by match of os and architecture
|
91
|
+
def ordered_by_os_arch_match
|
92
|
+
PATHS.sort_by do |path|
|
93
|
+
[path.os == OS ? 0 : 1, path.arch == ARCH ? 0 : 1]
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# Messages based on success of getting versions of bins
|
98
|
+
def debug_message(path)
|
99
|
+
case
|
100
|
+
when path.all_bins_working?
|
101
|
+
"all bins from #{path} worked"
|
102
|
+
when path.all_bins_failing?
|
103
|
+
"all bins from #{path} failed"
|
104
|
+
else
|
105
|
+
"#{path.failing_bins.map(&:name).join(', ')} from #{path} failed"
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'image_optim/pack'
|
data/script/livecheck
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'yaml'
|
4
|
+
require 'uri'
|
5
|
+
require 'net/http'
|
6
|
+
require 'versionomy'
|
7
|
+
|
8
|
+
bare = ARGV.delete('--bare')
|
9
|
+
|
10
|
+
unless [1, 2].include?(ARGV.length)
|
11
|
+
abort 'expected project name and optional current version'
|
12
|
+
end
|
13
|
+
|
14
|
+
def version(string)
|
15
|
+
Versionomy.parse(string)
|
16
|
+
end
|
17
|
+
|
18
|
+
name = ARGV[0].downcase
|
19
|
+
config = YAML.load(DATA)[name]
|
20
|
+
abort "Livecheck for #{name} was not defined" unless config
|
21
|
+
|
22
|
+
uri = URI(config['url'])
|
23
|
+
version_regex = Regexp.new(config['regexp'])
|
24
|
+
current_version = ARGV[1] && version(ARGV[1])
|
25
|
+
|
26
|
+
data = Net::HTTP.get(uri)
|
27
|
+
versions = data.scan(version_regex).uniq.map{ |match| version(match[0]) }
|
28
|
+
abort 'No versions found' if versions.empty?
|
29
|
+
|
30
|
+
latest_version = versions.max
|
31
|
+
case
|
32
|
+
when bare
|
33
|
+
print latest_version
|
34
|
+
when current_version
|
35
|
+
if latest_version > current_version
|
36
|
+
puts "#{name} #{latest_version} > #{current_version}"
|
37
|
+
end
|
38
|
+
else
|
39
|
+
puts "#{name} #{latest_version}"
|
40
|
+
end
|
41
|
+
|
42
|
+
__END__
|
43
|
+
advancecomp:
|
44
|
+
url: http://sourceforge.net/projects/advancemame/rss?path=/advancecomp
|
45
|
+
regexp: /advancecomp/(\d+(?:\.\d+)*)/
|
46
|
+
gifsicle:
|
47
|
+
url: http://www.lcdf.org/gifsicle/
|
48
|
+
regexp: gifsicle-(\d+(?:\.\d+)*)\.tar\.gz
|
49
|
+
jhead:
|
50
|
+
url: http://www.sentex.net/~mwandel/jhead/
|
51
|
+
regexp: jhead-(\d+(?:\.\d+)*)
|
52
|
+
jpegoptim:
|
53
|
+
url: http://www.kokkonen.net/tjko/src/
|
54
|
+
regexp: jpegoptim-(\d+(?:\.\d+)*)
|
55
|
+
libjpeg:
|
56
|
+
url: http://www.ijg.org/files/
|
57
|
+
regexp: jpegsrc.v(.*?).tar.gz
|
58
|
+
libpng:
|
59
|
+
url: http://sourceforge.net/projects/libpng/rss
|
60
|
+
regexp: /libpng\d*/(\d+(?:\.\d+)*)/
|
61
|
+
libz:
|
62
|
+
url: http://sourceforge.net/projects/libpng/rss?path=/zlib
|
63
|
+
regexp: /zlib/(\d+(?:\.\d+)*)/
|
64
|
+
optipng:
|
65
|
+
url: http://sourceforge.net/projects/optipng/rss
|
66
|
+
regexp: /OptiPNG/optipng-(\d+(?:\.\d+)*)/
|
67
|
+
pngcrush:
|
68
|
+
url: http://sourceforge.net/projects/pmt/rss?path=/pngcrush
|
69
|
+
regexp: /pngcrush/(\d+(?:\.\d+)*)/
|
70
|
+
pngquant:
|
71
|
+
url: http://pngquant.org/releases.html
|
72
|
+
regexp: pngquant-([0-9.]+)-src.tar.bz2
|
data/script/run
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
|
3
|
+
set -xe
|
4
|
+
|
5
|
+
MAKE_COMMAND='make all -j'
|
6
|
+
|
7
|
+
for arg in "$@"; do
|
8
|
+
if [[ "$arg" =~ ^([A-Z_]+)=(.*)$ ]]; then
|
9
|
+
eval "$(printf %q=%q "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}")"
|
10
|
+
fi
|
11
|
+
done
|
12
|
+
|
13
|
+
if [ "$(uname -s | tr A-Z a-z)" != 'darwin' ]; then
|
14
|
+
echo 'expected to run on Mac OS X'
|
15
|
+
exit 1
|
16
|
+
fi
|
17
|
+
|
18
|
+
for arch in i386 x86_64; do
|
19
|
+
$MAKE_COMMAND ARCH=$arch
|
20
|
+
done
|
21
|
+
|
22
|
+
for vm in linux_{i686,x86_64}; do
|
23
|
+
vagrant up $vm
|
24
|
+
vagrant ssh $vm -c "cd /vagrant; $MAKE_COMMAND"
|
25
|
+
[ -n "$NO_HALT" ] || vagrant halt
|
26
|
+
done
|
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'English'
|
4
|
+
|
5
|
+
tty = $stdout.tty?
|
6
|
+
|
7
|
+
ARGF.each do |line|
|
8
|
+
if (name = line[/^([A-Z]+)_VER *:= *.*/, 1])
|
9
|
+
$stderr << name << ' := ' unless tty
|
10
|
+
latest_version = `script/livecheck --bare #{name}`.strip
|
11
|
+
abort unless $CHILD_STATUS.success?
|
12
|
+
$stderr << latest_version << "\n" unless tty
|
13
|
+
$stdout << "#{name}_VER := #{latest_version}\n"
|
14
|
+
else
|
15
|
+
$stdout << line
|
16
|
+
end
|
17
|
+
end
|
data/script/vm_init
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
|
3
|
+
present(){
|
4
|
+
local missing=0
|
5
|
+
for name in "$@"; do
|
6
|
+
if command -v "$name" >/dev/null 2>&1; then
|
7
|
+
echo "got $name"
|
8
|
+
else
|
9
|
+
echo "no $name"
|
10
|
+
missing=1
|
11
|
+
fi
|
12
|
+
done
|
13
|
+
[ $missing -eq 0 ] || return 127
|
14
|
+
}
|
15
|
+
|
16
|
+
if ! present make wget gcc g++ chrpath perl pkg-config automake; then
|
17
|
+
if present apt-get; then
|
18
|
+
apt-get -y install make wget gcc g++ chrpath perl pkg-config automake
|
19
|
+
elif present yum; then
|
20
|
+
yum -y install make wget gcc gcc-c++ chrpath perl pkg-config automake
|
21
|
+
else
|
22
|
+
echo 'unknown package manager'
|
23
|
+
exit 1
|
24
|
+
fi
|
25
|
+
fi
|
26
|
+
|
27
|
+
if ! make --version 2>&1 | grep -q 'GNU Make'; then
|
28
|
+
echo 'non gnu make'
|
29
|
+
exit 1
|
30
|
+
fi
|
@@ -0,0 +1,114 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'image_optim/pack'
|
3
|
+
|
4
|
+
describe ImageOptim::Pack do
|
5
|
+
before do
|
6
|
+
stub_const('Pack', ImageOptim::Pack)
|
7
|
+
stub_const('Path', Pack::Path)
|
8
|
+
end
|
9
|
+
|
10
|
+
describe :path do
|
11
|
+
it 'returns path' do
|
12
|
+
expect(Pack.path).to be
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'returns instance of Path' do
|
16
|
+
expect(Pack.path).to be_an(Path)
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'yields debug messages' do
|
20
|
+
expect{ |block| Pack.path(&block) }.
|
21
|
+
to yield_with_args(/^image_optim_pack: all bins .* worked$/)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe ImageOptim::Pack::Path do
|
26
|
+
describe :path do
|
27
|
+
it 'returns FSPath with path' do
|
28
|
+
expect(Path.new('path').path).to eq(FSPath('path'))
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe :to_s do
|
33
|
+
it 'returns stringified path' do
|
34
|
+
expect(Path.new(Pathname('path')).to_s).to eq('path')
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe :os do
|
39
|
+
it 'returns last but one part of path' do
|
40
|
+
expect(Path.new('path/futureos/Kqbit').os).to eq('futureos')
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe :arch do
|
45
|
+
it 'returns last but one part of path' do
|
46
|
+
expect(Path.new('path/futureos/Kqbit').arch).to eq('Kqbit')
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe :bins do
|
51
|
+
subject{ Pack.path.bins }
|
52
|
+
|
53
|
+
define :be_non_libraries do
|
54
|
+
match do |bin|
|
55
|
+
bin.name !~ /^lib/
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
it{ should be_an(Array) }
|
60
|
+
|
61
|
+
it{ should_not be_empty }
|
62
|
+
|
63
|
+
it{ should all(be_an(ImageOptim::BinResolver::Bin)) }
|
64
|
+
|
65
|
+
it{ should all(have_attributes(:version => be)) }
|
66
|
+
|
67
|
+
it{ should all(be_non_libraries) }
|
68
|
+
end
|
69
|
+
|
70
|
+
describe 'bin helpers' do
|
71
|
+
def bins_with_versions(*versions)
|
72
|
+
versions.map do |version|
|
73
|
+
double(:version => version, :inspect => version ? 'good' : 'bad')
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def path_with_bins(*bins)
|
78
|
+
path = Path.new('path')
|
79
|
+
allow(path).to receive(:bins).and_return(bins)
|
80
|
+
path
|
81
|
+
end
|
82
|
+
|
83
|
+
describe 'all good bins' do
|
84
|
+
let(:bins){ bins_with_versions('1.3', '6.1.6') }
|
85
|
+
subject{ path_with_bins(*bins) }
|
86
|
+
|
87
|
+
it{ should be_all_bins_working }
|
88
|
+
it{ should_not be_all_bins_failing }
|
89
|
+
it{ should have_attributes(:working_bins => eq(bins)) }
|
90
|
+
it{ should have_attributes(:failing_bins => be_empty) }
|
91
|
+
end
|
92
|
+
|
93
|
+
describe 'mixed good/bad bins' do
|
94
|
+
let(:bins){ bins_with_versions('1.3', nil, '6.1.6', nil) }
|
95
|
+
subject{ path_with_bins(*bins) }
|
96
|
+
|
97
|
+
it{ should_not be_all_bins_working }
|
98
|
+
it{ should_not be_all_bins_failing }
|
99
|
+
it{ should have_attributes(:working_bins => bins.select(&:version)) }
|
100
|
+
it{ should have_attributes(:failing_bins => bins.reject(&:version)) }
|
101
|
+
end
|
102
|
+
|
103
|
+
describe 'all bad bins' do
|
104
|
+
let(:bins){ bins_with_versions(nil, nil) }
|
105
|
+
subject{ path_with_bins(*bins) }
|
106
|
+
|
107
|
+
it{ should_not be_all_bins_working }
|
108
|
+
it{ should be_all_bins_failing }
|
109
|
+
it{ should have_attributes(:working_bins => be_empty) }
|
110
|
+
it{ should have_attributes(:failing_bins => eq(bins)) }
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'image_optim'
|
3
|
+
require 'image_optim/cmd'
|
4
|
+
require 'tempfile'
|
5
|
+
require 'English'
|
6
|
+
|
7
|
+
describe ImageOptim do
|
8
|
+
def self.temp_copy(image)
|
9
|
+
image.temp_path.tap{ |path| image.copy(path) }
|
10
|
+
end
|
11
|
+
|
12
|
+
before do
|
13
|
+
stub_const('Cmd', ImageOptim::Cmd)
|
14
|
+
end
|
15
|
+
|
16
|
+
def flatten_animation(image)
|
17
|
+
if image.format == :gif
|
18
|
+
flattened = image.temp_path
|
19
|
+
flatten_command = %W[
|
20
|
+
convert
|
21
|
+
#{image.to_s.shellescape}
|
22
|
+
-coalesce
|
23
|
+
-append
|
24
|
+
#{flattened.to_s.shellescape}
|
25
|
+
].join(' ')
|
26
|
+
expect(Cmd.run(flatten_command)).to be_truthy
|
27
|
+
flattened
|
28
|
+
else
|
29
|
+
image
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def nrmse(image_a, image_b)
|
34
|
+
coalesce_a = flatten_animation(image_a)
|
35
|
+
coalesce_b = flatten_animation(image_b)
|
36
|
+
nrmse_command = %W[
|
37
|
+
compare
|
38
|
+
-metric RMSE
|
39
|
+
#{coalesce_a.to_s.shellescape}
|
40
|
+
#{coalesce_b.to_s.shellescape}
|
41
|
+
/dev/null
|
42
|
+
2>&1
|
43
|
+
].join(' ')
|
44
|
+
output = Cmd.capture(nrmse_command)
|
45
|
+
if [0, 1].include?($CHILD_STATUS.exitstatus)
|
46
|
+
output[/\((\d+(\.\d+)?)\)/, 1].to_f
|
47
|
+
else
|
48
|
+
fail "compare #{image_a} with #{image_b} failed with `#{output}`"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
define :have_same_data_as do |expected|
|
53
|
+
match{ |actual| actual.binread == expected.binread }
|
54
|
+
end
|
55
|
+
|
56
|
+
define :have_size do
|
57
|
+
match(&:size?)
|
58
|
+
end
|
59
|
+
|
60
|
+
define :be_smaller_than do |expected|
|
61
|
+
match{ |actual| actual.size < expected.size }
|
62
|
+
end
|
63
|
+
|
64
|
+
define :be_pixel_identical_to do |expected|
|
65
|
+
match do |actual|
|
66
|
+
@diff = nrmse(actual, expected)
|
67
|
+
@diff == 0
|
68
|
+
end
|
69
|
+
failure_message do |actual|
|
70
|
+
"expected #{actual} to be pixel identical to #{expected}, got "\
|
71
|
+
"normalized root-mean-square error of #{@diff}"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
image_optim = ImageOptim.new
|
76
|
+
|
77
|
+
# grab images from image_optim gem
|
78
|
+
image_optim_root = Gem.loaded_specs['image_optim'].gem_dir
|
79
|
+
images_dir = ImageOptim::ImagePath.new(image_optim_root) / 'spec/images'
|
80
|
+
test_images = images_dir.glob('**/*.*')
|
81
|
+
|
82
|
+
# select images which for which there are workers
|
83
|
+
test_images = test_images.select do |image|
|
84
|
+
image_optim.workers_for_image(image)
|
85
|
+
end
|
86
|
+
|
87
|
+
rotated = images_dir / 'orient/original.jpg'
|
88
|
+
rotate_images = images_dir.glob('orient/?.jpg')
|
89
|
+
|
90
|
+
copies = test_images.map{ |image| temp_copy(image) }
|
91
|
+
original_by_copy = Hash[copies.zip(test_images)]
|
92
|
+
|
93
|
+
image_optim.optimize_images(copies) do |copy, optimized|
|
94
|
+
fail 'expected copy to not be nil' if copy.nil?
|
95
|
+
original = original_by_copy[copy]
|
96
|
+
|
97
|
+
it "optimizes #{original}" do
|
98
|
+
expect(copy).to have_same_data_as(original)
|
99
|
+
|
100
|
+
expect(optimized).not_to be_nil
|
101
|
+
expect(optimized).to have_size
|
102
|
+
expect(optimized).to be_smaller_than(original)
|
103
|
+
expect(optimized).not_to have_same_data_as(original)
|
104
|
+
|
105
|
+
compare_to = rotate_images.include?(original) ? rotated : original
|
106
|
+
expect(optimized).to be_pixel_identical_to(compare_to)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|