WWDC Quick Look 💓 By SwiftGGTeam
Support HDR images in your app

Support HDR images in your app

观看原视频

Highlight

iOS 17 引入了对 ISO HDR 静态图像标准的完整支持,开发者可以用 SwiftUI、UIKit 和 Core Graphics 直接加载、显示和创建 HDR 照片,无需手动处理复杂的色调映射。

核心内容

SDR(标准动态范围)显示器的亮度范围有限,拍摄场景中的高光部分只能被压缩或裁切。HDR 显示器可以呈现更宽的亮度范围,让图像更接近真实场景。

Apple 今年引入了对 ISO HDR 标准的支持。这个标准(TS22028-5)定义了如何把 HDR 内容编码到现有的静态图像格式中。关键参数包括:使用 HLG 或 PQ 作为传递函数,BT.2020 宽色域,10 位或更高位深。HEIF 可以编码 HDR,但传统 JPEG 不行(只有 8 位)。

对于开发者来说,最大的变化是系统框架已经帮你处理好了 HDR 的识别和显示。SwiftUI 的 Image、UIKit 的 UIImageView、以及 CALayer 都能自动识别 HDR 内容并正确渲染。你只需要确保图像元数据正确,系统会自动利用 EDR(Extended Dynamic Range)在支持的显示器上呈现超出 SDR 白点亮度的内容。

详细内容

HDR 基础概念

00:40)HDR 显示的核心是 headroom(头部空间)。SDR 显示器的最亮白色称为 reference white(参考白),HDR 可以显示比 reference white 更亮的内容。

在 EDR 范式中:

  • reference white = 1.0
  • peak = 显示器能表示的最大值

ISO HDR 标准定义:

  • 黑色:0.0005 cd/m²
  • 默认 reference white:203 cd/m²
  • 高于 203 的部分都是 headroom

对比 SDR:

  • sRGB/Display P3 的黑色:0.2 cd/m²
  • 白色:80 cd/m²

识别 HDR 图像

02:35)系统提供了多种方式判断一张图是否是 HDR:

SwiftUI 自动处理:

import SwiftUI

struct ContentView: View {
    var body: some View {
        Image("sunrise_hdr")
            .resizable()
            .scaledToFit()
    }
}

SwiftUI 的 Image 会自动识别 HDR 内容并在支持 EDR 的显示器上正确渲染。

UIKit 处理:

import UIKit

let imageView = UIImageView()
imageView.image = UIImage(named: "sunrise_hdr")
imageView.preferredImageDynamicRange = .high

关键点:

  • preferredImageDynamicRange = .high 告诉系统这张图像应该按 HDR 渲染
  • 系统会自动处理 EDR 映射

从 ProRAW/RAW 创建 HDR 图像

04:30)iPhone 拍摄的 ProRAW 包含高动态范围数据,可以导出为 HDR 静态图像:

import CoreImage
import ImageIO

// 从 ProRAW 创建 HDR CGImage
guard let rawImage = CIImage(contentsOf: prorawURL,
                             options: [.rawFilterOptions: true]) else { return }

// 应用色调映射以保留 HDR 数据
let toneMapped = rawImage.applyingFilter("CIToneCurve",
    parameters: [
        "inputPoint0": CIVector(x: 0, y: 0),
        "inputPoint1": CIVector(x: 0.25, y: 0.25),
        "inputPoint2": CIVector(x: 0.5, y: 0.5),
        "inputPoint3": CIVector(x: 0.75, y: 0.75),
        "inputPoint4": CIVector(x: 1, y: 1.2)  // 超白区域保留
    ])

// 导出为 HEIF with HDR
let context = CIContext()
guard let cgImage = context.createCGImage(toneMapped, from: toneMapped.extent) else { return }

let destination = CGImageDestinationCreateWithURL(outputURL,
                                                   UTType.heic.identifier as CFString,
                                                   1,
                                                   nil)
let hdrProperties: [String: Any] = [
    kCGImagePropertyHEICSDRHint as String: true,
    kCGImagePropertyHEICGainMap as String: gainMapData
]
CGImageDestinationAddImage(destination!, cgImage, hdrProperties as CFDictionary)
CGImageDestinationFinalize(destination!)

