图片压缩——你的浏览器为每种格式各花掉多少字节
把压缩量称给你看,而不是许诺:你的浏览器能编码的每种格式实际写出多少字节,需要卡体积时它对质量梯子做的那次搜索,还有元数据和透明度各失去了什么。你的图片不会离开这台设备。
称出来的,不是估出来的
| 是什么 | 用的档位 | 像素 | 字节 | 对照你的文件 |
|---|
这一条路上发生了什么
| 改变 | 它会怎样 | 这一次 |
|---|
向你的浏览器要一种格式时,它答了什么
| 要的是 | 回来的是 | 结论 |
|---|
有损压缩在压掉什么
压缩走的是哪条路:解码,再交回浏览器编码
这里没有第二只手:图片被解码成一块像素的矩形,然后再被请出你浏览器自己的编码器编回去。表格里称出来的一切都由这条路径决定。出去的字节是由你浏览器里装的那个编码器写下的,而报出来的就是拿到的那个文件,不是它觉得这个文件应该是多大。
这也正是结果可以比源文件更大的原因。重新编码从原始像素起步,所以一个本来就被压得很讲究的文件,除了往旁边或往上走,没有别的地方可去。这一类页面大多摆一个滑块和一个谁也没量过的百分比;摆出来的那个数字是你的浏览器真正写下的,包括它走反了方向的那几趟。
为什么质量数字不是一个体积
质量是伸进编码器内部的一个旋钮,不是一个目标。一张细节丰富的照片压到 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,而必须由你的标签页把它抱住。大的扫描件属于一个能够流式处理它们的程序。