has_image 0.2.3 → 0.3.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.
- data/CHANGELOG +12 -0
- data/README.textile +193 -0
- data/Rakefile +3 -1
- data/init.rb +1 -1
- data/lib/has_image.rb +152 -104
- data/lib/has_image/processor.rb +58 -31
- data/lib/has_image/storage.rb +72 -45
- data/test/storage_test.rb +44 -2
- data/test_rails/complex_pic_test.rb +42 -0
- data/test_rails/pic_test.rb +72 -9
- data/test_rails/schema.rb +7 -1
- data/test_rails/test_helper.rb +1 -3
- metadata +6 -9
- data/README +0 -161
- data/test_rails/pic.rb +0 -3
data/lib/has_image/processor.rb
CHANGED
@@ -9,24 +9,32 @@ module HasImage
|
|
9
9
|
|
10
10
|
class << self
|
11
11
|
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
12
|
+
# The form of an {extended geometry string}[http://www.imagemagick.org/script/command-line-options.php?#resize] is:
|
13
|
+
#
|
14
|
+
# <width>x<height>{+-}<xoffset>{+-}<yoffset>{%}{!}{<}{>}
|
15
15
|
def geometry_string_valid?(string)
|
16
16
|
string =~ /\A[\d]*x[\d]*([+-][0-9][+-][0-9])?[%@!<>^]?\Z/
|
17
17
|
end
|
18
18
|
|
19
|
-
# Arg should be either a file
|
20
|
-
# "identify" command and looks for an exit status indicating an error.
|
21
|
-
# there is no error, then ImageMagick has identified the file as
|
22
|
-
# it can work with and it will be converted to the desired
|
19
|
+
# Arg should be either a file or a path. This runs ImageMagick's
|
20
|
+
# "identify" command and looks for an exit status indicating an error.
|
21
|
+
# If there is no error, then ImageMagick has identified the file as
|
22
|
+
# something it can work with and it will be converted to the desired
|
23
|
+
# output format.
|
24
|
+
#
|
25
|
+
# Note that this is used in place of any mimetype checks. HasImage
|
26
|
+
# assumes that is ImageMagick is able to process the file, then it's OK.
|
27
|
+
# Since ImageMagick can be compiled with many different options for
|
28
|
+
# supporting various file types (or not) this is safer and more complete
|
29
|
+
# than checking the mime type.
|
23
30
|
def valid?(arg)
|
24
31
|
arg.close if arg.respond_to?(:close) && !arg.closed?
|
25
32
|
silence_stderr do
|
26
33
|
`identify #{arg.respond_to?(:path) ? arg.path : arg.to_s}`
|
27
34
|
$? == 0
|
28
35
|
end
|
29
|
-
end
|
36
|
+
end
|
37
|
+
|
30
38
|
end
|
31
39
|
|
32
40
|
# The constuctor should be invoked with the options set by has_image.
|
@@ -34,25 +42,47 @@ module HasImage
|
|
34
42
|
@options = options
|
35
43
|
end
|
36
44
|
|
37
|
-
#
|
38
|
-
# format if necessary.
|
39
|
-
#
|
40
|
-
|
41
|
-
|
45
|
+
# Creates the resized image, and transforms it to the desired output
|
46
|
+
# format if necessary.
|
47
|
+
#
|
48
|
+
# +size+ should be a valid ImageMagick {geometry string}[http://www.imagemagick.org/script/command-line-options.php#resize].
|
49
|
+
# +format+ should be an image format supported by ImageMagick, e.g. "PNG", "JPEG"
|
50
|
+
# If a block is given, it yields the processed image file as a file-like object using IO#read.
|
51
|
+
def process(file, size = options[:resize_to], format = options[:convert_to])
|
52
|
+
unless size.blank? || Processor.geometry_string_valid?(size)
|
42
53
|
raise InvalidGeometryError.new('"%s" is not a valid ImageMagick geometry string' % size)
|
43
54
|
end
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
resize_image(size)
|
50
|
-
return @image
|
55
|
+
with_image(file) do |image|
|
56
|
+
convert_image(image, format) if format
|
57
|
+
resize_image(image, size) if size
|
58
|
+
yield IO.read(image.path) if block_given?
|
59
|
+
image
|
51
60
|
end
|
52
|
-
rescue MiniMagick::MiniMagickError
|
53
|
-
raise ProcessorError.new("That doesn't look like an image file.")
|
54
61
|
end
|
62
|
+
alias_method :resize, :process #Backwards-compat
|
55
63
|
|
64
|
+
# Gets the given +dimension+ (width/height) from the image file at +path+.
|
65
|
+
def measure(path, dimension)
|
66
|
+
MiniMagick::Image.from_file(path)[dimension.to_sym]
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
# Operates on the image with MiniMagick. Yields a MiniMagick::Image object.
|
71
|
+
def with_image(file)
|
72
|
+
path = file.respond_to?(:path) ? file.path : file
|
73
|
+
file.close if file.respond_to?(:close) && !file.closed?
|
74
|
+
silence_stderr do
|
75
|
+
begin
|
76
|
+
image = MiniMagick::Image.from_file(path)
|
77
|
+
yield image
|
78
|
+
rescue MiniMagick::MiniMagickError
|
79
|
+
raise ProcessorError.new("#{path} doesn't look like an image file.")
|
80
|
+
ensure
|
81
|
+
image.tempfile.close! if defined?(image) && image
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
56
86
|
# Image resizing is placed in a separate method for easy monkey-patching.
|
57
87
|
# This is intended to be invoked from resize, rather than directly.
|
58
88
|
# By default, the following ImageMagick functionality is invoked:
|
@@ -62,8 +92,10 @@ module HasImage
|
|
62
92
|
# * gravity[http://www.imagemagick.org/script/command-line-options.php#gravity]
|
63
93
|
# * extent[http://www.imagemagick.org/script/command-line-options.php#extent]
|
64
94
|
# * quality[http://www.imagemagick.org/script/command-line-options.php#quality]
|
65
|
-
|
66
|
-
|
95
|
+
#
|
96
|
+
# +image+ should be a MiniMagick::Image. +size+ should be a geometry string.
|
97
|
+
def resize_image(image, size)
|
98
|
+
image.combine_options do |commands|
|
67
99
|
commands.send("auto-orient".to_sym)
|
68
100
|
commands.strip
|
69
101
|
# Fixed-dimension images
|
@@ -79,13 +111,8 @@ module HasImage
|
|
79
111
|
end
|
80
112
|
end
|
81
113
|
|
82
|
-
|
83
|
-
|
84
|
-
# This was placed in a separate method largely to facilitate debugging
|
85
|
-
# and profiling.
|
86
|
-
def convert_image
|
87
|
-
return if @image[:format] == options[:convert_to]
|
88
|
-
@image.format(options[:convert_to])
|
114
|
+
def convert_image(image, format=options[:convert_to])
|
115
|
+
image.format(format) unless image[:format] == format
|
89
116
|
end
|
90
117
|
|
91
118
|
end
|
data/lib/has_image/storage.rb
CHANGED
@@ -11,6 +11,8 @@ module HasImage
|
|
11
11
|
# storage mechanism for Amazon AWS, Photobucket, DBFile, SFTP, or whatever
|
12
12
|
# you want.
|
13
13
|
class Storage
|
14
|
+
class_inheritable_accessor :thumbnail_separator
|
15
|
+
write_inheritable_attribute :thumbnail_separator, '_'
|
14
16
|
|
15
17
|
attr_accessor :image_data, :options, :temp_file
|
16
18
|
|
@@ -21,17 +23,29 @@ module HasImage
|
|
21
23
|
# to this problem fails with high ids, such as those created by
|
22
24
|
# db:fixture:load. This version scales to large ids more gracefully.
|
23
25
|
# Thanks to Adrian Mugnolo for the fix.
|
26
|
+
#++
|
27
|
+
# FIXME: collides with IDs with more than 8 digits
|
28
|
+
#--
|
24
29
|
def partitioned_path(id, *args)
|
25
30
|
["%04d" % ((id.to_i / 1e4) % 1e4), "%04d" % (id.to_i % 1e4)].concat(args)
|
26
31
|
end
|
27
|
-
|
32
|
+
|
33
|
+
def id_from_partitioned_path(partitioned_path)
|
34
|
+
partitioned_path.join.to_i
|
35
|
+
end
|
36
|
+
|
37
|
+
def id_from_path(path)
|
38
|
+
path = path.split('/') if path.is_a?(String)
|
39
|
+
path_partitions = 2
|
40
|
+
id_from_partitioned_path(path.first(path_partitions))
|
41
|
+
end
|
42
|
+
|
28
43
|
# By default, simply accepts and returns the id of the object. This is
|
29
44
|
# here to allow you to monkey patch this method, for example, if you
|
30
45
|
# wish instead to generate and return a UUID.
|
31
46
|
def generated_file_name(*args)
|
32
47
|
return args.first.to_param.to_s
|
33
48
|
end
|
34
|
-
|
35
49
|
end
|
36
50
|
|
37
51
|
# The constuctor should be invoked with the options set by has_image.
|
@@ -49,7 +63,7 @@ module HasImage
|
|
49
63
|
else
|
50
64
|
image_data.rewind
|
51
65
|
@temp_file = Tempfile.new 'has_image_data_%s' % Storage.generated_file_name
|
52
|
-
@temp_file.write(image_data.read)
|
66
|
+
@temp_file.write(image_data.read)
|
53
67
|
end
|
54
68
|
end
|
55
69
|
|
@@ -65,24 +79,23 @@ module HasImage
|
|
65
79
|
@temp_file.size > options[:max_size]
|
66
80
|
end
|
67
81
|
|
68
|
-
# A tip of the hat to attachment_fu.
|
69
|
-
alias uploaded_data= image_data=
|
70
|
-
|
71
|
-
# A tip of the hat to attachment_fu.
|
72
|
-
alias uploaded_data image_data
|
73
|
-
|
74
82
|
# Invokes the processor to resize the image(s) and the installs them to
|
75
83
|
# the appropriate directory.
|
76
84
|
def install_images(object)
|
77
85
|
generated_name = Storage.generated_file_name(object)
|
78
86
|
install_main_image(object.has_image_id, generated_name)
|
79
|
-
|
87
|
+
generate_thumbnails(object.has_image_id, generated_name) if thumbnails_needed?
|
80
88
|
return generated_name
|
81
89
|
ensure
|
82
90
|
@temp_file.close! if !@temp_file.closed?
|
83
91
|
@temp_file = nil
|
84
92
|
end
|
85
93
|
|
94
|
+
# Measures the given dimension using the processor
|
95
|
+
def measure(path, dimension)
|
96
|
+
processor.measure(path, dimension)
|
97
|
+
end
|
98
|
+
|
86
99
|
# Gets the "web" path for an image. For example:
|
87
100
|
#
|
88
101
|
# /photos/0000/0001/3er0zs.jpg
|
@@ -108,10 +121,32 @@ module HasImage
|
|
108
121
|
!(image_too_small? || image_too_big?)
|
109
122
|
end
|
110
123
|
|
111
|
-
|
112
|
-
|
124
|
+
# Write the thumbnails to the install directory - probably somewhere under
|
125
|
+
# RAILS_ROOT/public.
|
126
|
+
def generate_thumbnails(id, name)
|
127
|
+
ensure_directory_exists!(id)
|
128
|
+
options[:thumbnails].keys.each { |thumb_name| generate_thumbnail(id, name, thumb_name) }
|
129
|
+
end
|
130
|
+
alias_method :regenerate_thumbnails, :generate_thumbnails #Backwards-compat
|
131
|
+
|
132
|
+
def generate_thumbnail(id, name, thumb_name)
|
133
|
+
size_spec = options[:thumbnails][thumb_name.to_sym]
|
134
|
+
raise StorageError unless size_spec
|
135
|
+
ensure_directory_exists!(id)
|
136
|
+
File.open absolute_path(id, name, thumb_name), "w" do |thumbnail_destination|
|
137
|
+
processor.process absolute_path(id, name), size_spec do |thumbnail_data|
|
138
|
+
thumbnail_destination.write thumbnail_data
|
139
|
+
end
|
140
|
+
end
|
113
141
|
end
|
114
|
-
|
142
|
+
|
143
|
+
# Gets the full local filesystem path for an image. For example:
|
144
|
+
#
|
145
|
+
# /var/sites/example.com/production/public/photos/0000/0001/3er0zs.jpg
|
146
|
+
def filesystem_path_for(object, thumbnail = nil)
|
147
|
+
File.join(path_for(object.has_image_id), file_name_for(object.send(options[:column]), thumbnail))
|
148
|
+
end
|
149
|
+
|
115
150
|
protected
|
116
151
|
|
117
152
|
# Gets the extension to append to the image. Transforms "jpeg" to "jpg."
|
@@ -129,49 +164,42 @@ module HasImage
|
|
129
164
|
#
|
130
165
|
# "abc123_thumb.jpg"
|
131
166
|
#
|
132
|
-
#
|
167
|
+
# It uses an underscore to separatore parts by default, but that is configurable
|
168
|
+
# by setting HasImage::Storage.thumbnail_separator
|
133
169
|
def file_name_for(*args)
|
134
|
-
"%s.%s" % [args.compact.join(
|
170
|
+
"%s.%s" % [args.compact.join(self.class.thumbnail_separator), extension]
|
135
171
|
end
|
136
172
|
|
137
|
-
#
|
173
|
+
# Get the full path for the id. For example:
|
138
174
|
#
|
139
|
-
#
|
140
|
-
def
|
141
|
-
|
175
|
+
# /var/sites/example.org/production/public/photos/0000/0001
|
176
|
+
def path_for(id)
|
177
|
+
debugger if $debug
|
178
|
+
File.join(options[:base_path], options[:path_prefix], Storage.partitioned_path(id))
|
142
179
|
end
|
143
180
|
|
144
|
-
|
145
|
-
|
146
|
-
|
181
|
+
def absolute_path(id, *args)
|
182
|
+
File.join(path_for(id), file_name_for(*args))
|
183
|
+
end
|
184
|
+
|
185
|
+
def ensure_directory_exists!(id)
|
147
186
|
FileUtils.mkdir_p path_for(id)
|
148
|
-
main = processor.resize(@temp_file, @options[:resize_to])
|
149
|
-
file = File.open(File.join(path_for(id), file_name_for(name)), "w")
|
150
|
-
file.write(IO.read(main.path))
|
151
|
-
file.close
|
152
|
-
main.tempfile.close!
|
153
187
|
end
|
154
188
|
|
155
|
-
# Write the
|
189
|
+
# Write the main image to the install directory - probably somewhere under
|
156
190
|
# RAILS_ROOT/public.
|
157
|
-
def
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
file = File.open(File.join(path_for(id), file_name_for(name, thumb_name)), "w")
|
164
|
-
file.write(IO.read(thumb.tempfile.path))
|
165
|
-
file.close
|
166
|
-
thumb.tempfile.close!
|
191
|
+
def install_main_image(id, name)
|
192
|
+
ensure_directory_exists!(id)
|
193
|
+
File.open absolute_path(id, name), "w" do |final_destination|
|
194
|
+
processor.process(@temp_file) do |processed_image|
|
195
|
+
final_destination.write processed_image
|
196
|
+
end
|
167
197
|
end
|
168
198
|
end
|
169
|
-
|
170
|
-
#
|
171
|
-
|
172
|
-
|
173
|
-
def path_for(id)
|
174
|
-
File.join(options[:base_path], options[:path_prefix], Storage.partitioned_path(id))
|
199
|
+
|
200
|
+
# used in #install_images
|
201
|
+
def thumbnails_needed?
|
202
|
+
!options[:thumbnails].empty? && options[:auto_generate_thumbnails]
|
175
203
|
end
|
176
204
|
|
177
205
|
# Instantiates the processor using the options set in my contructor (if
|
@@ -180,7 +208,6 @@ module HasImage
|
|
180
208
|
def processor
|
181
209
|
@processor ||= Processor.new(options)
|
182
210
|
end
|
183
|
-
|
184
211
|
end
|
185
212
|
|
186
213
|
end
|
data/test/storage_test.rb
CHANGED
@@ -11,7 +11,9 @@ class StorageTest < Test::Unit::TestCase
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def default_options
|
14
|
-
|
14
|
+
mock_class = "test"
|
15
|
+
mock_class.stubs(:table_name).returns('tests')
|
16
|
+
HasImage.default_options_for(mock_class).merge(
|
15
17
|
:base_path => File.join(File.dirname(__FILE__), '..', 'tmp')
|
16
18
|
)
|
17
19
|
end
|
@@ -23,6 +25,25 @@ class StorageTest < Test::Unit::TestCase
|
|
23
25
|
def test_partitioned_path_doesnt_collide_with_high_ids
|
24
26
|
assert_not_equal HasImage::Storage.partitioned_path(867792732),
|
25
27
|
HasImage::Storage.partitioned_path(867792731)
|
28
|
+
# FIXME: collisions when IDs have more than 8 digits
|
29
|
+
# assert_not_equal HasImage::Storage.partitioned_path(967792731),
|
30
|
+
# HasImage::Storage.partitioned_path(967792731)
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_id_from_partitioned_path
|
34
|
+
assert_equal 123, HasImage::Storage.id_from_partitioned_path(HasImage::Storage.partitioned_path(123))
|
35
|
+
assert_equal 56, HasImage::Storage.id_from_partitioned_path(HasImage::Storage.partitioned_path(56))
|
36
|
+
assert_equal 67792732, HasImage::Storage.id_from_partitioned_path(HasImage::Storage.partitioned_path(67792732))
|
37
|
+
# FIXME: for IDs with more than 8 digits partitioned path is destructive
|
38
|
+
# assert_equal 867792731, HasImage::Storage.id_from_partitioned_path(HasImage::Storage.partitioned_path(867792731))
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_id_from_path_accepts_array
|
42
|
+
assert_equal 123, HasImage::Storage.id_from_path(['0000','0123','image_something.jpg'])
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_id_from_path_accepts_path
|
46
|
+
assert_equal 12345, HasImage::Storage.id_from_path('0001/2345/0123/image_something.jpg')
|
26
47
|
end
|
27
48
|
|
28
49
|
def test_generated_file_name
|
@@ -45,6 +66,17 @@ class StorageTest < Test::Unit::TestCase
|
|
45
66
|
pic = stub(:has_image_file => "my+pic", :has_image_id => 1)
|
46
67
|
assert_equal "/tests/0000/0001/my%2Bpic_square.jpg", @storage.public_path_for(pic, :square)
|
47
68
|
end
|
69
|
+
|
70
|
+
def test_name_generation_takes_into_account_thumbnail_separator_constant
|
71
|
+
old_separator = HasImage::Storage.thumbnail_separator
|
72
|
+
|
73
|
+
@storage = HasImage::Storage.new(default_options.merge(:thumbnails => {:schick => '22x22'}, :base_path => '/public'))
|
74
|
+
HasImage::Storage.thumbnail_separator = '.'
|
75
|
+
pic = stub(:has_image_file => "pic", :has_image_id => 1)
|
76
|
+
assert_equal "/tests/0000/0001/pic.schick.jpg", @storage.public_path_for(pic, :schick)
|
77
|
+
|
78
|
+
HasImage::Storage.thumbnail_separator = old_separator
|
79
|
+
end
|
48
80
|
|
49
81
|
def test_escape_file_name_for_http
|
50
82
|
@storage = HasImage::Storage.new(default_options.merge(:base_path => '/public'))
|
@@ -83,7 +115,17 @@ class StorageTest < Test::Unit::TestCase
|
|
83
115
|
:one => "100x100", :two => "200x200"}))
|
84
116
|
@storage.image_data = temp_file("image.jpg")
|
85
117
|
@name = @storage.install_images(stub(:has_image_id => 1))
|
86
|
-
assert @storage.remove_images(stub(:has_image_id => 1), @name)
|
118
|
+
assert @storage.remove_images(stub(:has_image_id => 1), @name)
|
119
|
+
end
|
120
|
+
|
121
|
+
def test_install_images_doesnt_automatically_generate_thumbnails_if_that_option_is_set
|
122
|
+
@storage = HasImage::Storage.new(default_options.merge(
|
123
|
+
:thumbnails => {:two => "200x200"},
|
124
|
+
:auto_generate_thumbnails => false
|
125
|
+
))
|
126
|
+
@storage.image_data = temp_file("image.jpg")
|
127
|
+
@storage.expects(:generate_thumbnails).never
|
128
|
+
@storage.install_images(stub(:has_image_id => 1))
|
87
129
|
end
|
88
130
|
|
89
131
|
def test_image_not_too_small
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class ComplexPic < ActiveRecord::Base
|
4
|
+
has_image
|
5
|
+
end
|
6
|
+
|
7
|
+
class ComplexPicTest < Test::Unit::TestCase
|
8
|
+
def setup
|
9
|
+
# Note: Be sure to not set the whole options hash in your tests below
|
10
|
+
ComplexPic.has_image_options = HasImage.default_options_for(ComplexPic)
|
11
|
+
ComplexPic.has_image_options[:column] = :filename
|
12
|
+
ComplexPic.has_image_options[:base_path] = File.join(RAILS_ROOT, 'tmp')
|
13
|
+
ComplexPic.has_image_options[:resize_to] = nil
|
14
|
+
end
|
15
|
+
|
16
|
+
def teardown
|
17
|
+
FileUtils.rm_rf(File.join(RAILS_ROOT, 'tmp', 'complex_pics'))
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_should_save_width_to_db_on_create
|
21
|
+
@pic = ComplexPic.create!(:image_data => fixture_file_upload("/image.jpg", "image/jpeg"))
|
22
|
+
assert_equal 1916, @pic[:width]
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_should_save_height_to_db_on_create
|
26
|
+
@pic = ComplexPic.create!(:image_data => fixture_file_upload("/image.jpg", "image/jpeg"))
|
27
|
+
assert_equal 1990, @pic[:height]
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_should_use_value_from_db_in_height_reader
|
31
|
+
@pic = ComplexPic.create!(:image_data => fixture_file_upload("/image.jpg", "image/jpeg"))
|
32
|
+
@pic[:height] = 60_000
|
33
|
+
assert_equal 60_000, @pic.height
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_should_use_value_from_db_in_width_reader
|
37
|
+
@pic = ComplexPic.create!(:image_data => fixture_file_upload("/image.jpg", "image/jpeg"))
|
38
|
+
@pic[:width] = 60_000
|
39
|
+
assert_equal 60_000, @pic.width
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
data/test_rails/pic_test.rb
CHANGED
@@ -1,16 +1,24 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
|
+
class Pic < ActiveRecord::Base
|
4
|
+
has_image
|
5
|
+
end
|
6
|
+
|
7
|
+
class PicWithDifferentTableName < ActiveRecord::Base
|
8
|
+
set_table_name 'pics'
|
9
|
+
end
|
10
|
+
|
3
11
|
class PicTest < Test::Unit::TestCase
|
4
|
-
|
5
12
|
def setup
|
13
|
+
# Note: Be sure to not set the whole options hash in your tests below
|
6
14
|
Pic.has_image_options = HasImage.default_options_for(Pic)
|
7
|
-
Pic.has_image_options[:base_path] = File.join(RAILS_ROOT, '
|
15
|
+
Pic.has_image_options[:base_path] = File.join(RAILS_ROOT, 'tmp')
|
8
16
|
end
|
9
|
-
|
17
|
+
|
10
18
|
def teardown
|
11
19
|
FileUtils.rm_rf(File.join(RAILS_ROOT, 'tmp', 'pics'))
|
12
20
|
end
|
13
|
-
|
21
|
+
|
14
22
|
def test_should_be_valid
|
15
23
|
@pic = Pic.new(:image_data => fixture_file_upload("/image.jpg", "image/jpeg"))
|
16
24
|
assert @pic.valid? , "#{@pic.errors.full_messages.to_sentence}"
|
@@ -47,14 +55,37 @@ class PicTest < Test::Unit::TestCase
|
|
47
55
|
assert @pic.save!
|
48
56
|
end
|
49
57
|
|
50
|
-
def
|
51
|
-
Pic.has_image_options = HasImage.default_options_for(Pic).merge(
|
52
|
-
:thumbnails => {:small => "100x100", :tiny => "16x16"})
|
58
|
+
def test_finding_from_url_path
|
53
59
|
@pic = Pic.new(:image_data => fixture_file_upload("/image.jpg", "image/jpeg"))
|
54
60
|
@pic.save!
|
55
|
-
|
61
|
+
path = HasImage::Storage.partitioned_path @pic.id
|
62
|
+
assert_equal @pic, Pic.from_partitioned_path(path)
|
56
63
|
end
|
57
64
|
|
65
|
+
def test_default_options_respect_table_name
|
66
|
+
assert_equal 'pics', HasImage.default_options_for(PicWithDifferentTableName)[:path_prefix]
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_generate_thumbnails_on_create
|
70
|
+
Pic.has_image_options[:thumbnails] = {:tiny => "16x16"}
|
71
|
+
@pic = Pic.create!(:image_data => fixture_file_upload("/image.jpg", "image/jpeg"))
|
72
|
+
assert File.exist?(@pic.absolute_path(:tiny))
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_doesnt_generate_thumbnails_if_option_disabled
|
76
|
+
Pic.has_image_options[:thumbnails] = {:tiny => "16x16"}
|
77
|
+
Pic.has_image_options[:auto_generate_thumbnails] = false
|
78
|
+
@pic = Pic.create!(:image_data => fixture_file_upload("/image.jpg", "image/jpeg"))
|
79
|
+
assert !File.exist?(@pic.absolute_path(:tiny))
|
80
|
+
end
|
81
|
+
|
82
|
+
def test_regenerate_thumbnails_succeeds
|
83
|
+
Pic.has_image_options[:thumbnails] = {:small => "100x100", :tiny => "16x16"}
|
84
|
+
|
85
|
+
@pic = Pic.new(:image_data => fixture_file_upload("/image.jpg", "image/jpeg"))
|
86
|
+
@pic.save!
|
87
|
+
assert @pic.regenerate_thumbnails
|
88
|
+
end
|
58
89
|
|
59
90
|
def test_create_model_without_setting_image_data
|
60
91
|
assert Pic.new.save!
|
@@ -66,6 +97,13 @@ class PicTest < Test::Unit::TestCase
|
|
66
97
|
assert @pic.destroy
|
67
98
|
end
|
68
99
|
|
100
|
+
def test_destroy_should_not_remove_image_file_if_option_is_set
|
101
|
+
Pic.has_image_options[:delete] = false
|
102
|
+
@pic = Pic.create!(:image_data => fixture_file_upload("/image.jpg", "image/jpeg"))
|
103
|
+
@pic.destroy
|
104
|
+
assert File.exist?(@pic.absolute_path)
|
105
|
+
end
|
106
|
+
|
69
107
|
def test_destroy_model_with_images_already_deleted_from_filesystem
|
70
108
|
@pic = Pic.new
|
71
109
|
@pic.save!
|
@@ -86,5 +124,30 @@ class PicTest < Test::Unit::TestCase
|
|
86
124
|
assert @pic.valid?
|
87
125
|
end
|
88
126
|
|
89
|
-
|
127
|
+
def test_dimension_getters
|
128
|
+
Pic.has_image_options[:resize_to] = "100x200"
|
129
|
+
pic = Pic.create!(:image_data => fixture_file_upload("/image.jpg", "image/jpeg"))
|
130
|
+
assert_equal 100, pic.width
|
131
|
+
assert_equal 200, pic.height
|
132
|
+
assert_equal '100x200', pic.image_size
|
133
|
+
end
|
134
|
+
|
135
|
+
def test_image_isnt_resized_when_resize_to_set_to_nil
|
136
|
+
Pic.has_image_options[:resize_to] = nil
|
137
|
+
pic = Pic.create!(:image_data => fixture_file_upload("/image.jpg", "image/jpeg"))
|
138
|
+
|
139
|
+
assert_equal 1916, pic.width
|
140
|
+
assert_equal 1990, pic.height
|
141
|
+
end
|
142
|
+
|
143
|
+
def test_image_isnt_resized_but_converted_when_resize_to_set_to_nil
|
144
|
+
Pic.has_image_options[:resize_to] = nil
|
145
|
+
Pic.has_image_options[:convert_to] = 'PNG'
|
146
|
+
pic = Pic.create!(:image_data => fixture_file_upload("/image.jpg", "image/jpeg"))
|
147
|
+
|
148
|
+
assert_equal 'PNG', MiniMagick::Image.from_file(pic.absolute_path)[:format]
|
149
|
+
assert_equal 1916, pic.width
|
150
|
+
assert_equal 1990, pic.height
|
151
|
+
end
|
90
152
|
|
153
|
+
end
|