1 | module FileColumn # :nodoc: |
---|
2 | |
---|
3 | class BaseUploadedFile # :nodoc: |
---|
4 | def transform_with_magick |
---|
5 | if needs_resize? |
---|
6 | begin |
---|
7 | img = ::Magick::Image::read(absolute_path).first |
---|
8 | rescue ::Magick::ImageMagickError |
---|
9 | @magick_errors ||= [] |
---|
10 | @magick_errors << "invalid image" |
---|
11 | return |
---|
12 | end |
---|
13 | |
---|
14 | if @options[:magick][:versions] |
---|
15 | @options[:magick][:versions].each_pair do |name, version_options| |
---|
16 | resize_image(img, version_options[:geometry], absolute_path(name)) |
---|
17 | end |
---|
18 | end |
---|
19 | if @options[:magick][:geometry] |
---|
20 | resize_image(img, @options[:magick][:geometry], absolute_path) |
---|
21 | end |
---|
22 | end |
---|
23 | end |
---|
24 | |
---|
25 | attr_reader :magick_errors |
---|
26 | |
---|
27 | def has_magick_errors? |
---|
28 | @magick_errors and !@magick_errors.empty? |
---|
29 | end |
---|
30 | |
---|
31 | private |
---|
32 | |
---|
33 | def needs_resize? |
---|
34 | @options[:magick] and just_uploaded? and |
---|
35 | (@options[:magick][:geometry] or@options[:magick][:versions]) |
---|
36 | end |
---|
37 | |
---|
38 | def resize_image(img, geometry, path) |
---|
39 | new_img = img.change_geometry(geometry) do |c, r, i| |
---|
40 | i.resize(c, r) |
---|
41 | end |
---|
42 | new_img.write path |
---|
43 | end |
---|
44 | end |
---|
45 | |
---|
46 | # If you are using file_column to upload images, you can |
---|
47 | # directly process the images with RMagick, |
---|
48 | # a ruby extension |
---|
49 | # for accessing the popular imagemagick libraries. You can find |
---|
50 | # more information about RMagick at http://rmagick.rubyforge.org. |
---|
51 | # |
---|
52 | # You can control what to do by adding a <tt>:magick</tt> option |
---|
53 | # to your options hash. All operations are performed immediately |
---|
54 | # after a new file is assigned to the file_column attribute. |
---|
55 | # |
---|
56 | # To resize the uploaded image according to an imagemagick geometry |
---|
57 | # string, just use the <tt>:geometry</tt> option: |
---|
58 | # |
---|
59 | # file_column :image, :magick => {:geometry => "800x600>"} |
---|
60 | # |
---|
61 | # You can also create additional versions of your image, for example |
---|
62 | # thumb-nails, like this: |
---|
63 | # file_column :image, :magick => {:versions => |
---|
64 | # { "thumb" => "50x50", "medium" => "640x480>" } |
---|
65 | # } |
---|
66 | # |
---|
67 | # These versions can later be accessed via file_column's <em>suffix</em> |
---|
68 | # mechanism. So if the uploaded image was named "vancouver.jpg", you can |
---|
69 | # access the additional versions like this: |
---|
70 | # |
---|
71 | # o.image("thumb") # produces ".../vancouver-thumb.jpg" |
---|
72 | # o.image_relative_path("medium") # produces ".../vancouver-medium.jpg" |
---|
73 | # |
---|
74 | # The same mechanism can be used in the +url_for_file_column+ helper: |
---|
75 | # |
---|
76 | # <%= url_for_file_column "entry", "image", "thumb" %> |
---|
77 | # |
---|
78 | # <b>Note:</b> You'll need the |
---|
79 | # rmagick extension installed as a gem in order to use file_column's |
---|
80 | # rmagick integration. |
---|
81 | module Magick |
---|
82 | |
---|
83 | def self.file_column(klass, attr, options) # :nodoc: |
---|
84 | require 'RMagick' |
---|
85 | if options[:magick][:versions] |
---|
86 | options[:magick][:versions].each_pair do |name, value| |
---|
87 | if value.kind_of?(String) |
---|
88 | options[:magick][:versions][name] = {:geometry => value} |
---|
89 | end |
---|
90 | end |
---|
91 | end |
---|
92 | state_method = "#{attr}_state".to_sym |
---|
93 | after_assign_method = "#{attr}_magick_after_assign".to_sym |
---|
94 | |
---|
95 | klass.send(:define_method, after_assign_method) do |
---|
96 | self.send(state_method).transform_with_magick |
---|
97 | end |
---|
98 | |
---|
99 | options[:after_assign] ||= [] |
---|
100 | options[:after_assign] << after_assign_method |
---|
101 | |
---|
102 | klass.validate do |record| |
---|
103 | state = record.send(state_method) |
---|
104 | if state.has_magick_errors? |
---|
105 | state.magick_errors.each do |error| |
---|
106 | record.errors.add attr, error |
---|
107 | end |
---|
108 | end |
---|
109 | end |
---|
110 | end |
---|
111 | |
---|
112 | end |
---|
113 | end |
---|