image_squeeze 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -6,6 +6,8 @@ A library for automated lossless image optimization
6
6
 
7
7
  The default processors depend on ImageMagick, pngcrush, gifsicle, and jpegtran. ImageMagick is required for all processors.
8
8
 
9
+ gem install image_squeeze
10
+
9
11
  ## Usage
10
12
 
11
13
  # set up an ImageSqueeze with the default processors
data/lib/image_squeeze.rb CHANGED
@@ -1,6 +1,8 @@
1
1
  $:.unshift File.dirname(__FILE__)
2
2
 
3
+ require 'tempfile'
3
4
  require 'logger'
5
+
4
6
  require 'image_squeeze/log_factory'
5
7
  require 'image_squeeze/utils'
6
8
  require 'image_squeeze/image_identifier'
@@ -16,8 +18,9 @@ require 'image_squeeze/processors/gif_to_png_processor'
16
18
 
17
19
  class ImageSqueeze
18
20
  attr_reader :processors
21
+ attr_reader :tmpdir
19
22
 
20
- VERSION = '0.1.0'
23
+ VERSION = '0.1.1'
21
24
 
22
25
  # Image Types
23
26
  GIF = 'gif'
@@ -40,6 +43,8 @@ class ImageSqueeze
40
43
 
41
44
  @processors = options[:processors] || []
42
45
  @processors += self.class.default_processors if options[:default_processors]
46
+
47
+ @tmpdir = options[:tmpdir] || Dir::tmpdir
43
48
  end
44
49
 
45
50
  def self.default
@@ -55,7 +60,8 @@ class ImageSqueeze
55
60
 
56
61
  original_file_size = File.size(filename)
57
62
  sorted_results = processors.map do |processor_class|
58
- output_filename = processor_class.squeeze_to_tmp(filename)
63
+ output_filename = tmp_filename(filename)
64
+ processor_class.squeeze(filename, output_filename)
59
65
  output_file_size = File.size(output_filename)
60
66
  result_options = { :filename => filename, :output_filename => output_filename, :bytes_saved => original_file_size - output_file_size, :output_extension => processor_class.output_extension }
61
67
  Result.new(result_options)
@@ -87,22 +93,35 @@ class ImageSqueeze
87
93
  output_filename
88
94
  end
89
95
 
90
- def logger
96
+ def self.logger
91
97
  LogFactory.logger
92
98
  end
93
99
 
100
+ def logger
101
+ self.class.logger
102
+ end
103
+
94
104
  def self.default_processors
95
105
  processors = []
96
- ImageSqueeze::Utils.image_utility_available?('identify', 'all image', Logger::ERROR)
97
- if ImageSqueeze::Utils.image_utility_available?('pngcrush', 'pngs and gif', Logger::WARN)
106
+ ImageSqueeze::Utils.image_utility_available?('identify', 'all image', true)
107
+ if ImageSqueeze::Utils.image_utility_available?('pngcrush', 'pngs and gif')
98
108
  processors << PNGCrushProcessor
99
- processors << GIFToPNGProcessor if ImageSqueeze::Utils.image_utility_available?('convert', 'gif', Logger::WARN)
109
+ processors << GIFToPNGProcessor if ImageSqueeze::Utils.image_utility_available?('convert', 'gif')
100
110
  end
101
- processors << GifsicleProcessor if ImageSqueeze::Utils.image_utility_available?('gifsicle', 'animated gif', Logger::WARN)
102
- if ImageSqueeze::Utils.image_utility_available?('jpegtran', 'jpeg', Logger::WARN)
111
+ processors << GifsicleProcessor if ImageSqueeze::Utils.image_utility_available?('gifsicle', 'animated gif')
112
+ if ImageSqueeze::Utils.image_utility_available?('jpegtran', 'jpeg')
103
113
  processors << JPEGTranProgressiveProcessor
104
114
  processors << JPEGTranNonProgressiveProcessor
105
115
  end
106
116
  processors
107
117
  end
