Late last year Google introduced support for a feature called Ultra HDR that allows storing additional dynamic range information1 in a standard JPEG container. I only found out about it when I noticed the an "Ultra HDR" tag on a couple of my more recent photos when I was looking through them in Google Photos.
So great, new format. How do I get it into a format that anything outside of Android will recognise?
Google helpfully has provided a library called libultrahdr which can be used to encode and decode these special JPEGs, and even better, there's a demo command-line app for it2.
It supports a couple of output formats, but we're going to go with the simplest one which is UHDR_IMG_FMT_64bppRGBAHalfFloat with a linear transfer function. The nice thing about this is we can skip futzing around with non-linear transfer functions like Hybrid Log Gamma (HLG) and Perceptual Quantizer (PQ) (colourspace conversion is notoriously tricky to get right). The downside that is requires 64-bits (8 bytes) per pixel to store each sample as a half-precision float.
First lets convert the Ultra HDR JPEG to raw half-float samples:
# `-m 1` is decode
# `-O 4` is 64bppRGBAHalfFloat
# `-o 0` is linear transfer function
# `-j` for the Ultra HDR JPEG to be decoded
# Output is always named "outrgb.raw"
ultrahdr_app -m 1 -O 4 -o 0 -j ultra_hdr_image.jpg
This will give us a outrgb.raw file that's quite a bit larger than what we started with (my 3072x4080 test image went from a 3 MB JPEG to a 95 MB outrgb.raw). Next we need to convert these raw samples into a format that we can open in an image editor. Thankfully this is something that ImageMagick's convert tool is perfect for:
convert -define quantum:format=floating-point -depth 16 -size 3072x4080 \
RGBA:outrgb.raw ultra_hdr_image.exr
Since outrgb.raw contains only raw samples, you also have to provide the correct image size.
OpenEXR (.exr) is probably the easiest format for working with HDR images as it keeps everything in linear format, though it's going to be just as large as our outrgb.raw file. If you're tight on space, Radiance HDR (.hdr) will be half the size and likely fine for something like this.
And, ta-da! We can open it up in whatever image tool can work with HDR images. I'm using Affinity Photo but tools like Kritta and Blender can also handle HDR / 32-bit linear colour spaces.
One of the big challenges is that there isn't many formats that support HDR on the web. AVIF does, but it seems cohost doesn't let you upload it3. So you'll just have to trust me that the reflection is almost painfully bright on a HDR display.
-
a.k.a. "Your whites, whiter and your brights, brighter"
-
Though it's far from what I'd call "user friendly"
-
Though it was possible in the past (example)