为啥透明图通过小番茄算法混淆后会背景变黑色?

很多人会遇到这个现象:上传一张透明 PNG,混淆后背景变黑。先说结论:这不是 Gilbert 曲线混淆算法本身导致的,而是导出格式被固定成 JPEG 引起的透明通道丢失。
根因不在“混淆”,在“输出格式”
小番茄当前处理链路是:
- 把图片画到
canvas; - 用
getImageData读取 RGBA 像素; - 按 Gilbert2d 路径 + 偏移重排像素;
putImageData写回画布;canvas.toBlob(..., 'image/jpeg', 1)导出结果。
关键点在第 5 步:image/jpeg 不支持 alpha(透明通道)。你原图里本来透明的像素,在导出 JPEG 时必须“落地”为不透明颜色。当前实现里这些透明像素在合成后常表现为黑色,所以你看到的是“透明变黑底”。
为什么你会感觉“混淆后才变黑”
因为你往往是在混淆完成后第一次看到 JPEG 输出。算法本身做的是像素重排,RGBA 四通道都会搬运;但一旦进入 JPEG 导出,A 通道被丢弃,透明区域就不再透明。
再补一个容易忽略的点:当前上传大图触发缩放分支时,也走了 toBlob('image/jpeg', 1)。也就是说,有些图在“进入正式混淆前”就已经失去透明信息,后续再怎么解混淆都不可能恢复原来的透明边缘。
黑底是否影响“可还原”
分两层看:
- 结构可还原性:混淆-解混淆的像素重排关系仍成立;
- 视觉完整性:透明信息一旦在 JPEG 阶段丢失,就会出现黑底或边缘脏色,无法还原回原始透明外观。
所以你会看到“主体能解出来,但边缘不对、背景发黑”的情况。
什么时候最容易触发
- 原图是透明 PNG/WebP;
- LOGO、贴纸、头像抠图这类大面积透明素材;
- 大图上传后触发了前置缩放分支;
- 多次反复导出 JPEG,边缘脏色会更明显。
怎么避免透明图变黑
如果你的目标是保留透明背景,实操上就三条:
- 优先使用支持透明的输出格式(PNG 或 WebP lossless);
- 如必须用 JPEG,先手动铺白底/指定底色,再做混淆,避免系统默认黑底;
- 减少“中间环节二次导出”,一次处理一次保存,避免边缘反复劣化。
一句话结论
透明图混淆后变黑,不是算法重排错了,而是导出到 JPEG 导致 alpha 通道被抹掉。要保透明,关键不是改偏移参数,而是改输出格式策略。
相关阅读: