Нарисуйте часть CGImage - PullRequest
       8

Нарисуйте часть CGImage

1 голос
/ 25 августа 2010

У меня есть приложение, которое рисует изображения из CGImage.

Сам CImage загружается с использованием CGImageSourceCreateImageAtIndex для создания изображения из файла PNG.

Это является частью механизма спрайтов- существует несколько изображений спрайтов в одном файле PNG, поэтому каждый спрайт имеет CGRect, определяющий, где он находится в CGImage.

Проблема в том, что CGContextDraw принимает только прямоугольник назначения - и растягивает исходный CGImage дозаполните его.

Итак, чтобы нарисовать каждое изображение спрайта, нам нужно создать несколько CGImage из исходного источника, используя CGImageCreateWithImageInRect ().

Сначала я подумал, что это будет «дешево»операция - не кажется необходимым, чтобы каждый CGImage содержал свою собственную копию битов изображений - однако профилирование показало, что использование CGImageCreateWithImageInRect () является довольно дорогой операцией.

Существует ли более оптимальный метод длянарисовать подраздел CGImage на CGContext, поэтому мне не нужно CGImageCreateWithImageInRect () так часто?


Учитывая отсутствие исходного прямоугольника и простоту создания CGImage из прямоугольника на CGImage, я начал подозревать, что, возможно, CGImage реализовал функцию копирования при записи.семантическая, где CGImage, созданный из CGImage, будет ссылаться на подчиненный объект из тех же физических битов, что и родительский.Профилирование, кажется, доказывает это неправильно: /

Ответы [ 4 ]

2 голосов
/ 04 декабря 2012

Я был в той же лодке, что и ты. CGImageCreateWithImageInRect() работал лучше для моих нужд, но ранее я пытался преобразовать в NSImage, а до этого я вырезал контекст, в котором я рисовал, и переводил так, чтобы CGContextDrawImage() рисовал правильные данные в вырезанном обл.

Из всех решений, которые я пробовал:

  1. Отсечение и перевод на ЦП были непомерно высокими. Это было слишком медленно. Казалось, что увеличение количества растровых данных лишь незначительно повлияло на производительность, что говорит о том, что в этом подходе отсутствует какая-либо масштабируемость.

  2. Преобразование в NSImage было относительно эффективным, по крайней мере, для данных, которые мы использовали. Похоже, я не видел никакого дублирования растровых данных, и это было главным образом из-за того, что я боялся переходить от одного объекта изображения к другому.

  3. В какой-то момент я преобразовал в CIImage, так как этот класс также позволяет рисовать субрегионы изображения. Это казалось медленнее, чем преобразование в NSImage, но дало мне возможность поиграть с растровым изображением, пропустив некоторые фильтры Core Image.

  4. Использование CGImageCreateWithImageInRect() было самым быстрым из лота; возможно, это было оптимизировано с тех пор, как вы в последний раз использовали его. Документация для этой функции гласит, что полученное изображение сохраняет ссылку на исходное изображение, что, похоже, согласуется с тем, что вы предположили относительно семантики копирования при записи. В моих тестах, похоже, нет дублирования данных, но, возможно, я неправильно читаю результаты. Мы выбрали этот метод, потому что он был не только самым быстрым, но и более «чистым». подход, сохраняя весь процесс в одной структуре.

0 голосов
/ 25 апреля 2019

У меня была похожая проблема при написании простой 2D-игры на основе тайлов.

Единственный способ получить приличную производительность - это:

1) Предварительный рендеринг CGImage листа листов в CGBitmapContext с использованием CGContextDrawImage ()

2) Создайте еще один CGBitmapContext в качестве буфера внеэкранного рендеринга, того же размера, что и UIView, в котором я рисовал, и того же формата пикселей, что и контекст из (1).

3) Напишите мою собственную процедуру быстрого блитирования, которая будет копировать область (CGRect) пикселей из контекста растрового изображения, созданного в (1), в контекст растрового изображения, созданного в (2). Это довольно просто: просто копирование памяти (и некоторые дополнительные операции для каждого пикселя для выполнения альфа-смешения, если необходимо), учитывая, что растры расположены в буфере в обратном порядке (последняя строка пикселей на изображении находится на начало буфера).

4) После отрисовки кадра нарисуйте внеэкранный буфер в представлении с помощью CGContextDrawImage ().

Насколько я мог сказать, каждый раз, когда вы вызываете CGImageCreateWithImageInRect (), он декодирует весь файл PNG в необработанное растровое изображение, а затем копирует желаемую область растрового изображения в целевой контекст.

0 голосов
/ 25 августа 2010

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

0 голосов
/ 25 августа 2010
...