118
+
119
+ private
120
+ def tmp_filename(filename)
121
+ t = Time.now.strftime("%Y%m%d")
122
+ path = "#{File.basename(filename)}#{t}-#{$$}-#{rand(0x100000000).to_s(36)}"
123
+
124
+ File.join(tmpdir, path)
125
+ end
126
+
108
127
  end
@@ -9,11 +9,14 @@ class ImageSqueeze
9
9
  end
10
10
 
11
11
  def self.squeeze(filename, output_filename)
12
- intermediate_tmp_filename = tmp_filename(filename)
12
+ intermediate_tmp_filename = "%s-%s" % [output_filename, '.tmp']
13
13
 
14
14
  system("convert #{filename} PNG:#{intermediate_tmp_filename} 2> /dev/null")
15
+ response = PNGCrushProcessor.squeeze(intermediate_tmp_filename, output_filename) # run it through PNGCrush afterwards
15
16
 
16
- PNGCrushProcessor.squeeze(intermediate_tmp_filename, output_filename) # run it through PNGCrush afterwards
17
+ FileUtils.rm(intermediate_tmp_filename) # clean up after ourselves
18
+
19
+ response
17
20
  end
18
21
  end
19
22
  end
@@ -1,22 +1,7 @@
1
- require 'tempfile'
2
-
3
1
  class ImageSqueeze
4
2
  class Processor
5
3
  attr_reader :filename
6
4
 
7
- def self.tmp_filename(filename)
8
- t = Time.now.strftime("%Y%m%d")
9
- path = "#{File.basename(filename)}#{t}-#{$$}-#{rand(0x100000000).to_s(36)}"
10
-
11
- File.join(Dir::tmpdir, path)
12
- end
13
-
14
- def self.squeeze_to_tmp(filename)
15
- tmp = tmp_filename(filename)
16
- squeeze(filename, tmp)
17
- tmp
18
- end
19
-
20
5
  def self.squeeze(filename, output_filename)
21
6
  raise "#{to_s}#squeeze should be defined in subclass and should convert filename to something at output_filename"
22
7
  end
@@ -1,13 +1,14 @@
1
1
  class ImageSqueeze
2
2
  module Utils
3
- def self.image_utility_available?(bin, extension, log_level = Logger::WARN)
3
+ def self.image_utility_available?(bin, extension, raise_when_missing = false)
4
4
  return true if system("which #{bin} > /dev/null")
5
- if log_level >= Logger::ERROR
5
+ if raise_when_missing
6
6
  ImageSqueeze.logger.error("#{bin} utility is required for running ImageSqueeze, get it installed already")
7
7
  raise StandardError, "#{bin} utility is required for running ImageSqueeze, get it installed already"
8
8
  else
9
- ImageSqueeze.logger.log(log_level, "#{bin} utility could not be found, your #{extension} files won't be squeezed")
9
+ ImageSqueeze.logger.warn("#{bin} utility could not be found, your #{extension} files won't be squeezed")
10
10
  end
11
+ false
11
12
  end
12
13
  end
13
14
  end
@@ -55,6 +55,7 @@ class DefaultProcessorsTest < Test::Unit::TestCase
55
55
  filename = fixtures(file)
56
56
  old_size = File.size(filename)
57
57
  new_filename = squeezer.squeeze!(filename)
58
- assert File.size(new_filename) >= old_size, "New file size of #{File.size(new_filename)} should be at least as big as original of #{old_size}"
58
+ new_file_size = File.size(new_filename) if new_filename
59
+ assert new_filename.nil?, "New file size of #{new_file_size} should be at least as big as original of #{old_size}"
59
60
  end
60
61
  end
@@ -1,5 +1,4 @@
1
1
  require File.join(File.dirname(__FILE__), '..', 'test_helper')
2
- require 'mocha'
3
2
 
4
3
  class SqueezeTest < Test::Unit::TestCase
5
4
  def setup
@@ -77,6 +76,17 @@ class SqueezeTest < Test::Unit::TestCase
77
76
  assert_equal old_size, File.size(filename)
78
77
  end
79
78
 
