multiple paperclip attachements with watermark processor - ruby-on-rails

I'm having a ton of trouble with uploading multiple attachments with paperclip and processing them with a watermark.
I have 2 models, Ad and Photo.
The Ad has_many :photos and the Photo belongs_to :ad.
To be more exact in /models/ad.rb I have:
class Ad < ActiveRecord::Base
has_many :photos, :dependent => :destroy
accepts_nested_attributes_for :photos, :allow_destroy => true
end
and my photo.rb file looks like this:
class Photo < ActiveRecord::Base
belongs_to :ad
has_attached_file :data,
:styles => {
:thumb => "100x100#",
:first => {
:processors => [:watermark],
:geometry => '300x250#',
:watermark_path => ':rails_root/public/images/watermark.png',
:position => 'SouthEast' },
:large => {
:processors => [:watermark],
:geometry => '640x480#',
:watermark_path => ':rails_root/public/images/watermark.png',
:position => 'SouthEast' }
}
end
In my view I use this to add the file fields
<% f.fields_for :photos do |p| %>
<%= p.label :data, 'Poza:' %> <%= p.file_field :data %>
<% end %>
In my controller, in the edit action i use 4.times {#ad.photos.build} to generate the file fields.
It all works fine and dandy if I don't use the watermark processor, if I use a normal has_attached_file declaration, like this:
has_attached_file :data,
:styles => {
:thumb => "100x100#",
:first => '300x250#',
:large => '640x480#'
}
But when I use the watermark processor I always get this error:
NoMethodError in PublicController#update_ad
You have a nil object when you didn't expect it!
You might have expected an instance of ActiveRecord::Base.
The error occurred while evaluating nil.[]
..............................
/usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/nested_attributes.rb:350:in `assign_nested_attributes_for_collection_association'
/usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/nested_attributes.rb:345:in `each'
/usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/nested_attributes.rb:345:in `assign_nested_attributes_for_collection_association'
/usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/nested_attributes.rb:243:in `photos_attributes='
/usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/base.rb:2746:in `send'
/usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/base.rb:2746:in `attributes='
/usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/base.rb:2742:in `each'
/usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/base.rb:2742:in `attributes='
/usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/base.rb:2628:in `update_attributes'
/home/alexg/Sites/vandmasina/app/controllers/public_controller.rb:217
/home/alexg/Sites/vandmasina/app/controllers/public_controller.rb:216:in `update_ad'
The parameters are ok, as far as I can say
Parameters:
{"commit"=>"Salveaza modificarile",
"ad"=>{"price"=>"6000",
"oras"=>"9",
"photos_attributes"=>{"0"=>{"data"=>#<File:/tmp/RackMultipart20100928-5130-b42noe-0>},
"1"=>{"data"=>#<File:/tmp/RackMultipart20100928-5130-r0ukcr-0>},
"2"=>{"data"=>#<File:/tmp/RackMultipart20100928-5130-mb23ei-0>},
"3"=>{"data"=>#<File:/tmp/RackMultipart20100928-5130-1bpkm3b-0>}},
The Watermark processor /lib/paperclip_processors/watermark.rb looks like this:
module Paperclip
class Watermark < Processor
class InstanceNotGiven < ArgumentError;
end
def initialize(file, options = {},attachment = nil)
super
#file = file
#current_format = File.extname(#file.path)
#basename = File.basename(#file.path, #current_format)
#watermark = ':rails_root/public/images/watermark.png'
#current_geometry = Geometry.from_file file # This is pretty slow
#watermark_geometry = watermark_dimensions
end
def watermark_dimensions
return #watermark_dimensions if #watermark_dimensions
#watermark_dimensions = Geometry.from_file #watermark
end
def make
dst = Tempfile.new([#basename, #format].compact.join("."))
watermark = " \\( #{#watermark} -extract #{#current_geometry.width.to_i}x#{#current_geometry.height.to_i}+#{#watermark_geometry.height.to_i /
2}+#{#watermark_geometry.width.to_i / 2} \\) "
command = "-gravity center " + watermark + File.expand_path(#file.path) + " " +File.expand_path(dst.path)
begin
success = Paperclip.run("composite", command.gsub(/\s+/, " "))
rescue PaperclipCommandLineError
raise PaperclipError, "There was an error processing the watermark for #{#basename}" if #whiny_thumbnails
end
dst
end
end
end
I have tried the processor in a normal app, without multiple attachments and it works perfect. It doesn't work with nested_attributes as far as I can tell.
The app is rails 2.3.5 with ruby 1.8.7 and paperclip 2.3.11
If you can provide any help it would be appreciated a lot, since I've been trying to figure this out for 2 days now :)

If you use rails 3 and paperclip > 2.3.3, try https://gist.github.com/843418 source.

Oh, man, that was a tough one!
You have few errors in your code and none is related to nested models. My explanation is for Rails 3 & Paperclip 2.3.3
a) the :rails_root thing doesn't work. This interpolation is used only in url/path and not on custom options. So you should replace it with Rails.root.join("public/images...")
b) you simply ignore the :watermark_path option and you use only hardcoded path (in initialization method). So it doesn't matter what you have in your :styles as it always go for .../images/watermark.png. The :rails_root thingy there again so it cannot work.
c) when you pass a parameter to Paperclip.run("composite", "foo bar there") it actually executes this command:
composite 'foo bar there'
can you see the single quotes? Because of that the composite command see your parameters as one huge parameter and doesn't understand it at all. If you pass it as an array, then every item is enclosed in the quotes, not the array as a whole.
So here is the improved version of watermark processor:
module Paperclip
class Watermark < Processor
class InstanceNotGiven < ArgumentError;
end
def initialize(file, options = {},attachment = nil)
super
#file = file
#current_format = File.extname(#file.path)
#basename = File.basename(#file.path, #current_format)
# PAWIEN: use default value only if option is not specified
#watermark = options[:watermark_path] || Rails.root.join('public/images/watermark.png')
#current_geometry = Geometry.from_file file # This is pretty slow
#watermark_geometry = watermark_dimensions
end
def watermark_dimensions
return #watermark_dimensions if #watermark_dimensions
#watermark_dimensions = Geometry.from_file #watermark
end
def make
dst = Tempfile.new([#basename, #format].compact.join("."))
dst.binmode
begin
# PAWIEN: change original "stringy" approach to arrayish approach
# inspired by the thumbnail processor
options = [
"-gravity",
"center",
"#{#watermark}",
"-extract",
"#{#current_geometry.width.to_i}x#{#current_geometry.height.to_i}+#{#watermark_geometry.height.to_i / 2}+#{#watermark_geometry.width.to_i / 2}",
File.expand_path(#file.path),
File.expand_path(dst.path)
].flatten.compact.join(" ").strip.squeeze(" ")
success = Paperclip.run("composite", options)
rescue PaperclipCommandLineError
raise PaperclipError, "There was an error processing the watermark for #{#basename}" if #whiny_thumbnails
end
dst
end
end
end
Hope that helped you!
UPDATE: You need to use latest paperclip gem from github
gem 'paperclip', '>= 2.3.3', :git => "http://github.com/thoughtbot/paperclip.git"
In this version the formats of #run were changed once again so I've updated the code. It really should work as I've created test application and it's doing what supposed.
UPDATE 2: Repo with working example:
git://repo.or.cz/paperclip-mass-example.git

Just from a quick glance it looks like watermark_path should be "#{Rails.root}/..." though it looks like you have a lot going on here.
Also, I don't see your form as in form_for. Make sure you have {:multipart => true}

Related

Watermark images with paperclip, rails 4

I've been attempting to add watermarks to my images, following the answer listed in watermark with paperclip :
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, :watermark_offset, :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]
#watermark_offset = options[:watermark_offset]
#overlay = options[:overlay].nil? ? true : false
#current_format = File.extname(#file.path)
#basename = File.basename(#file.path, #current_format)
end
# TODO: extend watermark
# 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
if watermark_path
command = "composite"
params = %W[-gravity #{#position}]
params += %W[-geometry '#{#watermark_offset}'] if #watermark_offset
params += %W['#{watermark_path}' '#{fromfile}']
params += transformation_command
params << "'#{tofile(dst)}'"
else
command = "convert"
params = ["'#{fromfile}'"]
params += transformation_command
params << "'#{tofile(dst)}'"
end
begin
Paperclip.run(command, params.join(' '))
rescue ArgumentError, Cocaine::CommandLineError
raise PaperclipError, "There was an error processing the watermark for #{#basename}" if #whiny
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
and model code:
has_attached_file :image,
:processors => [:watermark],
:styles => {
:large => "640x480",
:thumb => "100x100",
:medium => "300x300",
:content => {
:geometry => '150x153',
:watermark_path => Rails.root.join('app/assets/images/watermark.jpg'),
:position => 'SouthWest'
},
},
dependent: :allow_destroy
I've attempted to update this to work with Rails 4 (moving attr_accessor to params in the model), but I get the error:
uninitialized constant Paperclip::Watermark::PaperclipError
Any tips on how to get implement watermarks in a rails 4 app?
UPDATE: I was able to get past the uninitialized constant error with Graeme's suggestion below of changing:
raise PaperclipError, "There was an error processing the watermark for #{#basename}" if #whiny
to:
raise Paperclip::Error.new("There was an error processing the watermark for #{#basename}") if #whiny
I also had to remove the following from the model in order for the upload to process:
:url => "/images/:style/:id_:style.:extension",
:path => ":rails_root/app/assets/images/:style/:id_:style.:extension"
I don't understand what the purpose of :url and :path are in this scenario, when users are uploading images?
The problem is, even though the images now get uploaded, no watermark is being displayed. Thoughts?
Update 2:
In order to get the watermark displaying correctly, I had to change the model to:
has_attached_file :image,
:processors => [:watermark],
:url => "/system/:class/:attachment/:id_partition/:style/:filename",
:path => ":rails_root/public/system/:class/:attachment/:id_partition/:style/:filename",
:styles => {
:large => "640x480",
:thumb => "100x100",
:medium => {
:processors => [:watermark],
:geometry => '300x300',
:watermark_path => Rails.root.join('app/assets/images/icon.gif'),
:position => 'SouthWest'
},
},
dependent: :allow_destroy
The key piece was removing :content => . Only remaining issue is that the watermark is scaling up to fit the entire width of the image. Any recommendations on how to stop the watermark-scaling?
The problem with the watermark being stretched is the Imagemagick command which is combining the two images together and then resizing the result.
Effectively the command being run will be (I've abbreviated the actual filenames for clarity):
composite -gravity SouthWest icon.gif uploaded_image.gif -resize 300x300 output_image.gif
As you see the images are joined and then resized.
The command I believe you need is:
convert uploaded_image.gif -resize 300x300 icon.gif -gravity SouthWest -composite output_image.gif
i.e. resize the uploaded image and then add on the watermark.
I've tested this using composite and convert on the command line and it does what I believe you are looking for.
To achieve it in the code, you need to change if watermark_path statement in the make method:
def make
dst = Tempfile.new([#basename, #format].compact.join("."))
dst.binmode
if watermark_path
# -- original code --
# command = "composite"
# params = %W[-gravity #{#position}]
# params += %W[-geometry '#{#watermark_offset}'] if #watermark_offset
# params += %W['#{watermark_path}' '#{fromfile}']
# params += transformation_command
# params << "'#{tofile(dst)}'"
# -- new code --
command = "convert"
params = %W['#{fromfile}']
params += transformation_command
params += %W['#{watermark_path}' -gravity #{#position} -composite]
params << "'#{tofile(dst)}'"
else
command = "convert"
params = ["'#{fromfile}'"]
params += transformation_command
params << "'#{tofile(dst)}'"
end
begin
Paperclip.run(command, params.join(' '))
rescue ArgumentError, Cocaine::CommandLineError
raise PaperclipError, "There was an error processing the watermark for #{#basename}" if #whiny
end
dst
end
Disclaimer: I have not actually tested this so please forgive any errors.
PaperclipError doesn't exist.
Try changing:
raise PaperclipError, "There was an error processing the watermark for #{#basename}" if #whiny
to:
raise Paperclip::Error.new("There was an error processing the watermark for #{#basename}") if #whiny
Since you are now asking a different question I'll make a new answer.
:path is used to define where Paperclip will store the uploaded image. By default this will be :rails_root/public/system/:class/:attachment/:id_partition/:style/:filename.
:url is used to access the image later. By default this will be /system/:class/:attachment/:id_partition/:style/:filename.
(Actually, to save having to duplicate the url part, :path is really defined as :rails_root/public:url by default.)
By specifying them in the model you are changing the save location. I wouldn't recommend putting them in the assets directory as assets are really part of your application and you don't want user uploaded files to be going there.
As to why you are not seeing the watermark with the uploaded image, I guess the Imagemagick composite command is not being called correctly. Try running it on the command line, or adding the parameter -debug to see why it is failing.

Generate Thumbnail From pdf in rails paperclip

How can I generate the first page of a pdf as a thumbnail in paperclip?
I tried a lot but it's not working
has_attached_file :book_url, :styles => {
:thumb => "100x100#",
:small => "150x150>",
:medium => "200x200" }
This is giving the name of the pdf as a link but it's not giving the first page of the pdf
<%= link_to 'My PDF', #book.book_url.url %>
Tadas' answer is right, but for those who need more context, you can do something like this: The model below only creates thumbnails for certain kinds of files (e.g. it doesn't make thumbnails of audio files), but does make thumbnails for pdfs, image files, and video files:
class Record < ActiveRecord::Base
print self # for logging on heroku
belongs_to :user
# Ensure user has provided the required fields
validates :title, presence: true
validates :file_upload, presence: true
validates :description, presence: true
# Use the has_attached_file method to add a file_upload property to the Record
# class.
has_attached_file :file_upload,
# In order to determine the styles of the image we want to save
# e.g. a small style copy of the image, plus a large style copy
# of the image, call the check_file_type method
styles: lambda { |a| a.instance.check_file_type },
processors: lambda {
|a| a.is_video? ? [ :ffmpeg ] : [ :thumbnail ]
}
# Validate that we accept the type of file the user is uploading
# by explicitly listing the mimetypes we are willing to accept
validates_attachment_content_type :file_upload,
:content_type => [
"video/mp4",
"video/quicktime",
"image/jpg",
"image/jpeg",
"image/png",
"image/gif",
"application/pdf",
"audio/mpeg",
"audio/x-mpeg",
"audio/mp3",
"audio/x-mp3",
"file/txt",
"text/plain",
"application/doc",
"application/msword",
"application/vnd.ms-excel",
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"application/vnd.ms-powerpoint"
],
:message => "Sorry! We do not accept the attached file type"
# Before applying the Imagemagick post processing to this record
# check to see if we indeed wish to process the file. In the case
# of audio files, we don't want to apply post processing
before_post_process :apply_post_processing?
# Helper method that uses the =~ regex method to see if
# the current file_upload has a content_type
# attribute that contains the string "image" / "video", or "audio"
def is_image?
self.file_upload.content_type =~ %r(image)
end
def is_video?
self.file_upload.content_type =~ %r(video)
end
def is_audio?
self.file_upload.content_type =~ /\Aaudio\/.*\Z/
end
def is_plain_text?
self.file_upload_file_name =~ %r{\.(txt)$}i
end
def is_excel?
self.file_upload_file_name =~ %r{\.(xls|xlt|xla|xlsx|xlsm|xltx|xltm|xlsb|xlam|csv|tsv)$}i
end
def is_word_document?
self.file_upload_file_name =~ %r{\.(docx|doc|dotx|docm|dotm)$}i
end
def is_powerpoint?
self.file_upload_file_name =~ %r{\.(pptx|ppt|potx|pot|ppsx|pps|pptm|potm|ppsm|ppam)$}i
end
def is_pdf?
self.file_upload_file_name =~ %r{\.(pdf)$}i
end
def has_default_image?
is_audio?
is_plain_text?
is_excel?
is_word_document?
end
# If the uploaded content type is an audio file,
# return false so that we'll skip audio post processing
def apply_post_processing?
if self.has_default_image?
return false
else
return true
end
end
# Method to be called in order to determine what styles we should
# save of a file.
def check_file_type
if self.is_image?
{
:thumb => "200x200>",
:medium => "500x500>"
}
elsif self.is_pdf?
{
:thumb => ["200x200>", :png],
:medium => ["500x500>", :png]
}
elsif self.is_video?
{
:thumb => {
:geometry => "200x200>",
:format => 'jpg',
:time => 0
},
:medium => {
:geometry => "500x500>",
:format => 'jpg',
:time => 0
}
}
elsif self.is_audio?
{
:audio => {
:format => "mp3"
}
}
else
{}
end
end
end
I think I once got it working by enforcing a file type, e.g.
:thumb => ["100x100#", :png]
of course it's not ideal, because it enforces this filetype for every upload
Thanks a million to #duhaime for his beautiful answer.
Since this is the most complete source of information I found to have PDF attached, I'd like to document it further:
Requirements:
imagemagick
ghostscript (I forgot about this one)
(optional) ffmpeg if you want to handle video files
Also I replaced has_default_image? and apply_post_processing? with the single:
def can_thumbnail?
self.check_file_type.try(:{], :thumb).present?
end
Finally I created a method for the not-thumbable attachments:
def thumb
return self.file.url(:thumb) if self.can_thumbnail?
if self.is_video?
'/thumb/video.png'
else
'/thumb/default.png'
end
end
But thanks again #duhaime

PaperClip -- save a new attachment without deleting the old one

I am using Paperclip (w/ Amazon s3) on Rails 3. I want to attach a new file to my model without replacing the old file. I don't want the old file to be accessible, I only want to have it there on s3 as a back up.
Do you know if there is a way of telling paperclip to take care of it, itself?
in post.rb I have:
has_attached_file :sound,
:storage => :s3,
:s3_credentials => "....",
:styles => {:mp3 => {:format => :mp3}},
:processors => [:sound_processor],
:s3_host_alias => '....',
:bucket => '....',
:path => ":attachment/:id/:style/out.:extension",
:url => ":s3_alias_url"
and the processor is as follows:
class Paperclip::SoundProcessor < Paperclip::Processor
def initialize file, options = {}, attachment = nil
super
#format = options[:format] || "mp3"
#current_format = File.extname(#file.path)
#basename = File.basename(#file.path, #current_format)
end
def make
src = #file
dst = Tempfile.new([#basename,".#{#format}"])
dst.binmode
cmd = "ffmpeg -y -ab 128k -t 600 -i #{File.expand_path(src.path)} #{File.expand_path(dst.path)}"
Paperclip.log(cmd)
out = `#{cmd}`
raise Paperclip::PaperclipError, "processor does not accept the given audio file" unless $?.exitstatus == 0
dst
end
end
Here's what I do. I timestamp the filename before saving it (to prevent another file with the same name overwriting the original), and force paperclip to never delete anything.
before_create :timestamp_filename
def timestamp_filename
fname = Time.now.to_s(:db).gsub(/[^0-9]/,'') + '_' + sound_file_name
sound.instance_write(:file_name, fname)
end
# override paperclip's destroy files
# method to always keep them around
def destroy_attached_files
true
end
It's quite straightforward to add versioning to your models, recently I user CarrierWave and paper_trail in combo to achieve this. We were deploying to Heroku so S3 was in the mix too.
The reason I'm posting this as an answer is because, although controversial, I don't think libraries like PaperClip should support backing up files, a library specific to solve that problem feels better to me personally.
Here is a good resource that you can take a look at: http://eggsonbread.com/2009/07/23/file-versioning-in-ruby-on-rails-with-paperclip-acts_as_versioned/
It creates new versions of a file. Hope this helps.

paperclip processors in rails3

I'm trying to upload mp3s to S3 using paperclip which works fine, but when I try using a custom processor to create a lower quality audio file I run into problems.
It seems to work, but instead of outputting the whole song in 128k, it only does the first 6 seconds. (it works fine when i try using ffmpeg at the command line) And it does it for both "styles" not just the snippet style, the original gets processed as well which I don't want.
song.rb
class Song < ActiveRecord::Base
belongs_to :record
#after_save :create_metadata
Paperclip.interpolates :record_id do |attachment, style|
attachment.instance.record_id
end
has_attached_file :mp3,
:styles => {
:snippet => { :processors => [:audio_prehear] }
},
:storage => 's3',
:s3_credentials => "#{RAILS_ROOT}/config/s3_credentials.yml"....
My processor
module Paperclip
class AudioPrehear < Processor
attr_accessor :resolution, :whiny
def initialize(file, options = {}, attachment = nil)
super
#file = file
#whiny = options[:whiny].nil? ? true : options[:whiny]
#basename = File.basename(#file.path, File.extname(#file.path))
end
def make
target = File.dirname(#file.path) + "/" + #basename + ".mp3"
convert File.expand_path(file.path), target
dst = File.open target
end
def convert (infile, outfile)
cmd = "-y -i #{infile} -ab 128k #{outfile}"
begin
success = Paperclip.run('ffmpeg', cmd)
rescue PaperclipCommandLineError
raise PaperclipError, "There was an error processing the preview for #{#basename}" if whiny
end
end
end
end
log
[paperclip] ffmpeg -y -i /var/folders/Ue/UehOEbyxHkS9voyeIiUx3++++TI/-Tmp-/stream20101223-93966-18vy7po-0.mp3 -ab 128k /var/folders/Ue/UehOEbyxHkS9voyeIiUx3++++TI/-Tmp-/stream20101223-93966-18vy7po-0.mp3 2>/dev/null
....
[paperclip] Saving attachments.
[paperclip] saving music/7635/snippet/monkey.mp3
[paperclip] saving music/7635/original/monkey.mp3
....

Rails Paperclip how to use filter options of ImageMagick?

I recently implemented Paperclip with Rails and want to try out some of the filter options from ImageMagick such as blur. I've not been able to find any examples of how to do this. Does it get passed through :style as another option?
:styles => { :medium => "300x300#", :thumb => "100x100#" }
#plang's answer was correct but I wanted to give the exact solution to the blur, just in case someone was looking and found this question:
:convert_options => { :all => "-blur 0x8" }
// -blur {radius}x{sigma}
Which changed this:
To this:
I did not test this, but you should be able to use the "convert_options" parameter, like this:
:convert_options => { :all => ‘-colorspace Gray’ }
Have a look at https://github.com/thoughtbot/paperclip/blob/master/lib/paperclip/thumbnail.rb
I personnaly use my own processor.
In Model:
has_attached_file :logo,
:url => PaperclipAssetsController.config_url,
:path => PaperclipAssetsController.config_path,
:styles => {
:grayscale => { :processors => [:grayscale] }
}
In lib:
module Paperclip
# Handles grayscale conversion of images that are uploaded.
class Grayscale < Processor
def initialize file, options = {}, attachment = nil
super
#format = File.extname(#file.path)
#basename = File.basename(#file.path, #format)
end
def make
src = #file
dst = Tempfile.new([#basename, #format])
dst.binmode
begin
parameters = []
parameters << ":source"
parameters << "-colorspace Gray"
parameters << ":dest"
parameters = parameters.flatten.compact.join(" ").strip.squeeze(" ")
success = Paperclip.run("convert", parameters, :source => "#{File.expand_path(src.path)}[0]", :dest => File.expand_path(dst.path))
rescue PaperclipCommandLineError => e
raise PaperclipError, "There was an error during the grayscale conversion for #{#basename}" if #whiny
end
dst
end
end
end
This might not be 100% necessary for a simple grayscale conversion, but it works!
Rails 5, Paperclip 5 update
Instead of having to add a library now, you can just call out to ImageMagick's convert command on the system to use its grayscale option. You can do the same for blur or any of the other ImageMagick options, but I needed to do this for conversion to grayscale.
In your model (client that has a logo):
class Client < ApplicationRecord
has_attached_file :logo,
styles: { thumb: "243x243#", grayscale: "243x243#" }
# ensure it's an image
validates_attachment_content_type :logo, content_type: /\Aimage\/.*\z/
# optional, just for name and url to be required
validates :name, presence: true
validates :url, presence: true
after_save :convert_grayscale
def convert_grayscale
system "convert #{self.logo.path(:thumb)} -grayscale Rec709Luminance #{self.logo.path(:grayscale)}"
end
def logo_attached?
self.logo.file?
end
end
Then just use in the view like this (per Paperclips github docs).
In your view:
<%= image_tag(client.logo.url(:grayscale), class: 'thumbnail', alt: client.name, title: client.name) %>
or with a link if you prefer:
<%= link_to(image_tag(client.logo.url(:grayscale), class: 'thumbnail', alt: client.name, title: client.name), client.url ) %>

Resources