JavaEye提供了很多图片上传的功能,比如个人头像,博客相册,帖子附件等等,这些功能都是用
attachment_fu插件实现的。
为了避免图片过大,给用户带来浏览速度的麻烦,我们最近加上了图片压缩功能:比如用户上传的是BMP格式,自动转化成PNG。再比如用户上传动态GIF头像,自动取第一帧作为头像。
而attachment_fu插件本身并没有这个功能,我们来看一下如何实现:
attachment_fu支持多个图像处理的库,我推荐使用mini_magick,下面的代码以它为例,给MiniMagick::Image添加压缩的方法:
module MiniMagick
class Image
def compressing(convert_gif)
format = self[:format]
if convert_gif && format == "GIF"
#convert 1st frame for animation gif
run_command("convert","#{@path}[0]", "#{@path}")
elsif format == "BMP"
format("PNG")
end
end
end
end
然后我们只需要修改attachment_fu插件的源代码,在mini_magick_processor.rb的 resize_image方法开头添加一行:
img.compressing(true)
在process_attachment_with_processing方法修改with_image block,添加2行:
img.compressing(false)
self.temp_path = img
但是这样做有一个缺点,就是需要直接修改plugin的源代码,这样在升级plugin的时候,会带来一些麻烦:你得记住自己做的改动,然后再手工合并。我们可以利用ruby open class的特性在外部来修改:
Technoweenie::AttachmentFu::Processors::MiniMagickProcessor.module_eval do
def resize_image_with_compressing(img, size)
img.compressing(true)
resize_image_without_compressing(img, size)
end
alias_method_chain :resize_image, :compressing
def process_attachment_with_processing_with_compressing
with_image do |img|
img.compressing(false)
self.temp_path = img
end if image?
process_attachment_with_processing_without_compressing
end
alias_method_chain :process_attachment_with_processing, :compressing
end
我们可以把这段代码和最开始的压缩方法代码放在一个initializer里面,这样就实现了无侵入的plugin hack,虽然代码比直接修改要复杂一些,但对于plugin升级和维护会很方便,如果你有其他的插件需要自定制,也可以考虑采用这种方式。
除了格式转化达到压缩效果以外,你也可以使用更高PNG或者JPG格式的压缩率,或者添加水印功能,具体的命令api可参考magick文档。