Как программно загрузить необработанное изображение с помощью PHPicker в iOS?

Могу загружать обычные изображения: типы public.image.
Apple proRaw(тип изображения Adobe Raw: формат DNG) можно использовать в iPhone 12 серии.
Итак, я сделал снимок в формате RAW и хочу загрузить файл DNG из приложения.
Но я не могу загрузить изображение с помощью PHPicker. Обычно коды ниже.

      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;
                ...
            }
        }];
    }

В строке комментария 1 возвращается NO.
Как загрузить необработанное изображение с помощью PHPicker?

3 ответа

С использованием loadFileRepresentationчтобы получить данные фотографии в CGImageобъект работал для меня. Что-то типа:

      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)
    ...
}

или же

      [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];
        ...
    }
}];

Вам может понадобиться получить правильную ориентацию, используя CGImageSourceCopyPropertiesAtIndexчтобы получить словарь метаданных, найдите правильное значение с помощью kCGImagePropertyOrientationключ, преобразовать его из CGImagePropertyOrientationк UIImage.Orientation, и передать его в UIImageинициализатор.

Это немного сложнее, чем просто использование loadObjectOfClassно для этого не потребуется авторизация доступа к фотографиям.

Я нашел решение, которое сделает это без потери качества изображения RAW:

      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)
}
  1. Вы также можете использовать этот код. для открытия нового PHPicker .

  2. Для получения дополнительных знаний о PHPicker в видео WWDC21 PHPicker WWDC20 и видео PHPicker WWDC21

  3. WWDC Заметки PHPicker Заметки PHPicker


      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)
   }
}
Другие вопросы по тегам