我正在尝试使用Core Graphics构建橡皮擦工具,但发现制作高性能的橡皮擦非常困难-归结为:CGContextSetBlendMode(context, kCGBlendModeClear)
如果您四处搜寻有关如何“擦除” 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();
)CGContext
从性能角度来看,这太可怕了。使用仪器的时间工具,很明显该方法的问题在哪里:
UIGraphicsBeginImageContextWithOptions
很贵很自然,代码在真正的iPad上表现出惊人的性能。
我不太确定该怎么做。我一直在尝试找出如何在非位图上下文中清除像素,但是据我所知,依靠
kCGBlendModeClear
是一个死胡同。有什么想法或建议吗?其他iOS绘图应用程序如何处理擦除?
附加信息
我一直在使用
CGLayer
方法,因为根据我做过的一些谷歌搜索,CGContextSetBlendMode(context, kCGBlendModeClear)
似乎可以在CGLayer
中工作。但是,我不太希望这种方法能成功。用
drawRect
绘制图层(甚至使用setNeedsDisplayInRect
)也非常不方便; Core Graphics陷入困境,将以CGContextDrawLayerAtPoint
渲染层中的每个路径(根据Instruments)。据我所知,就性能而言,使用位图上下文绝对是首选-当然,唯一的问题就是上述问题(我将位图上下文分配到kCGBlendModeClear
中的主要CGContext
后,drawRect
无法正常工作)。 最佳答案
通过使用以下代码,我设法获得了良好的结果:
- (void)drawRect:(CGRect)rect
{
if (drawingStroke) {
if (eraseModeOn) {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextBeginTransparencyLayer(context, NULL);
[eraseImage drawAtPoint:CGPointZero];
CGContextAddPath(context, currentPath);
CGContextSetLineCap(context, kCGLineCapRound);
CGContextSetLineWidth(context, ERASE_WIDTH);
CGContextSetBlendMode(context, kCGBlendModeClear);
CGContextSetStrokeColorWithColor(context, [[UIColor clearColor] CGColor]);
CGContextStrokePath(context);
CGContextEndTransparencyLayer(context);
} else {
[curImage drawAtPoint:CGPointZero];
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextAddPath(context, currentPath);
CGContextSetLineCap(context, kCGLineCapRound);
CGContextSetLineWidth(context, self.lineWidth);
CGContextSetBlendMode(context, kCGBlendModeNormal);
CGContextSetStrokeColorWithColor(context, self.lineColor.CGColor);
CGContextStrokePath(context);
}
} else {
[curImage drawAtPoint:CGPointZero];
}
self.empty = NO;
}
诀窍是将以下内容包装到
CGContextBeginTransparencyLayer
/CGContextEndTransparencyLayer
调用中:kCGBlendModeClear
由于擦除背景图像的像素数据和擦除路径都在同一层中,因此具有清除像素的效果。