futuresinc-attachment_fu 1.0.4

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.
Files changed (51) hide show
  1. data/.gitignore +4 -0
  2. data/CHANGELOG +35 -0
  3. data/LICENSE +20 -0
  4. data/README +202 -0
  5. data/Rakefile +37 -0
  6. data/VERSION.yml +4 -0
  7. data/amazon_s3.yml.tpl +17 -0
  8. data/attachment_fu.gemspec +103 -0
  9. data/init.rb +1 -0
  10. data/install.rb +7 -0
  11. data/lib/geometry.rb +93 -0
  12. data/lib/technoweenie/attachment_fu/backends/cloud_file_backend.rb +211 -0
  13. data/lib/technoweenie/attachment_fu/backends/db_file_backend.rb +39 -0
  14. data/lib/technoweenie/attachment_fu/backends/file_system_backend.rb +126 -0
  15. data/lib/technoweenie/attachment_fu/backends/s3_backend.rb +394 -0
  16. data/lib/technoweenie/attachment_fu/processors/core_image_processor.rb +59 -0
  17. data/lib/technoweenie/attachment_fu/processors/gd2_processor.rb +54 -0
  18. data/lib/technoweenie/attachment_fu/processors/image_science_processor.rb +61 -0
  19. data/lib/technoweenie/attachment_fu/processors/mini_magick_processor.rb +132 -0
  20. data/lib/technoweenie/attachment_fu/processors/rmagick_processor.rb +57 -0
  21. data/lib/technoweenie/attachment_fu.rb +545 -0
  22. data/rackspace_cloudfiles.yml.tpl +14 -0
  23. data/test/backends/db_file_test.rb +16 -0
  24. data/test/backends/file_system_test.rb +143 -0
  25. data/test/backends/remote/cloudfiles_test.rb +102 -0
  26. data/test/backends/remote/s3_test.rb +119 -0
  27. data/test/base_attachment_tests.rb +77 -0
  28. data/test/basic_test.rb +70 -0
  29. data/test/database.yml +18 -0
  30. data/test/extra_attachment_test.rb +67 -0
  31. data/test/fixtures/attachment.rb +226 -0
  32. data/test/fixtures/files/fake/rails.png +0 -0
  33. data/test/fixtures/files/foo.txt +1 -0
  34. data/test/fixtures/files/rails.png +0 -0
  35. data/test/geometry_test.rb +108 -0
  36. data/test/processors/core_image_test.rb +37 -0
  37. data/test/processors/gd2_test.rb +31 -0
  38. data/test/processors/image_science_test.rb +31 -0
  39. data/test/processors/mini_magick_test.rb +103 -0
  40. data/test/processors/rmagick_test.rb +255 -0
  41. data/test/schema.rb +134 -0
  42. data/test/test_helper.rb +157 -0
  43. data/test/validation_test.rb +55 -0
  44. data/vendor/red_artisan/core_image/filters/color.rb +27 -0
  45. data/vendor/red_artisan/core_image/filters/effects.rb +31 -0
  46. data/vendor/red_artisan/core_image/filters/perspective.rb +25 -0
  47. data/vendor/red_artisan/core_image/filters/quality.rb +25 -0
  48. data/vendor/red_artisan/core_image/filters/scale.rb +47 -0
  49. data/vendor/red_artisan/core_image/filters/watermark.rb +32 -0
  50. data/vendor/red_artisan/core_image/processor.rb +123 -0
  51. metadata +119 -0
@@ -0,0 +1,132 @@
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
@@ -0,0 +1,57 @@
1
+ require 'RMagick'
2
+ module Technoweenie # :nodoc:
3
+ module AttachmentFu # :nodoc:
4
+ module Processors
5
+ module RmagickProcessor
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 RMagick Image for the given binary data.
13
+ def with_image(file, &block)
14
+ begin
15
+ binary_data = file.is_a?(Magick::Image) ? file : Magick::Image.read(file).first unless !Object.const_defined?(:Magick)
16
+ rescue
17
+ # Log the failure to load the image. This should match ::Magick::ImageMagickError
18
+ # but that would cause acts_as_attachment to require rmagick.
19
+ logger.debug("Exception working with image: #{$!}")
20
+ binary_data = nil
21
+ end
22
+ block.call binary_data if block && binary_data
23
+ ensure
24
+ !binary_data.nil?
25
+ end
26
+ end
27
+
28
+ protected
29
+ def process_attachment_with_processing
30
+ return unless process_attachment_without_processing
31
+ with_image do |img|
32
+ resize_image_or_thumbnail! img
33
+ self.width = img.columns if respond_to?(:width)
34
+ self.height = img.rows if respond_to?(:height)
35
+ callback_with_args :after_resize, img
36
+ end if image?
37
+ end
38
+
39
+ # Performs the actual resizing operation for a thumbnail
40
+ def resize_image(img, size)
41
+ size = size.first if size.is_a?(Array) && size.length == 1 && !size.first.is_a?(Fixnum)
42
+ if size.is_a?(Fixnum) || (size.is_a?(Array) && size.first.is_a?(Fixnum))
43
+ size = [size, size] if size.is_a?(Fixnum)
44
+ img.thumbnail!(*size)
45
+ elsif size.is_a?(String) && size =~ /^c.*$/ # Image cropping - example geometry string: c75x75
46
+ dimensions = size[1..size.size].split("x")
47
+ img.crop_resized!(dimensions[0].to_i, dimensions[1].to_i)
48
+ else
49
+ img.change_geometry(size.to_s) { |cols, rows, image| image.resize!(cols<1 ? 1 : cols, rows<1 ? 1 : rows) }
50
+ end
51
+ img.strip! unless attachment_options[:keep_profile]
52
+ temp_paths.unshift write_to_temp_file(img.to_blob)
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end