My rails app uses Paperclip and ImageMagick to process uploaded photos.
I currently have it set up like this
as_attached_file :photo, :styles => { :original => "1500x1500>", :thumb => "400x400>#", :large => "1080x1080>" }, :convert_options => { :thumb => '-quality 60', :large => '-quality 60'}, :default_url => "/missing.png"
If someone uploads an image with dimension 1000x100 (10:1 aspect ratio) for example I would like to limit the aspect ratio (on the :large and :original) so that it will crop the image if the aspect ratio is too extreme.
ie: if ratio is beyond 4:1 or 1:4 then crop
The best way to do this is to implement a custom processor. That way you can implement your logic and decide when to change the image the way you want.
See an example implementation of a custom processor. In my case I needed to apply a watermark on the images.
lib/paperclip_processors/watermark.rb
module Paperclip
class Watermark < Thumbnail
attr_accessor :format, :watermark_path, :watermark_gravity, :watermark_dissolve
def initialize file, options = {}, attachment = nil
super
#file = file
#format = options[:format]
#watermark_path = options[:watermark_path]
#watermark_gravity = options[:watermark_gravity].nil? ? "center" : options[:watermark_gravity]
#watermark_dissolve = options[:watermark_dissolve].nil? ? 40 : options[:watermark_dissolve]
#current_format = File.extname(#file.path)
#basename = File.basename(#file.path, #current_format)
end
def make
return #file unless watermark_path
dst = Tempfile.new([#basename, #format].compact.join("."))
dst.binmode
command = "composite"
params = "-gravity #{#watermark_gravity} -dissolve #{#watermark_dissolve} #{watermark_path} #{fromfile} #{tofile(dst)}"
begin
success = Paperclip.run(command, params)
rescue PaperclipCommandLineError
raise PaperclipError, "There was an error processing the watermark for #{#basename}"
end
dst
end
def fromfile
"\"#{ File.expand_path(#file.path) }[0]\""
end
def tofile(destination)
"\"#{ File.expand_path(destination.path) }[0]\""
end
end
end
models/image.rb
has_attached_file :file,
processors: [:thumbnail, :watermark],
styles: {
layout: "100%",
preview: {geometry: "900x900>", watermark_path: "#{Rails.root}/app/assets/images/watermarks/watermark_200.png"},
thumbnail: "300x300>",
miniature: "150x150>"
},
convert_options: {
layout: "-units PixelsPerInch -density 100",
preview: "-units PixelsPerInch -density 72",
thumbnail: "-units PixelsPerInch -density 72",
miniature: "-units PixelsPerInch -density 72"
}
You can refer to the documentation for custom processors:
https://github.com/thoughtbot/paperclip#custom-attachment-processors
Related
When I'm trying to upload watermark on s3 image through paperclip then it will give error like not authorised and missing an image filename because I'm using dynamic watermark URL. It is also stored in s3
photo.rb
has_attached_file :image,
:processors => lambda {|attachment|
if attachment.class.apply_watermark
[:thumbnail,:watermark]
else
[:thumbnail]
end
},
:styles => lambda { |attachment|
{
:medium => {
:geometry => "259x259#",
:watermark_path => attachment.instance.class.watermark_thumb_url,
:position => "SouthEast",
:s3_protocol => :https
},
:thumb => {
:geometry => Proc.new { |instance| instance.resize },
},
:original => {
:geometry => '1200>',
},
}
}, default_url: "https://s3_bucket_name.s3.ap-south-1.amazonaws.com/shared_photos/missing.png",
:s3_protocol => :https
lib/paperclip_processors/watermark.rb
module Paperclip
class Watermark < Processor
# Handles watermarking of images that are uploaded.
attr_accessor :current_geometry, :target_geometry, :format, :whiny, :convert_options, :watermark_path, :overlay, :position
def initialize file, options = {}, attachment = nil
super
geometry = options[:geometry]
#file = file
#crop = geometry[-1,1] == '#'
#target_geometry = Geometry.parse geometry
#current_geometry = Geometry.from_file #file
#convert_options = options[:convert_options]
#whiny = options[:whiny].nil? ? true : options[:whiny]
#format = options[:format]
#watermark_path = options[:watermark_path]
#position = options[:position].nil? ? "center" : options[:position]
#overlay = options[:overlay].nil? ? true : false
#current_format = File.extname(#file.path)
#basename = File.basename(#file.path, #current_format)
end
# Returns true if the +target_geometry+ is meant to crop.
def crop?
#crop
end
# Returns true if the image is meant to make use of additional convert options.
def convert_options?
not #convert_options.blank?
end
# Performs the conversion of the +file+ into a watermark. Returns the Tempfile
# that contains the new image.
def make
dst = Tempfile.new([#basename, #format].compact.join("."))
dst.binmode
command = "convert"
params = [fromfile]
params += transformation_command
params << tofile(dst)
begin
success = Paperclip.run(command, params.flatten.compact.collect{|e| "'#{e}'"}.join(" "))
rescue PaperclipCommandLineError
raise PaperclipError, "There was an error resizing and cropping #{#basename}" if #whiny
end
if watermark_path
command = "composite"
params = %W[-gravity #{#position} #{watermark_path} #{tofile(dst)}]
params << tofile(dst)
begin
success = Paperclip.run(command, params.flatten.compact.collect{|e| "'#{e}'"}.join(" "))
rescue PaperclipCommandLineError
raise PaperclipError, "There was an error processing the watermark for #{#basename}" if #whiny
end
end
dst
end
def fromfile
File.expand_path(#file.path)
end
def tofile(destination)
File.expand_path(destination.path)
end
def transformation_command
scale, crop = #current_geometry.transformation_to(#target_geometry, crop?)
trans = %W[-resize #{scale}]
trans += %W[-crop #{crop} +repage] if crop
trans << convert_options if convert_options?
trans
end
end
end
watermarks_controller.rb
def upload_watermark_on_dummy_image
Photo.apply_watermark = true
Photo.watermark_thumb_url = #watermark.photo.image.url(:thumb)
current_resource_owner.photos.create(image: File.new("public/shared_photos/dummy-image.jpg"))
end
It is giving error when try to run below command in watermark processors
command = "composite"
params = ["-gravity",
"SouthEast",
"https://s3.ap-south-1.amazonaws.com/s3_bucket_name/photos/images/000/000/025/thumb/download.png?1560325300",
"/tmp/3151d071493084e42ac1e51947ef71ce20190612-25378-1usu3ji20190612-25378-135qwqy",
"/tmp/3151d071493084e42ac1e51947ef71ce20190612-25378-1usu3ji20190612-25378-135qwqy"]
success = Paperclip.run(command, params.flatten.compact.collect{|e| "'#{e}'"}.join(" "))
It is giving below error:
Command :: composite '-gravity' 'SouthEast' 'https://s3.ap-south-1.amazonaws.com/s3_bucket_name/photos/images/000/000/026/thumb/download.png?1560328681' '/tmp/703fb0e145df584135fc841239e8aa3020190612-27615-14xprt020190612-27615-10g8hgo' '/tmp/703fb0e145df584135fc841239e8aa3020190612-27615-14xprt020190612-27615-10g8hgo'
Cocaine::ExitStatusError: Command 'composite '-gravity' 'SouthEast' 'https://s3.ap-south-1.amazonaws.com/s3_bucket_name/photos/images/000/000/026/thumb/download.png?1560328681' '/tmp/703fb0e145df584135fc841239e8aa3020190612-27615-14xprt020190612-27615-10g8hgo' '/tmp/703fb0e145df584135fc841239e8aa3020190612-27615-14xprt020190612-27615-10g8hgo'' returned 1. Expected 0
Here is the command output: STDOUT:
I'm using Ruby on Rails and the paper-clip Gem and I would like to to convert a .gif image to .jpeg if the .gif image is not a animated gif.
This is my code:
has_attached_file :image, styles: Proc.new { |file| file.instance.check_image_gif? ? {
:'960' => ["960>x960", :gif],
:'640' => ["640>x640", :gif],
:'320' => ["320>x320", :gif]
}:{
:'960' => ["960>x960", :jpg],
:'640' => ["640>x640", :jpg],
:'320' => ["320>x320", :jpg]
}
}
def check_image_gif?
# I want to check animation gif here.
image.instance.image_content_type =~ %r(gif) ? true : false
end
I resolved by myself.
def check_image_gif?
begin
file = image.instance.image.queued_for_write[:original]
img = Magick::Image.read(file.path)
animation = (img.size>1)
unless animation
image.instance.image_content_type = "image/jpeg"
end
rescue => e
end
image.instance.image_content_type =~ %r(gif) ? true : false
end
I added rmagick Gem.
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
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
according to this example (http://dimaspriyanto.com/2010/06/08/image-watermarking-with-paperclip/), I try to put a watermark on every picture I upload (for now, I restrain myself to the large one).
And guess what? It doesn't work!
So in my picture model, I have
require 'paperclip_processors/watermark'
has_attached_file :image,
:styles => {:medium => "300x300^", :thumb => "150x105^",
:large => {
:geometry => "460",
:watermark_path => ":rails_root/public/images/watermark.png"
}
},
:url => "/images/:style/:id_:style.:extension",
:path => ":rails_root/public/images/:style/:id_:style.:extension"
and in /lib/paperclip_processors/watermark.rb, I have:
module Paperclip
class Watermark < Processor
attr_accessor :current_geometry, :target_geometry, :format, :whiny, :convert_options, :watermark_path, :overlay, :position
def initialize file, options = {}, attachment = nil
super
geometry = options[:geometry]
#file = file
#crop = geometry[-1,1] == '#'
#target_geometry = Geometry.parse geometry
#current_geometry = Geometry.from_file #file
#convert_options = options[:convert_options]
#whiny = options[:whiny].nil? ? true : options[:whiny]
#format = options[:format]
#watermark_path = options[:watermark_path]
#position = options[:position].nil? ? "SouthEast" : options[:position]
#overlay = options[:overlay].nil? ? true : false
#current_format = File.extname(#file.path)
#basename = File.basename(#file.path, #current_format)
end
def crop?
#crop
end
def convert_options?
not #convert_options.blank?
end
def make
dst = Tempfile.new([#basename, #format].compact.join("."))
dst.binmode
if watermark_path
command = "composite"
params = "-gravity #{#position} #{watermark_path} #{fromfile} #{transformation_command} #{tofile(dst)}"
else
command = "convert"
params = "#{fromfile} #{transformation_command} #{tofile(dst)}"
end
begin
success = Paperclip.run(command, params)
rescue PaperclipCommandLineError
raise PaperclipError, "There was an error processing the watermark for #{#basename}" if #whiny
end
dst
end
def fromfile
"\"#{ File.expand_path(#file.path) }[0]\""
end
def tofile(destination)
"\"#{ File.expand_path(destination.path) }[0]\""
end
def transformation_command
scale, crop = #current_geometry.transformation_to(#target_geometry, crop?)
trans = "-resize \"#{scale}\""
trans << " -crop \"#{crop}\" +repage" if crop
trans << " #{convert_options}" if convert_options?
trans
end
end
end
The watermark is in /public/images/ and it doesn't crash in the process, I mean the pictures are uploaded, in every size but the large one is nude, without the watermark.
Any idea?
Here's the preprocessor that works (I use it)
https://gist.github.com/2499137
Here's sample code for you model:
has_attached_file :data,
:processors => [:watermark],
:url => "/ckeditor_assets/pictures/:id/:style_:basename.:extension",
:path => ":rails_root/public/ckeditor_assets/pictures/:id/:style_:basename.:extension",
:styles => {
:thumb => '118x100#',
:content => {
:geometry => '700>',
:watermark_path => "#{Rails.root}/public/images/watermark.png",
:position => 'SouthWest'
},
}