前端-业务场景3
3.图片压缩算法
参考答案:
PNG图片的压缩,分两个阶段:
预解析(Prediction):这个阶段就是对png图片进行一个预处理,处理后让它更方便后续的压缩。说白了,就是一个女神,在化妆前,会先打底,先涂乳液和精华,方便后续上妆、美白、眼影、打光等等。压缩(Compression):执行Deflate压缩,该算法结合了 LZ77 算法和 Huffman 算法对图片进行编码。
预解析(Prediction)
png图片用差分编码(Delta encoding)对图片进行预处理,处理每一个的像素点中每条通道的值,差分编码主要有几种:
- 不过滤
- X-A
- X-B
- X-(A+B)/2(又称平均值)
- Paeth推断(这种比较复杂)
假设,一张png图片如下:

这张图片是一个红色逐渐增强的渐变色图,它的红色从左到右逐渐加强,映射成数组的值为[1,2,3,4,5,6,7,8],使用X-A的差分编码的话,那就是:
[2-1=1, 3-2=1, 4-3=1, 5-4=1, 6-5=1, 7-6=1, 8-7=1]
得到的结果为
[1,1,1,1,1,1,1]
最后的[1,1,1,1,1,1,1]这个结果出现了大量的重复数字,这样就非常适合进行压缩。
这就是为什么渐变色图片、颜色值变化不大并且颜色单一的图片更容易压缩的原理。
差分编码的目的,就是尽可能的将png图片数据值转换成一组重复的、低的值,这样的值更容易被压缩。
最后还要注意的是,差分编码处理的是每一个的像素点中每条颜色通道的值,R(红)、G(绿)、B(蓝)、A(透明)四个颜色通道的值分别进行处理。
压缩(Compression)
压缩阶段会将预处理阶段得到的结果进行Deflate压缩,它由 Huffman 编码 和 LZ77压缩构成。
如前面所说,Deflate压缩会标记图片所有的重复数据,并记录数据特征和结构,会得到一个压缩比最大的png图片 编码数据。
Deflate是一种压缩数据流的算法. 任何需要流式压缩的地方都可以用。
还有就是我们前面说过,一个png图片,是由很多的数据块构成的,但是数据块里面的一些信息其实是没有用的,比如用Photoshop保存了一张png图片,图片里就会有一个区块记录“这张图片是由photshop创建的”,很多类似这些信息都是无用的,如果用photoshop的“导出web格式”就能去掉这些无用信息。导出web格式前后对比效果如下图所示:

4. 加载很多图片时的优化方法,页面加载时的交互优化
参考答案:
1. 图片压缩
页面是由“小图”平铺来的,却需要加载大量原图,得不偿失。于是很自然的会想到,将“小图”变为真正的小图,当实际点击大图时再去请求原图,这样便会大大减少页面加载时间。
a. 图片异源加载
HTML代码img标签中将真实图片地址写在 data-original 属性中,而 src 属性中的图片换成占位符的图片(压缩图)
<!-- 添加 width 和 height 属性有助于在图片未加载时占满所需要的空间 --> <img class="lazy" src="grey.gif" data-original="example.jpg" width="640" heigh="480">
b. Java后台图片压缩
- 利用Java原生的imageIO类进行裁剪
/**
* 缩放图像(按比例缩放)
*
* @param src 源图像
* @param output 输出流
* @param scale 缩放比例
* @param flag 缩放选择:true 放大; false 缩小;
*/
public static final void zoomScale(BufferedImage src, OutputStream output, String type, double scale, boolean flag) {
try {
// 得到源图宽
int width = src.getWidth();
// 得到源图长
int height = src.getHeight();
if (flag) {
// 放大
width = Long.valueOf(Math.round(width * scale)).intValue();
height = Long.valueOf(Math.round(height * scale)).intValue();
} else {
// 缩小
width = Long.valueOf(Math.round(width / scale)).intValue();
height = Long.valueOf(Math.round(height / scale)).intValue();
}
Image image = src.getScaledInstance(width, height, Image.SCALE_DEFAULT);
BufferedImage tag = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics g = tag.getGraphics();
// 绘制缩小后的图
g.drawImage(image, 0, 0, null);
g.dispose();
// 输出为文件
ImageIO.write(tag, type, output);
} catch (IOException e) {
throw new KitException(e);
}
}
使用原生imageIO类进行压缩图片,速度较快,但仅能对图片尺寸进行压缩,但不能压缩图片质量。
借助一些三方插件,如使用google开源工具Thumbnailator实现图片压缩
Thumbnailator是一个用java生成高质量缩略图的第三方库,可以用来:
1.生成缩率图;2.添加水印;3.图片旋转;4.图片大小缩放;5.图片压缩;
Thumbnailator库只有一个jar,不依赖第三方库,maven依赖
<dependency> <groupId>net.coobird</groupId> <artifactId>thumbnailator</artifactId> <version>0.4.8</version> </dependency>
Thumbnailator接口链式风格写法,使用简单
Thumbnails.of("原图文件的路径").scale(1f).outputQuality(0.5f).toFile("压缩后文件的路径");
前端JS实现图片压缩
HTML5 file API加canvas实现图片JS压缩
/**
* 图片压缩,默认同比例压缩
* @param {Object} path
* 图片路径
* @param {Object} obj
* obj 对象 有 width, height, quality(0-1) 不传width和 height,图片大小不变只改变像素值
* @param {Object} callback
* 回调函数有一个参数,base64的字符串数据
*/
function dealImage(path, obj, callback){
var img = new Image();
img.src = path;
img.onload = function(){
var that = this;
// 默认按比例压缩
var w = that.width,
h = that.height,
scale = w / h;
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
本面试宝典均来自校招面试题目大数据进行的整理
查看14道真题和解析
vivo公司福利 739人发布