Sorry this page looks weird. It was automatically migrated from my old blog, which had a different layout and different CSS.

Converting Image Format When Thumbnailing

Recently I built a screen where the user can upload multiple images with SWFUpload and attachment_fu. In this case the user is an award-winning photographer and he uploads images in a wide variety of formats. So far, so good.

The catch is his wanting the thumbnail the site generates for each image to be a JPEG. So if he uploads a CR2, the site should generate a JPEG thumbnail (while leaving the original intact).

This is so that every browser can display thumbnails of his images regardless of their original formats. Sensible.

It sounds simple but, as I often find with attachment_fu, getting it working was harder than I anticipated. There may well be a more elegant solution than the code below. I’m sure you could generalise it to other formats and other image processors, pluginise it, and so on. However my code does have the virtue of working.

Assumptions

The Code

Let me know if you improve this.

class Asset < ActiveRecord::Base 
  has_attachment :storage    => :s3,
                 :thumbnails => {:thumb => '100x'}

  # All the image formats that should be thumbnailed
  # and converted to JPEG.  Must contain jpg and jpeg.
  @@converts = %w( gif jpg jpeg png tif tiff bmp cr2 crw )
  @@converts << %w( eps pcd pdf pef pict psd raf )
  @@converts.flatten!

  before_thumbnail_saved do |record, thumbnail|
    thumbnail.content_type = 'image/jpeg' if convertable? thumbnail.filename
  end

  def resize_image(img, size)
    img.format = 'JPEG' if convertable? thumbnail_name_for(thumbnail)
    super
  end

  def convertable?(name)
    self.class.convertable? name
  end

  def self.convertable?(name)
    ext = File.extname(name)[1..-1]
    @@converts.include?(ext) && rmagick_can_read_extension?(ext)
  end

  def self.rmagick_can_read_extension?(extension)
    # Convert extensions to ones that RMagick recognises.
    ext = case extension
          when 'tif': 'tiff'
          else extension
          end
    rmagick_can_read_format? ext.upcase
  end

  def self.rmagick_can_read_format?(format)
    code = Magick.formats[format]
    # Determine whether RMagick knows how to read files in this format.
    # TODO: test native blob support?  p.416 Ruby Cookbook.
    code && code[1] == ?r
  end

  def image?
    super || convertable?(filename)
  end

  def thumbnail_name_for(thumbnail = nil)
    name = super
    name.sub!(/\\.\\w+$/, '.jpg') if name.match(/_thumb/) && convertable?(name)
    name
  end
end

Comments

Hi there,

Thanks for the example code on how to resize to jpeg in rmagick when the original isn’t a format (e.g. tiff, bmp) that imagemagick/rmagick can resize as is.

I’ve taken your code and generalized it a little more and made it a module here:

http://github.com/kete/kete/tree/master/lib/resize_as_jpeg_when_necessary.rb

Thanks for you work! Walter

Walter McGinnis • 4 December 2008

Andrew Stewart • 15 January 2008 • Rails
You can reach me by email or on Twitter.