Search code examples
ruby-on-railsrubycarrierwaveminimagick

Get actual dimensions of image uploaded with carrierwave using fastimage


I am trying to get the dimensions of a image using carrierwave but I was hoping to get the dimensions with my own code I created trying to run fastimage after_save or after commit. I get this error:

wrong number of arguments (1 for 0)
  Extracted source (around line #45): 
  # [String] contents of the file
  #
  def read
    file.read if file.respond_to?(:read)
  end

carrierwave (0.11.2) lib/carrierwave/uploader/proxy.rb:45:in `read'
fastimage (2.1.0) lib/fastimage.rb:343:in `block in fetch_using_read'

model would look something like this

class Micropost < ApplicationRecord

  after_save :change_picture_dimensions
  mount_uploader :picture, PictureUploader

 def change_picture_dimensions
  if :picture?
    widthheight = FastImage.size(picture)
    if widthheight[0] >= 501
      newheightratio =  widthheight[1].to_f / widthheight[0].to_f
  newheight = newheightratio * 500
      self.picture = "<img src=\"" + picture.to_s + "\" width=\"500\" height=\"" +  newheight.to_s + "\">"
      else
      self.picture = "<img src=\"" + picture.to_s + "\" width=\"" + widthheight[0].to_s + "\" height=\"" + widthheight[1].to_s + "\">"
      end
    end
  end

This is just a local file on my system. I can get dimensions using minimagick here but wanted to know more about the process of carrierwave and why I cannot use my method to get the dimensions cause of this error? In my method I am just using a ratio to keep the aspect ratio but fit into the fixed width of a div I have for any image.

EDIT: I realised I need to do it before the object is saved but even with before_create I get the same error.


Solution

  • You cannot assign picture a string. It must be an URL, file or an IO object.

    If you want to preprocess your image width to fit 500px just declare the following:

    # app/uploaders/picture_uploader.rb
    class PictureUploader < CarrierWave::Uploader::Base
       ...
       process resize_to_fit: [500, nil]
    end
    
    class Micropost < ApplicationRecord
      mount_uploader :picture, PictureUploader
    end
    

    To save an image from another server you can do:

    micropost = Micropost.create(
      picture: 'http://server.example.org/image.png'
    )
    

    and now you can render it on the page

    = image_tag micropost.picture.url
    

    You can also store image size in your model. Read this documentation how to do this. After you saved your image dimensions into a picture model, you can specify them in image_tag, but it will be redundant I think because browser will detect image size automatically

    = image_tag micropost.picture.url, width: picture.width, height: picture.height