views:

483

answers:

2

I'm calling the following code from drawRect


- (void) drawPartial:(UIImage *)img colour:(UIColor *)colour  {

    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSaveGState(context);

    CGContextTranslateCTM(context, 0.0, self.bounds.size.height);
    CGContextScaleCTM(context, 1.0, -1.0);

    CGContextDrawImage(context, self.frame, img.CGImage);

    if (colour!=nil) {
        CGContextSetBlendMode (context, kCGBlendModeColor ); 
        CGContextClipToMask(context, self.bounds, img.CGImage); 
        CGContextSetFillColor(context, CGColorGetComponents(colour.CGColor));
        CGContextFillRect (context, self.bounds);
    }

    self.currentImage=UIGraphicsGetImageFromCurrentImageContext();
    CGContextRestoreGState(context);
}

Infact I call it multiple times to build a composite image dynamically coloured in. Each img passed in is effectively a transparent overlay with a different part of the image on it.

I can build my compound image by calling this multiple times in drawrect. The issue comes when I want to update one part of the image. Ideally I would be able to call the above function and just change the one part: I've tried playing with self.clearsContextBeforeDrawing to no avail.

Then I thought I would try to keep a copy of the image from each draw, as a cached image of the state - that way I just need to overlay the new part on that: two calls rather than 15.

However the line self.currentImage=UIGraphicsGetImageFromCurrentImageContext() is not returning me the current image so I can't build a cached copy.

Any help on either approach would really be appreciated. (or obviously point me the way I should be doing this!)

EDIT I also tried compositing the image separtly using virtually the same code, and then drawing that, but again I don't get the image out...


- (UIImage *) overlayImage:(UIImage *)srcImage withImage:(UIImage *)overlayImage ofColour:(UIColor *)colour   {

    CGSize size =srcImage.size;
    CGRect box = CGRectMake(0, 0, size.width, size.height);

    UIGraphicsBeginImageContext(size);
    CGContextRef context=UIGraphicsGetCurrentContext();

    CGContextTranslateCTM(context, 0.0, size.height);
    CGContextScaleCTM(context, 1.0, -1.0);

    CGContextDrawImage(context, box, srcImage.CGImage);


    if (colour!=nil) {
        CGContextSetBlendMode (context, kCGBlendModeColor ); //kCGBlendModeMultiply
        CGContextClipToMask(context, box, overlayImage.CGImage); // respect alpha mask
        CGContextSetFillColor(context, CGColorGetComponents(colour.CGColor));
        CGContextFillRect (context, box);
    }

    UIImage *result = UIGraphicsGetImageFromCurrentImageContext();
    //UIImage *result = [UIImage imageWithCGImage: CGBitmapContextCreateImage (context)];
    UIGraphicsEndImageContext();
    return result;
}
+1  A: 

As a rule, you want -drawRect: to be as simple as possible.

Move your drawing code from -drawRect: into a method that creates and draws the entire image you want. Reduce -drawRect: to just compositing this image into the current context.

NSResponder
I tried that (perhaps I should have included those details) but the same problem occurred: I couldn't retrieve the composited image. I'll update the question with that code too.
Andiih
This is *not* a good policy to follow in UIKit; a buffer is already maintained with the cached contents of the layer. Maintaining a separate buffer is just wasteful. A better policy is to replace UIKit's handling of the buffer entirely by managing a bitmap context manually and calling `[[self layer] setContents:(id)myCGImage]`
rpetrich
A: 

It's entirely possible that your UIImage object simply isn't retaining the stored data. Furthermore you should know that UIImage is not a mutable object type. You'll get memory leaks unless you release it before reassigning it. Try this:

UIImage *result = [UIGraphicsGetImageFromCurrentImageContext() retain];
Ash