为什么canvas.toDataURL()不会为Ruby生成与图像相同的base64?

时间:2014-11-14 03:40:45

标签: javascript image canvas md5

我试图在JavaScript和Ruby中为图像文件生成相同的base64数据。不幸的是,两者都输出了两个非常不同的值。

在Ruby中我这样做:

Base64.encode64(File.binread('test.png'));

然后在JavaScript中:

var image = new Image();
image.src = 'http://localhost:8000/test.png';

$(image).load(function() {
    var canvas, context, base64ImageData;

    canvas = document.createElement('canvas');
    context = canvas.getContext('2d');
    canvas.width = this.width;
    canvas.height = this.height;
    context.drawImage(this, 0, 0);
    imageData = canvas.toDataURL('image/png').replace(/data:image\/[a-z]+;base64,/, '');

    console.log(imageData);
});

知道为什么这些输出有所不同?

3 个答案:

答案 0 :(得分:3)

当你在Ruby中加载图像时,没有任何修改的二进制文件将直接编码到base-64。

当您在浏览器中加载图像时,它会对图像应用一些处理,然后才能将它用于画布:

  • 将应用ICC配置文件(如果图像文件包含该配置文件)
  • Gamma校正(支持的地方)

当您将图像绘制到画布时,位图值已经更改,并且不一定与在将其作为图像加载之前编码的位图相同(如果文件中有Alpha通道)这可能会影响绘制到画布时的颜色值 - 画布在这方面有点奇怪..)。

随着颜色值的改变,画布中的结果字符串自然也会有所不同,在你进入重新编码位图的阶段之前(因为PNG是无损的,编码/压缩应该是完全相同的,但是可能存在的因素取决于影响它的浏览器实现。测试,将黑色未处理的画布保存为PNG并与应用程序中的类似图像进行比较 - 所有值应为0,包括alpha和相同的大小疗程)。

避免这种情况的唯一方法是直接处理二进制数据。这当然有点矫枉过正(至少一般来说)和浏览器中相对较慢的过程。

在某些情况下可行的解决方案是从图像文件中删除任何ICC配置文件。要在没有ICC的情况下从Photoshop保存图像,请选择" Save for web .."在文件菜单中。

答案 1 :(得分:1)

浏览器在保存画布时重新编码图像。

它不会为您渲染的文件生成相同的编码。

答案 2 :(得分:0)

所以我实际上最终解决了这个......

幸运的是,我正在使用imgcache.js使用FileSystem API在本地文件系统中缓存图像。我的解决方案是使用此API(并且imgcache.js可以轻松实现)从文件的实际缓存副本中获取base64数据。代码如下所示:

var imageUrl = 'http://localhost:8000/test.png';

ImgCache.init(function() {
    ImgCache.cacheFile(imageUrl, function() {
        ImgCache.getCachedFile(imageUrl, function(url, fileEntry) {
            fileEntry.file(function(file) {
                var reader = new FileReader();
                reader.onloadend = function(e) {
                    console.log($.md5(this.result.replace(/data:image\/[a-z]+;base64,/, '')));
                };
                reader.readAsDataURL(file);
            });
        });
    });
});

另外,非常重要的是,我必须从Ruby中的base64中删除换行符:

Base64.encode64(File.binread('test.png')).gsub("\n", '');