将画布导出为PNG而不透明(Alpha通道)

时间:2018-05-25 12:37:13

标签: javascript canvas png transparency todataurl

** 编辑 ** 我必须导出一个大画布(5Mo< my_export< 40Mo)并用ajax发布它。 我必须使用较少的Content-Length字节来发布它。

当我导出我的画布(使用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中)
  4. 有没有办法将我的画布导出为.png但没有Alpha通道? 如果“不”,是否有一种方法(lib)在javascript中修剪alpha通道? 导出为.jpeg不是解决方案,我需要一个.png文件。

    谢谢! :)

4 个答案:

答案 0 :(得分:1)

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

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

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;
}

我希望这会有所帮助。

答案 1 :(得分:0)

在绘制之前,您应该填充画布(使用所需的背景颜色)。

例如,之前:

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();

答案 2 :(得分:0)

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 :(得分:0)

  

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

不,它不会返回" .png 文件", toDataURL 会返回一个数据网址,该网址是由标题和文件的base64表示形式。这个base64表示本身比所表示的二进制文件多占34%。

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

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

但目前,您必须自己动手,运行自己的png编码器。