Rorcraft Blog

Patching paperclip to create thumbnails only for images

Paperclip has some good features over attachment_fu that “attached files don’t need to have a seperare model (thank god). Your attachments are treated just like any other atribute. Images aren’t saved until your model is saved” ( by Jim Neath ).

The fall back of paperclip is that it tries to create a thumbnail for any type of file, including pdf. It won’t cause much problem if it cannot create a thumbnail to a certain file. But when it comes to pdf file, paperclip tries to generate a thumbnail for every page of the file, it becomes very slow when uploading the pdf file if the file has hundreds of pages. Sometimes it even times out! At the same time, attachment_fu does not have this problem.

attachment_fu.rb includes a class method #images? to distinguish if the file is an image.

—- ruby129 # Returns true or false if the given content type is recognized as an image.
130 def image?(content_type)
131 content_types.include?(content_type)
132 end

1
2
<p>Content types of images are initialized at the begin of the file:</p>
--- ruby5  @@content_types = ['image/jpeg', 'image/pjpeg', 'image/gif', 'image/png', 'image/x-png', 'image/jpg']

Then the #image? method is called in a instantial method #thumbnailable:

1
2
3
4
5
6
7
8
9
10
216       # Checks whether the attachment's content type is an image content type
217       def image?
218         self.class.image?(content_type)
219       end
220
221       # Returns true/false if an attachment is thumbnailable.  
            # A thumbnailable attachment has an image content type and the parent_id attribute.
222       def thumbnailable?
223         image? && respond_to?(:parent_id) && parent_id.nil?
224       end

In the #create_or_update_thumbnail it test if the content is thumbnailable? to determine going or not.

—- ruby243 # Creates or updates the thumbnail for the current attachment.
244 def create_or_update_thumbnail(temp_file, file_name_suffix, *size)
245 thumbnailable? || raise(ThumbnailError.new(“Can’t create a thumbnail if the content \
type is not an image or there is no parent_id column”))
246 returning find_or_initialize_thumbnail(file_name_suffix) do |thumb|
247 thumb.attributes = {
248 :content_type => content_type,
249 :filename => thumbnail_name_for(file_name_suffix),
250 :temp_path => temp_file,
251 :thumbnail_resize_options => size
252 }
253 callback_with_args :before_thumbnail_saved, thumb
254 thumb.save!
255 end
256 end

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<p>Paperclip has a similar structure like this, it makes it easier to make this patch.</p>

--- rubyFrom line #217
    def post_process #:nodoc:
      return if @queued_for_write[:original].nil?
      logger.info("[paperclip] Post-processing #{name}")
      @styles.each do |name, args|
        begin
          dimensions, format = args
          dimensions = dimensions.call(instance) if dimensions.respond_to? :call
          @queued_for_write[name] = Thumbnail.make(@queued_for_write[:original],
                                                   dimensions,
                                                   format,
                                                   @whiny_thumnails)
        rescue PaperclipError => e
          @errors << e.message if @whiny_thumbnails
        end
      end
    end

The trick here is to add the #thumbnailable? method in right after the #begin keyword and raise a PaperclipError if it fails:

—- ruby213 def post_process #:nodoc:
214 return if queued_for_write[:original].nil? 215 @styles.each do |name, args| 216 begin # Test here 217 thumbnailable? || raise(PaperclipError.new("Can not create thumbnails \ if the content type is not an image.")) 218 dimensions, format = args 219 dimensions = dimensions.call(instance) if dimensions.respond_to? :call 220 @queued_for_write[name] = Thumbnail.make(queued_for_write[:original],-
221 dimensions,
222 format,-
223 @whiny_thumnails)
224 rescue PaperclipError => e
225 @errors << e.message if @whiny_thumbnails
226 end
227 end
228 end
—-

Add the #image? and #thumbnailable? method to attachment.rb of paperclip, and initialize the thumbnailable content types at the beginning. That’s all, now you can upload pdf files very fast.


About how to use paperclip, Jim Neath has a great tutorial Paperclip: Attaching Files in Rails. Enjoy it!

blog comments powered by Disqus

Contact

We love to hear about your web projects.
Email:
Sydney: +61 421 591 943
Hong Kong:+852 6901 2682

Categories