与原始数据URI相比,javascript canvas.toDataURL更改

时间:2011-04-08 01:00:05

标签: javascript canvas mozilla

我正在开发一个mozilla扩展,尝试加载一个用数据URI编码的图像(PNG),在画布元素上绘制它,最后更改一些像素值并将其作为文件保存在磁盘上

我注意到的奇怪之处在于,即使我没有更改图像上的任何内容,我只是在画布上绘制图像并使用canvas.toDataURL()来查看生成的内容,此编码数据不同于原来。

我用来看这个代码非常基本:

var image = new Image();
image.onload = function() {
    var canvas = document.createElement('canvas')
    canvas.width = image.width;
    canvas.height = image.height;
    canvas.getContext('2d').drawImage(image, 0, 0);
    var data = canvas.toDataURL(); // this right here is different from image.scr data!
}
image.src = "data:image/png;base64," + encodedData;

我认为存在某种压缩或可能与透明度有关。

我已查看the documentation但无法找到解释。 我想我看到一些颜色被改为其他类似的东西,这可能是我想要实现的东西(即改变一些像素值)。

有关正在发生的事情的任何想法?

如果没有,有没有人知道是否有其他方法可以将画布图像保存到磁盘上的文件而不使用toDataURL方法? 可能是一个能够以PNG二进制格式保存所有像素的XPCOM组件吗?

由于

2 个答案:

答案 0 :(得分:1)

我发现有一个特殊情况,其中像素已被更改。 可能有更多案例。我不能提供深入的技术解释,因此,我不能说它实际上不会改变图像。

如果将alpha值设置为小于255(1.0)的任何值,那么该像素的其他组件似乎会被更改。该问题的解决方法是简单地将所有alpha值设置为255.

截至目前,我已成功地使用ImageData和Image DOM元素将精确的精确数据存储到Canvas中,然后通过将alpha分量设置为255并且不使用它来存储数据来检索这些完全相同的数据而不会丢失

以下是我目前正在使用的例程:

function make_image_with_data(contents) {
    // Fractional side length.
    var fside = Math.sqrt(contents.length / 3);
    // Whole integer side length.
    var side = Math.ceil(fside);

    var cv = document.createElement('canvas');

    cv.width = side;
    cv.height = side;

    var ctx = cv.getContext('2d');
    var id = ctx.createImageData(side, side);

    var data = id.data;

    data[0] = (contents.length >> 24) & 0xff;
    data[1] = (contents.length >> 16) & 0xff;
    data[2] = (contents.length >> 8) & 0xff;
    data[3] = 255;
    data[4] = (contents.length) & 0xff;

    var z = 5;
    var x = 0;

    for (; x < contents.length; ++x) {
        data[z] = contents.charCodeAt(x);
        // Skip the image alpha component.
        ++z;
        if (z % 4 == 3) {
            data[z] = 255;
            ++z;
        }
    }

    ctx.putImageData(id, 0, 0);

    var img = document.createElement('img');
    img.width = side;
    img.height = side;

    img.src = cv.toDataURL();

    $(document.body).append(img);

    return img;
}

然后将数据退回的功能是:

function load_data_from_image(img) {
    var cv = document.createElement('canvas');
    cv.width = img.width;
    cv.height = img.height;
    var ctx = cv.getContext('2d');

    ctx.drawImage(img, 0, 0, img.width, img.height);

    var id = ctx.getImageData(0, 0, img.width, img.height);
    var data = id.data;

    var len = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[4];
    var out = new Uint8Array(new ArrayBuffer(len)); 

    var z = 5;

    for (var x = 0; x < len; ++x) {
        out[x] = data[z];
        // This is skipping the alpha component.
        ++z;
        if (z % 4 == 3) {
            ++z;
        }
    }

    return out;
}

答案 1 :(得分:0)

PNG有legal ways to losslessly filter and encode种。例如,查看this chart,显示使用不同工具对同一图像进行无损编码时可能存在的巨大文件大小差异。

但是,如果你将toDataURL版本重新绘制到Canvas并获得一个新的toDataURL并且它有所不同,我会感到惊讶。我希望每次使用相同的浏览器对相同的图像进行相同的编码。