Функции вывода CIContext JPEG/PNG для создания пустых изображений

Я пытаюсь вывести CIImage на диск и ищу наиболее эффективный способ. Я нашел этот вопрос, в котором предлагается использовать методы writeJPEGRepresentation/writePNGRepresentation CIContext. Однако всякий раз, когда я пытаюсь использовать эти методы, они создают пустые изображения.

В случае с JPEG получается чисто черное изображение. PNG создает чистое прозрачное изображение. Метод HEIF также давал чисто черное изображение. Тот же результат, если я использую методы jpegRepresentation или pngRepresentation, которые генерируют Data вместо прямой записи на диск.

Если вместо этого я визуализирую эти объекты с помощью createCGImage, а затем записываю данные из CGImage, они выглядят нормально.

Любые идеи, почему это может происходить?

Вот простой пример, иллюстрирующий проблему:

let ciImage = CIImage(contentsOf: photoURL, options: [CIImageOption.applyOrientationProperty: true])!

let context = CIContext()
try! context.writeJPEGRepresentation(of: ciImage, to: FileManager.default.temporaryDirectory.appendingPathComponent("testFromCIImage.jpeg"), colorSpace: CGColorSpace(name: CGColorSpace.sRGB)!, options: [:])

let cgImage: CGImage = context.createCGImage(ciImage, from: ciImage.extent)!
let uiImage = UIImage(cgImage: cgImage)
try! uiImage.jpegData(compressionQuality: 1.0)!.write(to: FileManager.default.temporaryDirectory.appendingPathComponent("testFromUIImage.jpeg"))

testFromCIImage.jpeg отображается как пустое изображение того же размера, что и исходное входное изображение. testFromUIImage.jpeg выглядит так же, как исходное изображение.

Я создал пример проекта, который иллюстрирует проблему, а также несколько примеров изображений.

Обновить

Я нашел только одно условие, при котором изображение выводится правильно - когда исходное изображение является PNG, а параметр colorSpace writeJPEGRepresentation соответствует цветовому пространству исходного изображения. Я не добился успеха ни с одним JPEG, даже если цветовое пространство совпадает.


person Chris Vasselli    schedule 01.05.2020    source источник
comment
Это действительно очень странно. Вы пытались сохранить CIContext за пределами области, в которой вы вызываете writeJPEGRepresentation?   -  person Frank Schlegel    schedule 02.05.2020
comment
@FrankSchlegel Да, я пробовал, но не повезло. Хорошая мысль!   -  person Chris Vasselli    schedule 02.05.2020
comment
Не могли бы вы опубликовать немного больше кода/контекста или, в идеале, минимальный пример приложения, с которым мы могли бы поиграть?   -  person Frank Schlegel    schedule 02.05.2020
comment
@FrankSchlegel только что обновил вопрос, указав пример проекта и немного дополнительной информации.   -  person Chris Vasselli    schedule 03.05.2020
comment
Хм, я думаю, у нас есть классическая для меня проблема: на моем iPhone 11 Pro Max, iOS 13.41 все изображения записываются и снова читаются правильно... Какая у вас тестовая среда?   -  person Frank Schlegel    schedule 03.05.2020
comment
Конечно, я совершал классическую ошибку и тестировал в симуляторе, а не на реальном устройстве. На реальном устройстве у меня тоже работает. Так что я бы предположил, что это просто ошибка симулятора, если только вы не думаете, что есть какая-то причина, по которой это ожидаемое поведение. Если вы хотите написать это как ответ, я отмечу это правильно!   -  person Chris Vasselli    schedule 03.05.2020


Ответы (1)


Как вы сказали, похоже, это проблема исключительно Симулятора. Тем не менее, я еще немного покопался и нашел следующее:

При проверке того, что делает Core Image (устанавливая переменную среды CI_PRINT_TREE), я обнаружил, что дерево выглядит нормально (хотя результирующее изображение черное). Однако для рабочих конфигураций ничего вообще не печаталось! Мне кажется, что Core Image на самом деле не выполняет никакого рендеринга, но, возможно, ввод-вывод изображения используется непосредственно для написания JPG.

Это заставило меня попытаться заставить Core Image использовать программный рендерер (вместо стандартного рендерера Metal), передав CIContextOption.useSoftwareRenderer при создании контекста. Однако это полностью игнорируется. Результирующий контекст по-прежнему является контекстом Metal...

Так что да, кажется, что единственный возможный обходной путь — через CGImage прямо сейчас. Было бы здорово, если бы вы сообщили об ошибке в Apple.

person Frank Schlegel    schedule 04.05.2020
comment
Спасибо за дополнительные копания, очень интересно! Для этого я отправлю сообщение об ошибке в Apple. - person Chris Vasselli; 05.05.2020