Rails 3, Paperclip and uploading image from remote url - ruby-on-rails

I wrote simple code which takes url of an image, and uploads resized version of it to Amazon S3 storage. Code looks like this:
attr_accessor :profile_image_url
has_attached_file :avatar,
:default_url => "/system/avatars/:style_default.png",
:styles => {
:original => "128x128#",
:thumb => "48x48#"
},
:storage => :s3,
:s3_credentials => "#{RAILS_ROOT}/config/s3.yml",
:path => "/avatars/:id/:style.:extension"
before_validation :download_profile_pic
...
def download_profile_pic
begin
io = open(URI.parse(self.profile_image_url))
def io.original_filename; base_uri.path.split('/').last; end
self.avatar = io.original_filename.blank? ? nil : io
rescue Timeout::Error
self.avatar = nil
rescue OpenURI::Error => e
self.avatar = nil
end
end
It works, but the images are uploaded in a very low quality. What could be a problem?

It looks like the issue is the geometry string on your main image size, try changing:
:styles => {
:original => "128x128#",
:thumb => "48x48#"
},
to
:styles => {
:original => "128x128>",
:thumb => "48x48#"
},
Which should only resize/transform the image if the dimensions are too large.

Related

Paperclip error when uploading video: can't dump File

When I try to upload a video using Paperclip, I get an error message can't dump File.
Model Video :
class Video < ActiveRecord::Base
has_attached_file :avatar,
:storage => :s3,
:styles => {
:mp4 => { :geometry => "640x480", :format => 'mp4' },
:thumb => { :geometry => "300x300>", :format => 'jpg', :time => 5 }
}, :processors => [:ffmpeg]
validates_attachment_presence :avatar
validates_attachment_content_type :avatar,
:content_type => /video/,
:message => "Video not supported"
end

Paperclip dynamic Proc styles called before object initialized

I have the following paperclip setup. What happens is that I'm using a proc to set the sizes for various styles. However, the proc gets called on new and during the super call. I walked through the debugger and it seems like it processes the :photo parameter first so it initializes the attachment and calls the styles proc at which point the actual object (Photo) has not been initialized by the passed in params(particularly the photo.gallery_id so it doesn't set the styles correctly. I even tried reprocessing and it didn't help. I've spent a couple of days on this and still no luck. any help is appreciated!
class Photo < ActiveRecord::Base
has_and_belongs_to_many :staffs
has_attached_file :photo,
:storage => :s3,
:s3_credentials => "#{RAILS_ROOT}/config/s3.yml",
:path => "/assets/:id/:class/:style/:image_name.:extension",
:url => "/assets/:id/:class/:style/:image_name.:extension",
:styles => Proc.new { |clip| clip.instance.attachment_styles}
def attachment_styles
if self.gallery.nil?
{ :original => {
:processors => [:watermark],
:geometry =>"600x800!",
:watermark_path => ':rails_root/public/images/watermark.png',
:position => 'SouthEast'},
:thumbnail => {
:processors => [:watermark],
:geometry => "200x300!",
:watermark_path => ':rails_root/public/images/watermark.png',
:position => 'SouthEast'}
}
elsif self.photo.styles.empty?
gallery_type = GalleryType.find_by_id(self.gallery_id)
{ :original => {
:processors => [:watermark],
:geometry =>"#{gallery_type.width_max}x#{gallery_type.height_max}!",
:watermark_path => ':rails_root/public/images/watermark.png',
:position => 'SouthEast'},
:thumbnail => {
:processors => [:watermark],
:geometry => "#{gallery_type.width_min}x#{gallery_type.height_min}!",
:watermark_path => ':rails_root/public/images/watermark.png',
:position => 'SouthEast'}
}
else
self.photo.styles
end
end
def reprocess_att
self.photo.reprocess!
end
def initialize(galleryid, params = {})
begin
param.merge!({"gallery_id" => galleryid.to_s})
super(params)
rescue => e
puts e.message()
end
end
From what I can see, the order of the parameters is important. I had:
attachments.build(:upload => File.new(File.dirname(__FILE__) + '/../fixtures/test-image.jpg'),
:styles => {:small => ['100x100#', :jpg], :medium => ['250x250', :jpg]})
And this wasn't setting up the styles correctly. They they were nil. I changed it to:
attachments.build(:styles => {:small => ['100x100#', :jpg], :medium => ['250x250', :jpg]},
:upload => File.new(File.dirname(__FILE__) + '/../fixtures/test-image.jpg'))
And then the code:
:styles => lambda { |a| a.instance.styles || {} }
worked perfectly. Hope this helps.
Thanks for the answer!
I've been fighting with this for a few weeks now. I'm using Paperclip with FFMPEG to make thumbnails of uploaded videos. I have an option to set what frame to use as the thumbnail.
I'm also using a nested form (awesome nested forms) for my asset upload. So what I did was put the frame time param before the file browse button. This solved the problem for me since I'm not using builder.

