Saving the images Dimensions (width and height) in Paperclip?
Asked Answered
S

6

31

Any Paperclip wizards out there know if you can when using Paperclip to save an image, also save the image dimensions (width and height) in 2 extra fields? How do you get such data during the Paperclip upload process?

Sloop answered 31/10, 2010 at 21:43 Comment(0)
S
62

Just for the sake of completeness, even though previous answers already show good enough suggestions.

You can utilize Paperclip event handlers instead of Rails callbacks. In this case, size will be recalculated only when image changes. (If you're using S3 for storage, this can save quite some time)

has_attached_file :image, :styles => ...
after_post_process :save_image_dimensions

def save_image_dimensions
  geo = Paperclip::Geometry.from_file(image.queued_for_write[:original])
  self.image_width = geo.width
  self.image_height = geo.height
end

Image don't even have to be downloaded from S3 (or read from a file), paperclip provides it to event handler itself.

See Events section of the readme for details.

Surah answered 4/12, 2010 at 23:43 Comment(1)
downloaded 2 gems already to try (and fail) to achieve this. Wish I had found this simple snippet first. Many thanks :)Tonisha
U
5

When a user uploads an image with paperclip I process it with the following model:

class Picture < ActiveRecord::Base
  has_attached_file :pic, :styles => { :small => "100x100>" }, :whiny => true
  after_save :save_geometry

  def save_geometry
    unless @geometry_saved
      self.original_geometry = get_geometry(:original)
      self.small_geometry = get_geometry(:small)
      @geometry_saved = true
      self.save
    end
  end

  def get_geometry(style = :original)
    begin
      Paperclip::Geometry.from_file(pic.path(style)).to_s
    end
  end
end

The get_geometry function calls ImageMagick identify to find the geometry of your original and resized images.

I cache the results in a database field. For example if I uploaded an image that was 1024x768 my cached fields would contain:

original_geometry = "1024x768"
small_geometry = "100x75"
Unperforated answered 3/11, 2010 at 23:28 Comment(0)
N
0

You will need to require 'RMagick'

uploaded_image = Magick::Image.read(image).first  #image is what you've specified in paperclip to be your image
width = uploaded_image.columns
height = uploaded_image.rows

Not sure how to have it working with the callbacks, though. Maybe something like:

attr_accessor :write_image_dimensions?
before_save :check_image_changed

def check_image_changed
  self.write_image_dimensions? = image_changed?
end

after_save :write_image_dimensions, :if => :write_image_dimensions?

def write_image_dimensions
  uploaded_image = Magick::Image.read(image).first  #image is what you've specified in paperclip to be your image
  self.width = uploaded_image.columns
  self.height = uploaded_image.rows
  save
end
Nucleoprotein answered 31/10, 2010 at 22:53 Comment(0)
C
0

Using Rails 4 I use the following Concern to save image dimensions:

    module Dimensions

      extend ActiveSupport::Concern

      included do

      end

      module ClassMethods

        def extract_dimensions_for *fields

          define_method(:extract_dimensions_field_list) { fields }

          before_save :extract_dimensions

          fields.each do |f|
            serialize (f.to_s+"_dimensions"), Hash

            class_eval do

              [:width, :height].each do |axis|
                define_method("#{f}_#{axis}") do
                  return send(f.to_s+"_dimensions")[axis]
                end
              end

              define_method("#{f}_dimensions_max") do |width, height=nil|
                dims = send(f.to_s+"_dimensions")
                rw = width.to_f / dims[:width]
                rh = height.to_f / dims[:height] if height
                r = (!height || rw < rh) ? rw : rh
                return {width: (dims[:width] * r).to_i, height: (dims[:height] * r).to_i}
              end

              define_method("#{f}_is_portrait?") do
                dims = send(f.to_s+"_dimensions")
                return dims[:width] <= dims[:height]
              end

              define_method("#{f}_is_landscape?") do
                dims = send(f.to_s+"_dimensions")
                return dims[:width] > dims[:height]
              end

            end

          end

          class_eval do

            def extract_dimensions

              extract_dimensions_field_list.each do |f|

                tempfile = send(f).queued_for_write[:original]
                unless tempfile.nil?
                  geometry = Paperclip::Geometry.from_file(tempfile)
                  self.send(f.to_s+"_dimensions=", {width: geometry.width.to_i, height: geometry.height.to_i})
                end

              end

            end

          end

        end

      end


    end

Then in your model:

...

include Dimensions

extract_dimensions_for :image

...

This will save your dimensions to a serialized field called image_dimensions as well as adding a few other methods image_width, image_height and image_dimensions_max(width, height)

Comer answered 1/6, 2015 at 0:45 Comment(0)
S
0

I found the simplest solution: Fastimage gem (link)

It is fast and very, very simple. Example:

require 'fastimage'

FastImage.size("/some/local/file.gif")
=> [266, 56]  # width, height
FastImage.type("/some/local/file.gif")
=> :gif
Sulfathiazole answered 10/3, 2016 at 9:22 Comment(0)
C
0

The paperclip-meta gem caches image dimensions and file size for all image styles. Its referenced in the Paperclip README. The paperclip-meta repo is here: https://github.com/teeparham/paperclip-meta

Curling answered 17/3, 2017 at 8:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.