A: 

Although it doesn't directly answer your question, you may be able to get the effect you are looking for by using the kCGBlendModeLuminosity blend mode:

- (void)drawRect:(CGRect)rect {
 CGSize imageSize = [image size];
 CGContextRef c = UIGraphicsGetCurrentContext();
 if (isGrey)
  CGContextSetBlendMode(c, kCGBlendModeLuminosity);
 CGContextScaleCTM(c, 1.0, -1.0);
 CGContextDrawImage(c, CGRectMake(0.0f, 0.0f, imageSize.width, -imageSize.height), [image CGImage]);
}

Also, the rect passed to drawRect: is the invalid area, not the entire area. You should be using the bounds instead

rpetrich
Did you try this? Because it gives me the same incorrect results as all the other things I've tried.
willc2
It seems -[UIImage drawInRect:] doesn't take into account the blend mode set on the CGContext. I've updated my answer to use CGContextDrawImage instead--tested and working :)
rpetrich
Did you try this on an image with an alpha channel, with a clearColor backgroundColor or a non-opaque UIImageView? Your code works on non-masked images, or imageViews that have an opaque bg color, or imageViews who's Opaque property = YES. If the image is like the green ball in my example, the color does not change to greyscale.
willc2
Ah yes, it only really works on solid-color backgrounds. I don't think there is a general way to do this in CoreGraphics. The closest I can come up with the to set a mask, begin a transparency layer, draw as you have done and then end the transparency layer. This works in the general case, but results in color fringing on semitransparent areas. I can post the code if it's helpful.
rpetrich
For this specific case, it's probably easier to just create a copy of the image in the grayscale color space. In general, it would be easiest to split your image into the color data (24bpp image with no transparency) and mask data (grayscale image with no transparency). This could probably be done at runtime, but would be outside of the functions provided by CoreGraphics.
rpetrich
A: 

You could try to add a mask to the view's Core Animation layer.

CALayer *maskLayer = [CALayer layer];
[maskLayer setBounds:CGRectMake(0.0f, 0.0f, 100.0f, 100.0f)];

// Center the layer
[maskLayer setPosition:CGPointMake([self view].bounds.size.width/2, 
                          [self view].bounds.size.height/2)];

// Set the cornerRadius to half the width/height to get a circle.
[maskLayer setCornerRadius:50.f];
[maskLayer setMasksToBounds:YES];

// Any solid color will do. Just using black here.
[maskLayer setBackgroundColor:[[UIColor blackColor] CGColor]];

// Set the mask which will only allow that which is in the
// circle show through
[[[self view] layer] setMask:maskLayer];

One other thought. Why can't you just create a b&w version of the image and swap that out depending on your flag?

Matt Long
Because I want to learn how to solve the general problem of drawing into an image while respecting an existing alpha channel. Do you know how to do that?
willc2
I see. Seems reasonable. I don't know how to do that without doing some research. Sorry.
Matt Long
use the multiply blend mode... just a guess
dontWatchMyProfile
A: 

I'd take the easy way out and draw a black circle with the same size as the round image you have. Probably not what you are asking for.

mahboudz
+2  A: 

To draw a shape while respecting an image's alpha mask, just add one line before you draw:

 CGContextClipToMask(context, self.bounds, image.CGImage);

 // example usage
  - (void)drawRect:(CGRect)rect {

    if (isGrey) {
            CGContextRef context = UIGraphicsGetCurrentContext();

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

            // draw the image
            CGContextDrawImage(context, self.bounds, self.image.CGImage);

            // set the blend mode and draw rectangle on top of image
            CGContextSetBlendMode(context, kCGBlendModeColor);
            CGContextClipToMask(context, self.bounds, image.CGImage); // respect alpha mask
            CGContextSetRGBFillColor(context, 0.0, 0.0, 0.0, 1.0);
            CGContextFillRect(context, rect);               
    } else {
            [self.image drawInRect:rect];
    }

}

willc2
A: 

is there a way i can do it on uiimageview's image? I tried but it didn't worked....

Rahul Vyas