更改 iOS、swift 中像素的最佳方式

Best way to change pixels in iOS, swift

我目前正在实现某种着色书,我很好奇在 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
}

问题是,每次我更改像素时,我都必须在 context 上调用 makeImage 来生成新图像,这会花费很多时间:

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

    return uiimage
}

我的做法正确吗?有什么更好更快的实施方法?谢谢。

操作单个像素,然后将整个内存缓冲区复制到 CGContext,然后使用该上下文创建 UIImage 最终会变得效率低下,正如您所发现的那样。

您可以通过更有效地将屏幕外的部分复制到屏幕上来继续改进和优化 CoreGraphics canvas 方法。您可以检测已更改的像素,并仅将这些像素的最小边界矩形复制到屏幕上。这种方法可能足以满足您仅用颜色填充区域的用例。

与其复制整个屏幕外,不如复制更改的区域:

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

由您决定更改的矩形以及何时更新屏幕。

Here 是一个使用 CoreGraphics、CoreImage 和 CADisplayLink 的绘画应用程序示例。代码有点旧,但概念仍然有效,可以作为一个很好的起点。您可以使用 CADisplayLink 查看更改是如何累积并绘制到屏幕上的。

如果您想介绍各种类型的墨水和绘画效果,CoreGraphics 方法将更具挑战性。你会想看看 Apple 的 Metal API。 here.

是一个很好的教程