我正在尝试使用 Core Graphics 构建橡皮擦工具,但我发现制作高性能橡皮擦非常困难 - 这一切都归结为:
CGContextSetBlendMode(context, kCGBlendModeClear)
如果您在 Google 上搜索如何使用 Core Graphics 进行“擦除”,几乎每个答案都会返回该片段。问题是它仅(显然)在位图上下文中有效。如果您尝试实现交互式擦除,我看不出kCGBlendModeClear
对您有什么帮助-据我所知,您或多或少被锁定在屏幕上和屏幕外UIImage
/CGImage
并以著名的非-高性能[UIView drawRect]
。
这是我能做到的最好的:
-(void)drawRect:(CGRect)rect
{
if (drawingStroke) {
if (eraseModeOn) {
UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, 0.0);
CGContextRef context = UIGraphicsGetCurrentContext();
[eraseImage drawAtPoint:CGPointZero];
CGContextAddPath(context, currentPath);
CGContextSetLineCap(context, kCGLineCapRound);
CGContextSetLineWidth(context, lineWidth);
CGContextSetBlendMode(context, kCGBlendModeClear);
CGContextSetLineWidth(context, ERASE_WIDTH);
CGContextStrokePath(context);
curImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[curImage drawAtPoint:CGPointZero];
} else {
[curImage drawAtPoint:CGPointZero];
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextAddPath(context, currentPath);
CGContextSetLineCap(context, kCGLineCapRound);
CGContextSetLineWidth(context, lineWidth);
CGContextSetBlendMode(context, kCGBlendModeNormal);
CGContextSetStrokeColorWithColor(context, lineColor.CGColor);
CGContextStrokePath(context);
}
} else {
[curImage drawAtPoint:CGPointZero];
}
}
绘制法线 ( !eraseModeOn
) 是可以接受的;我正在将我的屏幕外绘图缓冲区(curImage
包含所有先前绘制的笔划)传送到当前CGContext
,并且我正在渲染当前正在绘制的线(路径)。它并不完美,但是嘿,它有效,而且性能相当不错。
但是,由于kCGBlendModeNormal
显然不能在位图上下文之外工作,我被迫:
- 创建位图上下文 (
UIGraphicsBeginImageContextWithOptions
)。 - 绘制我的屏幕外缓冲区(
eraseImage
实际上是从curImage
打开橡皮擦工具时派生的 - 所以实际上与参数几乎相同curImage
)。 - 将当前正在绘制的“擦除线”(路径)渲染到位图上下文(
kCGBlendModeClear
用于清除像素)。 - 将整个图像提取到屏幕外缓冲区 (
curImage = UIGraphicsGetImageFromCurrentImageContext();
) - 然后最后将屏幕外缓冲区blit到视图的
CGContext
这太可怕了,就性能而言。使用 Instrument 的 Time 工具,很明显这种方法的问题在哪里:
UIGraphicsBeginImageContextWithOptions
价格昂贵- 两次绘制屏幕外缓冲区很昂贵
- 将整个图像提取到屏幕外缓冲区是昂贵的
很自然,代码在真正的 iPad 上执行得非常糟糕。
我不确定在这里做什么。我一直在试图弄清楚如何在非位图上下文中清除像素,但据我所知,依赖kCGBlendModeClear
是一个死胡同。
有什么想法或建议吗?其他 iOS 绘图应用程序如何处理擦除?
附加信息
我一直在尝试一种CGLayer
方法,因为它似乎确实CGContextSetBlendMode(context, kCGBlendModeClear)
可以CGLayer
基于我所做的一些谷歌搜索工作。
但是,我对这种方法能否成功并不抱太大希望。drawRect
在(甚至使用)中绘制图层setNeedsDisplayInRect
是非常糟糕的;Core Graphics 正在阻塞将渲染层中的每个路径CGContextDrawLayerAtPoint
(根据 Instruments)。据我所知,就性能而言,在这里使用位图上下文绝对是更可取的 - 当然,唯一的问题是上述问题(kCGBlendModeClear
在我将位图上下文blit到main CGContext
in之后不起作用drawRect
)。