app后端设计(12)--图片的处理

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图片裁剪的工具类,

 

 

 

[java] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. /** 
  2.  *  
  3.  */  
  4. package com.bmob.worker.image;  
  5.   
  6. import java.awt.image.BufferedImage;  
  7. import java.io.FileInputStream;  
  8. import java.io.FileNotFoundException;  
  9. import java.io.IOException;  
  10. import java.io.InputStream;  
  11. import java.util.concurrent.ExecutionException;  
  12.   
  13.   
  14.   
  15. /** 
  16.  
  17.  */  
  18. public class Image {  
  19.   
  20.     /* 
  21.      1、指定宽,高自适应,等比例缩放; 
  22.      2、指定高, 宽自适应,等比例缩放; 
  23.      3、指定最长边,短边自适应,等比例缩放; 
  24.      4、指定最短边,长边自适应,等比例缩放; 
  25.      5、指定最大宽高, 等比例缩放; 
  26.      6、固定宽高, 居中裁剪) 
  27.      */  
  28.     public static int DefineWidth=1;   
  29.     public static int DefineHeight=2;   
  30.     public static int DefineLong=3;   
  31.     public static int DefineShort=4;   
  32.     public static int MaxWidthHeight=5;   
  33.     public static int DefineWidthHeight=6;   
  34.       
  35.     /** 
  36.      * 图片缩放的方法 
  37.      *  
  38.      * @param mode 
  39.      1、指定宽,高自适应,等比例缩放; 
  40.      2、指定高, 宽自适应,等比例缩放; 
  41.      3、指定最长边,短边自适应,等比例缩放; 
  42.      4、指定最短边,长边自适应,等比例缩放; 
  43.      5、指定最大宽高, 等比例缩放; 
  44.      6、固定宽高, 居中裁剪) 
  45.      * @param src 源文件路径 
  46.      * @param desc 目标文件路径 
  47.      * @param width 指定宽 
  48.      * @param height 指定高 
  49.      * @param maxFrame 指定最长边 
  50.      * @param minFrame 指定最短边 
  51.      * @return 
  52.      * @throws Exception 
  53.      */  
  54.     public  String resize(int mode, String src,String desc, int width, int height, int maxFrame, int minFrame) throws Exception {  
  55.           
  56.         String str="";  
  57.           
  58.         BHPApplication.init();  
  59.           
  60.         // create command  
  61.         ConvertCmd cmd = this.getCmd();  
  62.         IMOperation op =null;  
  63.         if( mode==Image.DefineWidth ){  
  64.             op=this.resizeDefineWidth( src,desc, width, height);  
  65.         }else if( mode==Image.DefineHeight ){  
  66.             op=this.resizeDefineHeight( src,desc, width, height);  
  67.         }else if( mode==Image.DefineLong ){  
  68.             op=this.resizeDefineLong( src,desc, maxFrame);  
  69.         }else if( mode==Image.DefineShort ){  
  70.             op=this.resizeDefineShort( src,desc, minFrame);  
  71.         }else if( mode==Image.MaxWidthHeight ){  
  72.             op=this.resizeMaxWidthHeight( src,desc, width, height);  
  73.         }else if( mode==Image.DefineWidthHeight ){  
  74.             op=this.resizeDefineWidthHeight( src,desc, width, height);  
  75.         }  
  76.           
  77.         cmd.run(op);  
  78.           
  79.         return str;  
  80.     }  
  81.       
  82.     //指定宽,高自适应,等比例缩放;  
  83.     public  IMOperation resizeDefineWidth(String src,String desc, int width, int height){  
  84.         IMOperation op = new IMOperation();  
  85.         op.addImage(src);  
  86.         op.resize(width,null);  
  87.         op.addImage(desc);        
  88.         return op;  
  89.     }  
  90.       
  91.     //指定高, 宽自适应,等比例缩放;  
  92.     public  IMOperation resizeDefineHeight(String src,String desc, int width, int height){  
  93.         IMOperation op = new IMOperation();  
  94.         op.addImage(src);  
  95.         op.resize(null,height);  
  96.         op.addImage(desc);        
  97.         return op;  
  98.     }  
  99.       
  100.     //指定最长边,短边自适应,等比例缩放;  
  101.     public  IMOperation resizeDefineLong(String src,String desc, int maxFrame) throws Exception{  
  102.           
  103.         InputStream is = new FileInputStream(src);//通过文件名称读取  
  104.         BufferedImage buff = ImageIO.read(is);  
  105.         int srcWidth=buff.getWidth();//得到图片的宽度  
  106.         int srcHeight=buff.getHeight();  //得到图片的高度  
  107.         is.close(); //关闭Stream  
  108.           
  109.         IMOperation op = new IMOperation();  
  110.         op.addImage(src);  
  111.         if( srcWidth>srcHeight ){  
  112.             op.resize(maxFrame,null);  
  113.         }else{  
  114.             op.resize(null,maxFrame);  
  115.         }  
  116.           
  117.         op.addImage(desc);        
  118.         return op;  
  119.     }  
  120.       
  121.     //指定最短边,长边自适应,等比例缩放;  
  122.     public  IMOperation resizeDefineShort(String src,String desc, int minFrame) throws Exception {  
  123.           
  124.         InputStream is = new FileInputStream(src);//通过文件名称读取  
  125.         BufferedImage buff = ImageIO.read(is);  
  126.         int srcWidth=buff.getWidth();//得到图片的宽度  
  127.         int srcHeight=buff.getHeight();  //得到图片的高度  
  128.         is.close(); //关闭Stream        
  129.           
  130.         IMOperation op = new IMOperation();  
  131.         op.addImage(src);  
  132.         if( srcWidth<srcHeight ){  
  133.             op.resize(minFrame,null);  
  134.         }else{  
  135.             op.resize(null,minFrame);  
  136.         }  
  137.         op.addImage(desc);        
  138.         return op;  
  139.     }  
  140.       
  141.     //指定最大宽高, 等比例缩放;  
  142.     public  IMOperation resizeMaxWidthHeight(String src,String desc, int width, int height){  
  143.         IMOperation op = new IMOperation();  
  144.         op.addImage(src);  
  145.         op.resize(width,height,'!');  
  146.         op.addImage(desc);        
  147.         return op;  
  148.     }  
  149.       
  150.     //固定宽高, 居中裁剪  
  151.     public  IMOperation resizeDefineWidthHeight(String src,String desc, int width, int height){  
  152.         IMOperation op = new IMOperation();  
  153.         op.addImage(src);  
  154.         op.gravity("center").extent(width, height);    
  155.         op.addImage(desc);        
  156.         return op;  
  157.     }     
  158.       
  159.     public  ConvertCmd getCmd(){  
  160.         ConvertCmd cmd = new ConvertCmd(true); //set true, use GraphicsMagick  
  161.         String path = "/usr/local/GraphicsMagick/bin"; //GraphicsMagick安装路径  
  162.         cmd.setSearchPath(path);          
  163.         return cmd;  
  164.     }  
  165.       
  166.       
  167.   
  168. }  



app后端系列文章总目录

 

如果您觉得这系列的文章对你有所帮助,欢迎打赏。
支付宝账号:190678908@qq.com 收款人:曾健生

 

新建了“app后端技术” 交流qq群:254659220 

posted on 2016-11-28 22:30  cn三少<script></script>  阅读(1197)  评论(0编辑  收藏  举报

导航