Skip to content

Instantly share code, notes, and snippets.

@kiding
Last active April 2, 2024 08:32
Show Gist options
  • Star 19 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save kiding/fa4876ab4ddc797e3f18c71b3c2eeb3a to your computer and use it in GitHub Desktop.
Save kiding/fa4876ab4ddc797e3f18c71b3c2eeb3a to your computer and use it in GitHub Desktop.
Extracting HDR Gain Map from iOS 14.1+ (iPhone 12+) photos
import UIKit
import MobileCoreServices.UTCoreTypes
if #available(iOS 14.1, *) {
let input = Bundle.main.url(forResource: "IMG_0037", withExtension: "HEIC")!
let output = FileManager().temporaryDirectory.appendingPathComponent("IMG_0037.GAIN_MAP.BMP")
let source = CGImageSourceCreateWithURL(input as CFURL, nil)!
// urn:com:apple:photo:2020:aux:hdrgainmap
let dataInfo = CGImageSourceCopyAuxiliaryDataInfoAtIndex(source, 0, kCGImageAuxiliaryDataTypeHDRGainMap)! as Dictionary
let data = dataInfo[kCGImageAuxiliaryDataInfoData] as! Data
let description = dataInfo[kCGImageAuxiliaryDataInfoDataDescription]! as! [String: Int]
let size = CGSize(width: description["Width"]!, height: description["Height"]!)
let ciImage = CIImage(bitmapData: data, bytesPerRow: description["BytesPerRow"]!, size: size, format: .L8, colorSpace: nil)
let cgImage = CIContext().createCGImage(ciImage, from: CGRect(origin: CGPoint(x: 0, y: 0), size: size))!
let destRef = CGImageDestinationCreateWithURL(output as CFURL, kUTTypeBMP, 1, nil)!
CGImageDestinationAddImage(destRef, cgImage, [:] as CFDictionary)
CGImageDestinationFinalize(destRef)
print(output)
}
@gregbenz
Copy link

gregbenz commented Nov 7, 2023

@jiawen That's great. If you are able to share it, I think just getting it as it currently stands to ImageMagick via ImageMagick/ImageMagick#6377 may be of great value to help expedite those efforts.

@frankschlegel
Copy link

I got the following in the aux image's XMP on a JPEG taken with an iPhone 15 Pro's rear camera.

@jiawen Very interesting! It seems Apple introduced a new version with the iPhone 15, including the new HDRGainMapHeadroom XMP field. I wonder what this does... It's not documented in their gain map documentation so far.

Surprisingly, it does render as HDR in Chrome (v118)!

Also in Brave. It seems support for Apple's format was added together with the support for Adobe's format to the Chrome engine. Very nice!

I wonder where this is all going. On the developer side, Apple seems to advocate for exporting HDR images in what they call "ISO HDR" format (basically an HDR video still frame). In fact, that's the only official way for exporting HDR images. There are no simple APIs for writing an SDR image + HDR gain map.

@gregbenz You are very deep into this topic. Do you have an idea what will be the dominant standard in the future? This "ISO HDR" format seems to be the obvious candidate, as it's simply the same as HDR video. But it comes with the big disadvantage that there is no clearly defined SDR representation for those images. It's up to the displaying application how to tone-map those to SDR. The gain map approach is much more explicit.

@gregbenz
Copy link

gregbenz commented Nov 8, 2023

I don’t know that I’d quite say ISO HDR is the same as a video still frame, not in a literal sense anyhow. Video tends to define a 100 nits white point, photography is using 203. There are certainly many commonalities (sadly including the lack of a common standard for tone mapping).

The “ISO HDR” refers to encoding of an HDR image. There is another ISO draft for gain maps. These are complimentary, as an ISO gain map can use an ISO HDR as the base image. You can use one without the other, but they work best together (if the base image in a gain map is HDR).

Gain maps are the obvious way forward. They offer a much better experience for viewing on any display which lacks the full HDR headroom encoded in the image. It’s vastly better than tone mapping.

JPG gain map is the obvious choice right now. Browsers representing ~75% of viewers (once fully updated) support it on systems with HDR display. And backwards compatibility is 100% (if your browser / image software doesn’t support HDR or gain maps, you gracefully fall back to a nice SDR).

However, JPG requires large files for high quality. There is a draft AVIF gain map standard (Adobe has shared sample files and Chrome/Brave support it). This is clearly the way things “should” go.

I say “should” because best doesn’t always win. As of now, Microsoft Edge (and the file explorer) doesn’t support any AVIF, and that needs to change for AVIF to be viable. Assuming that happens (they have support under a dev flag), we still need an encoder and more browsers to add support. It’s part of the same draft ISO proposal for gain maps and I hope to see it happen.

Another theoretical candidate would be JXL (JPEG XL). As browser support is zero and Chrome pulled support, it doesn’t seem promising anytime soon.

If it were all up to me: we’d use JPG gain maps for now, transition to AVIF gain maps as soon as MS Edge supports AVIF (encoded with an SDR base image for compatibility), then finally get to the ideal AVIF encoded with an HDR base image when support for AVIF gain maps is widely available.

The other thing I’d like to see is encoder support to let the artist provide the SDR rendition as well. This has many benefits, which I outlined in this feature request for Photoshop (please upvote it if you agree): https://community.adobe.com/t5/photoshop-ecosystem-ideas/allow-full-user-control-of-the-sdr-rendition-in-an-hdr-gain-map-export/idi-p/14205440#M19464

@grapeot
Copy link

grapeot commented Nov 20, 2023

Although I'm late to the party, I must say this thread is the most informative and inspiring resource on the entire internet regarding this specific topic. I've truly learned a lot from all the discussions above and want to sincerely thank every participant and contributor. Inspired by the discussion, it seems I've figured out how to use Apple's public APIs to generate a JPEG with a gain map that renders properly on both iPhone and Mac. It can also be inspected by Adobe's demo app and other third-party software like HoneyView. I've shared the code with detailed documentation, hoping it will be helpful to others: https://github.com/grapeot/AppleJPEGGainMap

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment