davideisinger.com

My personal website
Log | Files | Refs | README

index.md (3247B)


      1 ---
      2 title: "Manual Cropping with Paperclip"
      3 date: 2012-05-31T00:00:00+00:00
      4 draft: false
      5 canonical_url: https://www.viget.com/articles/manual-cropping-with-paperclip/
      6 ---
      7 
      8 It's relatively straightforward to add basic manual (browser-based)
      9 cropping support to your
     10 [Paperclip](https://github.com/thoughtbot/paperclip) image attachments.
     11 See [RJCrop](https://github.com/jschwindt/rjcrop) for one valid
     12 approach. What's not so straightforward, though, is adding manual
     13 cropping while preserving Paperclip's built-in thumbnailing
     14 capabilities. Here's how.
     15 
     16 Just so we're on the same page, when we're talking about "thumbnailing,"
     17 we're talking about the ability to set a size of `50x50#`, which means
     18 "scale and crop the image into a 50 by 50 pixel square." If the original
     19 image is 200x100, it would first be scaled down to 100x50, and then 25
     20 pixels trimmed from both sides to arrive at the final dimensions. This
     21 is not a native capability of ImageMagick, but rather the result of some
     22 decently complex code in Paperclip.
     23 
     24 Our goal is to allow a user to select a portion of an image and then
     25 create a thumbnail of *just that selected portion*, ideally taking
     26 advantage of Paperclip's existing cropping/scaling logic.
     27 
     28 Any time you're dealing with custom Paperclip image processing, you're
     29 talking about creating a custom
     30 [Processor](https://github.com/thoughtbot/paperclip#post-processing). In
     31 this case, we'll be subclassing the default
     32 [Thumbnail](https://github.com/thoughtbot/paperclip/blob/master/lib/paperclip/thumbnail.rb)
     33 processor and making a few small tweaks. We'll imagine you have a model
     34 with the fields `crop_x`, `crop_y`, `crop_width`, and `crop_height`. How
     35 those get set is left as an exercise for the reader (though I recommend
     36 [JCrop](http://deepliquid.com/content/Jcrop.html)). Some code, then:
     37 
     38 ```ruby
     39 module Paperclip
     40   class ManualCropper < Thumbnail
     41     def initialize(file, options = {}, attachment = nil)
     42       super
     43       @current_geometry.width = target.crop_width
     44       @current_geometry.height = target.crop_height
     45     end
     46 
     47     def target
     48       @attachment.instance
     49     end
     50 
     51     def transformation_command
     52       crop_command = [
     53         "-crop",
     54         "#{target.crop_width}x"
     55         "#{target.crop_height}+"
     56         "#{target.crop_x}+"
     57         "#{target.crop_y}",
     58         "+repage"
     59       ]
     60 
     61       crop_command + super
     62     end
     63   end
     64 end
     65 ```
     66 
     67 In our `initialize` method, we call super, which sets a whole host of
     68 instance variables, include `@current_geometry`, which is responsible
     69 for creating the geometry string that will crop and scale our image. We
     70 then set its `width` and `height` to be the dimensions of our cropped
     71 image.
     72 
     73 We also override the `transformation_command` method, prepending our
     74 manual crop to the instructions provided by `@current_geometry`. The end
     75 result is a geometry string which crops the image, repages it, then
     76 scales the image and crops it a second time. Simple, but not certainly
     77 not intuitive, at least not to me.
     78 
     79 From here, you can include this cropper using the `:processors`
     80 directive in your `has_attached_file` declaration, and you should be
     81 good to go. This simple approach assumes that the crop dimensions will
     82 always be set, so tweak accordingly if that's not the case.