Cropping using Paperclip, ImageMagick, Jcrop and S3 storage: Why won't 'image.reprocess!' reprocess?
Asked Answered
U

3

6

I'm (loosely) following RailsCasts tutorial #182, which uses Paperclip, ImageMagick, and Jcrop to allow custom cropping of uploaded images.

As I'm using Amazon S3 for file storage, I've had to rejigger parts of the tutorial to suit. Everything seems to be working perfectly except for the fact that the cropped version of my image isn't being reprocessed (or the result of that reprocess is not re-uploaded to S3)--so after the cropping process, I'm left with the same image I originally uploaded (this is true for all image sizes I store for each image).

Here is my Feature (as in Feature Image) model:

class Feature < ActiveRecord::Base
  require "#{Rails.root}/lib/paperclip_processors/cropper.rb"

  attr_accessible    :image_file_name, :image
  attr_accessor      :crop_x, :crop_y, :crop_w, :crop_h
  after_update       :reprocess_image, :if => :cropping?

  if Rails.env == "production"
  S3_CREDENTIALS = { :access_key_id     => '<REDACTED>',
                     :secret_access_key => '<REDACTED>',
                     :bucket            => "<REDACTED>"}
  else
  S3_CREDENTIALS = { :access_key_id     => '<REDACTED>',
                     :secret_access_key => '<REDACTED>',
                     :bucket            => "<REDACTED>"}
  end

  has_attached_file :image,
                    :styles          => { :small => "240x135>", :croppable => "960x960>", :display => "960x540>" },
                    :processors      => [:cropper],
                    :storage         => :s3,
                    :s3_credentials  => S3_CREDENTIALS,
                    :path            => "features/:id/:style.:extension"

  validates_attachment_content_type :image, :content_type => ['image/jpeg', 'image/gif', 'image/png',
                                                              'image/pjpeg', 'image/x-png'], 
                                            :message => 'must be a JPEG, GIF or PNG image'

  def cropping?
    !crop_x.blank? && !crop_y.blank? && !crop_w.blank? && !crop_h.blank?
  end

  def image_geometry(style = :original)
    @geometry ||= {}
    path = (image.options[:storage]==:s3) ? image.url(style) : image.path(style)
    @geometry[style] ||= Paperclip::Geometry.from_file(path)
  end

  private

  def reprocess_image
    image.reprocess!
  end
end

Here is my 'cropper.rb' (Paperclip processor):

module Paperclip
  class Cropper < 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 '#{target.crop_w}x#{target.crop_h}+#{target.crop_x}+#{target.crop_y}'"
      end
    end
  end
end

The relevant actions of my FeaturesController:

class FeaturesController < ApplicationController

  def new
    @feature = Feature.new
  end

  def create
    @feature = Feature.new(params[:feature])
    if @feature.save
      if params[:feature][:image].blank?
        flash[:notice] = "New feature added!"
        redirect_to @feature
      else
        render :crop
      end
    else
      @title = "Add a New Feature"
      render :new
    end
  end

  def edit
    @feature = Feature.find(params[:id])
    @title = "Edit #{@feature.headline}"
  end

  def update
    @feature = Feature.find(params[:id])
    if @feature.update_attributes(params[:feature])
      if params[:feature][:image].blank?
        flash[:notice] = "Feature updated!"
        redirect_to @feature
      else
        render :crop
      end
    else
      @title = "Edit Feature"
      render :edit
    end
  end
end

And the relevant lines of my 'crop.html.erb' view:

<% content_for :javascript_includes do %>
    <%= javascript_include_tag 'jquery.Jcrop.min' %>
    <script type="text/javascript" charset="utf-8">
    $(function() {
        $('#cropbox').Jcrop({
            onChange: update_crop,
            onSelect: update_crop,
            setSelect: [0, 0, 960, 540],
            aspectRatio: 960/540
        });
    });

    function update_crop(coords) {
        var ratio = <%= @feature.image_geometry(:original).width %> / <%= @feature.image_geometry(:croppable).width %>;
        $("#crop_x").val(Math.round(coords.x * ratio));
        $("#crop_y").val(Math.round(coords.y * ratio));
        $("#crop_w").val(Math.round(coords.w * ratio));
        $("#crop_h").val(Math.round(coords.h * ratio));
    };
    </script>
<% end %>
<% content_for :style_includes do %>
    <%= stylesheet_link_tag 'jquery.Jcrop', :media => 'screen' %>
<% end %>

<%= image_tag @feature.image.url(:croppable), :id => "cropbox" %>

<% form_for @feature do |f| %>
    <% for attribute in [:crop_x, :crop_y, :crop_w, :crop_h] %>
        <%= f.hidden_field attribute, :id => attribute %>
    <% end %>
    <p><%= f.submit "Crop" %></p>
<% end %>

The problem is not that there's an error with the custom crop (offset, crop area, etc.), it's that there is no crop happening when I click 'crop'--I'm just left with the images I got from the original upload/process. It doesn't appear that 'image.reprocess!' is happening at all (or the results of the reprocess aren't being saved to S3).

Why might that be, and what can I do about it?

Unhitch answered 7/7, 2011 at 19:1 Comment(0)
K
3

Don't know if this is the same but I had a problem with the reprocessing and fixed it by following the answer here:

paperclip error while reporcessing after rails 3 upgrade

Kamasutra answered 1/3, 2012 at 16:45 Comment(0)
S
2

Ok, let me try to help :)

Firstly, can you not include your Paperclip processor in the model, let Paperclip handle it.

Secondly, remove the :after_update and replace with a :before_update which should set your image.options[ :crop ] up for the processor. In your processor, try this:

def initialize file, options = {}, attachment = nil
  super
  #......

  @crop = options[ :crop ]

  #......

Thirdly, modify your transformation_command in the processor:

def transformation_command
  if @crop
      trans = " -quality 75"
      trans << " -crop \"#{<YOUR_CODE>}\" +repage" if @crop
      trans
  end
end

And then post your findings :)

Sheik answered 5/9, 2011 at 9:56 Comment(1)
Yes! I was having the same problem as the original asker, and your suggestion of changing after_update to before_update fixed it for me. Thanks so much!Absalom
C
0

I also used that same RailsCast video to help me get cropping to work. I was running into a similar issue with a NOSUCHKEY error which I was able to trace to the reprocessing! call that was being called after_update. I was able to fix the problem by using Vish's answer and modifying it. My solution may not be exactly what you need as I crop every time.

I simply removed the after_update call to reprocess! and left everything else in place. This caused the passed in processor (cropper in your case) to be used instead of the default and occurs before uploading the image to S3. Since you crop the file before uploading it for the first time everything works!

If you wanted to have conditional cropping then you would want to do what Vish suggested which is to set a variable or pass an option with the image object in a before_update. It needs to be available in your custom processor so you can put your conditional cropping logic in place based on its value.

Cletacleti answered 18/9, 2011 at 2:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.