Search code examples
iosios4uiscrollviewquartz-2dcgcontext

iOS drawing with CGContextStrokePath() lagging/crashing when drawing while zoomed in


Rundown of Problem

I an iPad app with a UIImageView inside of a UIScrollView. I want the user to be able to draw on-top of the UIImageView by using a stylus and/or their finger.

I have it working well on the simulator, but it completely lags out (and sometimes crashes) on the iPad. The problem becomes far more evident when you try and dry while already zoomed-in on the UIScrollView; it becomes incredibly laggy (essentially freezes) and then crashes.

(Scrolling on the UIScrollView does not conflict with drawing, as it is set to require 2 fingers when drawing is active.)

The Code

Here are the relevant methods. These methods are all inside of the view which handles the drawing:

 /**
 When the user first starts writing
 */
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
    isMouseMoved = NO;
    UITouch *touch = [touches anyObject]; 

    CGPoint currentPoint = [touch locationInView:imageView];

    if(isEraserOn){
        [self changeEraserLocationTo:currentPoint];
    } 

    [self resetEraser:FALSE];
    lastPoint = [touch locationInView:imageView];
} 

/**
 When the user first starts moving the pen
 */
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    isMouseMoved = YES; 
    UITouch *touch = [touches anyObject]; 
    CGPoint currentPoint = [touch locationInView:imageView]; 

    // Setting up the context
    UIGraphicsBeginImageContext(imageView.frame.size);
    [imageView.image drawInRect:CGRectMake(0, 0, imageView.frame.size.width, imageView.frame.size.height)];

    if (isEraserOn) {
        CGContextSetLineWidth(UIGraphicsGetCurrentContext(), eraserRadius);
        CGContextSetBlendMode(UIGraphicsGetCurrentContext(), kCGBlendModeClear);
        CGRect eraserFrame = eraser.frame; 
        eraserFrame.origin.x = currentPoint.x - (eraserRadius/2);
        eraserFrame.origin.y = currentPoint.y - (eraserRadius/2);
        eraser.frame = eraserFrame;
    } else {
        CGContextSetLineWidth(UIGraphicsGetCurrentContext(), penRadius);
        CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), r, g, b, 1.0); 
        CGContextSetBlendMode(UIGraphicsGetCurrentContext(), kCGBlendModeNormal);
    }

    CGContextBeginPath(UIGraphicsGetCurrentContext());
    CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
    CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint.x, currentPoint.y);
    CGContextStrokePath(UIGraphicsGetCurrentContext());

    imageView.image = UIGraphicsGetImageFromCurrentImageContext(); 
    UIGraphicsEndImageContext(); 
    lastPoint = currentPoint; 
    mouseMoved++; 

    if (mouseMoved == 1) {
        mouseMoved = 0;
    } 
} 

/**
 When the user stops writing
 */
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { 
    [self resetEraser:TRUE]; 

    if (!isMouseMoved) {
        UIGraphicsBeginImageContext(imageView.frame.size);
        CGContextRef contextRef = UIGraphicsGetCurrentContext(); 

        [imageView.image drawInRect:CGRectMake(0, 0, imageView.frame.size.width, imageView.frame.size.height)];

        CGContextSetLineWidth(contextRef, penRadius);
        CGContextSetRGBStrokeColor(contextRef, r, g, b, 1.0);
        CGContextMoveToPoint(contextRef, lastPoint.x, lastPoint.y);
        CGContextAddLineToPoint(contextRef, lastPoint.x, lastPoint.y);
        CGContextStrokePath(contextRef);
        imageView.image = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
    }
} 

Any help with this issue would be greatly appreciated; I'm really at my wits end with this one...

Thanks, Alex


Solution

  • I have recently developed an app that allows for drawing on images. The way I implemented it was to create another UIView layer and then do my graphics/gl drawing on that view. Then you can move all your touch events to the gl view. I haven't had any performance issues with my current implementation and it shouldn't be changed when zoomed in. Also check your memory, you may be leaking.

    Take a look at the following apple code:

    GLPaint