Question

this is my first question so please bear with me!

Im trying to write up a simple drawing app basically, I was using Core Graphics before, and the only problem was it was too slow, and when I drew with my finger it lagged, a hell of alot!

So, now I'm trying to use UIBezier paths to draw, as I understood to be alot faster, which it is!

When I was using Core Graphics, to keep the drawing speed up I was drawing to a custom bitmap context I created, which was constantly being updated as I drew.

So, I drew to my custom Bitmap context, then a CGImageRef was set to what was drawn in that context using -

cacheImage = CGBitmapContextCreateImage(imageContext); 

and that was then drawn back into the bitmap context using -

CGContextDrawImage(imageContext, self.bounds, cacheImage); )

I also did this so when I changed the colour of the line being drawn, the rest of the drawing stayed as it was previously drawn, if that makes sense.

Now the problem Ive come across is this.

Im trying to draw the UIBezier path to my image context using -

imageContext = UIGraphicsGetCurrentContext();

UIGraphicsPushContext(imageContext);


[path stroke];


if(imageContext != nil){
    cacheImage = CGBitmapContextCreateImage(imageContext);  //invalid context here so added to solve

}


CGContextScaleCTM(imageContext, 1, -1); // using this as UIBezier 

CGContextDrawImage(imageContext, self.bounds, cacheImage); // draws the current context;

[path removeAllPoints];

CGImageRelease(cacheImage); // releases the image to solve memory errors.

with path being my UIBezierPath. All the path set up is done in touches began and touched moved then calling [self setNeedsDisplay]; to call drawRect.

What's happening is when I draw, its either not drawing the CGImageRef to the context properly, or it is, but when its capturing the cache image its capturing a white background from somewhere, instead of just the path, and so its pasting over the entire image with the last path drawn together with a white background fill, so you cant see the last path that was drawn to build the image up, even though the views background colour is clearColor.

I really hope I'm making sense, I've just spent too many hours on this and Its drained me completely. Heres the drawing method I'm using -

This to create the image context -

 -(CGContextRef) myCreateBitmapContext: (int) pixelsWide:(int) pixelsHigh{


    imageContext = NULL;

    CGColorSpaceRef colorSpace; // creating a colorspaceref
    void *          bitmapData; // creating bitmap data
    int             bitmapByteCount; // the bytes per count
    int             bitmapBytesPerRow; // number of bytes per row

    bitmapBytesPerRow   = (pixelsWide * 4); // calculating how many bytes per row the context     needs
    bitmapByteCount     = (bitmapBytesPerRow * pixelsHigh); // how many bytes there are in     total

    colorSpace = CGColorSpaceCreateDeviceRGB(); // setting the colourspaceRef

    bitmapData = malloc( bitmapByteCount ); // calculating the data

    if (bitmapData == NULL)
    {
        //NSLog(@"Memory not allocated!");
        return NULL;
    }


    imageContext = CGBitmapContextCreate (bitmapData,
                                          pixelsWide,
                                          pixelsHigh,
                                          8, // bits per component
                                          bitmapBytesPerRow,
                                          colorSpace,kCGImageAlphaPremultipliedLast);

    if (imageContext== NULL)
    {
        free (bitmapData);
        NSLog(@"context not created allocated!");
        return NULL;
    }
    CGColorSpaceRelease( colorSpace ); //releasing the colorspace

    CGContextSetRGBFillColor(imageContext, 1.0, 1.0, 1.0, 0.0); // filling the bitmap with a     white background
    CGContextFillRect(imageContext, self.bounds);
    CGContextSetShouldAntialias(imageContext, YES); 




    return imageContext; 
    }

And heres my drawing -

 -(void)drawRect:(CGRect)rect
{

    DataClass *data = [DataClass sharedInstance];



    [data.lineColor setStroke];
    [path setLineWidth:data.lineWidth];
    imageContext = UIGraphicsGetCurrentContext();

    UIGraphicsPushContext(imageContext);


    [path stroke];


    if(imageContext != nil){
        cacheImage = CGBitmapContextCreateImage(imageContext);  
    }


    CGContextScaleCTM(imageContext, 1, -1); // this one


    CGContextDrawImage(imageContext, self.bounds, cacheImage); // draws the current     context;



    [path removeAllPoints];

    CGImageRelease(cacheImage); // releases the image to solve memory errors.



}





 -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{


    DataClass *data = [DataClass sharedInstance];

    CGContextSetStrokeColorWithColor(imageContext, [data.lineColor CGColor]);

    ctr = 0;
    UITouch *touch2 = [touches anyObject];
    pts[0] = [touch2 locationInView:self];

}


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

    UITouch *touch = [touches anyObject];
    CGPoint p = [touch locationInView:self];


    ctr++;
    pts[ctr] = p;
    if (ctr == 4)
    {

        pts[3] = CGPointMake((pts[2].x + pts[4].x)/2.0, (pts[2].y + pts[4].y)/2.0); // move     the endpoint to the middle of the line joining the second control point of the first Bezier     segment and the first control point of the second Bezier segment
        [path moveToPoint:pts[0]];
        [path addCurveToPoint:pts[3] controlPoint1:pts[1] controlPoint2:pts[2]]; // add a     cubic Bezier from pt[0] to pt[3], with control points pt[1] and pt[2]
        //[data.lineColor setStroke];

        [self setNeedsDisplay];
        // replace points and get ready to handle the next segment
        pts[0] = pts[3];
        pts[1] = pts[4];
        ctr = 1;
    }
}


 -(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{

    [path removeAllPoints];
    [self setNeedsDisplay];
    ctr = 0;
}

'path' is my UIBezierPath 'cacheImage' is a CGImageRef 'imageContext' is a CGContextRef

Any Help is much appreciated! And if you can think of a better way to do it, please let me know! I do however need the cache image to have a transparent background, so its just the paths visible, as I'm going to apply something later on when I get this working!

EDIT Also I'm removing the points everytime to keep the drawing speed up, just so you know!

Thanks in advance :)

Was it helpful?

Solution

Well, this is a big question. One potential lead would be to verify that you draw exactly what you need (not the whole image all the time), and to divide the invariant bitmap from those regions/rects which actively mutate across multiple layers.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top