Permalink
Browse files

add image science support

git-svn-id: http://svn.techno-weenie.net/projects/plugins/attachment_fu@2573 567b1171-46fb-0310-a4c9-b4bef9110e78
  • Loading branch information...
1 parent c3b5889 commit 43d1298a0cbba0205b0cc7ab9c657f8f5be0873a technoweenie committed Dec 23, 2006
View
@@ -1,9 +1,10 @@
require 'tempfile'
-class Tempfile
- # overwrite so tempfiles have no extension
+Tempfile.class_eval do
+ # overwrite so tempfiles keep the basename extension
def make_tmpname(basename, n)
- sprintf("%s%d-%d", basename, $$, n)
+ ext = nil
+ sprintf("%s%d-%d%s", basename.gsub(/\.\w+$/) { |s| ext = s; '' }, $$, n, ext)
end
end
@@ -1,6 +1,6 @@
module Technoweenie # :nodoc:
module AttachmentFu # :nodoc:
- @@default_processors = %w(Rmagick)
+ @@default_processors = %w(Rmagick ImageScience)
@@tempfile_path = File.join(RAILS_ROOT, 'tmp', 'attachment_fu')
@@content_types = ['image/jpeg', 'image/pjpeg', 'image/gif', 'image/png', 'image/x-png']
mattr_reader :content_types, :tempfile_path, :default_processors
@@ -253,9 +253,34 @@ def image_size
[width.to_s, height.to_s] * 'x'
end
+ # Allows you to work with an RMagick representation of the attachment in a block.
+ #
+ # @attachment.with_image do |img|
+ # self.data = img.thumbnail(100, 100).to_blob
+ # end
+ #
+ def with_image(&block)
+ self.class.with_image(temp_path, &block)
+ end
+
+ # Creates or updates the thumbnail for the current attachment.
+ def create_or_update_thumbnail(temp_file, file_name_suffix, *size)
+ thumbnailable? || raise(ThumbnailError.new("Can't create a thumbnail if the content type is not an image or there is no parent_id column"))
+ returning find_or_initialize_thumbnail(file_name_suffix) do |thumb|
+ thumb.attributes = {
+ :content_type => content_type,
+ :filename => thumbnail_name_for(file_name_suffix),
+ :temp_path => temp_file,
+ :thumbnail_resize_options => size
+ }
+ callback_with_args :before_thumbnail_saved, thumb
+ thumb.save!
+ end
+ end
+
protected
def random_tempfile_filename
- "#{filename || 'attachment'}#{rand Time.now.to_i}"
+ "#{rand Time.now.to_i}#{filename || 'attachment'}"
end
@@filename_basename_regex = /^.*(\\|\/)/
@@ -282,17 +307,37 @@ def attachment_attributes_valid?
errors.add attr_name, ActiveRecord::Errors.default_error_messages[:inclusion] unless enum.nil? || enum.include?(send(attr_name))
end
end
+
+ def find_or_initialize_thumbnail(file_name_suffix)
+ respond_to?(:parent_id) ?
+ thumbnail_class.find_or_initialize_by_thumbnail_and_parent_id(file_name_suffix.to_s, id) :
+ thumbnail_class.find_or_initialize_by_thumbnail(file_name_suffix.to_s)
+ end
# Stub for a #process_attachment method in a processor
def process_attachment
@saved_attachment = save_attachment?
end
def after_process_attachment
- save_to_storage
- @temp_paths.clear
- @saved_attachment = nil
- callback :after_attachment_saved
+ if @saved_attachment
+ if thumbnailable? && !attachment_options[:thumbnails].blank? && parent_id.nil?
+ temp_file = temp_path || create_temp_file
+ attachment_options[:thumbnails].each { |suffix, size| create_or_update_thumbnail(temp_file, suffix, *size) }
+ end
+ save_to_storage
+ @temp_paths.clear
+ @saved_attachment = nil
+ callback :after_attachment_saved
+ end
+ end
+
+ def resize_image_or_thumbnail!(img)
+ if (!respond_to?(:parent_id) || parent_id.nil?) && attachment_options[:resize_to] # parent image
+ resize_image(img, attachment_options[:resize_to])
+ elsif thumbnail_resize_options # thumbnail
+ resize_image(img, thumbnail_resize_options)
+ end
end
# Yanked from ActiveRecord::Callbacks, modified so I can pass args to the callbacks besides self.
@@ -0,0 +1,37 @@
+require 'image_science'
+module Technoweenie # :nodoc:
+ module AttachmentFu # :nodoc:
+ module Processors
+ module ImageScience
+ def self.included(base)
+ base.send :extend, ClassMethods
+ base.alias_method_chain :process_attachment, :processing
+ end
+
+ module ClassMethods
+ # Yields a block containing an RMagick Image for the given binary data.
+ def with_image(file, &block)
+ ::ImageScience.with_image file, &block
+ end
+ end
+
+ protected
+ def process_attachment_with_processing
+ return unless process_attachment_without_processing || !image?
+ with_image { |img| resize_image_or_thumbnail! img }
+ with_image do |img|
+ self.width = img.width if respond_to?(:width)
+ self.height = img.height if respond_to?(:height)
+ callback_with_args :after_resize, img
+ end
+ end
+
+ # Performs the actual resizing operation for a thumbnail
+ def resize_image(img, size)
+ self.temp_path = write_to_temp_file('foo')
+ img.thumbnail(temp_path, (size.is_a?(Array) ? size.first : size).to_i)
+ end
+ end
+ end
+ end
+end
@@ -6,7 +6,6 @@ module Rmagick
def self.included(base)
base.send :extend, ClassMethods
base.alias_method_chain :process_attachment, :processing
- base.alias_method_chain :after_process_attachment, :processing
end
module ClassMethods
@@ -25,58 +24,20 @@ def with_image(file, &block)
!binary_data.nil?
end
end
-
- # Allows you to work with an RMagick representation of the attachment in a block.
- #
- # @attachment.with_image do |img|
- # self.data = img.thumbnail(100, 100).to_blob
- # end
- #
- def with_image(&block)
- self.class.with_image(temp_path, &block)
- end
-
- # Creates or updates the thumbnail for the current attachment.
- def create_or_update_thumbnail(temp_file, file_name_suffix, *size)
- thumbnailable? || raise(ThumbnailError.new("Can't create a thumbnail if the content type is not an image or there is no parent_id column"))
- returning find_or_initialize_thumbnail(file_name_suffix) do |thumb|
- thumb.attributes = {
- :content_type => content_type,
- :filename => thumbnail_name_for(file_name_suffix),
- :temp_path => temp_file,
- :thumbnail_resize_options => size
- }
- callback_with_args :before_thumbnail_saved, thumb
- thumb.save!
- end
- end
-
+
protected
def process_attachment_with_processing
return unless process_attachment_without_processing
with_image do |img|
- if !respond_to?(:parent_id) || parent_id.nil? # parent image
- thumbnail_for_image(img, attachment_options[:resize_to]) if attachment_options[:resize_to]
- else # thumbnail
- thumbnail_for_image(img, thumbnail_resize_options) if thumbnail_resize_options
- end
+ resize_image_or_thumbnail! img
self.width = img.columns if respond_to?(:width)
self.height = img.rows if respond_to?(:height)
callback_with_args :after_resize, img
end if image?
end
-
- def after_process_attachment_with_processing
- return unless @saved_attachment
- if thumbnailable? && !attachment_options[:thumbnails].blank? && parent_id.nil?
- temp_file = temp_path || create_temp_file
- attachment_options[:thumbnails].each { |suffix, size| create_or_update_thumbnail(temp_file, suffix, *size) }
- end
- after_process_attachment_without_processing
- end
-
+
# Performs the actual resizing operation for a thumbnail
- def thumbnail_for_image(img, size)
+ def resize_image(img, size)
size = size.first if size.is_a?(Array) && size.length == 1 && !size.first.is_a?(Fixnum)
if size.is_a?(Fixnum) || (size.is_a?(Array) && size.first.is_a?(Fixnum))
size = [size, size] if size.is_a?(Fixnum)
@@ -86,12 +47,6 @@ def thumbnail_for_image(img, size)
end
self.temp_path = write_to_temp_file(img.to_blob)
end
-
- def find_or_initialize_thumbnail(file_name_suffix)
- respond_to?(:parent_id) ?
- thumbnail_class.find_or_initialize_by_thumbnail_and_parent_id(file_name_suffix.to_s, id) :
- thumbnail_class.find_or_initialize_by_thumbnail(file_name_suffix.to_s)
- end
end
end
end
@@ -1,7 +1,7 @@
class Attachment < ActiveRecord::Base
@@saves = 0
cattr_accessor :saves
- has_attachment
+ has_attachment :processor => :rmagick
validates_as_attachment
after_attachment_saved do |record|
self.saves += 1
@@ -40,7 +40,7 @@ class ImageWithThumbsAttachment < Attachment
end
class FileAttachment < ActiveRecord::Base
- has_attachment :file_system_path => 'vendor/plugins/attachment_fu/test/files'
+ has_attachment :file_system_path => 'vendor/plugins/attachment_fu/test/files', :processor => :rmagick
validates_as_attachment
end
@@ -69,16 +69,21 @@ class ImageThumbnail < FileAttachment
# no parent
class OrphanAttachment < ActiveRecord::Base
- has_attachment
+ has_attachment :processor => :rmagick
validates_as_attachment
end
# no filename, no size, no content_type
class MinimalAttachment < ActiveRecord::Base
- has_attachment :file_system_path => 'vendor/plugins/attachment_fu/test/files'
+ has_attachment :file_system_path => 'vendor/plugins/attachment_fu/test/files', :processor => :rmagick
validates_as_attachment
def filename
"#{id}.file"
end
-end
+end
+
+class ImageScienceAttachment < ActiveRecord::Base
+ has_attachment :file_system_path => 'vendor/plugins/attachment_fu/test/files',
+ :processor => :image_science, :thumbnails => { :thumb => [50, 50], :geometry => '53>', :width => 40 }, :resize_to => [55,55]
+end
@@ -1,63 +0,0 @@
-module ImageAttachmentTests
- def test_should_create_image_from_uploaded_file
- assert_created do
- attachment = upload_file :filename => '/files/rails.png'
- assert_valid attachment
- assert !attachment.db_file.new_record? if attachment.respond_to?(:db_file)
- assert attachment.image?
- assert !attachment.size.zero?
- #assert_equal 1784, attachment.size
- assert_equal 50, attachment.width
- assert_equal 64, attachment.height
- assert_equal '50x64', attachment.image_size
- end
- end
-
- def test_should_create_image_from_uploaded_file_with_custom_content_type
- assert_created do
- attachment = upload_file :content_type => 'foo/bar', :filename => '/files/rails.png'
- assert_valid attachment
- assert !attachment.image?
- assert !attachment.db_file.new_record? if attachment.respond_to?(:db_file)
- assert !attachment.size.zero?
- #assert_equal 1784, attachment.size
- assert_nil attachment.width
- assert_nil attachment.height
- assert_equal [], attachment.thumbnails
- end
- end
-
- def test_should_create_thumbnail
- attachment = upload_file :filename => '/files/rails.png'
-
- assert_created do
- basename, ext = attachment.filename.split '.'
- thumbnail = attachment.create_or_update_thumbnail(attachment.create_temp_file, 'thumb', 50, 50)
- assert_valid thumbnail
- assert !thumbnail.size.zero?
- #assert_in_delta 4673, thumbnail.size, 2
- assert_equal 50, thumbnail.width
- assert_equal 50, thumbnail.height
- assert_equal [thumbnail.id], attachment.thumbnails.collect(&:id)
- assert_equal attachment.id, thumbnail.parent_id if thumbnail.respond_to?(:parent_id)
- assert_equal "#{basename}_thumb.#{ext}", thumbnail.filename
- end
- end
-
- def test_should_create_thumbnail_with_geometry_string
- attachment = upload_file :filename => '/files/rails.png'
-
- assert_created do
- basename, ext = attachment.filename.split '.'
- thumbnail = attachment.create_or_update_thumbnail(attachment.create_temp_file, 'thumb', 'x50')
- assert_valid thumbnail
- assert !thumbnail.size.zero?
- #assert_equal 3915, thumbnail.size
- assert_equal 39, thumbnail.width
- assert_equal 50, thumbnail.height
- assert_equal [thumbnail], attachment.thumbnails
- assert_equal attachment.id, thumbnail.parent_id if thumbnail.respond_to?(:parent_id)
- assert_equal "#{basename}_thumb.#{ext}", thumbnail.filename
- end
- end
-end
@@ -0,0 +1,26 @@
+require File.expand_path(File.join(File.dirname(__FILE__), '..', 'test_helper'))
+
+class ImageScienceTest < Test::Unit::TestCase
+ attachment_model ImageScienceAttachment
+
+ def test_should_resize_image
+ attachment = upload_file :filename => '/files/rails.png'
+ assert_valid attachment
+ assert attachment.image?
+ assert_equal 43, attachment.width
+ assert_equal 55, attachment.height
+
+ thumb = attachment.thumbnails.detect { |t| t.filename =~ /_thumb/ }
+ geo = attachment.thumbnails.detect { |t| t.filename =~ /_geometry/ }
+ width = attachment.thumbnails.detect { |t| t.filename =~ /_width/ }
+
+ assert_equal 39, thumb.width
+ assert_equal 50, thumb.height
+
+ assert_equal 41, geo.width
+ assert_equal 53, geo.height
+
+ assert_equal 31, width.width
+ assert_equal 40, width.height
+ end
+end
Oops, something went wrong.

0 comments on commit 43d1298

Please sign in to comment.