前言
之前的文章——图片优化调研之理论篇——主要以理论的东西为主。正确选择合适的图片格式——不管你用Fireworks还是Photoshop,可用预览功能多去尝试,选择size最小的且确保质量(其场景与PM商定)的图片。另一个方面,就是无损压缩。本篇文章主要针对自动无损压缩,具体再啰嗦一下如何实现。
实践
1.pngout客户端实现图片批量无损压缩
pngout官网提供一个windows平台客户端版本——http://www.ardfry.com/pngoutwin/ 简单介绍它怎么用——
1.1 设置压缩图片输出路径
1.2 选择源图文件夹
这里仅仅针对批量压缩——
1.3 看结果
这里对common模块(随意举例)进行例子解析——
当压缩图片的格式选择gif的时候(仅仅针对gif格式的图片进行压缩),会看到——
所有的gif图片均转换为png格式图片,再进行无损压缩,整体压缩之后的结果——
出现一个问题,本来loading.gif是多帧动画,却被压缩成了单帧png,不符合预期。因此,这里的整体替换(gif-->png)存在一定风险,要确保排除动画gif的压缩。
在这里,就不介绍将jpg转换为png的过程了(同gif),不建议这样去做,以免造成大量失真。
在来看看它的压缩率,会看到批量压缩节省的字节数——
自然就能算出整体压缩率了。
2.smushit
《高性能网站建设进阶指南》这本书的作者提供的服务http://www.smushit.com/ysmush.it/ 这里使用node-smushit模块实现批量压缩——
1 var minifier = require('node-smushit'); 2 var log4js = require('log4js'); 3 var logger = log4js.getLogger(); 4 5 var util = (function() { 6 var src_total_size = 0; // 记录输入图片总大小 7 var dest_total_size = 0; // 记录输出图片总大小 8 var total_percent; // 记录总的压缩率 9 10 var total = 0; // 图片总个数 11 var saving = 0; // 需要压缩的图片总个数 12 13 // 递增图片总个数 14 var increaseTotal = function() { 15 total = total + 1; 16 }; 17 18 // 获取图片总个数 19 var getTotal = function() { 20 return total; 21 }; 22 23 // 递增需要压缩的图片总个数 24 var increaseSaving = function() { 25 saving = saving + 1; 26 }; 27 28 // 获取需要压缩的图片总个数 29 var getSaving = function() { 30 return saving; 31 }; 32 33 // 递增输入图片大小 34 var increaseSrcTotalSize = function(itemSize) { 35 src_total_size = src_total_size + itemSize; 36 }; 37 38 // 获取输入图片总大小 39 var getSrcTotalSize = function() { 40 return src_total_size; 41 }; 42 43 // 递增输出图片总大小 44 var increaseDestTotalSize = function(itemSize) { 45 dest_total_size = dest_total_size + itemSize; 46 }; 47 48 // 获取输出图片总大小 49 var getDestTotalSize = function() { 50 return dest_total_size; 51 }; 52 53 // 计算压缩率 54 var computeTotalPercent = function() { 55 total_percent = ((src_total_size - dest_total_size) / src_total_size * 100).toFixed(2) + '%'; 56 }; 57 58 // 获取压缩率 59 var getTotalPercent = function() { 60 return total_percent; 61 }; 62 63 // 压缩图片与原图片的大小差值,即节省了多少字节 64 var getReduce = function() { 65 return src_total_size - dest_total_size; 66 }; 67 68 return { 69 getTotal: getTotal, 70 getSaving: getSaving, 71 getSrcTotalSize: getSrcTotalSize, 72 getDestTotalSize: getDestTotalSize, 73 getTotalPercent: getTotalPercent, 74 increaseTotal: increaseTotal, 75 increaseSaving: increaseSaving, 76 increaseSrcTotalSize: increaseSrcTotalSize, 77 increaseDestTotalSize: increaseDestTotalSize, 78 computeTotalPercent: computeTotalPercent, 79 getReduce: getReduce 80 }; 81 })(); 82 83 // 打印日志 84 var printResult = function() { 85 logger.info('图片总个数:' + util.getTotal()); 86 logger.info('无损压缩图片总个数:' + util.getSaving()); 87 88 logger.info('输入需要压缩的图片总大小:' + util.getSrcTotalSize() + ' Bytes'); 89 logger.info('输出经过压缩的图片总大小:' + util.getDestTotalSize() + ' Bytes'); 90 logger.info('-------------共节省大小:' + util.getReduce() + ' Bytes'); 91 logger.info('压缩率(相对输入图片总大小):' + util.getTotalPercent()); 92 }; 93 94 // 这里可以指定多个图片文件夹目录,用数组表示 95 minifier.smushit(['./static/images/', './widget/'], { 96 97 // 循环遍历文件夹及其子目录中的图片设置 98 // true: 遍历循环 99 // false: 非遍历循环 100 recursive: true, 101 102 // 每张图片开始压缩 103 onItemStart: function(item) { 104 // 这里的item是每张输入图片的源地址 105 }, 106 107 // 每张图片完成压缩 108 onItemComplete: function(e, item, response) { 109 /** 110 * response的格式—— 111 * { 112 * src: '', 113 * src_size: , 114 * dest: '', 115 * dest_size: , 116 * percent: , 117 * id: '' 118 * } 119 */ 120 121 // 过滤掉svn目录中的文件 122 if (/.svn/g.test(response.src) === false) { 123 util.increaseTotal(); 124 125 /* 126 * 注意: 127 * 当检测到某些图片已经无法压缩或者已经经过压缩,此时response.src_size的值是undefined 128 * 因此在这儿加入一层过滤,针对可以压缩的图片进行统计 129 */ 130 if (response.src_size && response.dest_size) { 131 util.increaseSaving(); 132 util.increaseSrcTotalSize(response.src_size); 133 util.increaseDestTotalSize(response.dest_size); 134 } 135 } 136 137 }, 138 139 // 所有图片完成压缩 140 // 这里的reports变量记录所有图片的源地址、源大小、目标地址、目标大小、压缩率等信息的列表 141 onComplete: function(reports) { 142 143 // 统计压缩率 144 util.computeTotalPercent(); 145 146 // 打印统计日志 147 printResult(); 148 } 149 });
可以看到结果——
3. 其他实现方案
不管用node或者php或者shell,整体的实现思路均是循环遍历图片,然后使用合适的命令行工具实现无损压缩。在这儿就不继续说了。