79
+ def test_override_tmp_dir_stores_output_files_in_correct_location
80
+ tmpdir = File.join(File.dirname(__FILE__), '..', 'tmp')
81
+ FileUtils.mkdir_p(tmpdir)
82
+ image_squeezer = custom_image_squeezer(AlwaysOptimize, :tmpdir => tmpdir)
83
+
84
+ result = image_squeezer.squeeze(fixtures('already_optimized_gif.gif'))
85
+ assert_equal 0, result.output_filename.index(tmpdir), "Output file should be located in tmpdir: #{tmpdir}"
86
+ ensure
87
+ FileUtils.rm(result.output_filename) if result && result.output_filename && File.exists?(result.output_filename)
88
+ end
89
+
80
90
  private
81
91
  class AlwaysOptimize < ImageSqueeze::Processor
82
92
  def self.squeeze(filename, output_filename)
@@ -111,6 +121,8 @@ class SqueezeTest < Test::Unit::TestCase
111
121
  end
112
122
 
113
123
  def custom_image_squeezer(*processors)
114
- ImageSqueeze.new(:processors => processors )
124
+ options = processors.last.is_a?(Hash) ? processors.pop : {}
125
+
126
+ ImageSqueeze.new(options.merge(:processors => processors))
115
127
  end
116
128
  end
@@ -0,0 +1,29 @@
1
+ require File.join(File.dirname(__FILE__), '..', 'test_helper')
2
+
3
+ class UtilsTest < Test::Unit::TestCase
4
+ def test_utility_available_returns_true_when_found
5
+ assert ImageSqueeze::Utils.image_utility_available?('ls', 'files'), "You don't have ls, wtf?"
6
+ end
7
+
8
+ def test_utility_available_returns_false_when_not_found
9
+ ImageSqueeze.logger.stubs(:warn)
10
+ assert !ImageSqueeze::Utils.image_utility_available?('andrewMagicNonexistantFileDestroyer', 'magic'), "Uhhh...where'd you get that?"
11
+ end
12
+
13
+ def test_utility_logs_warning_when_not_found
14
+ ImageSqueeze.logger.expects(:warn).with(regexp_matches(/marbles/))
15
+ ImageSqueeze::Utils.image_utility_available?('andrewMagicNonexistantFileDestroyer', 'marbles')
16
+ end
17
+
18
+ def test_utility_available_raises_when_not_found_and_raise_when_missing_true
19
+ ImageSqueeze.logger.stubs(:error)
20
+ assert_raises StandardError do
21
+ !ImageSqueeze::Utils.image_utility_available?('andrewMagicNonexistantFileDestroyer', 'magic', true)
22
+ end
23
+ end
24
+
25
+ def test_utility_logs_error_when_missing_true
26
+ ImageSqueeze.logger.expects(:error)
27
+ ImageSqueeze::Utils.image_utility_available?('andrewMagicNonexistantFileDestroyer', 'dolphins', true) rescue StandardError
28
+ end
29
+ end
data/test/test_helper.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require 'test/unit'
2
2
  require 'ruby-debug'
3
+ require 'mocha'
3
4
  require File.join(File.dirname(__FILE__), '..', 'lib', 'image_squeeze')
4
5
 
5
6
  class Test::Unit::TestCase
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 1
8
- - 0
9
- version: 0.1.0
8
+ - 1
9
+ version: 0.1.1
10
10
  platform: ruby
11
11
  authors:
12
12
  - Andrew Grim
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-05-17 00:00:00 -07:00
17
+ date: 2010-05-20 00:00:00 -07:00
18
18
  default_executable:
19
19
  dependencies: []
20
20
 
@@ -54,7 +54,9 @@ files:
54
54
  - test/functional/image_identifier_test.rb
55
55
  - test/functional/result_test.rb
56
56
  - test/functional/squeeze_test.rb
57
+ - test/functional/utils_test.rb
57
58
  - test/test_helper.rb
59
+ - test/tmp/already_optimized_gif.gif20100520-30783-189g816
58
60
  - CONTRIBUTORS
59
61
  - LICENSE
60
62
  - Rakefile