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图片裁剪的工具类,
- /**
- *
- */
- 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;
- }
- }
如果您觉得这系列的文章对你有所帮助,欢迎打赏。
支付宝账号:190678908@qq.com 收款人:曾健生
新建了“app后端技术” 交流qq群:254659220
app后端设计(12)--图片的处理的更多相关文章
- app后端设计--总目录 (转)
特此说明,我转载的!!! app后端设计(1)--api app后端设计(2)--xmpp的使用 app后端设计(3)--短信,邮件,推送服务 app后端设计(4)-- 通讯的安全性 app后端设计( ...
- app后端设计--总目录
做了3年app相关的系统架构,api设计,先后在3个创业公司中工作,经历过手机网页端,android客户端,iphone客户端,现就职于app云后端平台bmob(想了解bmob点击这里).其中的乐与苦 ...
- [置顶] app后端设计--总目录
版权声明:本文为博主原创文章,未经博主允许不得转载. 做了3年app相关的系统架构,api设计,先后在3个创业公司中工作,经历过手机网页端,Android客户端,iphone客户端,现就职于app云后 ...
- app后端设计(php)
来源:http://blog.csdn.net/column/details/mobilebackend.html?page=1 做了3年app相关的系统架构,api设计,先后在3个创业公司中工作,经 ...
- app后端设计(0)--总文件夹
原文:http://blog.csdn.net/newjueqi/article/details/19003775 做了接近两年app相关的系统架构,api设计,先后在两个创业公司中工作,经历过手机网 ...
- app后端设计(0)--总目录(转)
原文:http://blog.csdn.net/newjueqi/article/details/19003775 做了接近两年app相关的系统架构,api设计,先后在两个创业公司中工作,经历过手机网 ...
- app后端设计(11)-- 系统架构(2014.12.05更新)
个人认为,在小型的创业团队中,特别是以应用产品为主,在架构后台的时候,需要集中精力解决自身业务上的问题,不是花时间解决第三方已经解决的问题,简单点来说,就是能用第三方服务就使用第三方的服务.基于这个原 ...
- app后端设计(3)--短信,邮件,推送服务(2014.12.05更新)
在app的后端设计中,免不了消息的推送,短信,邮件等服务,下面就个人的开发经验谈谈这方面. (1)最重要的是,各种推送一定要放在队列系统中处理,不然会严重影响api的响应时间. (2)短信方面 以前我 ...
- app后端设计(7)-- 项目管理
移动互联网行业是个快速发展的行业,需求不断变化,产品更新快.基于移动互联网的以上特点,在开发产品的过程中,我们放弃了传统的瀑布流开发模型,引入了精益的理念和scrum这个敏捷开发框架,下面谈谈实施过程 ...
随机推荐
- 伪装的方式实现js继承
看起来属性放到"父类"里了,这种方式原型中还是有属性的,只不过在"子类"的构造器中用call方法调用父类构造函数的时候,"子类"被强行赋值了 ...
- 【python】3.x,string与bytes的区别(文本,二进制数据)
Python 3对文本和二进制数据作了更为清晰的区分.文本总是Unicode,由str类型表示, 二进制数据则由bytes类型表示. 不能拼接字符串和字节包,也无法在字节包里搜索字符串(反之亦然),也 ...
- [SHELL] 修改xml的内容
解析和修改xml用python比较方便,但如果不方便使用python,可以用sed命令简单替换 例如,欲替换下面一行中的端口号的值: <param name="ftpPort" ...
- Cordova学习(一) 环境搭建
一.什么是cordova Cordova提供了一组设备相关的API,通过这组API,移动应用能够以JavaScript访问原生的设备功能,如摄像头.麦克风等. Cordova还提供了一组统一的Java ...
- VS2010的项目配置
一直对VS的项目配置都是不怎么了解的,以前用过点,半年不用后,什么都忘记了... 下面这个是免于输入过长的引用头文件的,比如:#include “D:/C++/curl-7.37.0/libcurl/ ...
- 【Excel】宏之初认识
出于提高效率的原因,希望excel能够不需要人为干预的完成一些操作,学习excel宏的编写与调试: 第一列输入公式,第二类输出计算结果:(如果自动获取文件的行数,待补充) Sub Calc() a = ...
- 写简单游戏,学编程语言-python篇:传说哥大战剧毒术士
上篇写的动画示例其实算不上一个游戏,顶多算是利用pygame进行的图形操作,今天着手实现一个小游戏:传说哥大战剧毒术士.名字很玄乎,其实就是最简单的一个射击游戏.好了废话不多说,先上截图吧: 一.初始 ...
- Draw_extend使用OpenGL显示数据点
//alter load_map.dev //safety verion 2016/1/12 #include <iostream> #include <fstream> #i ...
- HDU 5869 (离线+树状数组)
Problem Different GCD Subarray Query 题目大意 给定n个数的序列,有q个询问,每次询问一个区间中所有子区间所形成不同的gcd的数量. 解题分析 由于固定一个数为右端 ...
- 一款基于bootstrap的datetimepicker
<!DOCTYPE HTML> <html> <head> <link href="http://netdna.bootstrapcdn.com/t ...