CGImage с изображений, хранящихся на iCloud, выглядит неправильно - PullRequest
1 голос
/ 17 февраля 2020

Я извлекаю пиксельные цвета из CGImage, используя код, описанный в этого ответа .

Однако я только что понял, что если я загружаю изображение, созданное на другом устройство, значения пикселей выглядят неправильно. Первая очевидная проблема заключается в том, что альфа исчезла. CGImageAlphaInfo сообщает .noneSkipLast, но я знаю, что изображение RGBA. Если я читаю его с того же устройства, на котором он был создан, это выглядит нормально. Вторая проблема состоит в том, что есть некоторое цветное кровотечение, как будто изображение было изменено. Возможно, это сжатие или что-то.

Вот пример:

Исходное изображение - это арбуз, 12x12 Source image

Он был создан на моем iPad. Но если я загружаю его на свой iPhone через iCloud, используя тот код, который я связал, я получаю это:

Bad sampling

Альфа-канал пропал, и * Цвета кровоточат.

Если из того же iPhone я отправляю маленький арбуз своему Ма c, используя Airdrop, и снова отправляю его обратно, используя Airdrop (так что это, предположительно, то же изображение!), и загружаю теперь я получаю правильное изображение:

Correct image (темно-коричневые области - это где альфа равен 0)

Если у вас есть пара устройств iOS с включенным iCloud вы можете воспроизвести это поведение в этом приложении: http://swiftpixels.endavid.com, где я использую этот код для чтения цветов пикселей.

В чем может быть разница между этими изображениями? Как я могу прочитать правильное изображение из iCloud? Стоит ли искать подсказки в UIImage вместо CGImage?

Есть какие-нибудь подсказки? Спасибо!

Обновление

Для справки, я читаю изображение, используя UIImagePickerController, используя этот код:

    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
        if let image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage {
            loadImageInMemory(image)
        }
        picker.dismiss(animated: true, completion: nil)
        self.presentingViewController?.dismiss(animated: true, completion: nil)
    }

    fileprivate func loadImageInMemory(_ image: UIImage) {
       /// skipping some preparation
       guard let cgImage = image.cgImage else {
          return
       }
       /// getImageData is a function like getPixelColor linked above,
       /// but for a Rect 
       self.imageData = cgImage.getImageData(rect, width, height)
    }

I также нашел этот вопрос, который может быть связан: UIImagePickerController и фотографии iCloud

Как Роб предложил в комментариях ниже, я изменил настройки Фото в своем телефоне на «Загрузить и сохранить оригиналы» (вместо этого «Оптимизировать iPhone Хранилище»), и это решает проблему. Поэтому я предполагаю, что вопрос заключается в том, почему iCloud пытается сжать изображение PNG размером всего 1355 байт, и можно ли получить доступ к исходному изображению из UIImagePickerController

Ответы [ 2 ]

1 голос
/ 18 февраля 2020

В приложении «Настройки» в разделе «Фотографии» есть опция «Оптимизировать iPhone Хранилище» и «Загрузить и сохранить оригиналы». Последний должен синхронизировать библиотеку фотографий без какого-либо изменения изображений.

Похоже, Airdrop может получить доступ к исходному изображению.

Airdrop не полагается на фотографию Библиотека синхронизации iCloud для отправки изображения. Вот почему ресурс делает его доступным, без изменений.

Как я могу сделать так, чтобы мое приложение получало доступ к оригиналу?

Все зависит от того, действительно ли вы хотите использовать библиотека фотографий для синхронизации ваших активов. Это кажется особенно верным, поскольку многие люди могут вообще не синхронизировать c свою огромную библиотеку фотографий с iCloud. Я не уверен, что вы хотите положиться на это.

Возможно, вы захотите просто использовать CloudKit, а не полагаться на библиотеку фотографий. Возможно, у вас должна быть опция в приложении, чтобы пользователь мог вообще использовать хранилище iCloud, и если да, то используйте хранилище iCloud в своем приложении, а не полагайтесь на библиотеку Photos.

0 голосов
/ 19 февраля 2020

Причина, по которой изображение выглядело размытым и без альфа, заключается в том, что Photos по умолчанию передает потоки сжатых в формате JPEG изображений из iCloud. Даже если ваше исходное изображение будет меньше без сжатия, как в этом примере пиксельной графики.

Как указывает Роб , способ убедиться, что это так, - изменить ваши фотографии настройки. Из приложения Настройки:

Settings -> Photos -> Download and Keep Originals

Это решит проблему, но, конечно, это нежелательно. Если вы хотите продолжать использовать фотографии, вместо реализации собственного решения iCloud, сохраняя настройку Optimize iPhone Storage, вы можете использовать PhotoKit для получения исходного изображения.

Заменить этот код,

    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
        if let image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage {
            loadImageInMemory(image)
        }
        picker.dismiss(animated: true, completion: nil)
        self.presentingViewController?.dismiss(animated: true, completion: nil)
    }

с помощью этого другого кода:

import Photos

// ...

    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
        // it will be loaded asynchronously
        loadImageFromPicker(info: info)
        picker.dismiss(animated: true, completion: nil)
        self.presentingViewController?.dismiss(animated: true, completion: nil)
    }

    private func loadImageFromPicker(info: [UIImagePickerController.InfoKey : Any]) {
        guard let referenceURL = info[UIImagePickerController.InfoKey.referenceURL] as? URL else {
            return
        }
        let fetchResult = PHAsset.fetchAssets(withALAssetURLs: [referenceURL], options: nil)
        guard let phAsset = fetchResult.firstObject else {
            return
        }
        // size doesn't matter, because resizeMode = .none
        let size = CGSize(width: 32, height: 32)
        let options = PHImageRequestOptions()
        options.version = .original
        options.deliveryMode = .highQualityFormat
        options.resizeMode = .none
        options.isNetworkAccessAllowed = true
        PHImageManager.default().requestImage(for: phAsset, targetSize: size, contentMode: .aspectFit, options: options) { [weak self] (image, info) in
            if let s = self, let image = image {
                s.loadImageInMemory(image)
            }
        }
    }

Этот код будет работать как с локальными изображениями, так и с изображениями iCloud.

...