Лучший способ изменить пиксели в iOS, Swift - PullRequest
0 голосов
/ 26 октября 2019

В настоящее время я реализую какую-то книжку-раскраску, и мне интересно узнать, как лучше изменить пиксели в UIImage. Вот мой код:

self.context = CGContext(data: nil, width: image.width, height: image.height, bitsPerComponent: 8, bytesPerRow: image.width * 4, space: colorSpace, bitmapInfo: CGBitmapInfo.byteOrder32Little.rawValue | CGImageAlphaInfo.premultipliedFirst.rawValue)!
self.context?.draw(image.cgImage, in: CGRect(x: 0, y: 0, width: CGFloat(image.width), height: CGFloat(image.height)))
let ptr = context.data
self.pixelBuffer = ptr!.bindMemory(to: UInt32.self, capacity: image.width * image.height)

И меняйте пиксели с помощью этой функции:

@inline (__always) func fill(matrixPosition: MatrixPosition, color: UInt32) {
    pixelsBuffer?[self.linearIndex(for: matrixPosition)] = color
}

Проблема в том, что каждый раз, когда я меняю пиксели, я должен вызывать makeImage на context для создания нового изображения, и это занимает много времени:

func generateImage() -> UIImage {
    let cgImage = context.makeImage()!
    let uiimage = UIImage(cgImage: cgImage)

    return uiimage
}

Правильно ли подходит мой подход? Какие есть лучшие и более быстрые способы его реализации? Спасибо.

1 Ответ

2 голосов
/ 26 октября 2019

Манипулирование отдельными пикселями, а затем копирование всего буфера памяти в CGContext, а затем создание UIImage с этим контекстом может оказаться неэффективным, как вы обнаруживаете.

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

Вместо того, чтобы копировать весь экран, скопируйте только измененную область:

self.context?.draw(image.cgImage, in: CGRect(x: diffX, y: diffY, width: diffWidth, height: diffHeight))

ЭтоВы можете определить измененный прямоугольник и когда обновлять экран.

Здесь - пример приложения для рисования, использующего CoreGraphics, CoreImage и CADisplayLink. Код немного староват, но концепции все еще действительны и послужат хорошей отправной точкой. Вы можете увидеть, как изменения накапливаются и выводятся на экран с помощью CADisplayLink.

Если вы хотите представить различные типы чернил и рисованных эффектов, подход CoreGraphics будет более сложным. Вам захочется взглянуть на Apple Metal API. Хороший урок здесь .

...