merged in from code from the other master
[selectricity] / vendor / plugins / attachment_fu / lib / technoweenie / attachment_fu / processors / mini_magick_processor.rb
1 require 'mini_magick'
2 module Technoweenie # :nodoc:
3   module AttachmentFu # :nodoc:
4     module Processors
5       module MiniMagickProcessor
6         def self.included(base)
7           base.send :extend, ClassMethods
8           base.alias_method_chain :process_attachment, :processing
9         end
10  
11         module ClassMethods
12           # Yields a block containing an MiniMagick Image for the given binary data.
13           def with_image(file, &block)
14             begin
15               binary_data = file.is_a?(MiniMagick::Image) ? file : MiniMagick::Image.from_file(file) unless !Object.const_defined?(:MiniMagick)
16             rescue
17               # Log the failure to load the image.
18               logger.debug("Exception working with image: #{$!}")
19               binary_data = nil
20             end
21             block.call binary_data if block && binary_data
22           ensure
23             !binary_data.nil?
24           end
25         end
26  
27       protected
28         def process_attachment_with_processing
29           return unless process_attachment_without_processing
30           with_image do |img|
31             resize_image_or_thumbnail! img
32             self.width = img[:width] if respond_to?(:width)
33             self.height = img[:height] if respond_to?(:height)
34             callback_with_args :after_resize, img
35           end if image?
36         end
37  
38         # Performs the actual resizing operation for a thumbnail
39         def resize_image(img, size)
40           size = size.first if size.is_a?(Array) && size.length == 1
41           img.combine_options do |commands|
42             commands.strip unless attachment_options[:keep_profile]
43
44             # gif are not handled correct, this is a hack, but it seems to work.
45             if img.output =~ / GIF /
46               img.format("png")
47             end           
48             
49             if size.is_a?(Fixnum) || (size.is_a?(Array) && size.first.is_a?(Fixnum))
50               if size.is_a?(Fixnum)
51                 size = [size, size]
52                 commands.resize(size.join('x'))
53               else
54                 commands.resize(size.join('x') + '!')
55               end
56             # extend to thumbnail size
57             elsif size.is_a?(String) and size =~ /e$/
58               size = size.gsub(/e/, '')
59               commands.resize(size.to_s + '>')
60               commands.background('#ffffff')
61               commands.gravity('center')
62               commands.extent(size)
63             # crop thumbnail, the smart way
64             elsif size.is_a?(String) and size =~ /c$/
65                size = size.gsub(/c/, '')
66               
67               # calculate sizes and aspect ratio
68               thumb_width, thumb_height = size.split("x")
69               thumb_width   = thumb_width.to_f
70               thumb_height  = thumb_height.to_f
71               
72               thumb_aspect = thumb_width.to_f / thumb_height.to_f
73               image_width, image_height = img[:width].to_f, img[:height].to_f
74               image_aspect = image_width / image_height
75               
76               # only crop if image is not smaller in both dimensions
77               unless image_width < thumb_width and image_height < thumb_height
78                 command = calculate_offset(image_width,image_height,image_aspect,thumb_width,thumb_height,thumb_aspect)
79
80                 # crop image
81                 commands.extract(command)
82               end
83
84               # don not resize if image is not as height or width then thumbnail
85               if image_width < thumb_width or image_height < thumb_height                   
86                   commands.background('#ffffff')
87                   commands.gravity('center')
88                   commands.extent(size)
89               # resize image
90               else
91                 commands.resize("#{size.to_s}")
92               end
93             # crop end
94             else
95               commands.resize(size.to_s)
96             end
97           end
98           temp_paths.unshift img
99         end
100
101         def calculate_offset(image_width,image_height,image_aspect,thumb_width,thumb_height,thumb_aspect)
102         # only crop if image is not smaller in both dimensions
103
104           # special cases, image smaller in one dimension then thumbsize
105           if image_width < thumb_width
106             offset = (image_height / 2) - (thumb_height / 2)
107             command = "#{image_width}x#{thumb_height}+0+#{offset}"
108           elsif image_height < thumb_height
109             offset = (image_width / 2) - (thumb_width / 2)
110             command = "#{thumb_width}x#{image_height}+#{offset}+0"
111
112           # normal thumbnail generation
113           # calculate height and offset y, width is fixed                 
114           elsif (image_aspect <= thumb_aspect or image_width < thumb_width) and image_height > thumb_height
115             height = image_width / thumb_aspect
116             offset = (image_height / 2) - (height / 2)
117             command = "#{image_width}x#{height}+0+#{offset}"
118           # calculate width and offset x, height is fixed
119           else
120             width = image_height * thumb_aspect
121             offset = (image_width / 2) - (width / 2)
122             command = "#{width}x#{image_height}+#{offset}+0"
123           end
124           # crop image
125           command
126         end
127
128
129       end
130     end
131   end
132 end

Benjamin Mako Hill || Want to submit a patch?