How can I reduce the quality of an uploading image using Paperclip?

I am running Ruby on Rails 3 and I would like to reduce the quality of an uploading image using the Paperclip plugin/gem. How can I do that?
At this time in my model file I have:
has_attached_file :avatar,
:styles => {
:thumb => ["50x50#", :jpg],
:medium => ["250x250#", :jpg],
:original => ["600x600#", :jpg] }
that will convert images in to the .jpg format and will set dimensions.
Try using convert_options.
has_attached_file :avatar,
:styles => { :thumb => '50x50#' },
:convert_options => { :thumb => '-quality 80' }
From the paperclip wiki, there's an option for quality:
class User < ActiveRecord::Base
has_attached_file :photo,
:styles => {
:small => {
:geometry => '38x38#',
:quality => 40,
:format => 'JPG'
},
:medium => {
:geometry => '92x92#',
:quality => 50
}
end
As James says, once you figure out the correct arguments to pass to ImageMagick's convert by experimenting on the command line, you can pass these in to Paperclip through the convert_options option as in James' example.
If you have multiple arguments, pass them in as an array. Here's an example which I laboured over for a while:
:convert_options => {:medium => ["-shave", "2x2", "-background", "white",
"-gravity", "center", "-extent",
"530x322", "+repage"],
:small => ["-shave", "1x1"] }
Except -quality, the -strip option of ImageMagick can remove all profile and other fluff from the image which may reduce more size
has_attached_file :photo,
:styles => {
:thumb => "100x100#" },
:convert_options => {
:thumb => "-quality 75 -strip" }

rails model callbacks

How can I do something inside the model depending on the whether it's creating or updating a record? I'm sure it's really simple, but I can't seem to figure it out.
These are different styles for updating or creating attachments with paperclip.
class Photo < ActiveRecord::Base
belongs_to :product
#after_upate :flag_somthin
Paperclip.interpolates :product_id do |attachment, style|
attachment.instance.product_id
end
has_attached_file :data,
:storage => 's3',
:s3_credentials => "#{RAILS_ROOT}/config/s3_credentials.yml",
:bucket => 'leatherarts.com',
:s3_host_alias => 'leatherarts.com.s3.amazonaws.com',
:url => ':s3_alias_url',
:path => "images/products/:product_id/:style/:basename.:extension",
:styles => lambda { |style| style.instance.choose_styles },
:default_style => :medium,
:default_url => 'http://leatherarts.com.s3.amazonaws.com/images/records/m1.png',
:s3_headers => { 'Expires' => 2.months.from_now.httpdate }
validates_attachment_presence :data
validates_attachment_size :data, :less_than => 10.megabytes
validates_attachment_content_type :data, :content_type => ['image/jpeg','image/gif','image/png']
def choose_styles
{ :thumb => "60x60#", :small => "200x200>", :medium => "400x400>", :large => "1000x1000>", :backup => "2000x2000>" }, :on => :create
{ :thumb => "60x60#", :small => "200x200>", :medium => "400x400>", :large => "1000x1000>" }, :on => :update
end
end
Use the new_record? method to return different hashes:
def choose_styles
defaults = { :thumb => "60x60#", :small => "200x200>", :medium => "400x400>", :large => "1000x1000>" }
defaults.merge! :backup => "2000x2000>" if new_record?
defaults
end

Styles in Paperclip only if it's an image [rails]

I'm using paperclip to upload all sorts of files (text documents, binaries, images).
I'd like to put this in my model:
has_attached_file :attachment, :styles => { :medium => "300x300>", :thumb => "100x100>" }
but it has to perform the styles only if it's an image. I tried adding
if :attachment_content_type =~ /^image/
but it didn't work.
You can use before_<attachment>_post_process callback to halt thumbnail generation for non-images. If you return false in callback, there will be no attempts to use styles.
See "Events" section in docs
before_attachment_post_process :allow_only_images
def allow_only_images
if !(attachment.content_type =~ %r{^(image|(x-)?application)/(x-png|pjpeg|jpeg|jpg|png|gif)$})
return false
end
end
May be you need something like this:
:styles => lambda { |attachment|
!attachment.instance.image? ? {} : {:thumb => "80x24", :preview => "800x600>"}
}
And define method in your model:
def image?
attachment.content_type.index("image/") == 0
end
You can use on your model
`has_attached_file :avatar,
:styles => lambda { |a| if a.content_type =~ %r{^(image|(x-)?application)/(x-png|pjpeg|jpeg|jpg|png|gif)$}
{
:thumb => "100x100#",
:medium => "300x300>",
}
else
Hash.new
end
},:default_url => "/missing.png"`

Resources