【问题标题】:Why does canvas.toDataURL() not produce the same base64 as in Ruby for an image?为什么 canvas.toDataURL() 不会为图像生成与 Ruby 中相同的 base64?
【发布时间】:2014-11-14 16:32:41
【问题描述】:

我正在尝试为 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);
});

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

【问题讨论】:

  • 查看时图像看起来一样吗?
  • 是的,如果我在 Ruby 中解码 base64 并将原始数据保存到 PNG 文件中,它看起来是一样的。

标签: javascript image canvas md5


【解决方案1】:

当您在 Ruby 中加载图像时,未经任何修改的二进制文件将直接编码为 base-64。

当您在浏览器中加载图像时,它会对图像进行一些处理,然后您才能将其与画布一起使用:

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

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

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

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

在某些情况下可行的解决方案是从图像文件中删除任何 ICC 配置文件。要在不使用 ICC 的情况下从 Photoshop 保存图像,请在文件菜单中选择“保存为 web..”。

【讨论】:

  • 将此标记为答案,因为它回答了我的“为什么”问题;不过,我在这里的另一个答案中发布了解决方案。
【解决方案2】:

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

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

【讨论】:

  • 有没有办法以某种方式获得相同的 base64?
  • 向该 URL 发出 AJAX 请求,并且根本不使用画布。
  • 你知道哪里有这样的例子吗?
  • @ChadJohnson:举个例子?如何发出 AJAX 请求?
  • 否,以及考虑到图像是二进制格式的通过 AJAX 请求散列图像的示例。我找到了stackoverflow.com/a/15208760/83897,但它不起作用,因为“words”是空的。无论如何,我找到了另一种解决方案。
【解决方案3】:

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

幸运的是,我正在使用 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", '');

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2014-04-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多