首页 > 代码库 > app后端设计(12)--图片的处理.docx
app后端设计(12)--图片的处理.docx
app上线后,不断接受用户的反馈,于是,反馈非常差的情况下,都会有app的改版。
一旦app的改版,都会有比较大的UI改动,一改动UI,那么图片的尺寸也就必须要改变。
在app后端设计(1)—api(http://blog.csdn.net/newjueqi/article/details/14053733)这篇文章中,我提到过app后台图片处理的一个基本原则,数据库中只保存原图的路径。对于同一张图片来说,针对不同机型,不同app版本所需要的不同尺寸,使用动态生成的策略,大体思路如下:
(1) 在图片的url末尾加上参数,声明需要生成的图片的新的尺寸,例如:户端需要图片(http://www.baidu.com/img/bdlogo.gif)的80*80的尺寸,则在图片的路径加上宽和高的参数(类似于CDN的机制) http://www.baidu.com/img/bdlogo.gif?w=80&h=80
(2) 服务器接收到图片的请求,先在缓存中查找这个尺寸的图片是否已经生成,如果已经在缓存中有记录,则不用重新生成。
(3) 如果该尺寸的图片还没生成,则生成新的图片尺寸,并把新生成的图片路径放在缓存中。
在app整个系统架构中,图片应该有两层缓存:
(1) app本地的图片缓存,当app中没有该图片时,才去服务取
(2) 服务器的图片缓存,记录图片不同尺寸的保存路径
我的建议是,如果不差钱,直接使用七牛的云存储的服务吧,云存储不但可以加速图片的下载上传,也能实现图片的大量操作。要知道,速度才是用户体验最直接的部分。
如果真的要自己实现图片的裁切,那么要考虑到图片操作是非常消耗CPU,内存,和大量的磁盘IO,所以在选择图片处理工具要慎重!!!
推荐使用GraphicsMagick,一个久经考验的图片处理软件,支持多个平台,而且支持多种语言的客服端。GraphicsMagick是ImageMagick的一个分支,相对于ImageMagick而言,TA处理速度更快,消耗资源更少,并且大的图片处理网站,如 Flickr and Etsy 已经在使用TA了。
使用GraphicsMagick时,最折腾的是怎么配GraphicsMagick环境,查阅了大量的文章,都注明在linux下不能使用cmd.setSearchPath(path); ,但经过我实验,是可以的,而且配了这个的话,可以让linux和win下都运行同一段代码,只要把path放在配置文件中就好了。
下面我写的GraphicsMagick+Im4java图片裁剪的工具类,
/** * */ package com.bmob.worker.image; import java.awt.image.BufferedImage; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.util.concurrent.ExecutionException; /** */ public class Image { /* 1、指定宽,高自适应,等比例缩放; 2、指定高, 宽自适应,等比例缩放; 3、指定最长边,短边自适应,等比例缩放; 4、指定最短边,长边自适应,等比例缩放; 5、指定最大宽高, 等比例缩放; 6、固定宽高, 居中裁剪) */ public static int DefineWidth=1; public static int DefineHeight=2; public static int DefineLong=3; public static int DefineShort=4; public static int MaxWidthHeight=5; public static int DefineWidthHeight=6; /** * 图片缩放的方法 * * @param mode 1、指定宽,高自适应,等比例缩放; 2、指定高, 宽自适应,等比例缩放; 3、指定最长边,短边自适应,等比例缩放; 4、指定最短边,长边自适应,等比例缩放; 5、指定最大宽高, 等比例缩放; 6、固定宽高, 居中裁剪) * @param src 源文件路径 * @param desc 目标文件路径 * @param width 指定宽 * @param height 指定高 * @param maxFrame 指定最长边 * @param minFrame 指定最短边 * @return * @throws Exception */ public String resize(int mode, String src,String desc, int width, int height, int maxFrame, int minFrame) throws Exception { String str=""; BHPApplication.init(); // create command ConvertCmd cmd = this.getCmd(); IMOperation op =null; if( mode==Image.DefineWidth ){ op=this.resizeDefineWidth( src,desc, width, height); }else if( mode==Image.DefineHeight ){ op=this.resizeDefineHeight( src,desc, width, height); }else if( mode==Image.DefineLong ){ op=this.resizeDefineLong( src,desc, maxFrame); }else if( mode==Image.DefineShort ){ op=this.resizeDefineShort( src,desc, minFrame); }else if( mode==Image.MaxWidthHeight ){ op=this.resizeMaxWidthHeight( src,desc, width, height); }else if( mode==Image.DefineWidthHeight ){ op=this.resizeDefineWidthHeight( src,desc, width, height); } cmd.run(op); return str; } //指定宽,高自适应,等比例缩放; public IMOperation resizeDefineWidth(String src,String desc, int width, int height){ IMOperation op = new IMOperation(); op.addImage(src); op.resize(width,null); op.addImage(desc); return op; } //指定高, 宽自适应,等比例缩放; public IMOperation resizeDefineHeight(String src,String desc, int width, int height){ IMOperation op = new IMOperation(); op.addImage(src); op.resize(null,height); op.addImage(desc); return op; } //指定最长边,短边自适应,等比例缩放; public IMOperation resizeDefineLong(String src,String desc, int maxFrame) throws Exception{ InputStream is = new FileInputStream(src);//通过文件名称读取 BufferedImage buff = ImageIO.read(is); int srcWidth=buff.getWidth();//得到图片的宽度 int srcHeight=buff.getHeight(); //得到图片的高度 is.close(); //关闭Stream IMOperation op = new IMOperation(); op.addImage(src); if( srcWidth>srcHeight ){ op.resize(maxFrame,null); }else{ op.resize(null,maxFrame); } op.addImage(desc); return op; } //指定最短边,长边自适应,等比例缩放; public IMOperation resizeDefineShort(String src,String desc, int minFrame) throws Exception { InputStream is = new FileInputStream(src);//通过文件名称读取 BufferedImage buff = ImageIO.read(is); int srcWidth=buff.getWidth();//得到图片的宽度 int srcHeight=buff.getHeight(); //得到图片的高度 is.close(); //关闭Stream IMOperation op = new IMOperation(); op.addImage(src); if( srcWidth<srcHeight ){ op.resize(minFrame,null); }else{ op.resize(null,minFrame); } op.addImage(desc); return op; } //指定最大宽高, 等比例缩放; public IMOperation resizeMaxWidthHeight(String src,String desc, int width, int height){ IMOperation op = new IMOperation(); op.addImage(src); op.resize(width,height,'!'); op.addImage(desc); return op; } //固定宽高, 居中裁剪 public IMOperation resizeDefineWidthHeight(String src,String desc, int width, int height){ IMOperation op = new IMOperation(); op.addImage(src); op.gravity("center").extent(width, height); op.addImage(desc); return op; } public ConvertCmd getCmd(){ ConvertCmd cmd = new ConvertCmd(true); //set true, use GraphicsMagick String path = "/usr/local/GraphicsMagick/bin"; //GraphicsMagick安装路径 cmd.setSearchPath(path); return cmd; } }
新建了“app后端技术” 交流qq群:254659220
[文章作者]曾健生
[作者邮箱]h6k65@126.com
[作者QQ]190678908
[新浪微博] @newjueqi
[博客]http://blog.csdn.net/newjueqi
app后端设计(12)--图片的处理.docx