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?
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.
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"
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
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)
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
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
© 2022 - 2024 — McMap. All rights reserved.