image_optim 0.8.1 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- MmQ2Y2Q0NDBlYzJjYzQyODlhMjg1NjI1ZWJkODVhNzQwZGM4MzUwZA==
4
+ MTRmMzViYWYwZjQ2ZDQ3NzI4MzQ0MWZiNTA2MDgzNjc2OGU2MGM5ZA==
5
5
  data.tar.gz: !binary |-
6
- NzYxNjRjMjFiYWY2MzQwODdkY2NkZTkwMDM3ODY1NGQ2NDc0NGZiMA==
6
+ NjEzZTE5MmQ5NzcyM2M5NzQ0YTc4Zjk0YTcxODAzN2IyOTM2ODJjNg==
7
7
  !binary "U0hBNTEy":
8
8
  metadata.gz: !binary |-
9
- ZjEwZGVmNjE2YTBmYmFiM2M1ZTlkNWI0YzgyOWEzZTAzNzFkNDcxNDIwMGNh
10
- ODgyNGU5MjU5MTdlMjY4OGNmOGQ5NWUxYWU1MTZhZWEwNmE5ODI3NmZiNmE4
11
- MjM4NzNlNmI0MGU4YTM5NzFlMmVkOGQ0YTU1MTE5NTBkMzE2OGE=
9
+ NjZmMzM0YWIzMGI2ODg4NWVjZGMyY2U0NjBkMjdjM2U2ZTQ0NzM1YTk1NzU2
10
+ ZjI1OTk5Mzk3ODZmY2Q5MTM3NTI4ZmI4ZGJjMWViNzA2NDJlN2Q1NWE2ZjBj
11
+ YjAyMDBiYzFhZWM4ZTA2NzdlOGEzYjU1MzgwMDEzNTJhMThmZGY=
12
12
  data.tar.gz: !binary |-
13
- NWRmODhjMmE3Y2VhYTc0YTBjNjA2ZGIwNzY4ZGZiY2EzZTQxOWZhYjk0Mzhm
14
- YmRkYTUyMDUxZTZmZjA0NzQ2MzU0ODkyZGRlYjIyOWEzYTQxODUxZTliM2Ni
15
- MWVkMmJkNWVlMzZiOGM1ZTQzY2M5ZjEyNzZjYzkzOGU0YTZlMjY=
13
+ NGM2YmE2MGU3MDI0MjhjYWM5NzdjOWMwNWIyYzM2NzJmMTA3OWI4MzVhOGYy
14
+ YjUwZWFhMDQxNTg5MDk2YWY0YzUxODM2NTdkNjU3OGZhZjU0OTA5MTg5ZTY4
15
+ Y2Q2MGIzNjhjMmM4NDIyOTFiZTQzMzU5ZDhkYzAxODQ4MDJmZjQ=
data/.gitignore CHANGED
@@ -6,6 +6,7 @@
6
6
  /.yardoc/
7
7
  /coverage/
8
8
 
9
+ Gemfile.lock
9
10
  Makefile
10
11
  *.o
11
12
  *.bundle
