2

I can load normal images: public.image types.
The Apple proRaw(adobe raw image type: DNG format) can be used in iPhone 12 series.
So, I captured with RAW image and I want to load the DNG file from app.
But I can't load the image using PHPicker. Normally, the codes below.

PHPickerConfiguration *configuration = [[PHPickerConfiguration alloc] init];
configuration.filter = [PHPickerFilter anyFilterMatchingSubfilters:@[[PHPickerFilter imagesFilter], [PHPickerFilter livePhotosFilter]]];

PHPickerViewController *pickerController = [[PHPickerViewController alloc] initWithConfiguration:configuration];
pickerController.delegate = self;
[pickerController setModalPresentationStyle:UIModalPresentationCustom];
[pickerController setModalTransitionStyle:UIModalTransitionStyleCrossDissolve];
[viewController presentViewController:pickerController animated:YES completion:nil];

-(void)picker:(PHPickerViewController *)picker didFinishPicking:(NSArray<PHPickerResult *> *)results API_AVAILABLE(ios(14)) {
    [picker dismissViewControllerAnimated:YES completion:nil];
    
    PHPickerResult *result = [results firstObject];
    
    if ([result.itemProvider canLoadObjectOfClass:[UIImage class]]) {       // 1
        [result.itemProvider loadObjectOfClass:[NSObject class] completionHandler:^(__kindof id<NSItemProviderReading>  _Nullable object, NSError * _Nullable error) {
            if ([object isKindOfClass:[UIImage class]]) {
                UIImage *image = object;
                ...
            }
        }];
    }

In comment 1 line, returned NO.
How to load raw image using PHPicker?

4
  • You would need to set up the PHPickerConfiguration with the photo library, obtain the asset identifier, and return to the library to get the RAW data. Commented Jan 26, 2021 at 5:06
  • @matt I understand what you mean. If obtain PHAsset using the asset identifier, need to authorize to access photo library. But, actually PHPicker does not need to get authorization to access photo library. I want to keep this spec there is not authorization. Commented Jan 26, 2021 at 7:12
  • Cool but then you cannot get the RAW data. Commented Jan 26, 2021 at 7:28
  • @matt what the...😨 I just need not RAW data, but full-sized image. Can I export UIImage from RAW data image? Just image. not additional data like depth info, geo data... Commented Jan 27, 2021 at 1:15

3 Answers 3

3

Using loadFileRepresentation to get the photo's data into a CGImage object worked for me. Something like:

result.itemProvider.loadFileRepresentation(forTypeIdentifier: "public.image") { url, _ in
    guard let url = url,
          let data = NSData(contentsOf: url),
          let source = CGImageSourceCreateWithData(data, nil),
          let cgImage = CGImageSourceCreateImageAtIndex(source, 0, nil) else {
      // handle
    }
    let image = UIImage(cgImage)
    ...
}

or

[result.itemProvider loadFileRepresentationForTypeIdentifier:@"public.image" completionHandler:^(NSURL * _Nullable url, NSError * _Nullable error) {
    if (url) {
        NSData *data = [NSData dataWithContentsOfURL:url];
        CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);
        CGImageRef cgImage = CGImageSourceCreateImageAtIndex(source, 0, NULL);
        UIImage *image = [UIImage imageWithCGImage:cgImage];
        ...
    }
}];

You may need to get the correct orientation using CGImageSourceCopyPropertiesAtIndex to get the metadata dictionary, find the correct value with the kCGImagePropertyOrientation key, transform it from CGImagePropertyOrientation to UIImage.Orientation, and pass it to the UIImage initializer.

It's a bit more involved than just using loadObjectOfClass but it won't require photo access authorization.

Sign up to request clarification or add additional context in comments.

2 Comments

It works but the RAW image from CGImage are in super low resolution without any metadata with black line on top and bottom. IDK how to fix it 🤷🏻‍♂️ have spend so much time. Maybe Do you know how? Thanks 🙏
Oh, I have found out, never mind
1

I have found a solution that will do this without any loss in RAW image quality:

itemProvider.loadFileRepresentation(forTypeIdentifier: "public.image") { url, _ in
    guard let url = url else {
        debugPrint("No RAW Url")
        return
    }
    
    guard let imageSource = CGImageSourceCreateWithURL(url as CFURL, nil) else {
        debugPrint("Could not create image source from URL")
        return
    }

    let options = [kCGImageSourceShouldCache: false] as CFDictionary
    guard let cgImage = CGImageSourceCreateImageAtIndex(imageSource, 0, options) else {
        debugPrint("Could not create CGImage from source")
        return
    }
    
    let image = UIImage(cgImage: cgImage)
}

Comments

-2
  1. You can use this code also. for opening new PHPicker.

  2. For More Knowledge about PHPicker in WWDC21 PHPicker WWDC20 Video and PHPicker WWDC21 Video

  3. WWDC PHPicker Notes PHPicker Notes


import Photos
import PhotosUI


// MARK: - PHPicker Configurations (PHPickerViewControllerDelegate)
extension ViewController: PHPickerViewControllerDelegate {
    func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
         picker.dismiss(animated: true, completion: .none)
         results.forEach { result in
               result.itemProvider.loadObject(ofClass: UIImage.self) { reading, error in
               guard let image = reading as? UIImage, error == nil else { return }
               DispatchQueue.main.async {
                   self.profilePictureOutlet.image = image
                   // TODO: - Here you get UIImage
               }
               result.itemProvider.loadFileRepresentation(forTypeIdentifier: "public.image") { [weak self] url, _ in
                // TODO: - Here You Get The URL
               }
          }
       }
  }

   /// call this method for `PHPicker`
   func openPHPicker() {
       var phPickerConfig = PHPickerConfiguration(photoLibrary: .shared())
       phPickerConfig.selectionLimit = 1
       phPickerConfig.filter = PHPickerFilter.any(of: [.images, .livePhotos])
       let phPickerVC = PHPickerViewController(configuration: phPickerConfig)
       phPickerVC.delegate = self
       present(phPickerVC, animated: true)
   }
}

1 Comment

Yes, but this just don't work for RAW photos - you get nil when trying to loadObject(ofClass: UIImage.self)

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.