Dan Hixon
Dan Hixon

Reputation: 925

iOS 10 Save RAW Photo to camera roll

I have the following code to save a RAW image as a JPEG to the camera roll but it has three problems: 1) it is a mirror image, 2) it is rotated 90 degrees, and 3) it is low resolution.

// In my PhotoCaptureDelegate
func capture(_ captureOutput: AVCapturePhotoOutput, didFinishProcessingRawPhotoSampleBuffer rawSampleBuffer: CMSampleBuffer?,     previewPhotoSampleBuffer: CMSampleBuffer?, resolvedSettings: AVCaptureResolvedPhotoSettings, bracketSettings:     AVCaptureBracketedStillImageSettings?, error: Error?) {

  if ( rawSampleBuffer != nil) {
    let temporaryDNGFileURL = NSURL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("\(resolvedSettings.uniqueID)lld.dng")!
    let temporaryJPGFileURL = NSURL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("\(resolvedSettings.uniqueID)lld.jpg")!
    let imageData = AVCapturePhotoOutput.dngPhotoDataRepresentation(forRawSampleBuffer: rawSampleBuffer!, previewPhotoSampleBuffer:       previewPhotoSampleBuffer)


    try! imageData?.write(to: temporaryDNGFileURL)
    PHPhotoLibrary.requestAuthorization({ (status)  in
        if status == .authorized {
          PHPhotoLibrary.shared().performChanges({

            let options = PHAssetResourceCreationOptions()
            options.shouldMoveFile = true
            //Write Raw:
            PHAssetCreationRequest.forAsset().addResource(with: .photo, fileURL: temporaryDNGFileURL, options: options)

                    // Process Raw to JPG
                    if let ciRawFilter = CIFilter(imageData: imageData! as Data, options: nil) {
                        let cs = CGColorSpace(name: CGColorSpace.displayP3)!
                        do {
                            try self.contextForSaving.writeJPEGRepresentation(of: ciRawFilter.outputImage!, to: temporaryJPGFileURL, colorSpace: cs,   options: [    kCGImageDestinationLossyCompressionQuality as String: 1.0])
                            PHAssetCreationRequest.forAsset().addResource(with: .photo, fileURL: temporaryJPGFileURL, options: options)
                        } catch _ {
                            print("error with jpeg conversion")
                        }

                    }
            }, completionHandler: { [unowned self] success, error in
              if let error = error {
                print("Error occurered while saving photo to photo library: \(error)")
              } else {
                print("Raw photo written to photo library.")
              }

              if FileManager.default.fileExists(atPath: temporaryDNGFileURL.path) {
                do {
                  (try FileManager.default.removeItem(at: temporaryDNGFileURL))
                }
                catch _ {
                  print("could not remove temporary file")
                }
              }
              self.didFinish()
            }
          )
        }
        else {
          self.didFinish()
        }
    })
  } else {
    print("Error capturing photo: \(error)")
  }
}

I know how to capture the JPEG directly but I am trying to apply some custom filters to the RAW data first.

enter image description here

Please help if you can, thanks in advance!

Upvotes: 3

Views: 2911

Answers (2)

Dan Hixon
Dan Hixon

Reputation: 925

I needed to specify the kCGImageSourceTypeIdentifierHint. It was just grabbing the JPEG thumbnail representation from the DNG data instead of looking for the actual DNG data. Now that I have this option in place the JPEG file is full-sized and correctly oriented.

let imageData = AVCapturePhotoOutput.dngPhotoDataRepresentation(
                forRawSampleBuffer: rawSampleBuffer!, 
                previewPhotoSampleBuffer: previewPhotoSampleBuffer)
let rawOptions = [String(kCGImageSourceTypeIdentifierHint): "com.adobe.raw-image"]
if let ciRawFilter = CIFilter(imageData: imageData! as Data, options: rawOptions) {
  // raw Filters and stuff go here, then handle outputImage
}

Upvotes: 2

nav1729
nav1729

Reputation: 103

I have tested the following code to save the output image from raw filter in jpeg format with right orientation and resolution. change the jpeg quality and output color space according to your requirements. Hope this helps you.

    guard let opCiImage:CIImage = rawFilter!.outputImage else {
        print("Error in creating raw filter output")
        return
    }
    let dumpingContext:CIContext = CIContext(options: [kCIContextCacheIntermediates:false,
                                                       kCIContextPriorityRequestLow:false])



    //Convert to CGImage and then dump into a jpeg
    let opCgImage = dumpingContext.createCGImage(opCiImage,
                                                   from: opCiImage.extent,
                                                   format: kCIFormatARGB8,
                                                   colorSpace: CGColorSpace(name: CGColorSpace.sRGB),
                                                   deferred: false)
    let uImage = UIImage(cgImage: opCgImage!)
    guard let opImgData:Data = UIImageJPEGRepresentation(uImage, 0.95) else { return }

please let me know the feedback in comments.

Upvotes: 5

Related Questions