Export premultiplied pixels into a transparent PNG

11 views
Skip to first unread message

Andrew Varga

unread,
Jul 15, 2024, 8:18:17 PM (3 days ago) Jul 15
to WebGL Dev List
Hi all,

I have a 2D engine in WebGL which is doing blending / compositing when drawing some shapes on top of each other. To get rid of common problems it is working with premultiplied colors, and the matching ONE source blend mode instead of SRC_ALPHA.

The canvas itself is not composited with the dom, there is always a solid background color rendered first, but I also want to export the content of the canvas without the background into a PNG file, calling readPixels and some custom code to encode into a PNG. I realized that if there are semi-transparent pixels I'm getting the typical black "fringe" around objects which I think is because the pixels returned by readPixels are in premultiplied form and PNG expects them to be in straight alpha.

One solution is to run one more render pass on the final Framebuffer which unpremultiplies pixels (divides rgb by the alpha). Is this a good way of dealing with this problem or is there anything better I could do?

I can't really modify the rendering to work in straight alpha colors because that would mess up blending.

thanks,
Andrew

Kai Ninomiya

unread,
Jul 15, 2024, 10:15:29 PM (3 days ago) Jul 15
to webgl-d...@googlegroups.com
I think that's up to your PNG encoding library. Can it be configured to accept data in premultiplied format? If not, your un-premultiplication pass makes sense.

Or, can you use toBlob() (or toDataURL() if really necessary) to produce a PNG directly from the canvas, instead of reading back the canvas and encoding the PNG? This will probably be faster, and it removes a dependency on a user-space PNG encoder if you're using one.

-Kai (he/they)


--
You received this message because you are subscribed to the Google Groups "WebGL Dev List" group.
To unsubscribe from this group and stop receiving emails from it, send an email to webgl-dev-lis...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/webgl-dev-list/021516c5-25ab-406a-92a3-1eed571e06c2n%40googlegroups.com.

Andrew Varga

unread,
Jul 16, 2024, 3:04:26 AM (3 days ago) Jul 16
to webgl-d...@googlegroups.com
This time I'm using rust and this library, because this PNG generation runs on a server. The way I see there is no option to specify premultiplied alpha.
https://docs.rs/image/0.25.1/image/fn.save_buffer_with_format.html

I could also do the premultiplication on the CPU on the byte array but that would be slower and lose even more color information.
Interesting about toBlob/toDataURL, do those look at the WebGLRenderingContext's premultipliedAlpha context attribute and export accordingly?

Thank you!

Kai Ninomiya

unread,
Jul 16, 2024, 2:35:05 PM (3 days ago) Jul 16
to webgl-d...@googlegroups.com
Yes, toBlob/toDataURL save the image data from the canvas (that would be used to show the canvas on screen if it were visible, or used to draw to a 2d canvas with drawImage, or other methods) - regardless of how it's encoded inside WebGL. Example: https://codepen.io/kainino0x/pen/QWXjoMq
-Kai (he/they)


Reply all
Reply to author
Forward
0 new messages