如何使用 CgLayer 进行最佳绘图

Posted

技术标签:

【中文标题】如何使用 CgLayer 进行最佳绘图【英文标题】:How to use CgLayer for optimal drawing 【发布时间】:2012-07-05 09:46:08 【问题描述】:

我创建了一个简单的绘图项目,代码工作正常,但我想将绘图缓存到 CGlayer 中,因为我读到它更有效的绘图方式。我已阅读文件,但无法正确理解。所以朋友们,我请求你们在这方面帮助我。

下面是我的代码,我想知道如何在这里面使用CgLayer

- (void)drawRect:(CGRect)rect


   CGContextRef context = UIGraphicsGetCurrentContext();

   if(myLayerRef == nil)
   

       myLayerRef = CGLayerCreateWithContext(context, self.bounds.size, NULL);
   

    CGContextRef layerContext = CGLayerGetContext(myLayerRef);

    CGContextDrawLayerAtPoint(context, CGPointZero, myLayerRef);   



- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event


    UITouch *mytouch=[[touches allObjects] objectAtIndex:0];

    m_previousPoint2 = m_previousPoint1;
    m_previousPoint1 = [mytouch previousLocationInView:self];
    m_currentPoint = [mytouch locationInView:self];

    CGPoint mid1    = midPoint(m_previousPoint1, m_previousPoint2); 
    CGPoint mid2    = midPoint(m_currentPoint, m_previousPoint1);  

    testpath = CGPathCreateMutable();
    CGPathMoveToPoint(testpath, NULL, mid1.x, mid1.y);

    CGPathAddQuadCurveToPoint(testpath, NULL, m_previousPoint1.x, m_previousPoint1.y, mid2.x, mid2.y);       


    CGContextRef context = UIGraphicsGetCurrentContext();

    context = CGLayerGetContext(myLayerRef);

    CGRect bounds = CGPathGetBoundingBox(testpath);   

     CGPathRelease(testpath);


    CGRect drawBox = bounds;

    //Pad our values so the bounding box respects our line width
    drawBox.origin.x        -= self.lineWidth * 2;
    drawBox.origin.y        -= self.lineWidth * 2;
    drawBox.size.width      += self.lineWidth * 4;
    drawBox.size.height     += self.lineWidth * 4;


   [self setNeedsDisplayInRect:drawBox];       



- (void) drawingOperations


    CGContextRef context1 = CGLayerGetContext(myLayerRef);



    CGPoint mid1 = midPoint(m_previousPoint1, m_previousPoint2); 
    CGPoint mid2 = midPoint(m_currentPoint, m_previousPoint1);



    CGContextMoveToPoint(context1, mid1.x, mid1.y);
    CGContextAddQuadCurveToPoint(context1, m_previousPoint1.x, m_previousPoint1.y, mid2.x, mid2.y); 
    CGContextSetLineCap(context1, kCGLineCapRound);
    CGContextSetLineWidth(context1, self.lineWidth);
    CGContextSetStrokeColorWithColor(context1, self.lineColor.CGColor);

    CGContextSetFlatness(context1, 2.0);

    CGContextSetAllowsAntialiasing(context1, true);


    CGContextStrokePath(context1);

问候 兰吉特

【问题讨论】:

你好,谁能帮帮我 您好朋友,我想我已经解决了使用 CgLayer 缓存行的问题,但不确定是正确的方法,它工作正常。我已经用最新的代码更新了我的帖子,我想要有人请验证我的代码并让我知道我是否正确。这样我就可以将问题标记为已解决。谢谢 添加您的图层使用代码作为答案,而不是更新问题,否则问题没有意义。 这看起来不错。只在drawRect之外进行绘图操作可能会更好,但如果它足够平滑,那么它并不重要。此外,设置线帽宽度等只需执行一次(因为没有其他人使用图层的上下文,因此不会更改)。 嘿,谢谢 borrrden,正如你所说,绘图操作应该在 drawRect 之外完成,你的意思是说所有从 CGcontextmovetoPint() 到 CGcontextDrawLayeratPoint() 的代码都应该在外面吧?我为它创建了一个不同的函数并从 touchesmoved 调用它? 【参考方案1】:

@hfossli 发布的链接现已失效,但这里是存档内容:

不再推荐使用 CGLayer

robnapier 于 2012 年 7 月 13 日在图书更新中发表

我花了很多时间在 WWDC 的实验室里提出问题并与开发人员交谈。这次我和 Core Graphics 工程师坐下来,向他们询问了我最喜欢的未充分利用的工具之一:CGLayer,我将在第 6 章末尾讨论。CGLayer 听起来是个好主意:专门为在屏幕上绘图而优化的绘图上下文,与硬件优化。会出什么问题?

不过,我开始怀疑 CGLayer 始终是一场伟大的胜利。如果您的图层太大而无法存储在 GPU 纹理中怎么办? CGLayer 被宣传用作您反复绘制的“印章”。将数据移入和移出 GPU 的成本很高。除非你画了一定次数,否则 CGLayer 可能没有意义。文档对此没有提供任何指导。

所以我问 Core Graphics 团队“我应该什么时候使用 CGLayer?”

“从不。”

... ???绝不?但是要冲压对吗?

从不。

所以我们又谈了一些。看起来 CGLayer 是那些在纸上听起来很棒的东西之一,但在实践中并不总是有效。有时它会更快。有时它更慢。什么时候会更快,没有简单的规则。随着时间的推移,他们似乎已经悄悄地放弃了它而没有真正弃用它。我已要求更新文档以符合 Apple 当前的建议。 CGLayer 参考自 2006 年以来未更新。

我收到的建议是使用 CGBitmapContext 或 CALayer 进行标记。 对于第 131-132 页给出的具体示例,CATextLayer 可能是最好的工具。请记住,您可以使用 initWithLayer: 轻松克隆 CALayer。 (John Mueller 在下面指出实际上并不支持。)

【讨论】:

我认为最大的问题是他们没有微软的 Direct2D 已经实现的东西:依赖于设备的资源,当内存被其他人重用时会被丢弃。【参考方案2】:

不再适合使用 CGLayer

http://iosptl.com/posts/cglayer-no-longer-recommended/

【讨论】:

链接已失效,但我已在此问题的另一个答案中发布了存档内容。

以上是关于如何使用 CgLayer 进行最佳绘图的主要内容,如果未能解决你的问题,请参考以下文章

使用 CGImage / CGLayer 在另一个线程中绘图

撤消 CGLayer 的重做问题

在方法drawRect之外绘制CGLayer:更快?

在 Qt 中绘制绘图的最佳方法是啥?

如何存储多个坐标和地图套件绘图路线

在 HTML 上绘图的最佳方式是啥