图片压缩——你的浏览器为每种格式各花掉多少字节

把压缩量称给你看,而不是许诺:你的浏览器能编码的每种格式实际写出多少字节,需要卡体积时它对质量梯子做的那次搜索,还有元数据和透明度各失去了什么。你的图片不会离开这台设备。

有损压缩在压掉什么

压缩走的是哪条路:解码,再交回浏览器编码

这里没有第二只手:图片被解码成一块像素的矩形,然后再被请出你浏览器自己的编码器编回去。表格里称出来的一切都由这条路径决定。出去的字节是由你浏览器里装的那个编码器写下的,而报出来的就是拿到的那个文件,不是它觉得这个文件应该是多大。

这也正是结果可以比源文件更大的原因。重新编码从原始像素起步,所以一个本来就被压得很讲究的文件,除了往旁边或往上走,没有别的地方可去。这一类页面大多摆一个滑块和一个谁也没量过的百分比;摆出来的那个数字是你的浏览器真正写下的,包括它走反了方向的那几趟。

为什么质量数字不是一个体积

质量是伸进编码器内部的一个旋钮,不是一个目标。一张细节丰富的照片压到 JPEG 80,和一张平涂的标志压到 JPEG 80,是两个差得很远的文件,因为那个数字在两边走的是同一笔交易,而第二边本来就没多少东西可扔。所以有两件事会发生:字节被打印出来;而如果你给出一个以千字节计的体积,梯子上就会被搜索出还能装得下你那个数字的最高那一级——先试你给的上限,再试质量 1,然后在两者之间对半分,最多六次编码。

六次编码不够把缝合上的时候,这句话会被说出来,并且点名那些从来没有被量过的级。它不会为了凑出你的数字而悄悄丢像素:更少的像素是另一个决定,它属于最长边那个框,而你拿到的文件应该是你选定的那一个。

画布扔掉了什么

画布装的是像素。一张图片文件还能携带的其他一切——相机和镜头、拍摄日期、GPS 段、旋转标记、色彩配置、内嵌的缩略图、注释——都住在像素矩形之外,所以并不是有什么东西被刻意剥掉了:画布从来就看不见它们。在你把一张压缩过的照片当作"我当时站在那里"的凭证发往某处之前,这一点值得先停下来想一想。

回来的那个文件也不是裸的像素。编码器会在交给它的一切外面写下自己的头部——一个格式标记,有时还有一个色彩标签——而这些字节每一个都算在上面的表里,因为表格量的是你的浏览器真正做出了什么,不是一个编码器被希望做出的东西。

透明度是另一件,而且它看格式:PNG、WebP 和 AVIF 携带 alpha 通道,JPEG 不带,所以一个有透明的源走 JPEG 这条路,就变成一片死色。是哪一片颜色由你的浏览器决定,而能被报告的只有一件事:这个问题被问过了。

为什么格式名单是一个问题,不是一份声明

没有任何一份写着"你的浏览器能编码这些格式"的清单会被带在路上。脚本一启动,它就一个一个地去要四种格式,然后看着回来的是什么。一个不认识所请求类型的编码器会用一个 PNG 来回答,而这恰恰就是你会拿到一个名叫 .avif、里面装着 PNG 字节的文件的途径——所以那张表打印出要的是什么、回来的是什么,并且只提供两者相符的那几个。

这也是那份拒绝值得相信的原因:它是你的浏览器的行为,在一秒钟前、在你的机器上、在你还没有要求任何东西的时候量下来的。

问与答

问:我的图片会被上传吗? 不会。文件是由你的浏览器自己的图片解码器读进来的,像素是在一块画布上处理的,输出是这个标签页内存里的一个 Blob,保存链接指向的就是它。没有任何东西被发往任何地方,而表格里的字节数就是那个 Blob 的大小。

问:为什么我的 PNG 压过之后反而更大了? 因为 PNG 是无损的,所以没有质量档位可拧,而重新编码必须把浏览器缩放器做出的每一个像素都写出来。一个 PNG 要经由这里变小,杠杆只有更少的像素——然后把它的每一行拿去和同样像素下的 WebP 读一读,那通常才是更小的那个文件。

问:拍摄日期还能拿回来吗? 不能,这里也没有别的东西能。把原始文件留着,或者在压缩之前把元数据读出来,之后再用一个真正带着 EXIF 写入器的工具写回去。

问:最多能接进来多大的图片? 它接 20 MB 进来,这是一条关于内存的规则,不是关于文件的规则:一块解码后的矩形大约每个像素四个字节,所以一张 6000 x 4000 的照片在任何编码器开工之前就是大约 96 MB,而必须由你的标签页把它抱住。大的扫描件属于一个能够流式处理它们的程序。

微信
微信
支付宝
支付宝