#182 Cropping Images
Oct 05, 2009 | 14 minutes | Plugins
Present a slick user interface for cropping image attachments using Jcrop and Paperclip.
- Download:
- source codeProject Files in Zip (207 KB)
- mp4Full Size H.264 Video (26.2 MB)
- m4vSmaller H.264 Video (16.3 MB)
- webmFull Size VP8 Video (43.2 MB)
- ogvFull Size Theora Video (32 MB)
There is a newer version of this episode, see the revised episode.
Resources
models/user.rb
class User < ActiveRecord::Base has_attached_file :avatar, :styles => { :small => "100x100#", :large => "500x500>" }, :processors => [:cropper] attr_accessor :crop_x, :crop_y, :crop_w, :crop_h after_update :reprocess_avatar, :if => :cropping? def cropping? !crop_x.blank? && !crop_y.blank? && !crop_w.blank? && !crop_h.blank? end def avatar_geometry(style = :original) @geometry ||= {} @geometry[style] ||= Paperclip::Geometry.from_file(avatar.path(style)) end private def reprocess_avatar avatar.reprocess! end end
users_controller.rb
def create @user = User.new(params[:user]) if @user.save if params[:user][:avatar].blank? flash[:notice] = "Successfully created user." redirect_to @user else render :action => "crop" end else render :action => 'new' end end def update @user = User.find(params[:id]) if @user.update_attributes(params[:user]) if params[:user][:avatar].blank? flash[:notice] = "Successfully updated user." redirect_to @user else render :action => "crop" end else render :action => 'edit' end end
lib/paperclip_processors/cropper.rb
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.to_i}x#{target.crop_h.to_i}+#{target.crop_x.to_i}+#{target.crop_y.to_i}'" end end end end
views/users/crop.html.erb
<% title "Crop avatar" %> <% content_for(:head) do %> <%= stylesheet_link_tag "jquery.Jcrop" %> <%= 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, 500, 500], aspectRatio: 1 }); }); function update_crop(coords) { var rx = 100/coords.w; var ry = 100/coords.h; $('#preview').css({ width: Math.round(rx * <%= @user.avatar_geometry(:large).width %>) + 'px', height: Math.round(ry * <%= @user.avatar_geometry(:large).height %>) + 'px', marginLeft: '-' + Math.round(rx * coords.x) + 'px', marginTop: '-' + Math.round(ry * coords.y) + 'px' }); var ratio = <%= @user.avatar_geometry(:original).width %> / <%= @user.avatar_geometry(:large).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 %> <%= image_tag @user.avatar.url(:large), :id => "cropbox" %> <h4>Preview:</h4> <div style="width:100px; height:100px; overflow:hidden"> <%= image_tag @user.avatar.url(:large), :id => "preview" %> </div> <% form_for @user 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 %>