views:

86

answers:

1

Hi

I am trying to use an image (270 degrees of a circle, similar to a pacman logo, painted as Core Graphics) to create a mask. What I am doing is this

1. creating a Core Graphics path

    CGContextSaveGState(context);
    CGContextBeginPath(context);
    CGContextMoveToPoint(context,circleCenter.x,circleCenter.y);
    //CGContextSetAllowsAntialiasing(myBitmapContext, YES);
    CGContextAddArc(context,circleCenter.x, circleCenter.y,circleRadius,startingAngle, endingAngle, 0); // 0 is counterclockwise
    CGContextClosePath(context);
    CGContextSetRGBStrokeColor(context,1.0,0.0,0.0,1.0);
    CGContextSetRGBFillColor(context,1.0,0.0,0.0,0.2);
    CGContextDrawPath(context, kCGPathFillStroke);

2. then I'm creating an image of the path that has the path just painted

    CGImageRef pacmanImage              = CGBitmapContextCreateImage (context); 

3. restoring the context

CGContextRestoreGState(context);
CGContextSaveGState(context);

4. creating a 1 bit mask (which will provide the black-white mask)

bitsPerComponent                    = 1;
bitsPerPixel                        = bitsPerComponent * 1 ;
bytesPerRow                         = (CGImageGetWidth(imgToMaskRef) * bitsPerPixel);
mask                                = CGImageCreate(CGImageGetWidth(imgToMaskRef), 
                                                CGImageGetHeight(imgToMaskRef), 
                                                bitsPerComponent,
                                                bitsPerPixel, 
                                                bytesPerRow, 
                                                greyColorSpace,
                                                kCGImageAlphaNone, 
                                                CGImageGetDataProvider(pacmanImage), 
                                                NULL, //decode
                                                YES, //shouldInterpolate
                                                kCGRenderingIntentDefault);

5. masking the imgToMaskRef (which is a CGImageRef imgToMaskRef =imgToMask.CGImage;) with the mask just created

    imageMaskedWithImage                = CGImageCreateWithMask(imgToMaskRef, mask);
CGContextDrawImage(context,imgRectBox, imageMaskedWithImage);
CGImageRef maskedImageFinal         = CGBitmapContextCreateImage (context);

6. returning the maskedImageFinal to the caller of this method (as wheelChoiceMadeState, which is a CGImageRef) who then updates the CALayer contents property with the image

 theLayer.contents                  = (id) wheelChoiceMadeState;

the problem I am seeing is that the mask does not work properly and looks very strange indeed. I get strange patterns across the path painted by the Core Graphics. My hunch is there is something with CGImageGetDataProvider() but I am not sure.

Any help would be appreciated

thank you

A: 

CGImageGetDataProvider does not change the data at all. If the data of pacmanImage does not exactly match the parameters passed to CGImageCreate (bitsPer,bytesPer,colorSpace,...) the result is undefined. If it does exactly match, there would be no point in creating mask.

You need to create a grayscale CGBitmapContext to draw the mask into, and a CGImage that uses the same pixels and parameters as the bitmap. You can then use the CGImage to mask another image.

Only use CGBitmapContextCreateImage if you want a snapshot of a CGBitmapContext that you will continue to modify. For a single use bitmap, pass the same buffer to the bitmap and the matching CGImage you create.

Edit:

finalRect is the size the final image should be. It is either large enough to hold the original image, and the pacman is positioned inside it, or it is large enough to hold the pacman, and the original image is cropped to fit. In this example, the original image is cropped. Otherwise the pacman path would have to be positioned relative to the original image.

maskContext = CGBitmapContextCreate( ... , finalRect.size.width , finalRect.size.height , ... );
// add the pacman path and set the stroke and fill colors
CGContextDrawPath( maskContext , kCGPathFillStroke );
maskImage = CGBitmapContextCreateImage( maskContext );
imageToMask = CGImageCreateWithImageInRect( originalImage , finalRect );
finalImage = CGImageCreateWithMask( imageToMask , maskImage );
drawnonward
thanks Drawnonward. I am new to iphone and Core Graphics so your reply although not entirely clear is still clarifying. I managed to play around. I made a CGBitmapContextCreate with bitsPerComponent = 8;bitsPerPixel= bitsPerComponent * 1 ; bytesPerRow = (CGImageGetWidth(pacmanImage) * 8) and a CGColorSpaceCreateDeviceGray(). I then drew a path into that bitmap. then pacmanImage = CGBitmapContextCreateImage (mybitmapContext); then CGContextDrawImage(context,imgRectBox, pacmanImage);CGImageRef maskedImageFinal = CGBitmapContextCreateImage (context);but coordinates of pacmanImage are wrong
Peyman
You need to create two images of the same size to pass into CGImageCreateWithMask. You can either create the CGBitmapContext with the size of imgToMask, or crop imgToMask to a smaller size with CGImageCreateWithImageInRect and use that size for the bitmap context. Once you draw the pacman into the bitmap context and create an image from it with CGBitmapContextCreateImage, pass the image as the mask to CGImageCreateWithMask.
drawnonward
I am doing this1- mybitmapContext = MyCreateBitmapContext(imgToMask.size.width,imgToMask.size.height,theLayer);2- painting the pacman3- pacmanImage = CGBitmapContextCreateImage (mybitmapContext); 4- mask = CGImageCreate(..list of mask params)5- imageMaskedWithImage = CGImageCreateWithMask(imgToMaskRef, mask);6- CGContextDrawImage(context,imgRectBox, imageMaskedWithImage);7- CGImageRef maskedImageFinal= CGBitmapContextCreateImage (context);8- return maskedImageFinal;then 9- theLayer.contents = (id) maskedImageFinal;I don't need to use CGImageCreate() to create a mask?thank you
Peyman
sorry for being a dunce Drawnonward, but as a newbie this CG is a little confusing. one additional fact. i am setting the mask as follows:CGImageRef imgToMaskRef = imgToMask.CGImage;bitsPerComponent = 8; bitsPerPixel = bitsPerComponent * 1 ; bytesPerRow = (CGImageGetWidth(imgToMaskRef) * 8); mask= CGImageCreate(CGImageGetWidth(imgToMaskRef), CGImageGetHeight(imgToMaskRef), bitsPerComponent,bitsPerPixel, bytesPerRow,CGColorSpaceCreateDeviceGray(),kCGImageAlphaNone, CGImageGetDataProvider(pacmanImage), NULL,YES, kCGRenderingIntentDefault);tnx
Peyman
You are drawing the mask in a bitmap context, so the mask image is the result of CGBitmapContextCreateImage. You do not need to create an extra image.
drawnonward
thank you for your help and your patience drawnonwards. much appreciated
Peyman