Code Sample: Crop an image using the iPhone SDK
Posted in Game Trivia Catechism, code on 11/08/2008 11:10 pm by Josh M
One of the pieces of Game Trivia Catechism that I've been putting off for some time is the timer displayed on the question screen. The timer is basically a reverse progress indicator. It starts out full (with all of the lights on) and slowly counts down to empty (all lights off). The simplest method I know of for building a progress indicator is to use two images (one full, one empty) and simply crop the "full" to an appropriate sized based on the current progress position.
When it came time to implement this in GTC, I scoured the Cocoa Touch documentation for an easy way to crop a UIImage down to a specific size. Apparently this was something that didn't make the cut. Fortunately the lower level CoreGraphics methods provide a fairly simple method of doing this. Here's what I ended up with.
- (UIImage*)imageByCropping:(UIImage *)imageToCrop toRect:(CGRect)rect
{
//create a context to do our clipping in
UIGraphicsBeginImageContext(rect.size);
CGContextRef currentContext = UIGraphicsGetCurrentContext();
//create a rect with the size we want to crop the image to
//the X and Y here are zero so we start at the beginning of our
//newly created context
CGRect clippedRect = CGRectMake(0, 0, rect.size.width, rect.size.height);
CGContextClipToRect( currentContext, clippedRect);
//create a rect equivalent to the full size of the image
//offset the rect by the X and Y we want to start the crop
//from in order to cut off anything before them
CGRect drawRect = CGRectMake(rect.origin.x * -1,
rect.origin.y * -1,
imageToCrop.size.width,
imageToCrop.size.height);
//draw the image to our clipped context using our offset rect
CGContextDrawImage(currentContext, drawRect, imageToCrop.CGImage);
//pull the image from our cropped context
UIImage *cropped = UIGraphicsGetImageFromCurrentImageContext();
//pop the context to get back to the default
UIGraphicsEndImageContext();
//Note: this is autoreleased
return cropped;
}
Then call the code with something like:
- (void)drawRect:(CGRect)rect
{
//draw the whole lights off image
//the on images will be drawn overtop
[lightsOffImage drawInRect:rect];
//if we don't have any lights on... no point in continuing
if( numberOfLightsOn < 1 )
return;
//figure out the dimensions of numberOfLights on bulbs
CGSize croppedSize = CGSizeMake(LIGHT_WIDTH * numberOfLightsOn, LIGHT_HEIGHT);
CGRect clippedRect = CGRectMake(0, 0, croppedSize.width, croppedSize.height);
//get the "on" bulbs by cropping the image
UIImage *cropped = [self imageByCropping:lightsOnImage toRect:clippedRect];
//create a rect to draw the newly cropped on images to
CGRect lightsOnRect = CGRectMake(LIGHT_BULB_OFFSET_X,
LIGHT_BULB_OFFSET_Y,
croppedSize.width,
croppedSize.height);
//draw the "on" lights
[cropped drawInRect:lightsOnRect];
//cropped is autoreleased so no need to worry about cleanup
}

12/03/2008 at 10:48 pm
Very nice post. I found this cropper flips my image 180…any idea why? Thanks
12/03/2008 at 11:16 pm
Mike…
Do you have an image and code snippit for how you are calling it?
The spot where i could see it happening is where it creates the offset rect in the imageByCropping method. If you are passing in a negative value for origin point.
12/09/2008 at 2:17 am
[...] etc) showing the code to resize an UIImage. I also found some interesting link such as Code Sample: Crop an image using the iPhone SDK | Hive05 software products but it didn’t work well here. Any [...]
12/29/2008 at 4:06 am
Simply add these two lines just before the CGContextDrawImage line
CGContextTranslateCTM(currentContext, 0.0, drawRect.size.height);
CGContextScaleCTM(currentContext, 1.0, -1.0);
The result image was flip because Quartz start drawing from lower-left corner. (As stated in QuartzDemo sample code)
01/05/2009 at 12:00 am
[...] i did manage to make this work using Code Sample: Crop an image using the iPhone SDK | Hive05 software products had to do some manipulations though. And one more important thing the 0,0 of the image is taken as [...]
02/26/2009 at 10:07 am
Ahoy!
My hats off to ye! A wonderful bit of code to share that worked like a charm. It’s rare to find such true copy/paste code that works this well. I did have to implement the code RuuD posted to prevent the flippage but then all was well.
Thanks again, me hearty!
03/12/2009 at 9:16 pm
RuuD’s code required a slight tweak for me when rect.origin wasn’t at (0,0).
CGContextTranslateCTM(currentContext, 0.0, rect.size.height);
CGContextScaleCTM(currentContext, 1.0, -1.0);
(rect.origin.x, rect.origin.y) are the coordinates from the lower-left corner of imageToCrop in its normal orientation.
04/02/2009 at 8:15 pm
Actually there is a simple way to crop an image. Look up CGImageCreateWithImageInRect(CGImageRef, CGRect) in the documentation, it’s pretty nice.
You could change the guts of imageByCropping:toRect: basically to this:
- (UIImage *)imageByCropping:(UIImage *)imageToCrop toRect:(CGRect)rect {
CGImageRef imageRef = CGImageCreateWithImageInRect([imageToCrop CGImage], rect);
UIImage *cropped = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);
return cropped;
}
04/24/2009 at 7:35 am
Wow, Thank you much for this code. Excellent.
08/03/2009 at 12:26 pm
[...] the thumbnail to be skewed so cropping was required. All of the examples I found either focused on cropping only or resizing but I couldn’t find any that did [...]
08/30/2009 at 1:47 pm
Hey HitScan, thanks for the code. It worked very nicely.
10/13/2009 at 10:03 am
This code causes a crash for me. I can easily reproduce it and I’ve definitely narrowed it down to this code. When I take it out, the crash disappears. It may be the way I’m using it, but I can’t figure it out. The crash is caused by a double release. I copied and pasted this code into my app and then called it like so:
myImageView.image = [self imageByCropping:otherImageView.image toRect:CGRectMake(0, 0, 64, 64)];
I’ve tried everything to debug it, but I can’t figure it out. The debugger kindly suggests “set a breakpoint in malloc_error_break to debug” but that doesn’t seem to help.
12/04/2009 at 12:49 am
hello everyone,
Thanks for sharing code,that is really very helpful.
now we know that how to crop an image in rectangular shape.
but when i want to crop face or anything else rectangle may not help.
so my question is how to capture an image in oval or any other shape?
can we take pixel array for that?
any guidelines or help will be appreciated.