Use HDR for dynamic image experiences in your app
System Frameworks 进阶 20m

在应用中使用 HDR 实现动态图像体验

Use HDR for dynamic image experiences in your app

2024年6月10日

在 Apple 官方观看视频

一句话判断

如果你在处理照片编辑、图片查看或任何涉及 HDR 图像的场景,这场 Session 深入讲解了 Headroom、Tone Mapping 的核心概念以及全新的 Adaptive HDR 标准——一个向后兼容 SDR 系统的 HDR 解决方案,值得花时间消化。

这场 Session 讲了什么

这场 Session 是去年《Support HDR Images in Your App》的续篇,重点放在两个新概念和一个新标准上。首先是 Headroom——HDR 显示器能呈现的超出 SDR 参考白(Reference White)的额外亮度范围。在数学上,Headroom 是 HDR 峰值亮度与参考白的比值,也可以用对数形式表示为”几档”(stops)。区分两个概念很关键:Content Headroom 是图像文件中存储的超出参考白的数据,Display Headroom 是显示器实际能展示的超出参考白的亮度能力。

当 Display Headroom 不足以展示 Content Headroom 时(比如屏幕亮度调低了、电量不足、app 在后台),就需要 Tone Mapping——调整图像的亮度和颜色值使其适应显示条件,同时尽可能保留创作者意图。

今年最重要的新标准是 Adaptive HDR。它建立在去年引入的 ISO HDR 基础之上,但解决了三个关键问题:向后兼容 SDR 系统、解码器和应用;在单个文件中同时存储 HDR 和优化过的 SDR 表示;以及自适应 Tone Mapping 能力。这意味着一个 Adaptive HDR 文件在 HDR 设备上展示完整动态范围,在 SDR 设备上也不会出现颜色失真或曝光异常。

值得深挖的点

Adaptive HDR 的向后兼容设计是工程上的精妙之处

ISO HDR(去年的标准)有一个实际问题:在 SDR 显示器上需要通过默认 Tone Mapping 算子(ITU 2408、2446、2390)转换,而这个转换的质量取决于具体实现。不同 app 和平台可能产生不同的 SDR 渲染结果。

Adaptive HDR 的解决方案是在文件中同时存储 HDR 和优化过的 SDR 两个版本。这不是简单的”存两份”,而是利用增益图(Gain Map)技术——SDR 版本作为基础层,HDR 版本通过增益图与基础层的差值来表示。SDR 应用只需要读取基础层,完全不知道 HDR 信息的存在;HDR 应用则读取两层信息来还原图像。

这种设计让迁移成本降到了最低。现有的 SDR 解码器、编辑器、分享服务不需要任何修改就能继续工作。HDR 生态系统可以在这些 SDR 基础设施之上无缝生长。对于开发者来说,你不需要维护两套图片管线——一个文件搞定所有场景。

Tone Mapping 的触发场景比你以为的更广泛

很多人以为 Tone Mapping 只在 HDR 内容显示在 SDR 屏幕上时才需要。实际上它在更多场景中发挥作用:屏幕亮度降低导致 Display Headroom 缩小、低电量时显示器为了省电而降低亮度、操作系统将前景 app 提升为 HDR 而将后台 app Tone Map 到 SDR、甚至你作为开发者想用不同方式展示 HDR 效果。

这意味着你的 app 需要在运行时动态响应 Display Headroom 的变化,而不能只在加载图片时做一次 Tone Mapping。Apple 提供的 API 已经处理了这些情况,但你需要理解这个机制才能写出正确的代码。

代码片段

读取 Adaptive HDR 图像并保留 HDR 内容

import ImageIO
import UIKit

// 读取图像时使用正确的选项保留 HDR 数据
func loadHDRImage(from url: URL) -> UIImage? {
    let source = CGImageSourceCreateWithURL(url as CFURL, nil)
    guard let source else { return nil }
    
    // 使用 CGImageSource 读取,确保不丢失 HDR 信息
    let options: [CFString: Any] = [
        kCGImageSourceShouldCache: true,
        // 不强制解码为 SDR
        kCGImageSourceShouldAllowFloat: true
    ]
    
    guard let cgImage = CGImageSourceCreateImageAtIndex(source, 0, options as CFDictionary) else {
        return nil
    }
    
    return UIImage(cgImage: cgImage)
}

