extension CameraManagerPhotoOutput: @preconcurrency AVCapturePhotoCaptureDelegate { func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: (any Error)?) { guard let imageData = photo.fileDataRepresentation(), let ciImage = CIImage(data: imageData) else { return } // Retrieve metadata from AVCapturePhoto var metadata = photo.metadata // Process the CIImage with filters let capturedCIImage = prepareCIImage(ciImage, parent.attributes.cameraFilters) // Convert back to CGImage guard let capturedCGImage = prepareCGImage(capturedCIImage) else { return } // Convert to UIImage while preserving orientation guard let capturedUIImage = prepareUIImage(capturedCGImage) else { return } // Add orientation metadata if let orientationValue = metadata[kCGImagePropertyOrientation as String] as? NSNumber { metadata[kCGImagePropertyOrientation as String] = orientationValue } // Re-embed metadata into the final image data guard let finalImageData = createImageDataWithMetadata(image: capturedUIImage, metadata: metadata) else { return } // Wrap final data and pass it to the parent let capturedMedia = MCameraMedia(data: finalImageData) parent.setCapturedMedia(capturedMedia) } } private extension CameraManagerPhotoOutput { func prepareCIImage(_ ciImage: CIImage, _ filters: [CIFilter]) -> CIImage { ciImage.applyingFilters(filters) } func prepareCGImage(_ ciImage: CIImage) -> CGImage? { CIContext().createCGImage(ciImage, from: ciImage.extent) } func prepareUIImage(_ cgImage: CGImage?) -> UIImage? { guard let cgImage else { return nil } let frameOrientation = getFixedFrameOrientation() let orientation = UIImage.Orientation(frameOrientation) let uiImage = UIImage(cgImage: cgImage, scale: 1.0, orientation: orientation) return uiImage } /// Embeds metadata into image data func createImageDataWithMetadata(image: UIImage, metadata: [String: Any]) -> Data? { guard let cgImage = image.cgImage else { return nil } // Create a CFData representation of the image let imageData = NSMutableData() guard let destination = CGImageDestinationCreateWithData(imageData, kUTTypeJPEG, 1, nil) else { return nil } // Embed the CGImage and metadata CGImageDestinationAddImage(destination, cgImage, metadata as CFDictionary) CGImageDestinationFinalize(destination) return imageData as Data } }