iOS中基于Swift 4实现自定义画中画(PIP)相机的技术问询
针对你用Swift 4实现iOS画中画(PIP)相机的需求,结合你提到的几个控件,我整理了一套实时效果处理的可行方案,帮你落地实现:
核心控件职责梳理
先明确你用到的几个视图的分工,确保流程清晰:
- FrontCameraView: 作为背景层,显示模糊化的前置摄像头画面
- BackCameraView: 作为前景画中画窗口,显示后置摄像头的清晰画面
- MaskedCameraView: 叠加在最上层,显示自定义遮罩图像,配合Frame Image实现画中画边框效果
- Frame Image: 承载画中画的边框UI,和MaskedCameraView配合强化视觉层级
实时效果核心实现(captureOutput代理方法)
相机捕获帧的实时处理逻辑都在captureOutput(_:didOutput:from:)方法里,这里要完成帧转图像、效果处理、UI更新三个核心步骤,代码示例如下:
func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) { // 1. 将CMSampleBuffer转换为可处理的UIImage guard let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { print("无法获取图像缓冲区") return } let ciImage = CIImage(cvImageBuffer: imageBuffer) let context = CIContext(options: [.useSoftwareRenderer: false]) // 用GPU加速渲染 guard let cgImage = context.createCGImage(ciImage, from: ciImage.extent) else { print("无法转换为CGImage") return } let capturedImage = UIImage(cgImage: cgImage) // 2. 判断当前捕获的是前置/后置摄像头画面,分别处理 if connection.inputDevice.position == .front { // 给前置画面添加模糊效果 let blurredFrontImage = applyGaussianBlur(to: capturedImage, radius: 8) // 必须回到主线程更新UI DispatchQueue.main.async { self.FrontCameraView.image = blurredFrontImage } } else if connection.inputDevice.position == .back { // 后置画面作为画中画内容,直接赋值并调整位置 DispatchQueue.main.async { self.BackCameraView.image = capturedImage // 设置画中画的位置(示例:右下角),也可以用AutoLayout适配不同屏幕 self.BackCameraView.frame = CGRect( x: self.view.bounds.width - 140, y: self.view.bounds.height - 190, width: 120, height: 160 ) } } // 3. 更新遮罩层图像,实现自定义视觉效果 DispatchQueue.main.async { self.MaskedCameraView.image = self.customMaskImage // 替换为你的遮罩图 // 设置混合模式让遮罩和底层画面融合,可根据需求调整 self.MaskedCameraView.blendMode = .overlay } } // 自定义高斯模糊工具方法 private func applyGaussianBlur(to image: UIImage, radius: CGFloat) -> UIImage? { guard let ciImage = CIImage(image: image) else { return nil } let blurFilter = CIFilter(name: "CIGaussianBlur")! blurFilter.setValue(ciImage, forKey: kCIInputImageKey) blurFilter.setValue(radius, forKey: kCIInputRadiusKey) guard let outputImage = blurFilter.outputImage, let cgImage = CIContext().createCGImage(outputImage, from: outputImage.extent) else { return nil } return UIImage(cgImage: cgImage) }
关键注意事项
- 所有UI更新操作必须放在
DispatchQueue.main.async中,因为captureOutput方法在后台线程执行,直接操作UI会导致崩溃 - 画中画的位置和尺寸建议用AutoLayout约束代替硬编码frame,适配不同屏幕尺寸
- 遮罩图像的混合模式可以尝试不同选项(比如
.normal、.multiply、.screen),得到不同的视觉效果 - 别忘了在Info.plist中添加
NSCameraUsageDescription字段,申请相机权限,否则App会直接崩溃
内容的提问来源于stack exchange,提问作者Pratz_iOS
相关产品推荐
相关产品推荐

