Carrierwave: Saving Best Image Geometry

Back | rails, ruby | 4/4/2011 |

I recently needed to find out the geometry of the image being uploaded via Carrierwave. Images come in many different sizes and shapes. What I want is to have a “best” image and store its actual size along with my image model.

Define a Best Image

First, lets define a “best” version of the image. That’s one that’s not being resized, only converted into JPG.

  1. class ArtworkUploader < CarrierWave::Uploader::Base
  2.   version :best do
  3.     process :convert => 'jpg'
  4.   end
  5. end

Fetch Geometry on Upload

Notice the process declarations above: both resize_to_limit and convert are methods of the uploader class. We can therefore add a new get_geometry function and store the geometry of the uploaded image with this version.

  1. class ArtworkUploader < CarrierWave::Uploader::Base
  2.   include CarrierWave::RMagick
  3.  
  4.   version :best do
  5.     process :convert => 'jpg'
  6.     process :get_geometry
  7.     
  8.     def geometry
  9.       @geometry
  10.     end
  11.   end
  12.   
  13.   def get_geometry
  14.     if (@file)
  15.       img = ::Magick::Image::read(@file.file).first
  16.       @geometry = [ img.columns, img.rows ]
  17.     end
  18.   end
  19. end

Save Geometry

Finally, we would like to store best_width and best_height with the Image model. We use MongoId, so we can fetch the geometry before_save.

  1. class Image
  2.   
  3.   field :best_width
  4.   field :best_height
  5.  
  6.   before_save :saving
  7.  
  8.   def saving
  9.     geometry = self.image.best.geometry
  10.     if (! geometry.nil?)
  11.       self.best_width = geometry[0]
  12.       self.best_height = geometry[1]
  13.     end
  14.   end  
  15.  
  16. end

I think image geometry should be a built-in function and property of Carrierwave. Maybe this can be improved further and make it into the library?