iOS: Cropping a still image grabbed from a UIImagePickerController camera with overlay
When you can, it is easier to skip drawing images with Core Graphics:
- (UIImage *)cropImage:(UIImage *)oldImage {
CGSize imageSize = oldImage.size
UIGraphicsBeginImageContextWithOptions( CGSizeMake( imageSize.width,
imageSize.height - 200),
NO,
0.);
[oldImage drawAtPoint:CGPointMake( 0, -100)
blendMode:kCGBlendModeCopy
alpha:1.];
UIImage *croppedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return croppedImage;
}
Comments
-
Sagar Hatekar almost 2 years
I am new to iOS and I have been bashing head against the wall for this for the past week looking around online for tutorials such as: Dealing with Exif Images, Resizing images, and many more random questions here on StackOverflow. From these, I figured that
>=iOS 4.0
, all images taken from the camera containEXIF
-based rotation information.What's not working: After trying different image cropping techniques, all I end up with is cropping of the image at some random corners and also, the resulting image appears to be zoomed in :( When I use a
png
image from the internet (which don't contain EXIF data), the cropping is working. By random corners, I mean - the image ends up being cropped at the top-right/top-left and zoomed-in.What I am trying to accomplish:
I am trying to crop an image100 px
from top and100 px
from bottom. Essentially, I am using two overlay strips - 1 at the top, and 1 at the bottom with theCGRect(0.0, 0.0, SCREEN_WIDTH, 100.0)
[a100.0 px
tall strip at the top] and anotherCGRect(0.0, SCREEN_HEIGHT - 100, SCREEN_WIDTH, 100.0)
[another100 px
tall strip at the bottom]. I need to get the image between these two strips: I assume the height of the image is:SCREEN_HEIGHT - 200.0
.Displaying UIImagePickerController for camera with overlay:
//SCREEN_HEIGHT = 480 and SCREEN_WIDTH = 320 UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init]; if([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera] == NO) { NSLog(@"Camera not available"); return; } imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera; imagePicker.delegate = self; imagePicker.allowsEditing = NO; // Hide the controls imagePicker.showsCameraControls = NO; imagePicker.navigationBarHidden = YES; // Make camera view full screen imagePicker.wantsFullScreenLayout = YES; //imagePicker.cameraViewTransform = CGAffineTransformScale(imagePicker.cameraViewTransform, CAMERA_TRANSFORM_X, CAMERA_TRANSFORM_Y); //Overlay //OverlayView is a plain UIView with the CGRects mentioned in the question. OverlayView *overlay = [[OverlayView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT)]; [overlay initOverlay:self]; imagePicker.cameraOverlayView = overlay; [self presentModalViewController:imagePicker animated:YES];
Code to rotate image based on EXIF
imageOrientation
property and cropping it- (UIImage *) cropImage: (UIImage *) originalImage { CGRect cropRect = CGRectMake(0, 100.0, SCREEN_WIDTH, SCREEN_HEIGHT - 100); CGRect transformedRect = [self TransformCGRectForUIImageOrientation:cropRect :originalImage.imageOrientation :originalImage.size]; CGImageRef resultImageRef = CGImageCreateWithImageInRect(originalImage.CGImage, transformedRect); UIImage *newImage = [[[UIImage alloc] initWithCGImage:resultImageRef scale:1.0 orientation:originalImage.imageOrientation] autorelease]; return newImage; } - (CGRect) TransformCGRectForUIImageOrientation: (CGRect) source: (UIImageOrientation) orientation: (CGSize) imageSize { switch (orientation) { case UIImageOrientationLeft: { // EXIF #8 CGAffineTransform txTranslate = CGAffineTransformMakeTranslation( imageSize.height, 0.0); CGAffineTransform txCompound = CGAffineTransformRotate(txTranslate, M_PI_2); return CGRectApplyAffineTransform(source, txCompound); } case UIImageOrientationDown: { // EXIF #3 CGAffineTransform txTranslate = CGAffineTransformMakeTranslation( imageSize.width, imageSize.height); CGAffineTransform txCompound = CGAffineTransformRotate(txTranslate, M_PI); return CGRectApplyAffineTransform(source, txCompound); } case UIImageOrientationRight: { // EXIF #6 CGAffineTransform txTranslate = CGAffineTransformMakeTranslation( 0.0, imageSize.width); CGAffineTransform txCompound = CGAffineTransformRotate(txTranslate, M_PI + M_PI_2); return CGRectApplyAffineTransform(source, txCompound); } case UIImageOrientationUp: // EXIF #1 - do nothing default: // EXIF 2,4,5,7 - ignore return source; }
The
cropImage
method seems to work for images downloaded from the internet (which don't contain any orientation info). I am running out of options. Could someone PLEASE help me out?Thanks for reading!
-
Sagar Hatekar over 12 years+1 Thanks, Matt. Trying to understand the code: Line #2 "selects" the image with the bottom 200 px clipped and then places the new images 100 px upwards of the original image, thereby clipping the top 100px, and the bottom 100 px right? It worked for me! Thanks a lot for your efforts!! Although the clipped image isn't exactly similar to the one seen with the camera overlay but I will probably have to tweak the nos. a bit. BTW, this code isn't thread-safe right? And I guess the CG lib provides a thread-safe way of doing this - so would be great to use it in a thread-safe manner.
-
Mats over 12 yearsIt is thread safe on iOS 4.0 and later, QA 1637.
-
Sagar Hatekar over 12 years+1, Accepted! Awesome, this works then - beautifully! THANKS A TON! Much Appreciated!
-
Duck over 12 yearsperfect! I have tried several methods, none worked as expected considering the image orientation. I always ended with the image rotated. thanks.
-
Eugene over 12 years@Mats, is there a way to do a similar cropping, but also include x offset points? I mean something like crop a rect, not only top and bottom parts?
-
Evan Layman over 11 yearsOMG I'd give you +1000 if I could. This finally works!! thanks!
-
Dejell about 11 years@Mats I am trying the function, but it increases the allocation size significantly. Any reason?
-
quantumpotato almost 11 years@Odelya UIImages take a lot of memory