【问题标题】:Export canvas as PNG without transparency (alpha channel)将画布导出为不透明的 PNG(Alpha 通道)
【发布时间】:2018-11-04 20:47:04
【问题描述】:

** 编辑 ** 我必须导出一个大画布(5Mo

当我导出画布(使用 toDataUrl)时,它总是返回一个带有 alpha 通道的 .png 文件的 base64 表示。 Alpha 通道权重约为图像数据的 25%,我不需要它。

建议答案:

  1. PNG 压缩效果很好。如果 alpha 通道是平坦的(都是相同的值),那么它不会占用太多空间即使使用完全不透明的 Alpha 通道,(压缩的).png 文件也会更大。 (在一些测试中大约 +10%)。
  2. 你应该在画布之前填充画布(使用你想要的背景颜色)。 我已经在stackoverflow上建立了这个解决方案,但它似乎不起作用
  3. Base64 编码增加了 34% 的字节。已经解决了。使用这个 解决方案:convert-data-uri-to-file-then-append-to-formdata (一个 Uint8Array 变成一个 Blob 变成一个 FormData)

有没有办法将我的画布导出为 .png 但没有 alpha 通道? 如果“否”,javascript中有没有办法(lib)修剪alpha通道? 导出为 .jpeg 不是解决方案,我需要一个 .png 文件。

谢谢! :)

【问题讨论】:

  • 我只会将此作为评论发布,因为我不是 100% 确定,但我会说不要屏住呼吸。我尽我所能在 MDN 上进行了检查,没有迹象表明有这样的选择。您可以尝试使用getImageData(),将颜色值提取到新的ArrayBuffer,然后使用客户端库进行压缩(NPM 可能有一些有用的东西)。我不知道与实际的 .png 压缩相比会产生什么大小,但考虑到数据 URL 是 base64 编码的,它总是大于它的二进制形式,它可能与你的大小相当,甚至更好。
  • 显然,在这种情况下,后端必须准备好接收这种非标准格式的图像。
  • 我还没有尝试过这个解决方案。我希望找到另一种解决方案,而不是解析整个 png 文件,提取 RGB 值,然后重新创建一个没有 alpha 通道的 png

标签: javascript canvas png transparency todataurl


【解决方案1】:

你应该在画布之前填充画布(使用你想要的背景颜色)。

例如,之前:

var ctx = canvas.getContext('2d');
drawEverythingOnMyContext(ctx);
image = canvas.toDataURL();

之后:

var ctx = canvas.getContext('2d');
// draw a background
ctx.fillStyle = 'white';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// draw then
drawEverythingOnMyContext(ctx);
image = canvas.toDataURL();

【讨论】:

  • 我已经在 stackoverflow 上找到了这个解决方案,但它似乎不起作用:/
【解决方案2】:

PNG 压缩效果很好。如果 alpha 通道是平坦的(都是相同的值),那么它不会占用太多空间。

您可以使用复合操作“destination-over”填充透明和半透明像素。

以下函数会将所有像素的 alpha 值设置为 1。

function fillAlpha(ctx, bgColor){  // bgColor is a valid CSS color ctx is 2d context
   // save state
   ctx.save();
   // make sure defaults are set
   ctx.globalAlpha = 1;
   ctx.setTransform(1, 0, 0, 1, 0, 0);
   ctx.filter = "none";

   // fill transparent pixels with bgColor
   ctx.globalCompositeOperation = "destination-over";
   ctx.fillStyle = bgColor;
   ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);

   // cleanup
   ctx.restore();
}

然后,您可以将图像保存为 PNG,Alpha 通道尽可能小。

【讨论】:

    【解决方案3】:

    当我导出画布(使用 toDataUrl)时,它总是返回一个带有 Alpha 通道的 .png 文件。

    不,它不返回“.png file”,toDataURL 返回一个数据 URL,它是一个由标题和 base64 表示形式组成的字符串你的文件。这种 base64 表示本身将比表示的二进制文件多占用 34% 的字节。

    所以要修复你的XY问题send your png image as a binary Blob.的X。


    现在提供一些关于 Y 问题的内容,我没有检查每个浏览器,但我认为除了 32 位 png 输出之外没有实现任何其他内容。这可能会在未来发生变化,此外,因为大多数 UA 现在都支持{alpha: false} 2d 上下文参数,并且我们很可能在不久的将来对上下文中使用的位深度有更多的控制。

    但就目前而言,您必须自己完成,通过运行自己的 png 编码器。

    【讨论】:

      【解决方案4】:

      我的目标与您的类似:以 PNG 格式导出画布,并在将其发送到服务器之前从其 dataURL 表示中删除 alpha 通道信息。不过我的理由和你的不一样。我想在另一端将生成的图像文件合并为 PDF,而我使用的库 img2pdf 无法处理 alpha 通道信息。我用于画布的库是fabric.js,但是通过 toDataUrl() 导出任何 HTML5 画布时应该会出现问题。

      幸运的是,有一个不错的 JavaScript 库,名为 pngjs,它可以在 JavaScript 中处理 PNG 文件。它带有异步和同步例程。这就是我将 dataURLs 从 Alpha 转换为非 Alpha 的方式。您的第 3 步(到博客的 dataURL)应该足以完成这项工作。

      let PNG = require('pngjs').PNG;
      
      /* thehref: DataURL form of a png file. */
      function removeAlphaFromDataUrl(thehref) {
        let dataurlstring = "data:image/png;base64,"
        let buff = new Buffer(thehref.slice(22), 'base64')
        let png = PNG.sync.read(buff);
        let options = { colorType: 2 };
        let buffer = PNG.sync.write(png, options);
        let output = buffer.toString('base64');
        let newhref = dataurlstring + output
        return newhref;
      }

      我希望这会有所帮助。

      【讨论】:

        猜你喜欢
        • 2010-12-30
        • 2019-03-18
        • 2014-05-28
        • 2012-11-24
        • 2016-04-03
        • 2010-10-25
        • 2012-07-21
        • 2011-06-08
        • 2017-03-01
        相关资源
        最近更新 更多