如何在持久画布上绘图并将其绘制在视图内?

发布于 2024-11-10 16:27:19 字数 2877 浏览 2 评论 0原文

我正在为 iOS 编写一个小型绘画应用程序。我正在对 UIView 广告进行子类化,在其 drawRect: 方法内执行计算。一切都很好,直到我开始拥有大量对象(实际上是折线),然后性能开始下降。

- (void)drawRect:(CGRect)rect {
    [super drawRect:rect];

    CGContextRef imageContext = UIGraphicsGetCurrentContext();

    int i, j;
    for(i = 0; i < [_strokes count]; i++) {
        NSMutableArray *stroke = [_strokes objectAtIndex:i];
        if([stroke count] < 2) {
            continue;
        }
        CGContextSetStrokeColorWithColor(imageContext, [[_penColours objectAtIndex:i] CGColor]);
        for(j = 0; j < [stroke count]-1; j++) {
            CGPoint line[] = {
                [[stroke objectAtIndex:j] CGPointValue],
                [[stroke objectAtIndex:j+1] CGPointValue]
            };

            CGContextSetLineWidth(imageContext, _brushSize);
            CGContextSetLineCap(imageContext, kCGLineCapRound);
            CGContextSetLineJoin(imageContext, kCGLineJoinRound);

            CGContextAddLines(imageContext, line, 2);
            CGContextStrokePath(imageContext);
        }
    }

    CGContextFlush(imageContext);
}

其中 _lines 是点数组的数组。我的第一个想法是将图像制作为 ivar,将其绘制在上下文上,将附加笔画绘制到上下文(将 j = 0 更改为 j = [Stroke count] - 2< /code>),并获取图像的上下文并将其存储回 ivar。没用。

然后我尝试了许多其他并不值得一提的道路,直到我在 SO 上发现了另一个问题( Quartz2D 性能- 如何改进)。不幸的是,它没有像我预期的那样工作,因为我必须保留图像,导致内存警告 1、2、崩溃。

- (void)drawRect:(CGRect)rect {
    [super drawRect:rect];

    UIGraphicsBeginImageContext(CGSizeMake(1024, 768));
    CGContextRef imageContext = UIGraphicsGetCurrentContext();

    if(_image != nil) {
        CGContextDrawImage(imageContext, CGRectMake(0, 0, 1024, 768), [_image CGImage]);
    }

    int i, j;
    for(i = 0; i < [_strokes count]; i++) {
        NSMutableArray *stroke = [_strokes objectAtIndex:i];
        if([stroke count] < 2) {
            continue;
        }
        CGContextSetStrokeColorWithColor(imageContext, [[_penColours objectAtIndex:i] CGColor]);
        for(j = [stroke count]-2; j < [stroke count]-1; j++) {
            CGPoint line[] = {
                [[stroke objectAtIndex:j] CGPointValue],
                [[stroke objectAtIndex:j+1] CGPointValue]
            };

            CGContextSetLineWidth(imageContext, _brushSize);
            CGContextSetLineCap(imageContext, kCGLineCapRound);
            CGContextSetLineJoin(imageContext, kCGLineJoinRound);

            CGContextAddLines(imageContext, line, 2);
            CGContextStrokePath(imageContext);
        }
    }

    _image = UIGraphicsGetImageFromCurrentImageContext();
    [_image retain];
    UIGraphicsEndImageContext();

    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextDrawImage(context, CGRectMake(0, 0, 1024, 768), [_image CGImage]);
}

I'm writing a small painting app for iOS. I'm subclassing a UIView ad performing computations inside its drawRect: method. It's been all good until I started having lots of objects (actually polylines), then performance started to degrade.

- (void)drawRect:(CGRect)rect {
    [super drawRect:rect];

    CGContextRef imageContext = UIGraphicsGetCurrentContext();

    int i, j;
    for(i = 0; i < [_strokes count]; i++) {
        NSMutableArray *stroke = [_strokes objectAtIndex:i];
        if([stroke count] < 2) {
            continue;
        }
        CGContextSetStrokeColorWithColor(imageContext, [[_penColours objectAtIndex:i] CGColor]);
        for(j = 0; j < [stroke count]-1; j++) {
            CGPoint line[] = {
                [[stroke objectAtIndex:j] CGPointValue],
                [[stroke objectAtIndex:j+1] CGPointValue]
            };

            CGContextSetLineWidth(imageContext, _brushSize);
            CGContextSetLineCap(imageContext, kCGLineCapRound);
            CGContextSetLineJoin(imageContext, kCGLineJoinRound);

            CGContextAddLines(imageContext, line, 2);
            CGContextStrokePath(imageContext);
        }
    }

    CGContextFlush(imageContext);
}

where _strokes is an array of arrays of points. My first idea was to make an image as an ivar, paint it on the context, paint the additional strokes to the context (change j = 0 with j = [stroke count] - 2), and grab the context to an image and store it back to the ivar. Didn't work.

Then I tried many other roads not really worth mentioning, until I found this other question on SO ( Quartz2D performance - how to improve ). Unfortunately it didn't work as I expected as I had to retain the image, resulting in memory warning 1, 2, crash.

- (void)drawRect:(CGRect)rect {
    [super drawRect:rect];

    UIGraphicsBeginImageContext(CGSizeMake(1024, 768));
    CGContextRef imageContext = UIGraphicsGetCurrentContext();

    if(_image != nil) {
        CGContextDrawImage(imageContext, CGRectMake(0, 0, 1024, 768), [_image CGImage]);
    }

    int i, j;
    for(i = 0; i < [_strokes count]; i++) {
        NSMutableArray *stroke = [_strokes objectAtIndex:i];
        if([stroke count] < 2) {
            continue;
        }
        CGContextSetStrokeColorWithColor(imageContext, [[_penColours objectAtIndex:i] CGColor]);
        for(j = [stroke count]-2; j < [stroke count]-1; j++) {
            CGPoint line[] = {
                [[stroke objectAtIndex:j] CGPointValue],
                [[stroke objectAtIndex:j+1] CGPointValue]
            };

            CGContextSetLineWidth(imageContext, _brushSize);
            CGContextSetLineCap(imageContext, kCGLineCapRound);
            CGContextSetLineJoin(imageContext, kCGLineJoinRound);

            CGContextAddLines(imageContext, line, 2);
            CGContextStrokePath(imageContext);
        }
    }

    _image = UIGraphicsGetImageFromCurrentImageContext();
    [_image retain];
    UIGraphicsEndImageContext();

    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextDrawImage(context, CGRectMake(0, 0, 1024, 768), [_image CGImage]);
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

给妤﹃绝世温柔 2024-11-17 16:27:19

看起来至少部分问题是您保留 _image 但从未释放它。每次为 _image 分配新值时,都会泄漏前一个图像,这会很快填满内存。

除此之外,您可能应该使用 CGLayer 来进行离屏绘图,而不是位图。您可以随时绘制到图层中,然后只需在 -drawRect: 方法中将其复制到屏幕上即可。

It looks like at least part of the problem is that you retain _image but you never release it. Each time you assign a new value to _image, you're leaking the previous image, and that'll fill up memory very quickly.

Beyond that, you should probably be using a CGLayer for your offscreen drawing rather than a bitmap. You can draw into the layer whenever you like, and then just copy it to the screen in your -drawRect: method.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文