【问题标题】:Efficiently Restore RGB in HTML5 Canvas在 HTML5 Canvas 中高效恢复 RGB
【发布时间】:2018-08-02 01:33:18
【问题描述】:

我正在尝试使用 HTML5 画布创建图像编辑工具。输入图像是带有 alpha 通道的 png。有没有一种有效的方法可以将 alpha 值设置为 255 并恢复 RGB 颜色?

类似于下面的一段代码,但没有巨大的像素循环。我尝试使用混合,但似乎一旦 alpha 值为 0,就无法恢复 RGB。

var imageData = context.getImageData(0, 0, 512, 512);
var data = imageData.data;
for(var i = 0, n = data.length; i < n; i += 4) {
    data[i + 3] = 255;
}
...

【问题讨论】:

    标签: javascript html5-canvas


    【解决方案1】:

    虽然 png 格式确实是 store the "non-premutlipied" alpha,但另一方面,CanvasRenderingContext2D 总是 pre-multiply alpha。

    所以你所追求的不能通过 CanvasRenderingContext2D 来完成。

    确实,由于 alpha 在写入时被预乘,如果您在上下文中写入 #AABBCC00(透明)像素,实际绘制的将是 #00000000
    此外,由于binary floating points work 的方式,您无法确保在不同的浏览器/设备中具有相同的输出,即使 alpha 值不为零:

    // demonstrates alpha premultiplying at writing on a canvas 2d context
    //
    // 4 pixels are authored with the same RGB channels values but with different alpha values
    // If no pre-multiplying was done, all these would output the same RGB channels values at getting
    
    
    var ctx = document.createElement('canvas').getContext('2d'),
      img = ctx.createImageData(4,1),
    // we use an Uint32Array to write every pixel in a single op
      arr = new Uint32Array(img.data.buffer);
    // AARRGGBB in little endian
    arr[0] = 0x00AABBCC; // transparent (alpha 0)
    arr[1] = 0x01AABBCC; // almost-transparent (alpha 1/255)
    arr[2] = 0x7FAABBCC; // semi-transparent (alpha 0.5/1)
    arr[3] = 0xFFAABBCC; // opaque
    // write it to our context
    ctx.putImageData(img, 0,0);
    // grab it directly
    var result = ctx.getImageData(0,0,4,1).data;
    
    console.log('transparent', result.slice(0,4));
    // outputs [0, 0, 0, 0]
    console.log('almost-transparent', result.slice(4,8));
    // outputs something like [255, 255, 255, 1]
    console.log('semi-transparent', result.slice(8,12));
    // outputs something around [204, 187, 170, 127]
    // on my FF it is           [204, 188, 170, 127]
    // on my chrome it is       [205, 187, 171, 127]
    console.log('opaque', result.slice(12,16));
    // outputs [204, 187, 171, 125]

    如您所见,只有完全不透明的像素保持其初始 RGB 通道的值。


    因此,要执行您想要的操作,您实际上必须手动解析 png 文件,并手动提取 IDAT 块中包含的数据。
    要在前端执行此操作,您需要将文件加载为 ArrayBuffer 并按照 these specs 解析它。

    但在开始编写解析器之前,您必须考虑 100% 的用户实际使用可以保留 RGB 通道值的无损软件的可能性有多大(与画布不同)。

    【讨论】:

    • 感谢您的回答 :-) 我试图做的是将背景恢复为存储在 png 中的原始 rgb 颜色,而不是与新背景混合。有没有办法做到这一点?我现在使用 2 个单独的画布,一个仅用于 rgb,另一个仅用于 alpha,它可以工作但维护起来有点混乱......
    • @user3469029 你的意思是你真的想要#aabbcc00 到#aabbccff?虽然 png 格式 可以 确实存储非预乘 alpha 颜色,但 camvas 将始终进行预乘。这意味着您不能使用画布来取回可以存储在 png 中的颜色通道(因为在上述情况下,它将产生 #00000000 像素)。如果您真的想检索它,则必须自己解析 png 文件中的像素数据。但是你确定这些数据实际上已经被保存了吗?图片来自哪里?
    • 啊。是的。谢谢 这就是我的意思。 :-) 我正在尝试做类似 Photoshop 的东西,您可以在其中擦除 alpha 并稍后取消擦除。我认为我使用的工作实际上还可以。我分别为 rgb 和 alpha 使用了 2 个画布。如果他们有一个混合模式可以取消擦除,代码可能会更干净,但解决方法还不错。 :-)
    【解决方案2】:

    我的解决方案是使用 2 个画布,一个用于 rgb,另一个用于 alpha。我将 rgb 画布的 alpha 设置为 255。所以当我们擦除/取消擦除时,它只发生在 alpha 画布中。我使用“destination-in”将 rgb 画布与 alpha 画布混合以进行显示。

    【讨论】:

      猜你喜欢
      • 2012-06-13
      • 1970-01-01
      • 1970-01-01
      • 2014-12-21
      • 2017-07-10
      • 2013-12-09
      • 2014-05-22
      • 2013-11-09
      • 2015-05-24
      相关资源
      最近更新 更多