首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用CGBitmapContext进行绘图时速度太慢

使用CGBitmapContext进行绘图时速度太慢
EN

Stack Overflow用户
提问于 2012-06-29 20:05:21
回答 7查看 7.2K关注 0票数 5

因此,我在这个过程中有一个基本的绘图应用程序,它允许我绘制线条。我绘制到一个屏幕外的位图,然后在drawRect中呈现图像。它工作,但它的方式太慢,更新大约半秒后,你用你的手指绘制它。我将代码改编自本教程http://www.youtube.com/watch?v=UfWeMIL-Nu8&feature=relmfu,正如你在评论中看到的那样,人们也说它太慢了,但这个人没有回应。

那么,我如何才能加快速度呢?还是有更好的方法呢?任何指针都将不胜感激。

下面是我的DrawView.m中的代码。

代码语言:javascript
复制
-(id)initWithCoder:(NSCoder *)aDecoder {
     if ((self=[super initWithCoder:aDecoder])) {
         [self setUpBuffer];
     }

     return self;
}

-(void)setUpBuffer {
     CGContextRelease(offscreenBuffer);

     CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

     offscreenBuffer = CGBitmapContextCreate(NULL, self.bounds.size.width, self.bounds.size.height, 8, self.bounds.size.width*4, colorSpace, kCGImageAlphaPremultipliedLast);
     CGColorSpaceRelease(colorSpace);

     CGContextTranslateCTM(offscreenBuffer, 0, self.bounds.size.height);
     CGContextScaleCTM(offscreenBuffer, 1.0, -1.0);
}


-(void)drawToBuffer:(CGPoint)coordA :(CGPoint)coordB :(UIColor *)penColor :(int)thickness {

     CGContextBeginPath(offscreenBuffer);
     CGContextMoveToPoint(offscreenBuffer, coordA.x,coordA.y);
     CGContextAddLineToPoint(offscreenBuffer, coordB.x,coordB.y);
     CGContextSetLineWidth(offscreenBuffer, thickness);
     CGContextSetLineCap(offscreenBuffer, kCGLineCapRound);
     CGContextSetStrokeColorWithColor(offscreenBuffer, [penColor CGColor]);
     CGContextStrokePath(offscreenBuffer);

}

- (void)drawRect:(CGRect)rect {
    CGImageRef cgImage = CGBitmapContextCreateImage(offscreenBuffer);
    UIImage *image =[[UIImage alloc] initWithCGImage:cgImage];
    CGImageRelease(cgImage);
    [image drawInRect:self.bounds];

}

在模拟器上工作得很好,但在设备上就不行了,我想这与处理器的速度有关。

我用的是ARC。

EN

回答 7

Stack Overflow用户

回答已采纳

发布于 2012-07-07 21:50:57

我试图修复您的代码,但是由于您似乎只发布了一半代码,我无法使其正常工作(Copy+pasting代码会导致许多错误,更不用说开始对其进行性能调优了)。

然而,有一些技巧可以用来极大地提高性能。

第一个可能是最值得注意的,是-setNeedsDisplayInRect:而不是-setNeedsDisplay。这将意味着它只重新绘制更改过的小矩形。对于1024*768*4像素的iPad 3来说,这是一个很大的工作量。将每帧减少到大约20*20或更少将极大地提高性能。

代码语言:javascript
复制
CGRect rect;
rect.origin.x = minimum(coordA.x, coordB.x) - (thickness * 0.5);
rect.size.width = (maximum(coordA.x, coordB.x) + (thickness * 0.5)) - rect.origin.x;
rect.origin.y = minimum(coordA.y, coordB.y) - (thickness * 0.5);
rect.size.height = (maximum(coordA.y, coordB.y) + (thickness * 0.5)) - rect.origin.y;
[self setNeedsDisplayInRect:rect];

你可以做的另一个很大的改进是只绘制当前触摸的CGPath (你这样做了)。但是,您随后可以在绘图矩形中绘制保存/缓存图像。因此,每一帧都会重新绘制。一种更好的方法是让绘图视图是透明的,然后在后面使用UIImageView。UIImageView是在iOS上显示图像的最佳方式。

代码语言:javascript
复制
- DrawView (1 finger)
   -drawRect:
- BackgroundView (the image of the old touches)
   -self.image

然后,绘图视图本身将只绘制当前触摸,仅绘制每次更改的部分。当用户举起手指时,您可以将其缓存到UIImage,将其绘制在当前背景/缓存UIImageView的图像上,并将imageView.image设置为新图像。

组合图像时的最后一步涉及将2个全屏图像绘制到离屏CGContext中,因此如果在主线程上完成将导致延迟,相反,这应该在后台线程中完成,然后将结果推回到主线程。

代码语言:javascript
复制
* touch starts *
- DrawView : draw current touch
* touch ends *
- 'background thread' : combine backgroundView.image and DrawView.drawRect
    * thread finished *
    send resulting UIImage to main queue and set backgroundView.image to it;
    Clear DrawView's current path that is now in the cache;

所有这些结合在一起,可以制作一个非常流畅的60fps绘图应用程序。然而,视图的更新速度并不像我们希望的那样快,所以当图形更快地移动时,绘图看起来是参差不齐的。这可以通过使用UIBezierPath而不是CGPaths来改进。

代码语言:javascript
复制
CGPoint lastPoint = [touch previousLocationInView:self];
CGPoint mid = midPoint(currentPoint, lastPoint);
-[UIBezierPath addQuadCurveToPoint:mid controlPoint:lastPoint];
票数 7
EN

Stack Overflow用户

发布于 2012-07-02 16:41:48

它慢的原因是因为每一帧你都在创建一个位图,并试图绘制它。

你想要更好的方法吗?你看过the apple sample code for a drawing app on iOS吗?如果您不喜欢这样,那么您可以始终使用cocos2d,它提供了一个CCRenderTexture类(和示例代码)。

目前,您正在使用一种您已经知道效率不高的方法。

票数 5
EN

Stack Overflow用户

发布于 2012-07-04 06:41:27

使用这种方法,我想你应该考虑使用后台线程来处理所有繁重的图像渲染工作,而只使用主线程来进行UI更新,即。

代码语言:javascript
复制
__block UIImage *__imageBuffer = nil;

- (UIImage *)drawSomeImage
{
    UIGraphicsBeginImageContext(self.bounds);

    // draw image with CoreGraphics

    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

    return image;
}

- (void)updateUI
{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        // prepare image on background thread

        __imageBuffer = [self drawSomeImage];

        dispatch_async(dispatch_get_main_queue(), ^{

            // calling drawRect with prepared image

            [self setNeedsDisplay];

        });
    });
}

- (void)drawRect
{
    // draw image buffer on current context

    [__imageBuffer drawInRect:self.bounds];
}

为了使优化更清晰,我省略了一些细节。更好的做法是切换到UIImageView。这样,您就可以摆脱非常重要的- (void)drawDect方法,并在图像准备就绪时更新UIImageView的图像属性。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/11261450

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档