场景:加载 HDR 照片用于显示或编辑。坑点:如果使用了错误的加载选项,系统可能会静默地将 HDR 降级为 SDR,你不会收到任何错误提示。

编辑 HDR 图像时保留 HDR 内容

import CoreImage

// 使用 Core Image 处理 HDR 图像
func editHDRImage(_ inputImage: CIImage, brightness: Double) -> CIImage {
    let filter = CIFilter(name: "CIColorControls")
    filter?.setValue(inputImage, forKey: kCIInputImageKey)
    filter?.setValue(brightness, forKey: kCIInputBrightnessKey)
    
    // CIImage 天然支持 HDR 色彩空间
    // 处理结果保留完整的 HDR 动态范围
    return filter?.outputImage ?? inputImage
}

// 输出时确保使用 HDR 色彩空间
func renderToHDRContext(_ image: CIImage) -> CGImage? {
    let colorSpace = CGColorSpace(name: CGColorSpace.displayP3Linear)!
    let context = CIContext(options: [
        .workingColorSpace: colorSpace,
        .outputColorSpace: colorSpace
    ])
    
    return context.createCGImage(image, from: image.extent)
}

场景:在照片编辑 app 中调整 HDR 图像的亮度、对比度等参数。坑点:必须使用 displayP3Linear 或其他线性色彩空间作为工作空间,使用 sRGB 会导致 HDR 数据被压缩。

将 HDR 图像写入文件

import ImageIO
import UniformTypeIdentifiers

func writeHDRImage(_ cgImage: CGImage, to url: URL) {
    let destination = CGImageDestinationCreateWithURL(
        url as CFURL,
        UTType.heic.identifier as CFString,
        1, nil
    )
    
    // 写入时指定 HDR 属性
    let properties: [CFString: Any] = [
        kCGImagePropertyProfileContainer: [
            kCGImagePropertyProfileName: "Display P3"
        ],
        // 启用 Adaptive HDR 编码
        kCGImagePropertyHDRImage: true
    ]
    
    CGImageDestinationAddImage(destination!, cgImage, properties as CFDictionary)
    CGImageDestinationFinalize(destination!)
}

场景:将编辑后的 HDR 图像保存为支持 Adaptive HDR 的 HEIC 文件。坑点:不是所有 HEIC 编码器都支持 Adaptive HDR,确保使用 Apple 提供的编码器。

最佳实践

  • 使用系统提供的 API 处理 Tone Mapping:不要自己实现 Tone Mapping 算法,Apple 的实现已经考虑了各种 Display Headroom 变化的场景。
  • Adaptive HDR 优先于 ISO HDR:新项目应该使用 Adaptive HDR,它的向后兼容性让你不用担心 SDR 设备的渲染问题。
  • 编辑时保留完整的色彩空间信息:从文件读取到编辑到写回,整个管线都要保持 HDR 色彩空间,任何一步的降级都是不可逆的。
  • 关注前后台切换时的 HDR 状态:当你的 app 进入后台时,系统会将图像 Tone Map 到 SDR。回来时要重新加载完整 HDR 数据。
  • 测试不同 Display Headroom 条件:在各种屏幕亮度设置和电量状态下测试你的 HDR 渲染效果,确保 Tone Mapping 的结果符合预期。

还有什么值得关注

  • Adaptive HDR 文件可以在 HEIF、AVIF、JPEG XL 等多种格式中存储,选择格式时考虑目标平台的兼容性。
  • 增益图(Gain Map)技术是 Adaptive HDR 向后兼容的关键,SDR 应用读取基础图,HDR 应用叠加增益图。
  • Apple 在 ISO HDR 标准的制定中扮演了积极角色,Adaptive HDR 是这个标准的进一步扩展。
WWDC 2024