data/.travis.yml ADDED
@@ -0,0 +1,21 @@
1
+ language:
2
+ - ruby
3
+ rvm:
4
+ - 1.8.7
5
+ - 1.9.2
6
+ - 1.9.3
7
+ - 2.0.0
8
+ - jruby-18mode
9
+ - jruby-19mode
10
+ - rbx-18mode
11
+ - rbx-19mode
12
+ - ree
13
+ script: bundle exec rspec
14
+ before_install:
15
+ - sudo apt-get update -qq
16
+ - sudo apt-get install -qq advancecomp gifsicle jhead jpegoptim libjpeg-progs optipng pngcrush
17
+ - wget http://static.jonof.id.au/dl/kenutils/pngout-20130221-linux.tar.gz
18
+ - tar -xzf pngout-*-linux.tar.gz
19
+ - mv pngout-*-linux pngout-linux
20
+ env:
21
+ - PATH=pngout-linux/x86_64:$PATH
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
data/README.markdown CHANGED
@@ -4,6 +4,7 @@ Optimize (lossless compress) images (jpeg, png, gif) 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
6
  * [gifsicle](http://www.lcdf.org/gifsicle/)
7
+ * [jhead](http://www.sentex.net/~mwandel/jhead/)
7
8
  * [jpegoptim](http://www.kokkonen.net/tjko/projects.html)
8
9
  * jpegtran from [Independent JPEG Group's JPEG library](http://www.ijg.org/)
9
10
  * [optipng](http://optipng.sourceforge.net/)
@@ -46,11 +47,11 @@ Besides permanently setting environment variables in `~/.profile`, `~/.bash_prof
46
47
 
47
48
  ### Linux - Debian/Ubuntu
48
49
 
49
- sudo apt-get install -y advancecomp gifsicle jpegoptim libjpeg-progs optipng pngcrush
50
+ sudo apt-get install -y advancecomp gifsicle jhead jpegoptim libjpeg-progs optipng pngcrush
50
51
 
51
52
  ### Linux - RHEL/Fedora/Centos
52
53
 
53
- sudo yum install -y advancecomp gifsicle libjpeg optipng
54
+ sudo yum install -y advancecomp gifsicle jhead libjpeg optipng
54
55
 
55
56
  You will also need to install `jpegoptim` and `pngcrush` from source:
56
57
 
@@ -72,11 +73,11 @@ You will also need to install `jpegoptim` and `pngcrush` from source:
72
73
 
73
74
  ### OS X: Macports
74
75
 
75
- sudo port install advancecomp gifsicle jpegoptim jpeg optipng pngcrush
76
+ sudo port install advancecomp gifsicle jhead jpegoptim jpeg optipng pngcrush
76
77
 
77
78
  ### OS X: Brew
78
79
 
79
- brew install advancecomp gifsicle jpegoptim jpeg optipng pngcrush
80
+ brew install advancecomp gifsicle jhead jpegoptim jpeg optipng pngcrush
80
81
 
81
82
  ### pngout installation (optional)
82
83
 
data/TODO CHANGED
@@ -1,7 +1,6 @@
1
1
  preserve color (leave_color branch)
2
2
  preserve all extra stuff
3
3
  global level of optimization #10
4
- autorotate jpeg based on exif (jhead -auotrot)
5
4
  timeout workers?
6
5
  based on file size?
7
6
  fail worker instead of process on bin not present?
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.8.1'
5
+ s.version = '0.9.0'
6
6
  s.summary = %q{Optimize (lossless compress) images (jpeg, png, gif) using external utilities (advpng, gifsicle, jpegoptim, jpegtran, optipng, pngcrush, pngout)}
7
7
  s.homepage = "http://github.com/toy/#{s.name}"
8
8
  s.authors = ['Ivan Kuchin']
@@ -15,8 +15,9 @@ Gem::Specification.new do |s|
15
15
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
16
16
  s.require_paths = %w[lib]
17
17
 
18
- s.add_dependency 'fspath', '~> 2.0.3'
18
+ s.add_dependency 'fspath', '~> 2.0.5'
19
19
  s.add_dependency 'image_size', '~> 1.1.2'
20
+ s.add_dependency 'exifr', '~> 1.1.3'
20
21
  s.add_dependency 'progress', '~> 2.4.0'
21
22
  s.add_dependency 'in_threads', '~> 1.1.1'
22
23
  s.add_development_dependency 'rspec'
@@ -22,7 +22,7 @@ class ImageOptim
22
22
  src.temp_path(src.dirname) do |temp|
23
23
  src.copy(temp)
24
24
  temp.write(read)
25
- temp.rename(src)
25
+ temp.rename(src.to_s)
26
26
  end
27
27
  end
28
28
 
@@ -0,0 +1,27 @@
1
+ require 'image_optim/worker'
2
+ require 'exifr'
3
+
4
+ class ImageOptim
5
+ class Worker
6
+ class Jhead < Worker
7
+ def image_formats
8
+ [:jpeg]
9
+ end
10
+
11
+ def run_order
12
+ -10
13
+ end
14
+
15
+ def optimize(src, dst)
16
+ if (2..8).include?(EXIFR::JPEG.new(src.to_s).orientation.to_i)
17
+ src.copy(dst)
18
+ args = %W[-autorot #{dst}]
19
+ resolve_bin!(:jpegtran)
20
+ execute(:jhead, *args) && dst.size?
21
+ else
22
+ false
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -46,7 +46,8 @@ class ImageOptim
46
46
  # List of formats which worker can optimize
47
47
  def image_formats
48
48
  format_from_name = self.class.name.downcase[/gif|jpeg|png/]
49
- format_from_name ? [format_from_name.to_sym] : []
49
+ raise "#{self.class}: can't guess applicable format from worker name" unless format_from_name
50
+ [format_from_name.to_sym]
50
51
  end
51
52
 
52
53
  # Ordering in list of workers
@@ -68,18 +69,35 @@ class ImageOptim
68
69
 
69
70
  # Run command setting priority and hiding output
70
71
  def execute(bin, *arguments)
71
- resolve_bin!(bin)
72
+ command = build_command!(bin, *arguments)
72
73
 
73
- command = [bin, *arguments].map(&:to_s).shelljoin
74
74
  start = Time.now
75
75
 
76
- system "env PATH=#{@image_optim.env_path.shellescape} nice -n #{@image_optim.nice} #{command} > /dev/null 2>&1"
76
+ success = run_command(command)
77
+
78
+ $stderr << "#{success ? '✓' : '✗'} #{Time.now - start}s #{command}\n" if @image_optim.verbose?
77
79
 
78
- raise SignalException.new($?.termsig) if $?.signaled?
80
+ success
81
+ end
82
+
83
+ # Build command string
84
+ def build_command!(bin, *arguments)
85
+ resolve_bin!(bin)
79
86
 
80
- $stderr << "#{$?.success? ? '✓' : '✗'} #{Time.now - start}s #{command}\n" if @image_optim.verbose?
87
+ [bin, *arguments].map(&:to_s).shelljoin
88
+ end
89
+
90
+ # Run command defining environment, setting nice level, removing output and reraising signal exception
91
+ def run_command(command)
92
+ success = system "env PATH=#{@image_optim.env_path.shellescape} nice -n #{@image_optim.nice} #{command} > /dev/null 2>&1"
93
+
94
+ if $?.signaled?
95
+ unless defined?(JRUBY_VERSION) && $?.exitstatus == $?.termsig # jruby does not differ non zero exit status and signal number
96
+ raise SignalException.new($?.termsig)
97
+ end
98
+ end
81
99
 
82
- $?.success?
100
+ success
83
101
  end
84
102
  end
85
103
  end
data/lib/image_optim.rb CHANGED
@@ -248,7 +248,7 @@ end
248
248
 
249
249
  %w[
250
250
  pngcrush pngout optipng advpng
251
- jpegoptim jpegtran
251
+ jhead jpegoptim jpegtran
252
252
  gifsicle
253
253
  ].each do |worker|
254
254
  require "image_optim/worker/#{worker}"
@@ -3,7 +3,7 @@ require 'rspec'
3
3
  require 'image_optim'
4
4
  require 'tempfile'
5
5
 
6
- TEST_IMAGES = (ImageOptim::ImagePath.new(__FILE__).dirname.relative_path_from(Dir.pwd) / 'images').glob('*')
6
+ TEST_IMAGES = ImageOptim::ImagePath.new(__FILE__).dirname.glob('images/**/*.*')
7
7
 
8
8
  Fixnum.class_eval do
9
9
  def in_range?(range)
@@ -208,8 +208,8 @@ describe ImageOptim do
208
208
  it "should resolve bin specified in ENV" do
209
209
  path = (FSPath(__FILE__).dirname / '../bin/image_optim').relative_path_from(Dir.pwd).to_s
210
210
  with_env 'IMAGE_OPTIM_BIN', path do
211
- tmpdir = stub(:tmpdir)
212
- symlink = stub(:symlink)
211
+ tmpdir = double(:tmpdir)
212
+ symlink = double(:symlink)
213
213
 
214
214
  image_optim = ImageOptim.new
215
215
  image_optim.should_receive(:bin_accessible?).with(symlink).once.and_return(true)
@@ -249,8 +249,8 @@ describe ImageOptim do
249
249
  it "should raise on failure to resolve bin specified in ENV" do
250
250
  path = (FSPath(__FILE__).dirname / '../bin/should_not_exist_bin').relative_path_from(Dir.pwd).to_s
251
251
  with_env 'SHOULD_NOT_EXIST_BIN', path do
252
- tmpdir = stub(:tmpdir)
253
- symlink = stub(:symlink)
252
+ tmpdir = double(:tmpdir)
253
+ symlink = double(:symlink)
254
254
 
255
255
  image_optim = ImageOptim.new
256
256
  image_optim.should_receive(:bin_accessible?).with(symlink).once.and_return(false)
@@ -275,4 +275,17 @@ describe ImageOptim do
275
275
  end
276
276
  end
277
277
  end
278
+
279
+ describe "auto orienting" do
280
+ original = ImageOptim::ImagePath.new(__FILE__).dirname / 'images/orient/original.jpg'
281
+ ImageOptim::ImagePath.new(__FILE__).dirname.glob('images/orient/?.jpg').each do |jpg|
282
+ it "should rotate #{jpg}" do
283
+ image_optim = ImageOptim.new
284
+ oriented = image_optim.optimize_image(jpg)
285
+ nrmse = `compare -metric RMSE #{original.to_s.shellescape} #{oriented.to_s.shellescape} /dev/null 2>&1`[/\((\d+(\.\d+)?)\)/, 1]
286
+ nrmse.should_not be_nil
287
+ nrmse.to_f.should be < 0.005
288
+ end
289
+ end
290
+ end
278
291
  end
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,21 @@
1
+ #!/bin/sh
2
+
3
+ convert -size 2x2 xc:black -fill '#f00' -draw 'point 0,1' -fill '#0f0' -draw 'point 1,0' -fill '#00f' -draw 'point 1,1' -scale 64x64 original.png
4
+
5
+ convert original.png 0.jpg
6
+ convert original.png 1.jpg
7
+ convert original.png -flop 2.jpg
8
+ convert original.png -rotate 180 3.jpg
9
+ convert original.png -flip 4.jpg
10
+ convert original.png -transpose 5.jpg
11
+ convert original.png -rotate 270 6.jpg
12
+ convert original.png -transverse 7.jpg
13
+ convert original.png -rotate 90 8.jpg
14
+
15
+ convert original.png original.jpg
16
+ rm original.png
17
+
18
+ exiv2 -M"add Exif.Photo.UserComment image_optim-spec" *.jpg
19
+ for i in {1..8}; do
20
+ exiv2 -M"add Exif.Image.Orientation Short $i" $i.jpg
21
+ done
Binary file
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.8.1
4
+ version: 0.9.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: 2013-05-26 00:00:00.000000000 Z
11
+ date: 2013-07-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: fspath
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - ~>
18
18
  - !ruby/object:Gem::Version
19
- version: 2.0.3
19
+ version: 2.0.5
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ~>
25
25
  - !ruby/object:Gem::Version
26
- version: 2.0.3
26
+ version: 2.0.5
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: image_size
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - ~>
39
39
  - !ruby/object:Gem::Version
40
40
  version: 1.1.2
41
+ - !ruby/object:Gem::Dependency
42
+ name: exifr
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: 1.1.3
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 1.1.3
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: progress
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -88,6 +102,8 @@ extensions: []
88
102
  extra_rdoc_files: []
89
103
  files:
90
104
  - .gitignore
105
+ - .travis.yml
106
+ - Gemfile
91
107
  - LICENSE.txt
92
108
  - README.markdown
93
109
  - TODO
@@ -100,6 +116,7 @@ files:
100
116
  - lib/image_optim/worker.rb
101
117
  - lib/image_optim/worker/advpng.rb
102
118
  - lib/image_optim/worker/gifsicle.rb
119
+ - lib/image_optim/worker/jhead.rb
103
120
  - lib/image_optim/worker/jpegoptim.rb
104
121
  - lib/image_optim/worker/jpegtran.rb
105
122
  - lib/image_optim/worker/optipng.rb
@@ -112,6 +129,17 @@ files:
112
129
  - spec/images/icecream.gif
113
130
  - spec/images/image.jpg
114
131
  - spec/images/lena.jpg
132
+ - spec/images/orient/0.jpg
133
+ - spec/images/orient/1.jpg
134
+ - spec/images/orient/2.jpg
135
+ - spec/images/orient/3.jpg
136
+ - spec/images/orient/4.jpg
137
+ - spec/images/orient/5.jpg
138
+ - spec/images/orient/6.jpg
139
+ - spec/images/orient/7.jpg
140
+ - spec/images/orient/8.jpg
141
+ - spec/images/orient/generate
142
+ - spec/images/orient/original.jpg
115
143
  - spec/images/transparency1.png
116
144
  - spec/images/transparency2.png
117
145
  - spec/images/vergroessert.jpg
@@ -148,6 +176,17 @@ test_files:
148
176
  - spec/images/icecream.gif
149
177
  - spec/images/image.jpg
150
178
  - spec/images/lena.jpg
179
+ - spec/images/orient/0.jpg
180
+ - spec/images/orient/1.jpg
181
+ - spec/images/orient/2.jpg
182
+ - spec/images/orient/3.jpg
183
+ - spec/images/orient/4.jpg
184
+ - spec/images/orient/5.jpg
185
+ - spec/images/orient/6.jpg
186
+ - spec/images/orient/7.jpg
187
+ - spec/images/orient/8.jpg
188
+ - spec/images/orient/generate
189
+ - spec/images/orient/original.jpg
151
190
  - spec/images/transparency1.png
152
191
  - spec/images/transparency2.png
153
192
  - spec/images/vergroessert.jpg