gpt4 book ai didi

ios - CGContext:如何删除位图上下文之外的像素(例如 kCGBlendModeClear)?

转载 作者:技术小花猫 更新时间:2023-10-29 10:49:39 25 4
gpt4 key购买 nike

我正在尝试使用 Core Graphics 构建橡皮擦工具,但我发现制作高性能橡皮擦非常困难 - 这一切都归结为:

CGContextSetBlendMode(上下文, 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,其中包含所有以前绘制的笔画)blit 到当前的 CGContext,并且我正在渲染线(路径)当前绘制。它并不完美,但是嘿,它可以工作,而且性能相当不错。

但是,因为 kCGBlendModeNormal 显然不能在位图上下文之外工作,所以我不得不:

  1. 创建位图上下文 (UIGraphicsBeginImageContextWithOptions)。
  2. 绘制我的屏幕外缓冲区(eraseImage,当橡皮擦工具打开时,它实际上是从 curImage 派生的 - 所以实际上与 curImage 为了论证)。
  3. 渲染当前绘制到位图上下文的“删除线”(路径)(使用 kCGBlendModeClear 清除像素)。
  4. 将整个图像提取到屏幕外缓冲区中(curImage = UIGraphicsGetImageFromCurrentImageContext();)
  5. 最后将屏幕外缓冲区 blit 到 View 的 CGContext

从性能方面来说,这太糟糕了。使用 Instrument 的时间工具,很明显这种方法的问题在于:

  • UIGraphicsBeginImageContextWithOptions 很昂贵
  • 绘制屏幕外缓冲区两次是昂贵的
  • 将整个图像提取到屏幕外缓冲区的成本很高

很自然地,代码在真实 iPad 上的表现非常糟糕。

我不太确定在这里做什么。我一直在尝试弄清楚如何在非位图上下文中清除像素,但据我所知,依赖 kCGBlendModeClear 是死路一条。

有什么想法或建议吗?其他 iOS 绘图应用如何处理删除?


附加信息

我一直在尝试使用 CGLayer 方法,因为看起来 CGContextSetBlendMode(context, kCGBlendModeClear) 将在 CGLayer 基于我所做的一些谷歌搜索。

但是,我不太希望这种方法能够成功。在 drawRect 中绘制图层(即使使用 setNeedsDisplayInRect)性能非常差; Core Graphics 将在 CGContextDrawLayerAtPoint 中渲染图层中的每个路径(根据 Instruments)。据我所知,就性能而言,这里使用位图上下文绝对更可取 - 当然,唯一的问题是上述问题(kCGBlendModeClear 在我将位图上下文 blit 到drawRect 中的主要 CGContext

最佳答案

我已经通过使用以下代码获得了良好的结果:

- (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 调用中:

  • 将删除背景图像 block 传送到上下文
  • 使用 kCGBlendModeClear
  • 在删除背景图像之上绘制“删除”路径

由于删除背景图的像素数据和删除路径在同一层,所以起到清除像素的作用。

关于ios - CGContext:如何删除位图上下文之外的像素(例如 kCGBlendModeClear)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19876856/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com