Adding Exif data to your Image model with exifr

Posted on · · Tags: paperclip

I’m now using this great little gem called exifr in my project. It’s fairly nimble, but gets the job done. To include it in your rails project, add the following line in your config/environment.rb

config.gem "exifr"

You’ll also want to add some fields to the model you are saving the exif data to. The exif reading is quite fast so you might want to do it on-the-fly, but then you don’t get some new fields on your models for all those cool queries. Let’s add it to our Image model.

class AddExifFieldsToImages < ActiveRecord::Migration
  def self.up
    add_column :images, :width, :integer
    add_column :images, :height, :integer
    add_column :images, :camera_brand, :string
    add_column :images, :camera_model, :string
    add_column :images, :exposure_time, :string
    add_column :images, :f_number, :float
    add_column :images, :iso_speed_rating, :integer
    add_column :images, :focal_length, :float
    add_column :images, :shot_date_time, :datetime
  end
 
  def self.down
    remove_column :images, :width
    remove_column :images, :height
    remove_column :images, :camera_brand
    remove_column :images, :camera_model
    remove_column :images, :exposure_time
    remove_column :images, :f_number
    remove_column :images, :iso_speed_rating
    remove_column :images, :focal_length
    remove_column :images, :shot_date_time
  end
end

These are the fields I normally use, but there are probably more that are worth saving.

In order to get some data into these fields, we create this little method in our Image model:

def set_exif_data
  exif = EXIFR::JPEG.new( self.data.path )
  return if exif.nil? or not exif.exif?
  self.width            = exif.width
  self.height           = exif.height
  self.camera_brand     = exif.make
  self.camera_model     = exif.model
  self.exposure_time    = exif.exposure_time.to_s
  self.f_number         = exif.f_number.to_f
  self.iso_speed_rating = exif.iso_speed_ratings
  self.shot_date_time   = exif.date_time
  self.focal_length     = exif.focal_length.to_f
rescue
  false
end

In this example I get the path of the file from self.data.path, where data is my paperclip attachment called :data. If you have some other setup, you’ll have to change this to fit your needs.

Calling this method sets the fields to the correct values, but does not save the object. Using the setup with delayed_job from the last article you can a line in your perform() method to get exif data for all new Images, making the method as a whole like this:

def perform
  self.processing = false
  set_exif_data # this is the line we added
  data.reprocess!
  save
end

And voila, you now have added exif data to your images! Now it’s time to think out something cool to do with it…

blog comments powered by Disqus