Paperclip obtain real image size - ruby-on-rails

My problem is the next:
I am trying resize a image size depending a proportial size. Example If i have a image whose size is 1440*1000 its new size will be 648*440 (I use a proportion depending a max_size)
NOTE: Then i post my code so you will understand the size relations.
Ok. so I am reading this stackoverflow post:
Getting width and height of image in model in the Ruby Paperclip GEM
Now i post my code and then i will describe my problem.
class ProductImage < ActiveRecord::Base
belongs_to :product, :dependent => :destroy
MAXIMUM_SIZE = 650
has_attached_file :photo, :url => "/:attachment/:class/:id/:style_:basename.:extension", :styles => {:real_size => Proc.new { |instance| instance.real_size }, :original => "400x400>", :medium => "300x300>", :principal => "240x240>", :thumb => "100x100>", :small => "80x50>"}
def real_size
#image = Paperclip::Geometry.from_file(photo.to_file(:maximum_size))
#OBTAIN REAL IMAGE SIZE, NOT ATTACHMENT SIZES
if image_less_than_maximum_size?
return "#{image.width}x#{image.height}"
else
return adjust_image_size(self.width, self.height)
end
end
def adjust_image_size(image_width, image_height)
ratio = (image_width/image_height).to_f
difference_between_size = (image_width - image_height).abs
percentage_difference = ratio > 1 ? difference_between_size * 100.0 / image_width : difference_between_size * 100.0 / image_height
difference_respect_maximum_size = ratio > 1 ? MAXIMUM_SIZE * 100.0 / image_width : MAXIMUM_SIZE * 100.0 / image_height
width = height = 0.0
if ratio > 1
#USE 101.0 FOR INCREMENT OR DECREMENT THE VALUE A LITTLE BIT
width = image_width * difference_respect_maximum_size / 101.0
height = width - (percentage_difference * width / 101.0)
else
heigth = image_height * difference_respect_maximum_size / 101.0
width = height - (percentage_difference * height / 101.0)
end
return "#{width}x#{height}"
end
def image_less_than_maximum_size?
if self.width > self.height
return self.width < MAXIMUM_SIZE
else
return self.height < MAXIMUM_SIZE
end
end
end
My problem is how could i obtain the "real_size"?.
i.e, if image size is "1440*1000" to obtain this size (no attachment size)
UPDATE:
I am thinking a solution. So i think in declare two temp variable to ProductImage model and during initialize method use a before_post_process paperclip callback.
class ProductImage < ActiveRecord::Base
belongs_to :product, :dependent => :destroy
attr_accessor :height, :width
MAXIMUM_SIZE = 650
has_attached_file :photo, :url => "/:attachment/:class/:id/:style_:basename.:extension", :styles => {:real_size => Proc.new { |instance| instance.real_size }, :original => "400x400>", :medium => "300x300>", :principal => "240x240>", :thumb => "100x100>", :small => "80x50>"}
before_post_process :image?
before_post_process :assign_size
...
def assign_size
#width = Paperclip::Geometry.from_file(remote_original_photo_path).width
#height = Paperclip::Geometry.from_file(remote_original_photo_path).height
end
end
Then i could use this size in the other method.
My new problem is how could I determine the remote_original_photo_path in model?
in controller i use the params[:product][:product_images_attributes][index][:photo].
I could save the temp path in model. However because my real_size method during initilize i donĀ“t know how to pass the params info.
Thanks in advance again

With using a gem like image_size ?
[EDIT]
To determine the original upload path may be you can use :
remote_original_photo_path = File.basename(upload['datafile'].original_path)

Related

How to Re-size Images that are Too Large on-the-fly with Paperclip and Rails 3