关键点:

  • ProRAW 保留了传感器级别的动态范围数据
  • 导出时选择 HEIF 格式以支持 HDR 元数据
  • kCGImagePropertyHEICSDRHint 标记图像包含 HDR 内容

在 CALayer 中显示 HDR

06:15)对于自定义渲染场景,可以用 CALayer 的 EDR 支持:

import QuartzCore

let layer = CALayer()
layer.contents = hdrCGImage
layer.wantsExtendedDynamicRangeContent = true

// 设置 EDR 头部空间
layer.edrMetadata = .hdrContent(
    luminance: 1000.0  // 内容峰值亮度,单位 nits
)

关键点:

  • wantsExtendedDynamicRangeContent = true 启用 EDR 渲染
  • edrMetadata 告诉系统内容的亮度范围,帮助正确映射

Core Graphics 对 ISO HDR 的支持

08:00)Core Graphics 新增了对 ISO HDR 图像的读取和写入支持:

import CoreGraphics

// 读取 HDR 图像的元数据
let source = CGImageSourceCreateWithURL(imageURL as CFURL, nil)
let properties = CGImageSourceCopyPropertiesAtIndex(source!, 0, nil) as? [String: Any]

// 检查 HDR 相关属性
let isHDR = properties?[kCGImagePropertyHDRDictionary as String] != nil
let transferFunction = properties?[kCGImagePropertyHDRTransferFunction as String]
// "HLG" 或 "PQ"

// 写入 HDR 图像
let destination = CGImageDestinationCreateWithURL(outputURL as CFURL,
                                                   UTType.heic.identifier as CFString,
                                                   1, nil)
let hdrProps: [String: Any] = [
    kCGImagePropertyHDRDictionary as String: [
        kCGImagePropertyHDRTransferFunction as String: "HLG",
        kCGImagePropertyHDRReferenceWhite as String: 203.0
    ]
]
CGImageDestinationAddImage(destination!, cgImage, hdrProps as CFDictionary)

关键点:

  • kCGImagePropertyHDRDictionary 包含 HDR 特定元数据
  • 支持 HLG 和 PQ 两种传递函数
  • 10 位位深是 ISO HDR 的最低要求

核心启发

1. 照片编辑 App 的 HDR 导出

  • 做什么:让用户编辑后的照片可以导出为 HDR,保留高光细节
  • 为什么值得做:iPhone 15 Pro 系列用户拍摄的照片越来越多是 HDR,编辑后如果只能导出 SDR 就浪费了原始数据
  • 怎么开始:使用 CGImageDestination 导出 HEIF,设置 kCGImagePropertyHDRDictionary 元数据

2. 图库/社交 App 的 HDR 显示

  • 做什么:在 feed 和详情页自动识别并正确显示 HDR 照片
  • 为什么值得做:SwiftUI Image 和 UIKit UIImageView 已经自动支持,只需确保不破坏元数据
  • 怎么开始:检查图片加载流程,确保不丢失 HDR 元数据;在 UIImageView 上设置 preferredImageDynamicRange = .high

3. 相机 App 的 HDR 拍照预览

  • 做什么:在取景器实时显示 HDR 效果,让用户看到最终成像
  • 为什么值得做:HDR 预览帮助用户构图时判断曝光,特别是逆光场景
  • 怎么开始:使用 AVCaptureVideoPreviewLayer,设置 wantsExtendedDynamicRangeContent = true

4. 从 ProRAW 批量生成 HDR 相册

  • 做什么:把用户的 ProRAW 照片批量转换为可分享的 HDR HEIF
  • 为什么值得做:ProRAW 文件很大(25MB+),HDR HEIF 只有几 MB,更适合分享和存储
  • 怎么开始:用 CIImage(contentsOf:options:) 读取 ProRAW,通过 CGImageDestination 导出为带 HDR 元数据的 HEIF

关联 Session

评论

GitHub Issues · utterances