为什么编码为 base64 的图像数据会解码回错误的值?

Why image data encoded into base64 decodes back with wrong values?

我正在尝试将数组转换为 base64 字符串。然后再回来。我做了一个简单的示例,示例数组如下所示:[0, 1, 2, 3, 0, 1, 2, 3] 并在 canvas 中使用 .toDataURL() 进行转换。但由于某种原因,当我读回 base64 字符串并将其应用于 canvas 时,它 returns 不同的图像数据 : [0, 0, 0, 3, 0, 0, 0, 3].

为什么会这样?

示例:

const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');

const array = new Uint8ClampedArray([0, 1, 2, 3, 0, 1, 2, 3]);
const initialImageData = new ImageData(array, 2, 1);

ctx.putImageData(initialImageData, 0, 0);
const dataURL = canvas.toDataURL();

console.log(dataURL); // data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAABCAYAAAD0In+KAAAAAXNSR0IArs4c6QAAAA9JREFUGFdjZGBgYGYAAgAAIQAFoFclWQAAAABJRU5ErkJggg==

const img = new Image();
img.onload = () => {
    canvas.width = 2;
    canvas.height = 1;
    ctx.drawImage(img, 0, 0);
    const imageData = ctx.getImageData(0, 0, 2, 1);
    console.log(imageData.data); // [0, 0, 0, 3, 0, 0, 0, 3]
}
img.src = dataURL;

看来你被this gotcha in the Canvas implementation抓住了:

Warning: Due to the lossy nature of converting to and from premultiplied alpha color values, pixels that have just been set using putImageData() might be returned to an equivalent getImageData() as different values.

(强调我的)

您传入的 Uint8ClampedArray 格式为 [r, g, b, a] 并且 Alpha (a) 组件非常重要。在您的测试中,您提供了 3 的 Alpha,浏览器似乎正在选择将其他像素“优化”为 0

尝试 a 的 full-opacity 值,一切正常:

const array = new Uint8ClampedArray([0, 1, 2, 255, 0, 1, 2, 255]);

...

console.log(imageData.data); // [0, 1, 2, 255, 0, 1, 2, 255]