has_image 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,21 +1,21 @@
1
1
  require 'mini_magick'
2
2
 
3
3
  module HasImage
4
-
4
+
5
5
  # Image processing functionality for the HasImage gem.
6
6
  class Processor
7
-
7
+
8
8
  attr_accessor :options
9
-
9
+
10
10
  class << self
11
-
11
+
12
12
  # The form of an {extended geometry string}[http://www.imagemagick.org/script/command-line-options.php?#resize] is:
13
13
  #
14
14
  # <width>x<height>{+-}<xoffset>{+-}<yoffset>{%}{!}{<}{>}
15
15
  def geometry_string_valid?(string)
16
- string =~ /\A[\d]*x[\d]*([+-][0-9][+-][0-9])?[%@!<>^]?\Z/
16
+ string.nil? || string =~ /\A[\d]*x[\d]*([+-][0-9][+-][0-9])?[%@!<>^]?\z/
17
17
  end
18
-
18
+
19
19
  # Arg should be either a file or a path. This runs ImageMagick's
20
20
  # "identify" command and looks for an exit status indicating an error.
21
21
  # If there is no error, then ImageMagick has identified the file as
@@ -34,22 +34,22 @@ module HasImage
34
34
  $? == 0
35
35
  end
36
36
  end
37
-
37
+
38
38
  end
39
39
 
40
40
  # The constuctor should be invoked with the options set by has_image.
41
41
  def initialize(options) # :nodoc:
42
42
  @options = options
43
43
  end
44
-
44
+
45
45
  # Creates the resized image, and transforms it to the desired output
46
- # format if necessary.
47
- #
46
+ # format if necessary.
47
+ #
48
48
  # +size+ should be a valid ImageMagick {geometry string}[http://www.imagemagick.org/script/command-line-options.php#resize].
49
49
  # +format+ should be an image format supported by ImageMagick, e.g. "PNG", "JPEG"
50
50
  # If a block is given, it yields the processed image file as a file-like object using IO#read.
51
51
  def process(file, size = options[:resize_to], format = options[:convert_to])
52
- unless size.blank? || Processor.geometry_string_valid?(size)
52
+ unless Processor.geometry_string_valid?(size)
53
53
  raise InvalidGeometryError.new('"%s" is not a valid ImageMagick geometry string' % size)
54
54
  end
55
55
  with_image(file) do |image|
@@ -60,12 +60,12 @@ module HasImage
60
60
  end
61
61
  end
62
62
  alias_method :resize, :process #Backwards-compat
63
-
63
+
64
64
  # Gets the given +dimension+ (width/height) from the image file at +path+.
65
65
  def measure(path, dimension)
66
66
  MiniMagick::Image.from_file(path)[dimension.to_sym]
67
67
  end
68
-
68
+
69
69
  private
70
70
  # Operates on the image with MiniMagick. Yields a MiniMagick::Image object.
71
71
  def with_image(file)
@@ -75,14 +75,14 @@ module HasImage
75
75
  begin
76
76
  image = MiniMagick::Image.from_file(path)
77
77
  yield image
78
- rescue MiniMagick::MiniMagickError
78
+ rescue MiniMagick::Invalid
79
79
  raise ProcessorError.new("#{path} doesn't look like an image file.")
80
80
  ensure
81
81
  image.tempfile.close! if defined?(image) && image
82
82
  end
83
83
  end
84
84
  end
85
-
85
+
86
86
  # Image resizing is placed in a separate method for easy monkey-patching.
87
87
  # This is intended to be invoked from resize, rather than directly.
88
88
  # By default, the following ImageMagick functionality is invoked:
@@ -114,7 +114,6 @@ module HasImage
114
114
  def convert_image(image, format=options[:convert_to])
115
115
  image.format(format) unless image[:format] == format
116
116
  end
117
-
118
- end
119
117
 
120
- end
118
+ end
119
+ end
@@ -0,0 +1,7 @@
1
+ module FriendlyId
2
+ class Railtie < Rails::Railtie
3
+ initializer "has_image.configure_rails_initialization" do |app|
4
+ HasImage.enable
5
+ end
6
+ end
7
+ end
@@ -1,23 +1,23 @@
1
- require 'active_support'
1
+ require 'cgi'
2
2
  require 'stringio'
3
3
  require 'fileutils'
4
4
  require 'zlib'
5
5
 
6
- module HasImage
7
-
6
+ module HasImage
7
+
8
8
  # Filesystem storage for the HasImage gem. The methods that HasImage inserts
9
9
  # into ActiveRecord models only depend on the public methods in this class,
10
10
  # so it should be reasonably straightforward to implement a different
11
11
  # storage mechanism for Amazon AWS, Photobucket, DBFile, SFTP, or whatever
