image_squeeze 0.1.0 → 0.1.1

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.
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