简体   繁体   English

iOS中如何将JPEG/RAW图片数据保存到相册 11、无法访问处理后的图片数据

[英]How to save JPEG/RAW image data to camera roll in iOS 11, can't access processed image data

I'm attempting to write a photoapp that can take both RAW and JPEG images and save them to the camera roll.我正在尝试编写一个可以拍摄 RAW 和 JPEG 图像并将它们保存到相机胶卷的照片应用程序。 The functions jpegPhotoDataRepresentation and dngPhotoDataRepresentation seem to be the key to all examples I've found, however both of these are deprecated in iOS 11 and the function for saving after "capturePhoto" is now函数 jpegPhotoDataRepresentation 和 dngPhotoDataRepresentation 似乎是我找到的所有示例的关键,但是这两个在 iOS 11 和 function 中已弃用,用于在“capturePhoto”之后保存现在

func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {

The main example I've been able to find of a working RAW iOS11 app is this: https://ubunifu.co/swift/raw-photo-capture-sample-swift-4-ios-11 which works, however it only shoots RAW and saving is clumsy because it's not on the camera roll.我能够找到的工作 RAW iOS11 应用程序的主要示例是: https://ubunifu.co/swift/raw-photo-capture-sample-swift-4-ios-11有效,但它仅拍摄 RAW 并且保存很笨拙,因为它不在相机胶卷上。

I've changed my photo settings to allow for both raw and processed capture with this line我已经更改了我的照片设置以允许使用此行进行原始和处理后的捕获

photoSettings = AVCapturePhotoSettings(rawPixelFormatType: availableRawFormat.uint32Value, processedFormat: [AVVideoCodecKey : AVVideoCodecType.jpeg])

But once I've actually captured the photo I have no idea how to access the processedFormat data.但是一旦我真正拍摄了照片,我就不知道如何访问 processedFormat 数据。 fileDataRepresentation seems to be the only way to access the dng stuff, but there's no way to get at the jpeg separately? fileDataRepresentation 似乎是访问 dng 内容的唯一方法,但是没有办法单独获取 jpeg? The code I've found from Apple pre-iOS11 suggests to use PHPhotoLibrary and add a resource, but this requires a data representation which I'm unable to access other than as a dng file, which when saved to the library is just white because the library is not able to handle RAW files.我从 iOS11 之前的 Apple 找到的代码建议使用 PHPhotoLibrary 并添加资源,但这需要一个数据表示,除了 dng 文件之外我无法访问它,当保存到库中时它只是白色,因为该库无法处理 RAW 文件。 Here's my photoOutput code in case it helps.如果有帮助,这是我的 photoOutput 代码。

 func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {

    let dir = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first! as String
    let formatter = DateFormatter()
    formatter.dateFormat = "yyyyMMddHHmmss"
    formatter.locale = Locale.init(identifier: "en_US_POSIX")
    let filePath =  dir.appending(String(format: "/%@.dng", formatter.string(from: Date())))
    let dngFileURL = URL(fileURLWithPath: filePath)

    let dngData = photo.fileDataRepresentation()!
    do {
        try dngData.write(to: dngFileURL, options: [])
    } catch {
        print("Unable to write DNG file.")
        return
    }

    PHPhotoLibrary.shared().performChanges( {
        let creationRequest = PHAssetCreationRequest.forAsset()
        let creationOptions = PHAssetResourceCreationOptions()
        creationOptions.shouldMoveFile = true


        //dngData is the problem, this should be the jpeg representation
        creationRequest.addResource(with: .photo, data: dngData, options: nil)
        //This line works fine, the associated file is the correct RAW file, but the jpeg preview is garbage
        creationRequest.addResource(with: .alternatePhoto, fileURL: dngFileURL, options: creationOptions)

    }, completionHandler: nil)

}

Okay, following up on comment from earlier and the Apple docs on Capturing Photos in RAW Format :好的,跟进之前的评论和 Apple 文档中有关以 RAW 格式拍摄照片的内容:

As you've noticed, if you want to shoot RAW and save it in the Photos library, you need to save DNG+processed versions together in the same asset so that Photos library clients that don't support RAW still have a readable version of the asset.正如您所注意到的,如果您想拍摄 RAW 并将其保存在照片库中,您需要将 DNG+ 处理后的版本一起保存在同一资产中,以便不支持 RAW 的照片库客户端仍然具有可读版本的资产。 (That includes the Photos app itself...) Saving both RAW+processed means specifying that in the capture. (这包括照片应用程序本身......)同时保存 RAW+processed 意味着在捕获中指定它。

If you're requesting RAW+processed capture (where processed is JPEG, or even better, HEIF), you're getting two photos for every shot you take.如果您请求 RAW+ 处理的捕获(处理的是 JPEG,或者更好的是 HEIF),您拍摄的每张照片都会得到两张照片。 That means your didFinishProcessingPhoto callback gets called twice : once to deliver the JPEG (or HEIF), again to deliver the RAW.这意味着您的didFinishProcessingPhoto回调被调用两次:一次是传送 JPEG(或 HEIF),另一次是传送 RAW。

Since you need to add RAW+processed versions of the asset to Photos together, you should wait until the capture output delivers both versions before trying to create the Photos asset.由于您需要将资产的 RAW+ 处理版本一起添加到照片,因此您应该等到捕获 output 提供两个版本,然后再尝试创建照片资产。 You'll notice the code snippets in that Apple doc stash the data for both versions in the didFinishProcessingPhoto callback:您会注意到该Apple 文档中的代码片段将两个版本的数据存储在didFinishProcessingPhoto回调中:

func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
    if photo.isRawPhoto {
        // Save the RAW (DNG) fileDataRepresentation to a URL
    } else {
        // Hold JPEG/HEIF fileDataRepresentation in a property
    }
}

Then, when the didFinishCaptureFor callback fires, they make sure they have both versions, and add them together to the Photos library.然后,当didFinishCaptureFor回调触发时,他们确保它们具有两个版本,并将它们一起添加到照片库中。

Notice that when you add DNG and JPEG or HEIF versions of a photo together...请注意,当您同时添加照片的 DNG 和 JPEG 或 HEIF 版本时...

  • The JPEG/HEIF needs to be the primary photo resource, and the DNG the alternatePhoto resource. JPEG/HEIF 需要作为主要photo资源,而 DNG 需要作为alternatePhoto照片资源。
  • You can add a JPEG/HEIF resource straight from Data in memory, but DNG needs to be added from a file URL.您可以直接从 memory 中的Data添加 JPEG/HEIF 资源,但需要从文件 URL 添加 DNG。

So the Photos library part goes like this (again, inside the didFinishCaptureFor callback):所以照片库部分是这样的(同样,在didFinishCaptureFor回调中):

PHPhotoLibrary.shared().performChanges({
    // Add the compressed (HEIF) data as the main resource for the Photos asset.
    let creationRequest = PHAssetCreationRequest.forAsset()
    creationRequest.addResource(with: .photo, data: compressedData, options: nil)

    // Add the RAW (DNG) file as an altenate resource.
    let options = PHAssetResourceCreationOptions()
    options.shouldMoveFile = true
    creationRequest.addResource(with: .alternatePhoto, fileURL: rawURL, options: options)
}, completionHandler: self.handlePhotoLibraryError)

You can make CGImage extension like here and then get pixel buffer from that cgImage.您可以像这里一样制作 CGImage 扩展,然后从该 cgImage 获取像素缓冲区。

if let cgImage = photo.cgImageRepresentation() {
    let pixelBuffer = cgImage.pixelBuffer()
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM