ruby on rails - notidentifiedbyimagemagickerror - Guardar las dimensiones de las imágenes(ancho y alto) en Paperclip?
paperclip::errors::missingrequiredvalidatorerror (6)
Cuando un usuario carga una imagen con clip, la proceso con el siguiente modelo:
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
La función get_geometry
llama a ImageMagick identify
para encontrar la geometría de sus imágenes originales y redimensionadas.
Guardo los resultados en un campo de base de datos. Por ejemplo, si subí una imagen que era 1024x768
mis campos en caché contendrían:
original_geometry = "1024x768"
small_geometry = "100x75"
Cualquier asistente de Paperclip sabe si puede usar Paperclip para guardar una imagen, también guarda las dimensiones de la imagen (ancho y alto) en 2 campos adicionales. ¿Cómo se obtienen esos datos durante el proceso de carga de Paperclip?
Encontré la solución más simple: gema Fastimage (link)
Es rápido y muy, muy simple. Ejemplo:
require ''fastimage''
FastImage.size("/some/local/file.gif")
=> [266, 56] # width, height
FastImage.type("/some/local/file.gif")
=> :gif
La gema paperclip-meta almacena en caché las dimensiones de la imagen y el tamaño del archivo para todos los estilos de imagen. Se hace referencia en el Paperclip README. El paperclip-meta repo está aquí: https://github.com/teeparham/paperclip-meta
Necesitarás requerir ''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
Sin embargo, no estoy seguro de cómo hacerlo funcionar con las devoluciones de llamada. Tal vez algo así como:
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
Solo para completar, aunque las respuestas anteriores ya muestran sugerencias bastante buenas.
Puede utilizar manejadores de eventos Paperclip en lugar de devoluciones de llamada de Rails. En este caso, el tamaño se volverá a calcular solo cuando la imagen cambie. (Si está utilizando S3 para almacenamiento, esto puede ahorrar bastante tiempo)
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
La imagen ni siquiera tiene que descargarse de S3 (o leer de un archivo), el clip lo proporciona al controlador de eventos.
Ver la sección de Eventos del archivo léame para más detalles.
Uso de Rails 4 Utilizo la siguiente Preocupación para guardar las dimensiones de la imagen:
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
Entonces en tu modelo:
...
include Dimensions
extract_dimensions_for :image
...
Esto guardará sus dimensiones en un campo serializado llamado image_dimensions
así como también agregará algunos otros métodos image_width
, image_height
y image_dimensions_max(width, height)