(九)深入了解AVFoundation-采集:拍照 摄像头切换、拍照参数和照片数据EXIF 信息
引言
在 iOS 开发中,AVFoundation 提供了极为强大而灵活的拍照能力。在上一篇基础篇中,我们已经介绍了如何使用 AVCaptureSession 搭建一个基础的拍照流程。而在实际应用中,拍照功能远不止“按下快门”这么简单。
本篇将带你解锁 AVFoundation 拍照的进阶玩法,包括摄像头切换、拍照参数的精细化配置(如分辨率、闪光灯、HDR)、实时滤镜的应用,以及如何获取照片的原始数据、EXIF 信息和 HEIF 格式支持。这些内容不仅能提升拍照质量,也让你的 App 拍照体验更专业、更智能。
无论你是想做一个具备滤镜选择的相机应用,还是实现媲美系统相机的照片输出控制,本篇都能为你提供全面的技术支持。
摄像头切换实现
在拍照功能中,前后摄像头的自由切换是用户最常见的需求之一。比如自拍和普通拍照之间的切换,其核心就是替换当前 AVCaptureDeviceInput,并对 AVCaptureSession 做一次重配置。
1. 获取可用摄像头设备
iOS的摄像头设备可以通过 AVCaptureDevice.DiscoverySession 获取,常见的类型包括前置摄像头和后置广角摄像头。
/// 获取指定摄像头private func getCameraDevice(position: AVCaptureDevice.Position) -> AVCaptureDevice? {let devices = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera], mediaType: .video, position: position).devicesreturn devices.first}
2.实现切换逻辑
实现切换的核心逻辑是 开始配置->移除当前输入->添加新的输入->提交配置,整个过程建议放在session的beginConfiguration()和commitConfiguration()之间。
/// 切换摄像头func switchCamera() {guard let currentInput = captureDeviceInput else { return }session.beginConfiguration()session.removeInput(currentInput)let newPosition: AVCaptureDevice.Position = (currentInput.device.position == .back) ? .front : .backguard let newDevice = getCameraDevice(position: newPosition) else {delegate?.captureError(NSError(domain: "PHCaptureController", code: 1005, userInfo: [NSLocalizedDescriptionKey: "Failed to get new camera device"]))return}setupSessionInput(device: newDevice)session.commitConfiguration()}
拍照参数配置
在拍照功能中,灵活配置拍照参数可以极大提升用户体验与照片质量。AVFoundation 提供了多个可调参数,开发者可以根据设备能力和用户需求选择合适的配置。
1.分辨率设置(Session预设)
分辨率并非直接设置在 AVCapturePhotoSettings 上,而是通过配置 AVCaptureSession 的 sessionPreset 实现。常见的 preset 有:
预设名 | 说明 |
---|---|
.photo | 高质量静态照片(默认推荐) |
.high | 高质量视频或图像 |
.medium | 中等质量,适合上传或处理 |
.inputPriority | 优先使用输入设备最高质量 |
2. 闪光灯控制(Flash Mode)
闪光灯设置依赖于设备支持情况和当前的 AVCapturePhotoSettings 实例:
/// 拍照func takePhoto() {let settings = AVCapturePhotoSettings()settings.flashMode = .autosettings.isHighResolutionPhotoEnabled = truesessionQueue.async {self.photoOutput.capturePhoto(with: settings, delegate: self)}}
其中flashMode还可以是.on或者.off。
3. HDR(高动态范围)设置
iOS 支持的 HDR 功能主要有两类:传统自动 HDR 和虚拟设备融合(Dual/Triple Camera Fusion)。可通过如下方式启用:
let settings = AVCapturePhotoSettings()
settings.isHighResolutionPhotoEnabled = true// 自动融合(适用于 iPhone 双摄以上设备)
settings.isAutoVirtualDeviceFusionEnabled = true// 可选开启红眼自动去除
settings.isAutoRedEyeReductionEnabled = true
获取照片数据和 EXIF 信息
完成拍照触发后,我们会通过 AVCapturePhotoCaptureDelegate 获取到拍摄的照片数据。在这个过程中,我们不仅可以获得图像本身,还能读取包含曝光、设备信息、GPS 等的 EXIF 元数据,对调试和功能扩展都非常有用。
1. 捕获照片数据
在 AVCapturePhotoCaptureDelegate 的拍照完成回调方法里,我们可以直接获取到照片数据。
//MARK: - AVCapturePhotoCaptureDelegatefunc photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: (any Error)?) {if let error = error {delegate?.captureError(error)return}guard let imageData = photo.fileDataRepresentation() else {delegate?.captureError(NSError(domain: "PHCaptureController", code: 1003, userInfo: [NSLocalizedDescriptionKey: "Failed to get image data"]))return}guard let image = UIImage(data: imageData) else {delegate?.captureError(NSError(domain: "PHCaptureController", code: 1004, userInfo: [NSLocalizedDescriptionKey: "Failed to create image"]))return}delegate?.capturePhoto(image)}
这里的 photo.fileDataRepresentation() 返回的是 JPEG 或 HEIF 格式的压缩数据(取决于之前设置的编码格式)。
2. 获取原始元信息(Metadata)
除了图像数据,AVCapturePhoto 也提供了完整的 metadata 信息(包括 EXIF、TIFF、GPS、设备等):
let metadata = photo.metadata
print(metadata)
它是一个 [String: Any] 字典,常见字段如下:
Key | 描述 |
---|---|
{Exif} | 曝光时间、ISO、焦距等 |
{TIFF} | 相机厂商、型号、软件版本等 |
{GPS} | 拍照时的位置(若有授权) |
Orientation | 图片方向 |
PixelWidth/Height | 像素尺寸 |
我们可以这样来读取它的数据:
if let exif = metadata["{Exif}"] as? [String: Any] {let exposureTime = exif["ExposureTime"]let iso = exif["ISOSpeedRatings"]print("曝光时间:\(exposureTime ?? ""),ISO:\(iso ?? "")")
}
3.处理原始图像数据(CIImage)
如果你不使用 fileDataRepresentation(),而是想进一步对图像做处理(比如保存为 PNG、叠加图层等),也可以使用:
let pixelBuffer = photo.pixelBuffer
let ciImage = CIImage(cvPixelBuffer: pixelBuffer)
或者
if let cgImageRepresentation = photo.cgImageRepresentation() {let cgImage = cgImageRepresentation.takeUnretainedValue()let uiImage = UIImage(cgImage: cgImage)
}
结语
本文围绕 AVFoundation 的拍照能力进行了进阶实践,包括:
- 摄像头切换实现:通过灵活切换前后摄像头,提升用户使用自由度;
- 拍照参数配置:涵盖分辨率、闪光灯、HDR 等设置,实现更丰富的拍照效果;
- 获取照片数据与 EXIF 信息:掌握图像数据的保存与元信息提取,构建后续图像处理和展示的基础。
这些功能构成了一套可扩展、可自定义的 iOS 拍照模块核心,对于有定制拍照需求的 App 开发者来说,是一个值得掌握的基础能力。