Ruby on Rails and Rmagick Crop, Resize, Rotate, Thumbnail and Upload Images

Cropping Images With Rmagick

This post is a healthy mix of both ruby and rails methods for rmagick!

def submit_crop_image
   require 'RMagick'

   @user = curr_user

   tmpfile = "#{RAILS_ROOT}/public/images/users/tmp/#{}.jpg"
   img001 = "#{RAILS_ROOT}/public/images/users/#{}_001.jpg"
   img002 = "#{RAILS_ROOT}/public/images/users/#{}_002.jpg"
   img003 = "#{RAILS_ROOT}/public/images/users/#{}_003.jpg"
size001 = 100s
   size002 = 50
   size003 = 16

   top    = params['top'].to_i
   left   = params['left'].to_i
   width  = params['width'].to_i
   height = params['height'].to_i

     img = Magick::Image::read(tmpfile).first
     unless width == 0 or height == 0
     img.resize! size001, size001
     img.write img001
     img.resize! size002, size002
     img.write img002
     img.resize! size003, size003
     img.write img003
     File.delete tmpfile
   rescue Exception => err
     @upload_image_error = 'Could not process your image file.  Please
try again.' + err
     render :action => 'edit_image'
     @user.image_flag = 'Y'
     redirect_to :action => "profile", :username => @user.username

Thumbnail Images With Rmagick:

require 'RMagick'
 class PhotoController < ApplicationController
     def render_resized_image
                 maxw = @params["width"] != nil ? @params["width"].to_i : 90
                 maxh = @params["height"] != nil ? @params["height"].to_i : 90
                 aspectratio = maxw.to_f / maxh.to_f
                 pic = Magick::Image.from_blob(@photo.image)[0]
                 picw = pic.columns
                 pich = pic.rows
                 picratio = picw.to_f / pich.to_f
                 if picratio > aspectratio then
                         scaleratio = maxw.to_f / picw
                         scaleratio = maxh.to_f / pich
                 thumb = pic.resize(scaleratio)

Thumbnailer Number Two With Rmagick!

require 'RMagick'

maxwidth = 120
maxheight = 160
aspectratio = maxwidth.to_f / maxheight.to_f
imgfile = 'world'

pic = + '.jpg').first
imgwidth = pic.columns
imgheight = pic.rows
imgratio = imgwidth.to_f / imgheight.to_f
imgratio > aspectratio ? scaleratio = maxwidth.to_f / imgwidth : scaleratio = maxheight.to_f / imgheight
thumb = pic.resize(scaleratio)

white_bg =, thumb.height)
pic = white_bg.composite(thumb, Magick::CenterGravity, Magick::OverCompositeOp)
pic.write(imgfile + '.thumb.jpg')

Database storage of uploaded images

class DbFile < ActiveRecord::Base
  IMAGE_TYPES = ['image/jpeg', 'image/pjpeg', 'image/gif', 'image/png', 'image/x-png']
  before_validation     :sanitize_filename
  validates_presence_of :size, :filename, :content_type

  class << self
    def new_file(file_data)
      content_type = file_data.content_type.strip
      (IMAGE_TYPES.include?(content_type) ? DbImage : DbFile).new \
        :data         =>,
        :filename     => file_data.original_filename,
        :size         => file_data.size,
        :content_type => content_type

  def sanitize_filename
      # NOTE: File.basename doesn't work right with Windows paths on Unix
      # get only the filename, not the whole path
      filename.gsub! /^.*(\\|\/)/, ''

      # Finally, replace all non alphanumeric, underscore or periods with underscore
      filename.gsub! /[^\w\.\-]/, '_'

require 'rmagick'
require 'base64'
class DbImage < DbFile
  def data=(file_data)
    with_image(file_data, true) do |img|
      self.width  = img.columns
      self.height = img.rows

  def with_image(file_data = nil, save_image = false, &block)
    img = Magick::Image::read_inline(Base64.b64encode(file_data ||
    write_attribute('data', img.to_blob) if save_image
    img = nil

Controller Usage:

# returns DbImage if content_type matches
db_file = DbFile.new_file(params[:file][:data])

Model Usage:

# raw binary image data'my_file', 'w') { |f| f.write( }

# Image resizing with rmagick
# automatically creates RMagick::Image and 
# invokes GC.start
db_file.with_image do |img|

Rotating Images With RMagick and Ruby on Rails

This is archived from:Here

Photo model is fairly simple:

class Photo < ActiveRecord::Base
  file_column :file,
              :magick => {
                :size => ‘440×330',
                :crop => ‘4:3',
                :versions => {
                    :square => {
                                :crop => ‘1:1',
                                :size => ‘100×100'}

Basically, this crops the uploaded photo so that it is 4:3 in ratio with a max width of 440 and a max height of 330. It also creates a square thumbnail version that is 100px on each side. That was simple and easy and after a tweak, uploading and resizing was working great. I figured that rotating an image would be simple, so I browsed the RMagick docs until I found rotate. Yep, it is simple.

Add photos controller named rotate like so:

def rotate
    photo   = Photo.find(params[:id])
    degrees = if params[:direction] == 'left' then -90 else 90 end

    #main photo
    image   =
    image   = image.rotate(degrees)

    # thumb
    thumb   =  RAILS_ROOT + "/public/photo/file/#{}/square/#{File.basename(photo.file)}"
    image   =
    image   = image.rotate(degrees)

    redirect_to :action => 'list'

Rotating the main image

The first line finds the photo based on the id passed. I also pass a direction (either left or right). Based on the direction, I either rotate the photo 90 degrees (clockwise) or -90 degrees (counter clockwise). photo.file is the path to the image I want to resize. After having determined the degrees, I created a new RMagick image object and rotated it by degrees. image.write(photo.file) simply saves the rotated file. One photo down, but one more rotation to go.

Rotating the square thumbnail

The square thumbnail was trickier. File column by default stores files in public/model_name/column_name/id/name_of_image.jpg. Different versions of the image are then stored inside a folder named the same as the version name. For example, because my model is ‘photo’ and the column name is ‘file’, an image with an id of 24 would be stored in public/photo/file/24/name_of_image.jpg and a version of that photo named square would be stored in public/photo/file/24/square/name_of_image.jpg. Knowing this, I just made the thumbnail file path the RAILS_ROOT plus the known path and file name. I then performed the same rotation on the square version as the original and saved the changes. Nothing to complex, but I was feeling pretty good about the result. All that was left to do was add some fancy little arrows (as you saw above) and my rotation addition was complete. For those that are curious below is the code to show the arrow images and make them link to the rotation action is shown below. Happy rotating!

<%= link_to image_tag('admin/arrow_rotate_anticlockwise.gif', {:alt => 'Rotate Clockwise'}), :action => 'rotate', :id =>, :direction => 'left' %>

<%= link_to image_tag('admin/arrow_rotate_clockwise.gif', {:alt => 'Rotate Clockwise'}), :action => 'rotate', :id =>, :direction => 'right' %>

Rotating has an negative effect on the quality of the image. In order to rectify this, you have to add a block after each image.write call like so:

image.write(photo.file) {self.quality = 100}