ruby on rails 3 RMgick + paperclip + Jcrop 实现 图片上传 切割

上一篇ruby on rails 3 RMagick + paperclip 实现文件上传 图片上传
讲到了上传,但是在实际运用中,可能需要对用户的上传的图片做处理,比如加水印,重新缩放,裁剪等等,
这篇文章就是如何应用paperclip强大的功能和Jcrop简单的结合来实现上传后的图片裁剪
同样是参考了railscast的视频182-cropping-images
但是随着paperclip的升级和ruby on rails 3的普及,原文中的代码有些需要改动,我就结合实际运用来重新做下记录

首先是对model的修改
给has_attached_file添加一个属性,来自定义新的处理器

先看看截图吧
刚上传至服务器

切割以后

上一篇ruby on rails 3 RMagick + paperclip 实现文件上传 图片上传
讲到了上传,但是在实际运用中,可能需要对用户的上传的图片做处理,比如加水印,重新缩放,裁剪等等,
这篇文章就是如何应用paperclip强大的功能和Jcrop简单的结合来实现上传后的图片裁剪
同样是参考了railscast的视频182-cropping-images
但是随着paperclip的升级和ruby on rails 3的普及,原文中的代码有些需要改动,我就结合实际运用来重新做下记录

首先是对model的修改
给has_attached_file添加一个属性,来自定义新的处理器
[ccn lang="ruby" tab_size="4" theme="blackboard" width="800" ]
:processors => [:cropper],
[/ccn]
然后model里增加
attr_accessor :crop_x, :crop_y, :crop_w, :crop_h
after_update :reprocess_photo, :if => :cropping?
一个是新增的属性,针对坐标点和宽高,一个是在更新后的操作的定义

两个自定义方法
[ccn lang="ruby" tab_size="4" theme="blackboard" width="800" ]
def cropping?
!crop_x.blank? && !crop_y.blank? && !crop_w.blank? && !crop_h.blank?
end

def photo_geometry(style = :original)
@geometry ||= {}
@geometry[style] ||= Paperclip::Geometry.from_file(photo.path(style))
end

[/ccn]
和一个私有的方法
[ccn lang="ruby" tab_size="4" theme="blackboard" width="800" ]
def reprocess_photo
photo.reprocess!
end
[/ccn]
修改后的完整的model如下
[ccn lang="ruby" tab_size="4" theme="blackboard" width="800" ]
class DlThread < ActiveRecord::Base belongs_to :user,:class_name => "User"
belongs_to :dl_type,:class_name => "DlType"
#belongs_to :dl_image,:class_name => "DlImage"
has_attached_file :photo,
:styles => { :medium => "300x300>", :thumb => "100x100>" },
:processors => [:cropper],
:url => "#{DOWNLOAD_THREAD_PHOTO_ROOT_URL}/:attachment/:year/:month/:day/:id/:style/:filename",
:path => "#{DOWNLOAD_THREAD_PHOTO_ROOT_PATH}/:attachment/:year/:month/:day/:id/:style/:filename",
:use_timestamp => true
# 以下3个验证都可以添加message属性来返回错误
# 必填
#validates_attachment_presence :photo
# 文件类型验证
validates_attachment_content_type :photo, :content_type => ['image/jpeg', 'image/png', 'image/gif']
# 小于1M
validates_attachment_size :photo, :less_than => 1.megabyte
before_create :randomize_file_name

attr_accessor :crop_x, :crop_y, :crop_w, :crop_h
after_update :reprocess_photo, :if => :cropping?

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

def photo_geometry(style = :original)
@geometry ||= {}
@geometry[style] ||= Paperclip::Geometry.from_file(photo.path(style))
end

private

def randomize_file_name
extension = File.extname(photo_file_name).downcase
self.photo.instance_write(:file_name, "#{ActiveSupport::SecureRandom.hex(16)}#{extension}")
end
def reprocess_photo
photo.reprocess!
end

end

[/ccn]

然后修改controller
update方法修改为
[ccn lang="ruby" tab_size="4" theme="blackboard" width="800" ]
def update
@dl_thread = DlThread.find(params[:id])
@dl_thread.update_attributes(params[:dl_thread])
respond_to do |format|
if @dl_thread.update_attributes(params[:dl_thread])
format.html { redirect_to([:downloads, @dl_thread], :notice => 'Dl thread was successfully updated.') }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => @dl_thread.errors, :status => :unprocessable_entity }
end
end
end

[/ccn]
create方法修改为
[ccn lang="ruby" tab_size="4" theme="blackboard" width="800" ]
def create
@dl_thread = DlThread.new(params[:dl_thread])

respond_to do |format|
if @dl_thread.save
if params[:dl_thread][:photo].blank?
format.html { redirect_to([:downloads, @dl_thread], :notice => 'Dl thread was successfully created.') }
else
format.html { render :action => "crop" }
end
else
format.html { render :action => "new" }
format.xml { render :xml => @dl_thread.errors, :status => :unprocessable_entity }
end
end
end
[/ccn]

去jcrop的官方网站下载lib
分别放到public的javascripts和stylesheets里
新建一个crop的html.erb并在views里引用,并加上jcrop的处理代码和预览的代码
[ccn lang="ruby" tab_size="4" theme="blackboard" width="800" ]
<% content_for :head do %>
<%= stylesheet_link_tag('jquery.Jcrop.css') %>

<%= javascript_include_tag 'jquery.Jcrop.min.js' %>

<% end %>
[/ccn]

view里form的部分和预览的部分的代码
[ccn lang="ruby" tab_size="4" theme="blackboard" width="800" ]
<% form_for( [:downloads, @dl_thread] ) do |f| %>
<%= label_tag(:crop_origin, "原图:") %>
<%= image_tag @dl_thread.photo.url(:medium), :id => 'cropbox' %>
<%= label_tag(:crop_preview, "预览图:") %>

<%= image_tag @dl_thread.photo.url(:medium), :id => "preview" %>

<% for attribute in [:crop_x, :crop_y, :crop_w, :crop_h] %>
<%= f.hidden_field attribute, :id => attribute %>
<% end %>

<% end %>
[/ccn]
还没完
在lib下新建lib/paperclip_processors/cropper.rb
代码如下,(注意,这段代码和原视频中的不同,经过修改,因为paperclip的升级)
[ccn lang="ruby" tab_size="4" theme="blackboard" width="800" ]
module Paperclip
class Cropper < Thumbnail def transformation_command if crop_command crop_command + super.join(' ').sub(/ -crop \S+/, '').split(' ') # super returns an array like this: ["-resize", "100x", "-crop", "100x100+0+0", "+repage"] 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 [/ccn] 到此为止,所以的工作都做完了,加上了这个功能以后,他会对你显示的那张图重新切割和缩放,目录格式和原来一样,只是被覆盖了,但是origin的图片是不会改变的