12
- # you want.
12
+ # you want.
13
13
  class Storage
14
14
  class_inheritable_accessor :thumbnail_separator
15
15
  write_inheritable_attribute :thumbnail_separator, '_'
16
-
16
+
17
17
  attr_accessor :image_data, :options, :temp_file
18
18
 
19
19
  class << self
20
-
20
+
21
21
  # {Jamis Buck's well known
22
22
  # solution}[http://www.37signals.com/svn/archives2/id_partitioning.php]
23
23
  # to this problem fails with high ids, such as those created by
@@ -29,17 +29,17 @@ module HasImage
29
29
  def partitioned_path(id, *args)
30
30
  ["%04d" % ((id.to_i / 1e4) % 1e4), "%04d" % (id.to_i % 1e4)].concat(args)
31
31
  end
32
-
32
+
33
33
  def id_from_partitioned_path(partitioned_path)
34
34
  partitioned_path.join.to_i
35
35
  end
36
-
36
+
37
37
  def id_from_path(path)
38
38
  path = path.split('/') if path.is_a?(String)
39
39
  path_partitions = 2
40
40
  id_from_partitioned_path(path.first(path_partitions))
41
41
  end
42
-
42
+
43
43
  # By default, simply accepts and returns the id of the object. This is
44
44
  # here to allow you to monkey patch this method, for example, if you
45
45
  # wish instead to generate and return a UUID.
@@ -72,13 +72,13 @@ module HasImage
72
72
  @temp_file.open if @temp_file.closed?
73
73
  @temp_file.size < options[:min_size]
74
74
  end
75
-
75
+
76
76
  # Is uploaded file larger than the allowed maximum?
77
77
  def image_too_big?
78
78
  @temp_file.open if @temp_file.closed?
79
79
  @temp_file.size > options[:max_size]
80
80
  end
81
-
81
+
82
82
  # Invokes the processor to resize the image(s) and the installs them to
83
83
  # the appropriate directory.
84
84
  def install_images(object)
@@ -86,16 +86,16 @@ module HasImage
86
86
  install_main_image(object.has_image_id, generated_name)
87
87
  generate_thumbnails(object.has_image_id, generated_name) if thumbnails_needed?
88
88
  return generated_name
89
- ensure
89
+ ensure
90
90
  @temp_file.close! if !@temp_file.closed?
91
91
  @temp_file = nil
92
92
  end
93
-
93
+
94
94
  # Measures the given dimension using the processor
95
95
  def measure(path, dimension)
96
96
  processor.measure(path, dimension)
97
97
  end
98
-
98
+
99
99
  # Gets the "web" path for an image. For example:
100
100
  #
101
101
  # /photos/0000/0001/3er0zs.jpg
@@ -103,24 +103,24 @@ module HasImage
103
103
  webpath = filesystem_path_for(object, thumbnail).gsub(/\A.*public/, '')
104
104
  escape_file_name_for_http(webpath)
105
105
  end
106
-
106
+
107
107
  def escape_file_name_for_http(webpath)
108
108
  dir, file = File.split(webpath)
109
109
  File.join(dir, CGI.escape(file))
110
110
  end
111
-
111
+
112
112
  # Deletes the images and directory that contains them.
113
113
  def remove_images(object, name)
114
114
  FileUtils.rm Dir.glob(File.join(path_for(object.has_image_id), name + '*'))
115
115
  Dir.rmdir path_for(object.has_image_id)
116
- rescue SystemCallError
116
+ rescue SystemCallError
117
117
  end
118
118
 
119
119
  # Is the uploaded file within the min and max allowed sizes?
120
120
  def valid?
121
121
  !(image_too_small? || image_too_big?)
122
122
  end
123
-
123
+
124
124
  # Write the thumbnails to the install directory - probably somewhere under
125
125
  # RAILS_ROOT/public.
126
126
  def generate_thumbnails(id, name)
@@ -128,7 +128,7 @@ module HasImage
128
128
  options[:thumbnails].keys.each { |thumb_name| generate_thumbnail(id, name, thumb_name) }
129
129
  end
130
130
  alias_method :regenerate_thumbnails, :generate_thumbnails #Backwards-compat
131
-
131
+
132
132
  def generate_thumbnail(id, name, thumb_name)
133
133
  size_spec = options[:thumbnails][thumb_name.to_sym]
134
134
  raise StorageError unless size_spec
@@ -139,23 +139,23 @@ module HasImage
139
139
  end
140
140
  end
141
141
  end
142
-
142
+
143
143
  # Gets the full local filesystem path for an image. For example:
144
144
  #
145
145
  # /var/sites/example.com/production/public/photos/0000/0001/3er0zs.jpg
146
146
  def filesystem_path_for(object, thumbnail = nil)
