views:

154

answers:

3

How can I let the user of my iphone app to clip a UIImage by a dynamically generated CGPath. Basically I display a rectangle overlaid on a UIImageView and the user can move the 4 corners of the rectangle to get a polygon with 4 sides. The rectangle is not filled so you see four lines overlaid on an image.

The user should be able to clip out whatever is outside the 4 lines.

Any help or pointers is much appreciated.

A: 

If you already have the CGPath, you just have to use CGContextAddPath and CGContextClip, and after that you can draw your UIImage on that context. If you just want to display the clipped image, that context could be the current context in the DrawRect method of your view. If you actually want to have the clipped image data, the context would probably be a CGBitmapContext, something like this:

CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();

size_t bytesPerPixel = 1;
size_t bytesPerRow = bmpWidth * bytesPerPixel;
size_t bmpDataSize = ( bytesPerRow * bmpHeight);

unsigned char *bmpData = malloc(bmpDataSize);
memset(bmpData, 0, bmpDataSize);

CGContextRef bmpCtx = CGBitmapContextCreate(bmpData, bmpWidth, bmpHeight, 8, bytesPerRow, colorSpace, kCGImageAlphaNone | kCGBitmapByteOrderDefault);

(the code example is for a grey scale bitmap because I had that code ready, but it's not hard to figure out what has to be changed for an RGB bitmap.)

then to actually draw the clipped image to the bitmap context you would do something like this (I'm writing this code from memory, so there might be some mistakes):

// theContext could be
// UIGraphicsGetCurrentContext()
// or the bmpCtx

CGContextAddPath(theContext, yourCGPath);
CGContextClip(theContext);

// not sure you need the translate and scale...
CGContextTranslateCTM(theContext, 0, bmpHeight);
CGContextScaleCTM(theContext, 1, -1);

CGContextDrawImage(theContext, rect, yourUIImage.CGImage);
filipe
A: 

Let me give some code so the problem is understood better. With the code below I see the same image being drawn on the screen within the bounding box given by the CGPath polygon. But I want to clip the original image instead. The problem is with CGContextClip. I dont think it is working as it should. Appreciate any pointers.

-

>  (void)drawRect:(CGRect)rect {    
>   
> 
>   CGContextRef ctx = UIGraphicsGetCurrentContext();
>   boundary = rect;    
    CGFloat w =
>    rect.size.width;   CGFloat h =
>    rect.size.height;  
>   CGContextTranslateCTM (ctx, w, h);
>   CGContextRotateCTM (ctx, M_PI);
> 
>   CGMutablePathRef path = CGPathCreateMutable();
>   CGContextBeginPath (ctx);
>         ......
> 
>         ....
>   // attach a 4-sided polygon via CGPath
>   CGRect pathBoundingBox = CGPathGetPathBoundingBox (path);   
>   CGContextClosePath(ctx);
>   CGContextAddPath(ctx, path);
>   //CGContextClip(ctx); <-- Works if
> //this is commented out but I see the
> //entire image redrawn in a rectangle. Instead I would
> //like to clip that portion.  
>   CGPathRelease(path);
>   CGContextDrawImage(ctx, pathBoundingBox, [sourceImage CGImage]); // now I see the original image being redrawn in the rectangle but I want to clip out just the portion I want.
John Qualis
what happens if you use CGContextClip without the pathBoundingBox (just use rect instead)?
filipe
nothing. I dont see any image on the screen. Here's the modified code in next comment (only the last portion). It does draw a blank png image in the documents directory. I know that CGPath is correct as I can fill a color in it.
John Qualis
CGContextClosePath(ctx); CGContextAddPath(ctx, path); CGContextClip(ctx); CGContextDrawImage(ctx, [self frame], [sourceImage CGImage]); clippedImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); NSString *pngPath = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents/Test.png"]; [UIImagePNGRepresentation(clippedImage) writeToFile:pngPath atomically:YES];
John Qualis
pardon me.. it does work.. I see the png file with the clipping. May be I am doing something wrong with screen settings. I ill check on that. Thanks v much! Appreciate it!
John Qualis
A: 

I'm having the same problem (when i save the file it draws a blank png image). Did you succeed to make it work ? Thanks

SzilardD
yes.. the above answer works.. my screen setting weren't right..just be sure to retain the new image
John Qualis
Do you mean that the answer is to use the 'rect' instead of 'pathBoundingBox'? Do I have to add the code into the drawRect method or can i just create my own method for cropping the image in a UIViewController and use self.frame as the rect to be passed to CGContextDrawImage ? (as you can see i'm a total beginner so i'm sorry if the question is stupid :))
SzilardD
I have used a method called from drawRect of a UIView to get a clipped image. I use three steps - 1. Create a path depending upon the position of the rectangle. Use CGContextAddPath 2. CGContextTranslateCTM, Scale and Draw exactly as above. 3. Get the top image. Create bottom image and fill with white. Put top on bottom and create a clipped image. For exact code, browse Apple's code and this forum. Its all right there. :-)
John Qualis
Thanks for the tips...I'm trying to crop a user defined area (the user marks the part of the image which should be cropped using a finger) I've almost succeeded, the only problem now is that the cropped image is upside-down, but using your tips I think I can solve that too.
SzilardD