iOS Swift 如何增量绘制到 UIImage?
iOS Swift how to incrementally draw to a UIImage?
如何使用iOS核心图形在单个图像中增量绘制大数据集?
我有代码可以立即处理整个数据集(超过 100,000 个矩形)并生成单个图像。这是一个很长的 运行 操作,我希望这个数据集一次增量绘制 1000 个矩形,显示这些小图像更新(就像 90 年代从互联网下载的图像)
我的问题是:我是否会在整个操作过程中保持对同一个 context
的引用并简单地向其添加元素? - 或者 - 我应该使用 UIGraphicsGetImageFromCurrentImageContext()
捕获当前图像,然后在新的上下文中绘制它并在其上绘制其他矩形吗?
奖金问题 - 如果我想使用多个线程附加到同一图像,这是正确的方法吗?
let context = UIGraphicsGetCurrentContext()!
context.setStrokeColor(borderColor)
context.setLineWidth(CGFloat(borderWidth))
for elementIndex in 0 ..< data.count {
context.setFillColor(color.cgColor)
let marker = CGRect(x: toX(elementIndex),
y: toY(elementIndex),
width: rectWidth,
height: rectHeight)
context.addRect(marker)
context.drawPath(using: .fillStroke)
}
// Save the context as a new UIImage
let myImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
if let cgImage = myImage?.cgImage,
let orientation = myImage?.imageOrientation {
return UIImage(cgImage: cgImage, scale: 2, orientation: orientation)
}
你应该:
- 将整个事情分派到某个后台队列;
- 定期调用
UIGraphicsGetImageFromCurrentImageContext
并将图像视图更新分派到主队列
例如,这将每 ¼ 秒更新一次图像视图:
DispatchQueue.global().async {
var lastDrawn = CACurrentMediaTime()
UIGraphicsBeginImageContextWithOptions(size, false, 0)
for _ in 0 ..< 100_000 {
// draw whatever you want
let now = CACurrentMediaTime()
if now - lastDrawn > 0.25 {
self.updateImageView()
lastDrawn = now
}
}
self.updateImageView()
UIGraphicsEndImageContext()
}
其中:
func updateImageView() {
guard let image = UIGraphicsGetImageFromCurrentImageContext() else { return }
DispatchQueue.main.async {
self.imageView.image = image
}
}
因此:
func buildImage(of size: CGSize) {
DispatchQueue.global().async {
var lastDrawn = CACurrentMediaTime()
UIGraphicsBeginImageContextWithOptions(size, false, 0)
for _ in 0 ..< 100_000 {
self.someColor().setFill()
UIBezierPath(rect: self.someRectangle(in: size)).fill()
let now = CACurrentMediaTime()
if now - lastDrawn > 0.25 {
self.updateImageView()
lastDrawn = now
}
}
self.updateImageView()
UIGraphicsEndImageContext()
}
}
func updateImageView() {
let image = UIGraphicsGetImageFromCurrentImageContext()
DispatchQueue.main.async {
self.imageView.image = image
}
}
func someRectangle(in size: CGSize) -> CGRect {
let x = CGFloat.random(in: 0...size.width)
let y = CGFloat.random(in: 0...size.height)
let width = CGFloat.random(in: 0...(size.width - x))
let height = CGFloat.random(in: 0...(size.height - y))
return CGRect(x: x, y: y, width: width, height: height)
}
func someColor() -> UIColor {
return UIColor(red: .random(in: 0...1),
green: .random(in: 0...1),
blue: .random(in: 0...1),
alpha: 1)
}
产量:
现在,我不直接调用 CoreGraphics,但你可以,而且效果相同。
如何使用iOS核心图形在单个图像中增量绘制大数据集?
我有代码可以立即处理整个数据集(超过 100,000 个矩形)并生成单个图像。这是一个很长的 运行 操作,我希望这个数据集一次增量绘制 1000 个矩形,显示这些小图像更新(就像 90 年代从互联网下载的图像)
我的问题是:我是否会在整个操作过程中保持对同一个 context
的引用并简单地向其添加元素? - 或者 - 我应该使用 UIGraphicsGetImageFromCurrentImageContext()
捕获当前图像,然后在新的上下文中绘制它并在其上绘制其他矩形吗?
奖金问题 - 如果我想使用多个线程附加到同一图像,这是正确的方法吗?
let context = UIGraphicsGetCurrentContext()!
context.setStrokeColor(borderColor)
context.setLineWidth(CGFloat(borderWidth))
for elementIndex in 0 ..< data.count {
context.setFillColor(color.cgColor)
let marker = CGRect(x: toX(elementIndex),
y: toY(elementIndex),
width: rectWidth,
height: rectHeight)
context.addRect(marker)
context.drawPath(using: .fillStroke)
}
// Save the context as a new UIImage
let myImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
if let cgImage = myImage?.cgImage,
let orientation = myImage?.imageOrientation {
return UIImage(cgImage: cgImage, scale: 2, orientation: orientation)
}
你应该:
- 将整个事情分派到某个后台队列;
- 定期调用
UIGraphicsGetImageFromCurrentImageContext
并将图像视图更新分派到主队列
例如,这将每 ¼ 秒更新一次图像视图:
DispatchQueue.global().async {
var lastDrawn = CACurrentMediaTime()
UIGraphicsBeginImageContextWithOptions(size, false, 0)
for _ in 0 ..< 100_000 {
// draw whatever you want
let now = CACurrentMediaTime()
if now - lastDrawn > 0.25 {
self.updateImageView()
lastDrawn = now
}
}
self.updateImageView()
UIGraphicsEndImageContext()
}
其中:
func updateImageView() {
guard let image = UIGraphicsGetImageFromCurrentImageContext() else { return }
DispatchQueue.main.async {
self.imageView.image = image
}
}
因此:
func buildImage(of size: CGSize) {
DispatchQueue.global().async {
var lastDrawn = CACurrentMediaTime()
UIGraphicsBeginImageContextWithOptions(size, false, 0)
for _ in 0 ..< 100_000 {
self.someColor().setFill()
UIBezierPath(rect: self.someRectangle(in: size)).fill()
let now = CACurrentMediaTime()
if now - lastDrawn > 0.25 {
self.updateImageView()
lastDrawn = now
}
}
self.updateImageView()
UIGraphicsEndImageContext()
}
}
func updateImageView() {
let image = UIGraphicsGetImageFromCurrentImageContext()
DispatchQueue.main.async {
self.imageView.image = image
}
}
func someRectangle(in size: CGSize) -> CGRect {
let x = CGFloat.random(in: 0...size.width)
let y = CGFloat.random(in: 0...size.height)
let width = CGFloat.random(in: 0...(size.width - x))
let height = CGFloat.random(in: 0...(size.height - y))
return CGRect(x: x, y: y, width: width, height: height)
}
func someColor() -> UIColor {
return UIColor(red: .random(in: 0...1),
green: .random(in: 0...1),
blue: .random(in: 0...1),
alpha: 1)
}
产量:
现在,我不直接调用 CoreGraphics,但你可以,而且效果相同。