has_image 0.3.0 → 0.4.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.
@@ -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