I am trying to implement the steps to check and resize images with paperclip based on this blog post: http://www.techdarkside.com/how-to-re-size-images-that-are-too-large-on-the-fly-with-paperclip-and-rails
Here is what I have in place...
class Question < ActiveRecord::Base
# subclasses
class Question::Image < Asset
has_attached_file :attachment,
:url => "/uploads/:class/:attachment/:id_partition/:basename_:style.:extension",
:styles => Proc.new { |attachment| attachment.instance.styles },
:styles => Proc.new { |attachment| attachment.instance.resize }
attr_accessible :attachment
# http://www.ryanalynporter.com/2012/06/07/resizing-thumbnails-on-demand-with-paperclip-and-rails/
def dynamic_style_format_symbol
URI.escape(#dynamic_style_format).to_sym
end
def styles
unless #dynamic_style_format.blank?
{ dynamic_style_format_symbol => #dynamic_style_format }
else
{ :medium => "300x300>", :thumb => "100x100>" }
end
end
def dynamic_attachment_url(format)
#dynamic_style_format = format
attachment.reprocess!(dynamic_style_format_symbol) unless attachment.exists?(dynamic_style_format_symbol)
attachment.url(dynamic_style_format_symbol)
end
def resize
if self.attachment_file_size > 2000000
"300x300>"
else
" "
end
end
end
I'm thinking the issue is with the reuse of the :styles symbol, however I'm not sure how to work both the styles method AND the resize method into a single Proc statement.
Here is what I ended up with thanks to #janfoeh suggestion. I did need to add :originalto the options in style to get this to work. I also bumped the max file size up to 5mb.
class Question < ActiveRecord::Base
# subclasses
class Question::Image < Asset
has_attached_file :attachment,
:url => "/uploads/:class/:attachment/:id_partition/:basename_:style.:extension",
:styles => Proc.new { |attachment| attachment.instance.styles }
attr_accessible :attachment
# http://www.ryanalynporter.com/2012/06/07/resizing-thumbnails-on-demand-with-paperclip-and-rails/
def dynamic_style_format_symbol
URI.escape(#dynamic_style_format).to_sym
end
def styles
unless #dynamic_style_format.blank?
{ dynamic_style_format_symbol => #dynamic_style_format }
else
{ :original => resize, :medium => "300x300>", :thumb => "100x100>" }
end
end
def dynamic_attachment_url(format)
#dynamic_style_format = format
attachment.reprocess!(dynamic_style_format_symbol) unless attachment.exists?(dynamic_style_format_symbol)
attachment.url(dynamic_style_format_symbol)
end
def resize
if self.attachment_file_size > 5000000
"1000x1000>"
else
" "
end
end
end

Paperclip: width is 100%, height is 60% of width

How would I write a Paperclip style to keep the width of the uploaded image at 100% but crop only the height to 60% of the width?
Something like this:
has_attached_file :image, :styles => { :cropped => "100%x[60% of height]" }
has_attached_file :image, :styles => {
:original => "100x60>",
:thumb => Proc.new { |instance| instance.resize }
}
#### End Paperclip ####
def resize
geo = Paperclip::Geometry.from_file(image.to_file(:original))
height = (geo.width.to_i * 60)/100
width = geo.width
"#{width.round}x#{height.round}!"
end
Hope this could help you
has_attached_file :image, :styles => after_save :save_image_dimensions
def save_image_dimensions
geo = Paperclip::Geometry.from_file(image.path)
self.image_height = (geo.height.to_i * 60)/100
end
If you have problem on extract dimension From below you can get a good help
https://github.com/thoughtbot/paperclip/wiki/Extracting-image-dimensions
Please look into this link for cropping images using paperclip
http://viget.com/extend/manual-cropping-with-paperclip
Thanks

How to make Paperclip crop and NOT scale an attached image?

I want Paperclip to crop, and not scale (see :full1 in this excerpt)
class Graphic < ActiveRecord::Base
has_attached_file :image, :styles => { :full0 => "940x1000#" #want it to scale, and crop if neccessary
:full1 => "940#", #want it to crop width, not scale
}
I want :full1 to work, but it doesn't. By "work" I mean it should crop the image's width, but do nothing to it's height. The reason is I'm uploading web screenshots, and I want them to be trimmed to 940px wide (from the center), but their height should remain intact. As far as what I research on paperclip I'm not finding how to do this.
Apparently it's quite supported by ImageMagick: http://www.imagemagick.org/Usage/crop/#crop_strip But I don't know how to jam this into paperclip on rails.
Many thanks!
Could you just set the height to something absurdly large so that it will be a non-issue?
class Graphic < ActiveRecord::Base
has_attached_file :image, :styles => { :full0 => "940x1000#" #want it to scale, and crop if neccessary
:full1 => "940x9999999#", #want it to crop width, not scale
}
I think that will crop anything wider than 940px.
You can user convert options for image process, Following will crop the image centrally.
has_attached_file :profile_picture, :storage => :s3,
:styles => { :medium => "", :thumb => ""},
:convert_options => {
:thumb => Proc.new { |instance| instance.thumnail_dimension },
:medium => Proc.new { |instance| instance.thumnail_dimension(300) }
}
def thumnail_dimension(size=100)
dimensions = Paperclip::Geometry.from_file(profile_picture.queued_for_write[:original].path)
min = dimensions.width > dimensions.height ? dimensions.height : dimensions.width
"-gravity Center -crop #{min}x#{min}+0+0 +repage -resize #{size}x#{size}^"
end

Validate image size in carrierwave uploader

All uploads should be at least 150x150 pixels. How to validate it with Carrierwave?
Why not to use MiniMagick? Modified DelPiero's answer:
validate :validate_minimum_image_size
def validate_minimum_image_size
image = MiniMagick::Image.open(picture.path)
unless image[:width] > 400 && image[:height] > 400
errors.add :image, "should be 400x400px minimum!"
end
end
I made a slightly more complete validator based on #skalee's answer
class ImageSizeValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
unless value.blank?
image = MiniMagick::Image.open(value.path)
checks = [
{ :option => :width,
:field => :width,
:function => :'==',
:message =>"Image width must be %d px."},
{ :option => :height,
:field => :height,
:function => :'==',
:message =>"Image height must be %d px."},
{ :option => :max_width,
:field => :width,
:function => :'<=',
:message =>"Image width must be at most %d px."},
{ :option => :max_height,
:field => :height,
:function => :'<=',
:message =>"Image height must be at most %d px."},
{ :option => :min_width,
:field => :width,
:function => :'>=',
:message =>"Image width must be at least %d px."},
{ :option => :min_height,
:field => :height,
:function => :'>=',
:message =>"Image height must be at least %d px."},
]
checks.each do |p|
if options.has_key?(p[:option]) and
!image[p[:field]].send(p[:function], options[p[:option]])
record.errors[attribute] << p[:message] % options[p[:option]]
end
end
end
end
end
Use it like validates :image, :image_size => {:min_width=>400, :min_height => 400}.
It surprised me just how difficult it was to search around for a clear-cut way to validate image width & height with CarrierWave. #Kir's solution above is right on, but I wanted to go a step further in explaining what he did, and the minor changes I made.
If you look at his gist https://gist.github.com/1239078, the answer lies in the before :cache callback he has in the Uploader class. The magic line is
model.avatar_upload_width, model.avatar_upload_height = `identify -format "%wx %h" #{new_file.path}`.split(/x/).map { |dim| dim.to_i }
in his case, avatar_upload_width & avatar_upload_height are attributes of his User model. I didn't want to have to store width&height in the database, so in my model I said:
attr_accessor :image_width, :image_height
Remember, you can use attr_accessor for attributes you want to have on hand when messing with a record, but just don't want to persist them to the db. So my magic line actually turned into
model.image_width, model.image_height = `identify -format "%wx %h" #{new_file.path}`.split(/x/).map { |dim| dim.to_i }
So now I have the width & height of my image stored in the model object. The last step is to write a custom validation for the dimensions, so in your model you need something like
validate :validate_minimum_image_size
And then below it define your custom validation method, same as in the gist
# custom validation for image width & height minimum dimensions
def validate_minimum_image_size
if self.image_width < 400 && self.image_height < 400
errors.add :image, "should be 400x400px minimum!"
end
end
I just made a custom validator that aims to be more Rails 4+ syntax friendly.
I took ideas from the others responses on this thread.
Here is the gist: https://gist.github.com/lou/2881f1aa183078687f1e
And you can use it like this:
validates :image, image_size: { width: { min: 1024 }, height: { in: 200..500 } }
In this particular case it should be:
validates :image, image_size: { width: 150, height: 150 }

Getting width and height of image in model in the Ruby Paperclip GEM

Trying to get the width and height of the uploaded image while still in the model on the initial save.
Any way to do this?
Here's the snippet of code I've been testing with from my model. Of course it fails on "instance.photo_width".
has_attached_file :photo,
:styles => {
:original => "634x471>",
:thumb => Proc.new { |instance|
ratio = instance.photo_width/instance.photo_height
min_width = 142
min_height = 119
if ratio > 1
final_height = min_height
final_width = final_height * ratio
else
final_width = min_width
final_height = final_width * ratio
end
"#{final_width}x#{final_height}"
}
},
:storage => :s3,
:s3_credentials => "#{RAILS_ROOT}/config/s3.yml",
:path => ":attachment/:id/:style.:extension",
:bucket => 'foo_bucket'
So I'm basically trying to do this to get a custom thumbnail width and height based on the initial image dimensions.
Any ideas?
Ahh, figured it out. I just needed to make a proc.
Here's the code from my model:
class Submission < ActiveRecord::Base
#### Start Paperclip ####
has_attached_file :photo,
:styles => {
:original => "634x471>",
:thumb => Proc.new { |instance| instance.resize }
},
:storage => :s3,
:s3_credentials => "#{RAILS_ROOT}/config/s3.yml",
:path => ":attachment/:id/:style.:extension",
:bucket => 'foo_bucket'
#### End Paperclip ####
def resize
geo = Paperclip::Geometry.from_file(photo.to_file(:original))
ratio = geo.width/geo.height
min_width = 142
min_height = 119
if ratio > 1
# Horizontal Image
final_height = min_height
final_width = final_height * ratio
"#{final_width.round}x#{final_height.round}!"
else
# Vertical Image
final_width = min_width
final_height = final_width * ratio
"#{final_height.round}x#{final_width.round}!"
end
end
end
class Asset
include Mongoid::Paperclip
before_save :extract_dimensions
field :width, type: Integer
field :height, type: Integer
has_mongoid_attached_file :data
def extract_dimensions
return unless is_image?
tempfile = data.queued_for_write[:original]
unless tempfile.nil?
geometry = Paperclip::Geometry.from_file(tempfile)
self.width = geometry.width.to_i
self.height = geometry.height.to_i
end
true # wont save if false
end
def is_image?
data_content_type =~ %r{^(image|(x-)?application)/(bmp|gif|jpeg|jpg|pjpeg|png|x-png)$}
end
end

Resources