图片压缩

Canvas 重编码为 WebP/AVIF/JPEG,逐张对比体积与质量曲线。

这一页做的是 Canvas 重编码:把图片解码进画布、按你给的尺寸重画一次、再让浏览器把它编成另一种容器。候选输出只有 WebP、JPEG、PNG、AVIF 四个,而且不是按名字猜的:页面开张 8×8 画布填上 #0071e3、以质量 0.8 逐个 toBlob,把返回的 blob.type 与它前 32 字节的魔数双查一致、且字节数大于 0,才记「可编码」,不符的那颗在按钮旁直接置灰禁用并后缀(本机编不出);真正编码时还要再验一次实际类型,请求 A 拿到 B 就把「本页用实际类型统计与命名,不假装成功」写进那一行。尺寸给等比最长边、固定宽高与不改尺寸三种走法,质量滑杆范围 5 到 100、默认 75,传给 toBlob 的是这个数除以 100,PNG 那一档质量参数被显式传空,也就是无损、滑杆不动它。

GIF 不在候选里,因为 Canvas 从不提供 GIF 编码器,动图进来只会得到首帧静态图。图源只有文件选择、拖放与 Ctrl/⌘+V 粘贴三种,代码里只用 FileReader、createImageBitmap 与 Canvas 在本机解码重编码,图片不出这台设备;这一页不接收图片网址(那等于替你把一次请求发到别人的服务器),没有 fetch、XHR、sendBeacon,也不装 Service Worker。AVIF 只在浏览器真给出编码器时才可选,不改扩展名糊弄。PSNR 默认关:它逐像素只比 RGB、忽略 alpha、不含任何人眼加权,像素数越过 6_000_000 就不算了,原因写成「为一个近似指标卡住页面不值得」。裸 viewBox 的 SVG 没有固有尺寸、解出 0×0,而 SVG 进来本来就是按目标尺寸栅格化、不是压缩。这一页没有「下载全部」,也没有复制按钮。

图片压缩怎么用

  • 进队列与看体检:点选、拖放或粘贴都可以,一次可多张;入队即用文件头嗅签名、报格式标签与是否含透明通道,多帧 GIF 与动图 WebP 会当场写明「Canvas 只取首帧,输出是静态图,体积也只按这一帧算」。字节数超 24 MiB 的、头不是已知签名的,都只留一行失败原因:文件头不在已知图片签名表里的(本页只认 image-base64 那张表里的 11 种),直接报「可能是伪装的图片,或本页不认的格式」并且不解码。裸 viewBox 的 SVG 只有把尺寸模式切成固定宽高手动给一对值才有救。所有处理都在本机浏览器内存里完成,不上传、不发请求。
  • 定格式、质量与尺寸:格式那一排是分段按钮而不是下拉,默认落在第一个探测通过的;按钮组里探测不过的那颗直接禁用并标(本机编不出)。质量 5 到 100,旁边实时显示档位说明;尺寸三模式配最长边或固定宽高,锁定比例打开时按高度反算宽。透明压平底色只对 JPEG 生效(画布先 fillRect 再 drawImage),默认 #ffffff,颜色写法认不出时回落到 #ffffff;WebP 与 PNG 保留透明通道,页面直接说不需要底色。深色 logo 压白底会发灰,两张都看一眼再定。
  • 跑编码与读表:拖进来就按当前参数当场编一遍,不用点任何按钮;改参数只即时重编选中的那一行,要让整队都跟上就点「重新编码队列」(解码失败的行被跳过),点「跑质量曲线(30/50/70/85)」给选中那张出四档表,清空队列会顺手回收已建的 objectURL。表读输入输出字节、省或反而大、尺寸、耗时与实际 MIME,行里的 MIME、合计与文件名用的都是实际拿到的那个;PSNR 那一列常驻、没勾开关时它就是破折号;每行下面还跟一条备注,写它的来源格式与透明通道怎么处理(PNG 带透明转 WebP 时写「保留透明通道,不需要底色」,转 JPEG 时写按哪层底色压平)。右侧对比格把原图与输出叠在同一位置、用 clip-path 按一条分隔线左右划开,按住分隔条拖或 Tab 选中后用左右方向键微调(Shift 把步长从 2% 加到 10%,Home/End 到两端)都只改这一个比例,既不重新解码也不重新编码。要留存就按行点下载:blob 换成 objectURL 交给 <a download>,文件名取原名去掉最后一段扩展名再加 -keepcoder.真实类型扩展名(photo.jpg 编成 WebP 得 photo-keepcoder.webp,a.b.bin 编成 PNG 得 a.b-keepcoder.png,类型不认识落 .bin),三秒后回收 objectURL;这一页没有复制按钮。
  • 尺寸模式与拉伸判定:等比缩到最长边按 k = min(1, 最长边 ÷ 长边) 缩放后四舍五入、下限 1 像素;固定宽高是 1600×900 那种直接指定,锁定比例(默认开)时按高度反算宽(宽 = round(高 × 选中图的源比例),没选中行时比例按 1 算);还有不改尺寸。拉伸也不是靠感觉:目标宽高比减原宽高比的绝对值超过 0.01(按比例差算,不是百分比)才打标记,1000×1000 送进 100×102 算拉伸、送进 100×100.5 不算,命中时行里写明拉伸到哪个尺寸、原比例是多少,字形和脸都会变形。预设给的是 不改/512/1080/1600/2048/3840 六个最长边档,外加同一列「高 512…3840」的固定高度档。
  • 档位说明与两条护栏:档位说明写在 30/50/75/90 四个界上:低于 30 极低(色带与块效应明显)、30 到 49 缩略图档、50 到 74 网页主图档(多数照片这段性价比最高)、75 到 89 高质量档、90 以上接近无损(体积涨得快、画质提升有限);这四个界是本页按常见用法整理的,不是浏览器的规则。两条护栏管的不是同一段:单文件 24 MiB(写成 24.00 MB)在入队时判,超了就直接给失败原因、根本不解码;40 百万像素那条判的是目标画布(先算 targetDims 再 guardPixels),所以 9000×5000 这种 45.0 百万像素的源缩到 1600 再编是过得去的,不改尺寸直接重编会被拦下并写明「9000×5000(约 45.0 百万像素)超过 40 百万像素护栏」。解码这一步发生在像素护栏之前,源图本身夸张时仍可能在 createImageBitmap 那一环就失败或把内存吃紧。

