I am (free) after the RailsCasts # 182 tutorial , which uses patterning tools, ImageMagick and Jcrop, which allow you to customize the cropping of uploaded images.
Since I use Amazon S3 to store files, I had to relearn parts of the tutorial to satisfy. Everything seems to work just fine, except for the fact that the cropped version of my image is not being reprocessed (or the result of this reprogram is not reloaded onto S3) - so after the cropping process I am left with the same image that I originally uploaded (this true for all image sizes that I save for each image).
Here is my model (as in Feature Image):
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
Relevant actions of my FeatureController:
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 corresponding lines of my "crop.html.erb":
<% 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 is an error with custom cropping (offset, cropping area, etc.), it means that the crop does not occur when I click "crop" - I just stayed with the images I received from the original load / process. Doesn't seem like 'image.reprocess!' (or processing results are not stored on S3).
Why is this possible, and what can I do about it?