目录
介绍
最近在研究渐进式、交错图片(以下称渐进式),有2个意图。
- 想用一个方便的效果展示渐进式的加载过程
- 利用其特性,我们能做什么
原图片链接为c.png,后端使用php,图片处理引擎是php-GD,基于GD在交错模式下只有行扫描可选,因而本本文只限于交错行扫描模式。以下是数据可以在页面实验页面重现
原文件图片
用网页输出黄金螺旋,字体逐步增大,再稍微调整后参数得到页面,随后网页窗口全屏,用win自带的截屏功能截图。分辨率为1920*1080,位深度位32。大小为:214K。
PNG 编码模式、压缩效果比较
格式 |
压缩比例 |
编码 |
长度比例 |
大小 |
png |
100% |
交错、渐进式 |
100% |
4954.93kB |
png |
100% |
基础式 |
100% |
4954.21kB |
png |
60% |
基础式 |
100% |
184.21kB |
png |
60% |
交错、渐进式 |
100% |
266.59kB |
PNG的交错式会相比基础式稍微大一些,开启压缩式,基础式压缩效果会更好。
压缩小图可以考虑基础式PNG,高清原图图用交错式
JPG 编码模式、压缩效果比较
格式 |
压缩比例 |
编码 |
长度比例 |
大小 |
jpg |
100% |
基础式 |
100% |
226.03kB |
jpg |
100% |
交错、渐进式 |
100% |
190.01kB |
jpg |
60% |
交错、渐进式 |
100% |
56.05kB |
jpg |
60% |
基础式 |
100% |
65.95kB |
JPG格式渐进式在大小方面相比基础式是有优势的。细节方面几乎只和压缩比例有关,压缩的等级越高,图片越小,图片细节也会更差。如图60%的细节明显是由马赛克的。
JPG 用渐进式
PNG,JPG渐进式和压缩效果比较
格式 |
压缩比例 |
编码 |
长度比例 |
大小 |
jpg |
100% |
交错、渐进式 |
100% |
190.01kB |
jpg |
60% |
交错、渐进式 |
100% |
56.05kB |
png |
100% |
交错、渐进式 |
100% |
4954.93kB |
png |
60% |
交错、渐进式 |
100% |
266.59kB |
相对的JPG在大小方面还是有优势,在细节方法,只有压缩60%的JPG在放大后可以看到明显的锯齿,其他3个几乎没有差别。
不会被点开看细节的用jpg就可以了
PNG,JPG基础式和压缩效果比较
格式 |
压缩比例 |
编码 |
长度比例 |
大小 |
png |
100% |
基础式 |
100% |
4954.21kB |
jpg |
100% |
基础式 |
100% |
226.03kB |
jpg |
60% |
基础式 |
100% |
65.95kB |
png |
60% |
基础式 |
100% |
184.21kB |
效果同 PNG,JPG渐进式和压缩效果比较
渐进式和基础式加载特性
由于渐进式图片的特性,在不用完全加载完成我们就可以看到整个图片(没有细节),我在后端图片输出时增加了一个参数,可以控制图片输出长度比例,借此可以得到渐进式的加载过程。而基础式,不完全输出数据我们得到的就是一张半图,我将图片背景设置为红色,更加可观。
JPG 基础式加载过程
格式 |
压缩比例 |
编码 |
长度比例 |
大小 |
jpg |
60% |
基础式 |
25% |
16.49kB |
jpg |
60% |
基础式 |
50% |
32.98kB |
jpg |
60% |
基础式 |
75% |
49.46kB |
jpg |
60% |
基础式 |
100% |
65.95kB |
可以看出,基础式加载方式就是从左往右,从上到下逐步加载。这个过程只加载一次,加载到了就是最终效果,没有清晰的的变化,所以就不对比细节了。
png 基础式加载过程
格式 |
压缩比例 |
编码 |
长度比例 |
大小 |
png |
60% |
基础式 |
25% |
46.05kB |
png |
60% |
基础式 |
50% |
92.11kB |
png |
60% |
基础式 |
75% |
138.16kB |
png |
60% |
基础式 |
100% |
184.21kB |
加载过程和JPG没太大差别,都是基础式加载
JPG 渐进式加载过程
格式 |
压缩比例 |
编码 |
长度比例 |
大小 |
jpg |
60% |
交错、渐进式 |
25% |
14.01kB |
jpg |
60% |
交错、渐进式 |
50% |
28.03kB |
jpg |
60% |
交错、渐进式 |
75% |
42.04kB |
jpg |
60% |
交错、渐进式 |
100% |
56.05kB |
渐进式加载特点就是会直接出一张模糊的图片,再继续加载补充细节。并且有个特点JPG的渐进式加载也是从左往右,从上到下逐步进行补充的,这应该就是行式交错模式了。
从4个阶段的放大图可以看出明显的差别。
- 左上25% 文字还很模糊,甚至还能看到有个加载的过度
- 右上50% 大部分字已经可以看清,但明显的模糊边缘,
- 左下75% 中心小子大概能看清看,边缘更清晰
- 右下100% 相比75%没有太大的区别
但从原图的角度看,其实图片在加载50%后,就已经比较难发现区别了。
PNG 交错式加载过程
格式 |
压缩比例 |
编码 |
长度比例 |
大小 |
png |
60% |
交错、渐进式 |
25% |
66.65kB |
png |
60% |
交错、渐进式 |
50% |
133.29kB |
png |
60% |
交错、渐进式 |
75% |
199.94kB |
png |
60% |
交错、渐进式 |
100% |
266.59kB |
PNG的交错式加载也是由模糊逐渐变清晰,但25%时,也可以得到一张和最终很接近的图片,当然从文件大小的角度,已经和JGP60%压缩的大小接近了。
JPG 渐进式加载至25%过程
格式 |
压缩比例 |
编码 |
长度比例 |
大小 |
jpg |
60% |
交错、渐进式 |
1% |
0.56kB |
jpg |
60% |
交错、渐进式 |
5% |
2.80kB |
jpg |
60% |
交错、渐进式 |
10% |
5.61kB |
jpg |
60% |
交错、渐进式 |
15% |
8.41kB |
jpg |
60% |
交错、渐进式 |
20% |
11.21kB |
jpg |
60% |
交错、渐进式 |
25% |
14.01kB |
在这个阶段可以更清晰的看到JGP渐进式加载时图片质量的变化,在加载到15%时,接近铺满图像,此时的图片有个高斯模糊的效果,个人还挺喜欢的,相比下个阶段边缘虽然清晰了,但是过度时有断层的,肉眼看起来的效果还不如第一阶段的。
PNG 交错式加载至25%过程
格式 |
压缩比例 |
编码 |
长度比例 |
大小 |
png |
60% |
交错、渐进式 |
2% |
5.33kB |
png |
60% |
交错、渐进式 |
5% |
13.33kB |
png |
60% |
交错、渐进式 |
10% |
26.66kB |
png |
60% |
交错、渐进式 |
15% |
39.99kB |
png |
60% |
交错、渐进式 |
20% |
53.32kB |
png |
60% |
交错、渐进式 |
25% |
66.65kB |
在上面的我们发现在25%开始之后,渐进式加载的PNG的图像我们从肉眼已经很难区分。所以加一组0-25%的过程,但这个过程其实是很短的。可以发现,在不进行放大看细节的时候已经可以明显对比出6个阶段的图像质量有明显变化。
- 2%阶段可以发现,这应该就是首次接受到图像数据,并且不足以填满,仍可以看到背景色,此时图像中心的P、T和K,仍然只是像素块,甚至展示出了的颜色还是红和蓝
- 5% 颜色开始分离,P、T可以大概看出结构,K依然一坨
- 10% P、T已经可以分辨出来,竖直位置的部分还是由色差,K变成类似E的形状
- 15% 中心部分没有变化,应该是更新的数据不在中心部分。经过观察,可以发现图像中下的MPS边缘有明显变化。
- 20% 中心P、T已经大部分加载到位,而K才开始可以认出
- 25% 该阶段的变化集中在中上部分,上部分的字母边缘的锯齿状已经不是很明显,左上的K很有代表性,K上半部分和下半部分有明显差异
PNG 交错式不同压缩比、不同比例加载 图片效果
PNG 交错式不同压缩比 图片效果
格式 |
压缩比例 |
编码 |
长度比例 |
大小 |
png |
5% |
交错、渐进式 |
100% |
257.01kB |
png |
20% |
交错、渐进式 |
100% |
262.62kB |
png |
35% |
交错、渐进式 |
100% |
263.21kB |
png |
50% |
交错、渐进式 |
100% |
265.23kB |
png |
65% |
交错、渐进式 |
100% |
274.82kB |
png |
80% |
交错、渐进式 |
100% |
278.45kB |
png |
90% |
交错、渐进式 |
100% |
282.02kB |
png |
100% |
交错、渐进式 |
100% |
4954.93kB |
从数据中可以发现,PNG在压缩90%以下的大小几乎是没有太大差别的,而截图可以发现,在宽度250px的时候,这几个图片展示效果几乎一致。
PNG 交错式不同压缩比加载4% 图片效果
格式 |
压缩比例 |
编码 |
长度比例 |
大小 |
png |
5% |
交错、渐进式 |
4% |
10.28kB |
png |
20% |
交错、渐进式 |
4% |
10.50kB |
png |
35% |
交错、渐进式 |
4% |
10.53kB |
png |
50% |
交错、渐进式 |
4% |
10.61kB |
png |
65% |
交错、渐进式 |
4% |
10.99kB |
png |
80% |
交错、渐进式 |
4% |
11.14kB |
png |
90% |
交错、渐进式 |
4% |
11.28kB |
png |
100% |
交错、渐进式 |
4% |
198.20kB |
4%是一个在各个压缩比例中都可以铺满图像的设置,这里的截图里面的每张图片宽带都设置为250px。在加载同等比例的长度下,压缩比对图像显示效果没有太大差别。
PNG 交错式比例加载和指定大小缩略图效果对比
格式 |
压缩比例 |
编码 |
长度比例 |
大小 |
图片宽 |
显示宽度 |
png |
61% |
交错式 |
100% |
68.32kB |
500px |
500px |
png |
60% |
交错式 |
100% |
29.26kB |
250px |
500px |
png |
60% |
交错式 |
15% |
39.99kB |
1500px |
500px |
png |
60% |
交错式 |
12% |
31.99kB |
1500px |
500px |
png |
60% |
交错式 |
8% |
21.33kB |
1500px |
500px |
png |
60% |
交错式 |
4% |
10.66kB |
1500px |
500px |
图一压缩比例为61%,这是实验页面做了去重,生成宽度为手动调整的,请忽略这1%的差别。
- 图一和图二对比,前者尺寸是后者的2倍,大小是2.33倍,而图片质量有明显提升。毕竟后者被拉伸了。
- 图三和图四,在多加载3%的数据下,图像并没有发现明显的变化
- 图三和图二图片大小接近,但在非细节的显示效果上接近大2倍大小的图一,
补充显示宽度为250px的效果,因为差距不大,所以上诉设置为500px去比较
小结
- 对比100%加载和4%,在250px的宽度下,完全加载图像效果在细节上更好。当然这是在多加载96%数据的情况下。但同等加载比例情况下,压缩等级即不会有太高的压缩效果,展示效果也差不多
- 在250px宽度显示下,60%压缩、4%加载交错式可能会是我的选择
- 在500px宽度显示下,60%压缩、12%加载交错式可能会是我的选择
一个想法
平时我们在准备缩略图或者占位图时,都会事先去生成一张小尺寸图片,然后存起来。这个过程会有2个消耗,一是生成过程,二是存放的空间。而渐进式图片给了我另外一个思路,基于它可以部分加载就显示全尺寸的特性,加之上诉的例子,相信你也猜到我的想法。
- 处理用户上传的图片,将其转为渐进式图片保存。
- 当需要缩略图时,我们直接输出长度4%的图片。
这么做的优点
- 不用担心缩略图的生成和存放问题
- 输出的占位图尺寸与原图一致
- 输出的图片大小甚至比缩略图还要小
可能的疑问:
- 图片要转成渐进式,这也是一种开销呀,怎么就是生成缩略图就多余呢
在某些情况下,我们甚至可能不需要保留用户原图,比如微信聊天如果没显示的指明是原图。后续都会被压缩处理成非原图,而这个过程压缩处理的过程,就是我们设定为渐进式的时机。这和后续再生成缩略图的步骤是不同的
- 我会怎么实现
如你看到的网站,有自己的文件系统,每个图片链接都是一个文件映射。所以在获取图片时本来经过php检查的。以下为伪代码,即参数p有值是输出4%图片内容
<?php
$length = $file['length'];
$path = $file['path'];
$percent = !isset($_GET['p'])?100:4;
header('Content-Type: image/png');
echo file_get_contents($path, FALSE, NULL, 0,round( $length*$percent/100));
当然你还可以加上缓存处理或者在原图输出时启用nginx sendfile功能
3. 文件路径为相对路径,没有经过脚本语言怎么办
可以考虑nginx 路径转发,再由脚本语言处理
2021年11月27日 回来
缩略图的思路估计是不行,按照png交错式加载的第一张大概式原图的1/64,头部信息加点容错视为4%,如果图片式10M,那这种缩略图也要 400k+,那还不如一张小尺寸的缩略图。
自己的发现
渐进式jpeg(progressive jpeg)图片及其相关文中提到
- 渐进式图片一开始大小框架就定好,不会像基本式图片一样,由于尺寸未设定而造成回流——提高的渲染性能;
这一点我是存疑的,在实践的过程中发现,如果不设定图片尺寸,图片加载一定数据后(如:原图片,大概是500b),浏览器就会设定图片的宽度和高度,这时回流已经发生。而基本式图片也是类似的过程,并不会出现图片一边加载一边设定高度同时触发回流,我遇到的情况时,浏览器接受了大概300b数据后就设定了图片的宽的和高度,只发生一次回流。
补充一组PNG交错加载各阶段细节
[摘]png的压缩和过滤
中提到隔行扫描的过程
出于过滤的目的,每个隔行扫描都被视为具有自己宽度和高度的单独图像。例如,在 256 × 256 隔行扫描图像中,通道将被视为尺寸为 32 × 32、32 × 32、64 × 32、64 × 64、128 × 64、128 × 128 和 256 × 128 的七个较小图像, 分别。[69] 这避免了如何在不同宽度的行之间定义相应字节的棘手问题。
翻译下:
如果出去图片的头信息,图片每次会按照[1/64,1/64,2/64,4/64,8/64,16/64,32/64]累计加载,一共加载7次,换算成百分比为[0.015625, 0.015625, 0.03125, 0.0625, 0.125, 0.25, 0.5],按此数组,我们在实验场设定对应比例,非整数往往取整。并加缩放,得到以下图片:
- PNG交错加载各阶段细节 0倍放大
- PNG交错加载各阶段细节 2.5倍放大
- PNG交错加载各阶段细节 5倍放大
- PNG交错加载各阶段细节 10倍放大