Визуализация небольшого CIImage с центром в MTKView

Я визуализирую от CIImage до MTKView, и изображение меньше, чем можно рисовать.

let centered = image.transformed(by: CGAffineTransform(translationX: (view.drawableSize.width - image.extent.width) / 2, y: (view.drawableSize.height - image.extent.height) / 2))
context.render(centered, to: drawable.texture, commandBuffer: buffer, bounds: centered.extent, colorSpace: CGColorSpaceCreateDeviceRGB())

Я ожидал, что приведенный выше код отобразит изображение в центре представления, но вместо этого изображение располагается в исходной точке.

Вот репо, иллюстрирующее проблему: https://github.com/truemetal/centered-render-of-ciimage-to-mtkview

Прежде чем обвинять Metal или CoreImage, я хотел бы убедиться, что я не делаю что-то не так.

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

снимок экрана проблемы

Я могу обойти это, наложив изображение на другое, которое было бы точно такого же размера, как это, но меня все еще интересует, почему именно приведенный выше код не работает.

let centered = image.transformed(by: CGAffineTransform(translationX: (view.drawableSize.width - image.extent.width) / 2, y: (view.drawableSize.height - image.extent.height) / 2))
let background = CIImage(color: .white).cropped(to: CGRect(origin: .zero, size: view.drawableSize))
let preparedImage = centered.composited(over: background)
self.context.render(preparedImage, to: drawable.texture, commandBuffer: buffer, bounds: preparedImage.extent, colorSpace: CGColorSpaceCreateDeviceRGB())

person Dannie P    schedule 19.02.2019    source источник


Ответы (1)


Это очень любопытно. Если вы используете «новый» CIRenderDestination API вместо context.render(…), он действительно работает:

let destination = CIRenderDestination(width: Int(view.drawableSize.width),
                                      height: Int(view.drawableSize.height),
                                      pixelFormat: view.colorPixelFormat,
                                      commandBuffer: buffer,
                                      mtlTextureProvider: { () -> MTLTexture in
                                          return drawable.texture
                                      })
try! self.context.startTask(toRender: centered, to: destination)

Я не знаю почему, но context.render(…), похоже, не уважает перевод изображения или заданные границы. Может еще кто знает больше ...

person Frank Schlegel    schedule 20.02.2019
comment
Блестяще. Это фактически доказывает мне, что что-то пошло не так внутри основного образа. Большое спасибо. - person Dannie P; 21.02.2019
comment
Я считаю, что этот несколько более короткий аналог работает одинаково хорошо let destination = CIRenderDestination(mtlTexture: drawable.texture, commandBuffer: commandBuffer) - person Dannie P; 21.02.2019
comment
Да, версия с обратным вызовом имеет преимущество чередования выборки текстуры и рендеринга и, следовательно, более эффективна при рендеринге нескольких кадров в секунду. - person Frank Schlegel; 21.02.2019
comment
Интересный. У вас случайно есть ссылка на документы, подтверждающие эту точку зрения? - person Dannie P; 21.02.2019
comment
О да, это было упомянуто в презентации Advances in Core Image с WWDC 2017: developer.apple.com/videos/play/wwdc2017/510/?time=1393 - person Frank Schlegel; 21.02.2019
comment
Ах, получение currentDrawable в последний момент рекомендация. Я только что пересмотрел это видео, и вы правы, в нем упоминалось об этом. Однако для меня интересно то, что я не вижу каких-либо улучшений при использовании этой техники в моем приложении - возможно, по той причине, что я выдаю только одну задачу рендеринга, а следующая строка - presentDrawable, которая в любом случае фиксирует возможность рисования. . Возможно, этот метод поможет при выполнении нескольких задач рендеринга. Спасибо за ссылку на видео! - person Dannie P; 21.02.2019
comment
Я предполагаю, что это потому, что то, что вы делаете (по крайней мере, в демонстрационном приложении), очень просто и в любом случае не требует большой обработки. Для более сложных сценариев это, вероятно, полезно. - person Frank Schlegel; 21.02.2019
comment
Демонстрационное приложение - это то, что я собрал, чтобы продемонстрировать проблему с минимальным количеством кода. Я пробовал эту технику в проекте, в котором используются десятки основных фильтров изображения, которые применяются к входному изображению и создают одно выходное изображение, которое отображается в металлическом виде. Затем я измеряю среднее время в секунду, которое тратится на CIContext startTask(toRender:to:), и оно округляется до 150–300 мс в секунду с использованием обоих методов. Я предполагаю, что если будет дюжина обращений к startTask, это поможет сократить время ожидания, запросив эту возможность как можно позже. - person Dannie P; 22.02.2019