- From: Chris Lilley <chris@w3.org>
- Date: Mon, 6 Nov 2023 12:53:22 -0500
- To: "www-archive@w3.org" <www-archive@w3.org>
- Message-ID: <84613eb7-a29d-49eb-b3a6-4b5851c07cb9@w3.org>
-------- Forwarded Message -------- Subject: [Moderator Action (size limit exceeded)] half-float PNG files stored as 16-bit/component images Date: Mon, 06 Nov 2023 17:27:57 +0000 From: Richard Geldreich <rich@binomial.info> To: public-png@w3.org Hi all, *The one core strength of the PNG image format: predictable backwards compatibility.* If we introduce a new Colour Type value (where #7="16-bit half float RGBA" for example), /existing PNG decoders will fail to read half-float PNG files/. Users will then perceive PNG as an unreliable format, which is terrible for a standard file format (if not terminal). It could take many years for developers to add proper half-float support, and some old libs or software will never be updated. PNG currently works everywhere and is very reliable. *Crucially, Jim Blinn said years ago <https://stackoverflow.com/questions/75772363/why-does-the-integer-representation-of-a-floating-point-number-offer-a-piecewise>*: "/If you only deal with positive numbers, the bit pattern of a floating point number, interpreted as an integer, gives a piecewise linear approximation to the logarithm function/". This holds true for positive half floats interpreted as unsigned 16-bit values as well. Half floats <https://en.wikipedia.org/wiki/Half-precision_floating-point_format> are much like 32-bit floats, just with less mantissa/exponent bits. (This is how the BC6H/ASTC HDR GPU texture formats work internally, BTW: the half float values are manipulated and interpolated as 16-bit unsigned integers. BC6H/ASTC encoders work in half-float space, which is an approximation of a logarithmic space.) One true HDR PNG option is to store the half-float pixel values as plain 16-bit/component PNG Truecolour images (Colour Type=2, Bit Depth=16), with a special new ancillary chunk that hints to the reader software that it's actually a half-float image and not unsigned. *But crucially, what will loaded or displayed images look like when processed by legacy PNG software? It turns out the results are surprisingly decent.* Some popular PNG readers (such as stb_image.h, and mine) load 16-bit/component images by shifting each component right by 8 bits, to return the uppermost 8-bits (so 24 or 32 bits total for RGB/RGBA) to the caller. In half float space, this is approximately equivalent to floor(log2(value)*scale/256.0). *It's a built-in global tone map operator. *The upper 8-bits contain the sign (almost always positive, so 0), the 5-bit exponent, and the upper 2-bits of the 10-bit mantissa. Here's an HDR example: *candle-glass.exr*, with a max float component value of 413.25, converted to half float. I then extracted the high 8-bits of these half floats to make plain 24-bit images for visualization. Here's what the result looks like (and what a 16-bit half float PNG would look like loaded with legacy software): image.png After a histogram stretch (using Paint Shop Pro): image.png Alternatively, after a quick brightness/contrast adjustment: image.png This is a very simple/crude global tone map operator. The user can still load the image with old software, they will just have to adjust the brightness/contrast, which is probably fine for a true HDR PNG image loaded with legacy software. Another example (MtTamWest.exr): image.png After quick brightness/contrast adjustment: image.png
Received on Monday, 6 November 2023 17:53:41 UTC