Custom cropping in Rails with Paperclip
I'm currently using Paperclip to upload an image and automatically generate a thumbnail. Now I would also like to add a second style that generates a one-pixel-wide image using the left-most column of pixels in the uploaded image (it should also have the same height as the original image). I'll be using the one-pixel-wide image as a repeating background via CSS.
Is it possible to generate that background image using Paperclip's default Thumbnail processor, or will I need to create my own custom processor? I've already tried creating a custom processor that subclasses the Paperclip::Processor
, but I didn't understand how to use the Paperclip.run
method properly. Now I'm trying to subclass Paperclip::Thumbnail
based on Ryan Bate's Railcast here: http://railscasts.com/episodes/182-cropping-images, but that is throwing this error:
NoMethodError (You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.[]):
app/controllers/images_controller.rb:11:in `create'
Lin开发者_如何学编程e 11 of images_controller.rb:
@image = @review.images.build(params[:image])
Line 11 of images_controller.rb works fine if I don't try using the Autobackground custom processor, so the error must be the code in the processor.
Here's my code so far:
#/app/models/image.rb
class Image < ActiveRecord::Base
belongs_to :review
has_attached_file :image, :styles => {
:thumb => "32x32#",
:auto_bg => { :processors => [:autobackground] }
}
end
#/lib/paperclip_processors/Autobackground.rb
module Paperclip
class Autobackground < Thumbnail
def transformation_command
if crop_command
crop_command + super.sub(/ -crop \S+/, '')
else
super
end
end
def crop_command
target = @attachment.instance
if target.cropping?
" -crop '1x#{target.height}+0+0'"
end
end
end
end
If anyone is interested, I managed to get this working. The one thing that really helped me the most in fixing this was the Rails debugging console (which I finally started to properly use) which allowed me to look more closely at the variables in the Paperclip::Thumbnail class that my Autobackground
class is inheriting from.
Here's what I did: I changed the :auto_bg
style to point to a special string that I could identify in my processor. Since my processor is subclassed from Paperclip::Thumbnail
, the string that the style points to gets saved to @options[:geometry]
. All I have to do in the overridden transformation_command
method is check if @options[:geometry]
is set to the special auto_bg
string and then run my create_auto_bg
method instead of letting the Thumbnail
class do it's usual thing. My old create_auto_bg
method wasn't properly creating the array of strings that Thumbnail
needs to create the ImageMagick command, so I rewrote that and used the @current_geometry
variable to find the height of the original image instead of the faulty target = @attachment.instance
method that I had copied from Ryan Bate's railscast (not sure how it works in his code).
I'm sure there's a more elegant solution to this, but I'm still quite new to Ruby and RoR, so this will have to do for now. I Hope this helps anyone facing a similar challenge :)
#/app/models/image.rb
class Image < ActiveRecord::Base
belongs_to :review
has_attached_file :image, :styles => { :thumb => "32x32#", :auto_bg => "auto_bg" }, :processors => [:autobackground]
end
#/lib/paperclip_processors/Autobackground.rb
module Paperclip
class Autobackground < Thumbnail
def transformation_command
if @options[:geometry] == "auto_bg"
create_auto_bg
else
super
end
end
def create_auto_bg
#debugger
height = @current_geometry.height.to_i.to_s
trans = []
trans << "-crop" << "1x#{height}+0+0"
trans
end
end
end
I would suggest you to write a helper method and call it with a filter...
there are several tools available which can do this magic for ya...
one more comment about the coding style...
I would prefer to write ruby style of code like
def crop_command
target = @attachment.instance
if target.cropping?
" -crop '1x#{target.height}+0+0'"
end
end
to
def crop_command
target = @attachment.instance
" -crop '1x#{target.height}+0+0'" if target.cropping?
end
wherever it is possible, please use the ruby specific style...
精彩评论