为什么图片尺寸“裁剪”后,体积反而变大了?
事情是这样的:
有一次我从某 App 上下载了一张图片准备用来做手机壁纸,由于图片底部带了水印,我就用手机自带的图片编辑功能将“底部水印”裁剪掉了。
作为程序员,总有一个查看图片体积大小的习惯。
这一查看,瞬间就让我难绷了!
原始的图片体积只有58KB,裁剪后的图片体积居然达到了705KB!
增长了 10 倍不止!
于是我再次确定了两张图片的格式,也都是png格式的图片。

此时,我已经忘记“设置壁纸”这回事儿了,这个问题如果不搞清楚,怕是晚上睡觉都睡不着了。
脑子里立马想到的是:可能是没有压缩吧!
于是,我将两张图片上传到了 PC 端。使用了多种压缩工具包括TinyPNG,最终也没能将裁剪后的图片压缩到几十 KB。

这个时候,我脑子里又冒出了另一个问题:原图是如何做到只有 58KB 的?
一张1904 x 4096分辨率的 PNG 格式的图片,按道理来说是不应该只有 58KB 的!难道是因为大面积的纯黑色背景的缘故?
其实,之前我也会遇到编辑、裁剪后图片体积变大的情况,但都可以通过压缩工具将图片变得比原图小,只是这次遇到的着实有点离谱了。
后来又问了一个ChatGPT,给的回答好像也没有找到真正的原因。

既然裁剪后的图片无论如何都无法压缩到原图大小,那有没有可能原图本身就有问题?
做开发的同学应该都知道,文件的后缀是不能代表文件真实的类型的,它只是方便识别。
问题的关键原因肯定是这个,但是,我还是想 100%来确定一下这张原图到底是什么格式。
我将原图使用TinyPNG进行压缩,本来只是想看下能不能再压缩,没想到得到了意外的收获。

竟然自动变成了WEBP 压缩!由此更能证实了我的猜想。
但TinyPNG并不是专业用来查看图片类型的,我还是想从图片本身的数据信息进行证实。
这自然就要上代码了!
在编码之前,我先向 AI 要来了一份数据,用来判断图片的类型。

我需要做的就是将图片的字节码进行一一比对,就能确定它真实的类型了。
import * as fs from 'fs/promises';
import * as path from 'path';
const imgPath = path.resolve(process.argv[2]!);
const buf = await fs.readFile(imgPath);
console.log('图片的二进制数据:', buf);直接使用Bun环境进行运行,可以省去编译 TypeScript 环节。
bun run index.ts 'c:/Users/.../...f71b4f60dd67201a.png'
果然!
原图就是妥妥的一张 WEBP 格式的图片!
如果对前面 12 个字节转成字符串输出:
console.log(buf.slice(0, 12).toString());就可以看到:RIFF和WEBP两个关键信息。

所以,图片裁剪后体积变大,可能有两个原因:
- 如 ChatGPT 所说,手机自带编辑器通常不会对图片进行压缩;
- 原图与编辑后的图片格式可能不同。
所以不要盲目地相信文件的扩展名,它可能会欺骗你的眼睛,让你浪费很多时间。
对于开发同学,这里也提供一个更便捷的查看图片类型的方法:
import * as path from 'path';
import { fileTypeFromFile } from 'file-type';
const imgPath = path.resolve(process.argv[2]!);
const fileType = await fileTypeFromFile(imgPath);
console.log('图片类型:', fileType);file-type库可以快速帮我们查看文件类型,运行输出:

最后,也给Bun点个赞,使用起来是真爽!
感谢阅读。