147
147
  File.join(path_for(object.has_image_id), file_name_for(object.send(options[:column]), thumbnail))
148
148
  end
149
-
149
+
150
150
  protected
151
151
 
152
152
  # Gets the extension to append to the image. Transforms "jpeg" to "jpg."
153
153
  def extension
154
154
  options[:convert_to].to_s.downcase.gsub("jpeg", "jpg")
155
155
  end
156
-
156
+
157
157
  private
158
-
158
+
159
159
  # File name, plus thumbnail suffix, plus extension. For example:
160
160
  #
161
161
  # file_name_for("abc123", :thumb)
@@ -163,7 +163,7 @@ module HasImage
163
163
  # gives you:
164
164
  #
165
165
  # "abc123_thumb.jpg"
166
- #
166
+ #
167
167
  # It uses an underscore to separatore parts by default, but that is configurable
168
168
  # by setting HasImage::Storage.thumbnail_separator
169
169
  def file_name_for(*args)
@@ -177,15 +177,15 @@ module HasImage
177
177
  debugger if $debug
178
178
  File.join(options[:base_path], options[:path_prefix], Storage.partitioned_path(id))
179
179
  end
180
-
180
+
181
181
  def absolute_path(id, *args)
182
182
  File.join(path_for(id), file_name_for(*args))
183
183
  end
184
-
184
+
185
185
  def ensure_directory_exists!(id)
186
186
  FileUtils.mkdir_p path_for(id)
187
187
  end
188
-
188
+
189
189
  # Write the main image to the install directory - probably somewhere under
190
190
  # RAILS_ROOT/public.
191
191
  def install_main_image(id, name)
@@ -196,12 +196,12 @@ module HasImage
196
196
  end
197
197
  end
198
198
  end
199
-
199
+
200
200
  # used in #install_images
201
201
  def thumbnails_needed?
202
202
  !options[:thumbnails].empty? && options[:auto_generate_thumbnails]
203
203
  end
204
-
204
+
205
205
  # Instantiates the processor using the options set in my contructor (if
206
206
  # not already instantiated), stores it in an instance variable, and
207
207
  # returns it.
@@ -209,5 +209,5 @@ module HasImage
209
209
  @processor ||= Processor.new(options)
210
210
  end
211
211
  end
212
-
213
- end
212
+
213
+ end
@@ -0,0 +1,3 @@
1
+ module HasImage
2
+ VERSION = "0.4.0"
3
+ end
@@ -1,9 +1,8 @@
1
1
  module HasImage
2
-
3
2
  # Some helpers to make working with HasImage models in views a little
4
3
  # easier.
5
4
  module ViewHelpers
6
-
5
+
7
6
  # Wraps the image_tag helper from Rails. Instead of passing the path to
8
7
  # an image, you can pass any object that uses HasImage. The options can
9
8
  # include the name of one of your thumbnails, for example:
@@ -23,7 +22,7 @@ module HasImage
23
22
  def image_tag_for(object, options = {})
24
23
  thumb = options.delete(:thumb)
25
24
  if !options[:size]
26
- if thumb
25
+ if thumb
27
26
  size = object.class.thumbnails[thumb.to_sym]
28
27
  options[:size] = size if size =~ /\A[\d]*x[\d]*\Z/
29
28
  else
@@ -31,9 +30,7 @@ module HasImage
31
30
  options[:size] = size if size =~ /\A[\d]*x[\d]*\Z/
32
31
  end
33
32
  end
34
- image_tag(object.public_path(thumb), options)
33
+ image_tag(object.public_path(thumb), options)
35
34
  end
36
-
37
35
  end
38
-
39
36
  end
@@ -1,4 +1,4 @@
1
- require 'test_helper'
1
+ require File.expand_path('../test_helper', __FILE__)
2
2
 
3
3
  class ComplexPic < ActiveRecord::Base
4
4
  has_image
@@ -12,11 +12,11 @@ class ComplexPicTest < Test::Unit::TestCase
12
12
  ComplexPic.has_image_options[:base_path] = File.join(RAILS_ROOT, 'tmp')
13
13
  ComplexPic.has_image_options[:resize_to] = nil
14
14
  end
15
-
15
+
16
16
  def teardown
17
17
  FileUtils.rm_rf(File.join(RAILS_ROOT, 'tmp', 'complex_pics'))
18
18
  end
19
-
19
+
20
20
  def test_should_save_width_to_db_on_create
21
21
  @pic = ComplexPic.create!(:image_data => fixture_file_upload("/image.jpg", "image/jpeg"))
22
22
  assert_equal 1916, @pic[:width]
@@ -26,7 +26,12 @@ class ComplexPicTest < Test::Unit::TestCase
26
26
  @pic = ComplexPic.create!(:image_data => fixture_file_upload("/image.jpg", "image/jpeg"))
