开发者

Custom cropping in Rails with Paperclip

开发者 https://www.devze.com 2023-01-20 08:43 出处:网络
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 o

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...

0

精彩评论

暂无评论...
验证码 换一张
取 消