常见问题

我要 WebP,为什么拿到的是 PNG?AVIF 为什么是灰的?

toBlob 按 HTML 规范在不支持请求的类型时静默退回 image/png,浏览器不会报错,所以这一页改成双查:blob.type 与返回体前 32 字节的魔数都得等于你要的那个才算支持。Safari 要 WebP 给出 PNG 就是这么被抓出来的,那一档直接标不可用,行里写「要的是 image/webp,实际拿到 image/png」。AVIF 同理:编不出就是编不出,页面不会改个 .avif 后缀假装成功——要 AVIF 得换有 AVIF 编码器的浏览器。

压完怎么反而更大了?

三种情况都属正常,且都被如实写出来。其一,选 PNG 就是无损重编码,只有改尺寸或原图本身有冗余时才可能变小,JPEG 原尺寸转 PNG 通常会变大,页面在这行补一句「比原文件大是正常结果,原图多半是有损格式」。其二,90 以上的接近无损档体积涨得快而画质提升有限。其三,不改尺寸又换了容器时省下的可能只是头部字节。表格把负数写成「反而大 8.1%」,合计里数出几张变大,全失败时不参与体积统计,所以不会出现虚高的节省率。

GIF 动图和 HEIC 照片能压吗?

GIF 不能:候选列表里没有它,Canvas 侧从来没有 GIF 编码器,动图进来了也只会拿到首帧静态图——页面靠数 0x21 0xF9(图形控制扩展)出现次数判 GIF 是否多帧、靠 VP8X 的 flags 位 0x02 与 ANIM 块判动图 WebP,命中就把「只取首帧」写在行里;要诚实补充的是 APNG 的 acTL 块不在这套嗅探里,它同样只剩首帧却不会得到警告。HEIC 这类能被 ftyp 品牌识别出来(报 image/heic),但识别归识别、能不能被这台浏览器解码成画布是另一件事:createImageBitmap 与 <img> 兜底都失败时,行里给的是「浏览器画不出这张图(格式不支持或数据被截断)」。方向也一样如实:走 createImageBitmap(file, {imageOrientation:"from-image"}) 时 EXIF 方向在画进画布前就被转正,浏览器不认这个选项时退回无选项调用、按默认走,最后兜底用 <img> 时根本不解析方向,可能歪着输出——页面按实际走过的那条路把三种说法之一写在你眼前。

为什么队列的合计可能混着两次参数?

改参数只有选中的那一行随 150 ms 防抖即时重编,其余行要点「重新编码队列」才按新参数整队重算,所以合计可能混着两次参数,右侧那一栏才是选中这张当前的数;解了码还没编的行输出栏写「还没编」,末尾单独数出「N 张还没编(未计入)」。

PSNR 那一列到底比的是什么?

PSNR 比的是编码前的画布与把输出 blob 重新解码画回同尺寸画布之差,也就是这一条有损编码回路,不等于「看着好不好」;MSE 为 0 时记成「∞(像素完全相同)」,其余读成两位小数的 dB。队列表逐行给输入字节、输出字节与实际 MIME、尺寸 in→out、耗时(保留一位小数)与 PSNR;失败行在输出、省、耗时、PSNR 四栏各写一个破折号且不进合计,所以一批全失败时不会给出「省 100%」这种假数字,行末另标「N 张变大」「N 张失败」。

对应功能编号 #81无需安装,手机端同样可用按 Ctrl + K 换工具