27
27
  assert_equal 1990, @pic[:height]
28
28
  end
29
-
29
+
30
+ def test_should_save_image_size_to_db_on_create
31
+ @pic = ComplexPic.create!(:image_data => fixture_file_upload("/image.jpg", "image/jpeg"))
32
+ assert_equal '1916x1990', @pic[:image_size]
33
+ end
34
+
30
35
  def test_should_use_value_from_db_in_height_reader
31
36
  @pic = ComplexPic.create!(:image_data => fixture_file_upload("/image.jpg", "image/jpeg"))
32
37
  @pic[:height] = 60_000
@@ -38,5 +43,5 @@ class ComplexPicTest < Test::Unit::TestCase
38
43
  @pic[:width] = 60_000
39
44
  assert_equal 60_000, @pic.width
40
45
  end
41
-
46
+
42
47
  end
File without changes
File without changes
File without changes
@@ -1,4 +1,4 @@
1
- require 'test_helper'
1
+ require File.expand_path('../test_helper', __FILE__)
2
2
 
3
3
  class Pic < ActiveRecord::Base
4
4
  has_image
@@ -9,6 +9,7 @@ class PicWithDifferentTableName < ActiveRecord::Base
9
9
  end
10
10
 
11
11
  class PicTest < Test::Unit::TestCase
12
+
12
13
  def setup
13
14
  # Note: Be sure to not set the whole options hash in your tests below
14
15
  Pic.has_image_options = HasImage.default_options_for(Pic)
@@ -81,7 +82,7 @@ class PicTest < Test::Unit::TestCase
81
82
 
82
83
  def test_regenerate_thumbnails_succeeds
83
84
  Pic.has_image_options[:thumbnails] = {:small => "100x100", :tiny => "16x16"}
84
-
85
+
85
86
  @pic = Pic.new(:image_data => fixture_file_upload("/image.jpg", "image/jpeg"))
86
87
  @pic.save!
87
88
  assert @pic.regenerate_thumbnails
@@ -150,4 +151,4 @@ class PicTest < Test::Unit::TestCase
150
151
  assert_equal 1990, pic.height
151
152
  end
152
153
 
153
- end
154
+ end
@@ -1,20 +1,20 @@
1
- require File.dirname(__FILE__) + '/test_helper.rb'
1
+ require File.expand_path('../test_helper.rb', __FILE__)
2
2
 
3
3
  class StorageTest < Test::Unit::TestCase
4
-
4
+
5
5
  def teardown
6
6
  @temp_file.close if @temp_file
7
7
  FileUtils.rm_rf(File.dirname(__FILE__) + '/../tmp')
8
8
  end
9
-
9
+
10
10
  def temp_file(fixture)
11
11
  @temp_file = Tempfile.new('test')
12
- @temp_file.write(File.new(File.dirname(__FILE__) + "/../test_rails/fixtures/#{fixture}", "r").read)
12
+ @temp_file.write(File.new(File.expand_path("../fixtures/#{fixture}", __FILE__), "r").read)
13
13
  return @temp_file
14
14
  end
15
-
15
+
16
16
  def test_detect_valid_image
17
- assert HasImage::Processor.valid?(File.dirname(__FILE__) + "/../test_rails/fixtures/image.jpg")
17
+ assert HasImage::Processor.valid?(File.expand_path("../fixtures/image.jpg", __FILE__))
18
18
  end
19
19
 
20
20
  def test_detect_valid_image_from_tmp_file
@@ -22,7 +22,7 @@ class StorageTest < Test::Unit::TestCase
22
22
  end
23
23
 
24
24
  def test_detect_invalid_image
25
- assert !HasImage::Processor.valid?(File.dirname(__FILE__) + "/../test_rails/fixtures/bad_image.jpg")
25
+ assert !HasImage::Processor.valid?(File.expand_path("../fixtures/bad_image.jpg", __FILE__))
26
26
  end
27
27
 
28
28
  def test_detect_invalid_image_from_tmp_file
@@ -35,7 +35,7 @@ class StorageTest < Test::Unit::TestCase
35
35
  @processor.resize(temp_file("image.jpg"), "bad_geometry")
36
36
  end
37
37
  end
38
-
38
+
39
39
  def test_resize_fixed
40
40
  @processor = HasImage::Processor.new({:convert_to => "JPEG", :output_quality => "85"})
41
41
  assert @processor.resize(temp_file("image.jpg"), "100x100")
@@ -57,5 +57,4 @@ class StorageTest < Test::Unit::TestCase
57
57
  @processor.resize(temp_file("bad_image.jpg"), "100x100")
58
58
  end
59
59
  end
60
-
61
- end
60
+ end