Skip to content
Browse files

Merge branch 'master' of git://github.com/aka47/attachment_fu into mm

  • Loading branch information...
2 parents 1f9784c + 01c80b7 commit 1a74c25a424bc26989722e730d56c305d87e430c rick committed
View
85 lib/technoweenie/attachment_fu/processors/mini_magick_processor.rb
@@ -7,7 +7,7 @@ def self.included(base)
base.send :extend, ClassMethods
base.alias_method_chain :process_attachment, :processing
end
-
+
module ClassMethods
# Yields a block containing an MiniMagick Image for the given binary data.
def with_image(file, &block)
@@ -23,23 +23,29 @@ def with_image(file, &block)
!binary_data.nil?
end
end
-
+
protected
def process_attachment_with_processing
return unless process_attachment_without_processing
with_image do |img|
resize_image_or_thumbnail! img
- self.width = img[:width] if respond_to?(:width)
- self.height = img[:height] if respond_to?(:height)
+ self.width = img[:width] if respond_to?(:width)
+ self.height = img[:height] if respond_to?(:height)
callback_with_args :after_resize, img
end if image?
end
-
+
# Performs the actual resizing operation for a thumbnail
def resize_image(img, size)
size = size.first if size.is_a?(Array) && size.length == 1
img.combine_options do |commands|
commands.strip unless attachment_options[:keep_profile]
+
+ # gif are not handled correct, this is a hack, but it seems to work.
+ if img.output =~ / GIF /
+ img.format("png")
+ end
+
if size.is_a?(Fixnum) || (size.is_a?(Array) && size.first.is_a?(Fixnum))
if size.is_a?(Fixnum)
size = [size, size]
@@ -47,13 +53,80 @@ def resize_image(img, size)
else
commands.resize(size.join('x') + '!')
end
+ # extend to thumbnail size
+ elsif size.is_a?(String) and size =~ /e$/
+ size = size.gsub(/e/, '')
+ commands.resize(size.to_s + '>')
+ commands.background('#ffffff')
+ commands.gravity('center')
+ commands.extent(size)
+ # crop thumbnail, the smart way
+ elsif size.is_a?(String) and size =~ /c$/
+ size = size.gsub(/c/, '')
+
+ # calculate sizes and aspect ratio
+ thumb_width, thumb_height = size.split("x")
+ thumb_width = thumb_width.to_f
+ thumb_height = thumb_height.to_f
+
+ thumb_aspect = thumb_width.to_f / thumb_height.to_f
+ image_width, image_height = img[:width].to_f, img[:height].to_f
+ image_aspect = image_width / image_height
+
+ # only crop if image is not smaller in both dimensions
+ unless image_width < thumb_width and image_height < thumb_height
+ command = calculate_offset(image_width,image_height,image_aspect,thumb_width,thumb_height,thumb_aspect)
+
+ # crop image
+ commands.extract(command)
+ end
+
+ # don not resize if image is not as height or width then thumbnail
+ if image_width < thumb_width or image_height < thumb_height
+ commands.background('#ffffff')
+ commands.gravity('center')
+ commands.extent(size)
+ # resize image
+ else
+ commands.resize("#{size.to_s}")
+ end
+ # crop end
else
commands.resize(size.to_s)
end
end
temp_paths.unshift img
end
+
+ def calculate_offset(image_width,image_height,image_aspect,thumb_width,thumb_height,thumb_aspect)
+ # only crop if image is not smaller in both dimensions
+
+ # special cases, image smaller in one dimension then thumbsize
+ if image_width < thumb_width
+ offset = (image_height / 2) - (thumb_height / 2)
+ command = "#{image_width}x#{thumb_height}+0+#{offset}"
+ elsif image_height < thumb_height
+ offset = (image_width / 2) - (thumb_width / 2)
+ command = "#{thumb_width}x#{image_height}+#{offset}+0"
+
+ # normal thumbnail generation
+ # calculate height and offset y, width is fixed
+ elsif (image_aspect <= thumb_aspect or image_width < thumb_width) and image_height > thumb_height
+ height = image_width / thumb_aspect
+ offset = (image_height / 2) - (height / 2)
+ command = "#{image_width}x#{height}+0+#{offset}"
+ # calculate width and offset x, height is fixed
+ else
+ width = image_height * thumb_aspect
+ offset = (image_width / 2) - (width / 2)
+ command = "#{width}x#{image_height}+#{offset}+0"
+ end
+ # crop image
+ command
+ end
+
+
end
end
end
-end
+end
View
39 test/fixtures/attachment.rb
@@ -35,7 +35,7 @@ class ImageOrPdfAttachment < Attachment
class ImageWithThumbsAttachment < Attachment
has_attachment :thumbnails => { :thumb => [50, 50], :geometry => 'x50' }, :resize_to => [55,55]
after_resize do |record, img|
- record.aspect_ratio = img.columns.to_f / img.rows.to_f
+ # record.aspect_ratio = img.columns.to_f / img.rows.to_f
end
end
@@ -53,7 +53,7 @@ class ImageWithThumbsFileAttachment < FileAttachment
has_attachment :path_prefix => 'vendor/plugins/attachment_fu/test/files',
:thumbnails => { :thumb => [50, 50], :geometry => 'x50' }, :resize_to => [55,55]
after_resize do |record, img|
- record.aspect_ratio = img.columns.to_f / img.rows.to_f
+ # record.aspect_ratio = img.columns.to_f / img.rows.to_f
end
end
@@ -130,9 +130,44 @@ class MiniMagickAttachment < ActiveRecord::Base
has_attachment :path_prefix => 'vendor/plugins/attachment_fu/test/files',
:processor => :mini_magick, :thumbnails => { :thumb => [50, 51], :geometry => '31>' }, :resize_to => 55
end
+ class ImageThumbnailCrop < MiniMagickAttachment
+ has_attachment :path_prefix => 'vendor/plugins/attachment_fu/test/files',
+ :thumbnails => { :square => "50x50c", :vertical => "30x60c", :horizontal => "60x30c"}
+
+ # TODO this is a bad duplication, this method is in the MiniMagick Processor
+ def self.calculate_offset(image_width,image_height,image_aspect,thumb_width,thumb_height,thumb_aspect)
+ # only crop if image is not smaller in both dimensions
+
+ # special cases, image smaller in one dimension then thumbsize
+ if image_width < thumb_width
+ offset = (image_height / 2) - (thumb_height / 2)
+ command = "#{image_width}x#{thumb_height}+0+#{offset}"
+ elsif image_height < thumb_height
+ offset = (image_width / 2) - (thumb_width / 2)
+ command = "#{thumb_width}x#{image_height}+#{offset}+0"
+
+ # normal thumbnail generation
+ # calculate height and offset y, width is fixed
+ elsif (image_aspect <= thumb_aspect or image_width < thumb_width) and image_height > thumb_height
+ height = image_width / thumb_aspect
+ offset = (image_height / 2) - (height / 2)
+ command = "#{image_width}x#{height}+0+#{offset}"
+ # calculate width and offset x, height is fixed
+ else
+ width = image_height * thumb_aspect
+ offset = (image_width / 2) - (width / 2)
+ command = "#{width}x#{image_height}+#{offset}+0"
+ end
+ # crop image
+ command
+ end
+ end
+
rescue MissingSourceFile
end
+
+
begin
class S3Attachment < ActiveRecord::Base
has_attachment :storage => :s3, :processor => :rmagick, :s3_config_path => File.join(File.dirname(__FILE__), '../amazon_s3.yml')
View
72 test/processors/mini_magick_test.rb
@@ -23,9 +23,81 @@ def test_should_resize_image
assert_equal 31, geo.width
assert_equal 40, geo.height
end
+
+ def test_should_crop_image(klass = ImageThumbnailCrop)
+ attachment_model klass
+ attachment = upload_file :filename => '/files/rails.png'
+ assert_valid attachment
+ assert attachment.image?
+ # has_attachment :thumbnails => { :square => "50x50c", :vertical => "30x60c", :horizontal => "60x30c"}
+
+ square = attachment.thumbnails.detect { |t| t.filename =~ /_square/ }
+ vertical = attachment.thumbnails.detect { |t| t.filename =~ /_vertical/ }
+ horizontal = attachment.thumbnails.detect { |t| t.filename =~ /_horizontal/ }
+
+ # test excat resize
+ assert_equal 50, square.width
+ assert_equal 50, square.height
+
+ assert_equal 30, vertical.width
+ assert_equal 60, vertical.height
+
+ assert_equal 60, horizontal.width
+ assert_equal 30, horizontal.height
+ end
+
+ # tests the first step in resize, crop the image in original size to right format
+ def test_should_crop_image_right(klass = ImageThumbnailCrop)
+ @@testcases.collect do |testcase|
+ image_width, image_height, thumb_width, thumb_height = testcase[:data]
+ image_aspect, thumb_aspect = image_width/image_height, thumb_width/thumb_height
+ crop_comand = klass.calculate_offset(image_width, image_height, image_aspect, thumb_width, thumb_height,thumb_aspect)
+ # pattern matching on crop command
+ if testcase.has_key?(:height)
+ assert crop_comand.match(/^#{image_width}x#{testcase[:height]}\+0\+#{testcase[:yoffset]}$/)
+ else
+ assert crop_comand.match(/^#{testcase[:width]}x#{image_height}\+#{testcase[:xoffset]}\+0$/)
+ end
+ end
+ end
+
else
def test_flunk
puts "MiniMagick not loaded, tests not running"
end
end
+
+ @@testcases = [
+ # image_aspect <= 1 && thumb_aspect >= 1
+ {:data => [10.0,40.0,2.0,1.0], :height => 5.0, :yoffset => 17.5}, # 1b
+ {:data => [10.0,40.0,1.0,1.0], :height => 10.0, :yoffset => 15.0}, # 1b
+
+ # image_aspect < 1 && thumb_aspect < 1
+ {:data => [10.0,40.0,1.0,2.0], :height => 20.0, :yoffset => 10.0}, # 1a
+ {:data => [2.0,3.0,1.0,2.0], :width => 1.5, :xoffset => 0.25}, # 1a
+
+ # image_aspect = thumb_aspect
+ {:data => [10.0,10.0,1.0,1.0], :height => 10.0, :yoffset => 0.0}, # QUADRAT 1c
+
+ # image_aspect >= 1 && thumb_aspect > 1 && image_aspect < thumb_aspect
+ {:data => [6.0,3.0,4.0,1.0], :height => 1.5, :yoffset => 0.75}, # 2b
+ {:data => [6.0,6.0,4.0,1.0], :height => 1.5, :yoffset => 2.25}, # 2b
+
+ # image_aspect > 1 && thumb_aspect > 1 && image_aspect > thumb_aspect
+ {:data => [9.0,3.0,2.0,1.0], :width => 6.0, :xoffset => 1.5}, # 2a
+
+ # image_aspect > 1 && thumb_aspect < 1 && image_aspect < thumb_aspect
+ {:data => [10.0,5.0,0.1,2.0], :width => 0.25, :xoffset => 4.875}, # 4
+ {:data => [10.0,5.0,1.0,2.0], :width => 2.5, :xoffset => 3.75}, # 4
+
+ # image_aspect > 1 && thumb_aspect > 1 && image_aspect > thumb_aspect
+ {:data => [9.0,3.0,2.0,1.0], :width => 6.0, :xoffset => 1.5}, # 3a
+ # image_aspect > 1 && thumb_aspect > 1 && image_aspect < thumb_aspect
+ {:data => [9.0,3.0,5.0,1.0], :height => 1.8, :yoffset => 0.6} # 3a
+ ]
+
+
+
+
+
end

0 comments on commit 1a74c25

Please sign in to comment.
Something went wrong with that request. Please try again.