Update:
With iPhone OS 3.0+, the whole UIImagePickerController API has changed. This question and answer should be considered 2.2. legacy code.
When using
This appears to be a hindrance of the SDK, at least when setting the allowsImageEditing to TRUE on the image picker. There's a bit of discussion on this topic in the Apple forums here:
http://discussions.apple.com/message.jspa?messageID=7841993
I wrote a category on UIImage that provides a full-resolution crop. The easiest way to install is with CocoaPods, by adding UIImage-ImagePickerCrop to your podfile.
#import <UIImage+ImagePickerCrop.h>
...
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo: (NSDictionary *)info {
[self dismissViewControllerAnimated:YES completion:nil];
UIImage *croppedImage = [UIImage croppedImageWithImagePickerInfo:info];
...
}
With iPhone OS 3.0+, the whole UIImagePickerController API has changed. This question and answer should be considered 2.2. legacy code.
Despite your warning, it took me a precious dev hour to realize iOS 3.0+ gave us UIImagePickerControllerEditedImage which makes dealing with manually cropping to the user's pinch/zoom and dealing with orientation unnecessary.
This is in case anyone was still using UIImagePickerControllerOriginalImage and trying to figure out how best to apply cropping via UIImagePickerControllerCropRect, etc. No longer needed.
I must be too late to answer this question, but I have got a better way to get this job done.
static inline double radians (double degrees) {return degrees * M_PI/180;}
+(UIImage*)editedImageFromMediaWithInfo:(NSDictionary*)info{
if(![info objectForKey:UIImagePickerControllerCropRect])return nil;
if(![info objectForKey:UIImagePickerControllerOriginalImage])return nil;
UIImage *originalImage=[info objectForKey:UIImagePickerControllerOriginalImage];
CGRect rect=[[info objectForKey:UIImagePickerControllerCropRect] CGRectValue];
CGImageRef imageRef = CGImageCreateWithImageInRect([originalImage CGImage], rect);
CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef);
CGColorSpaceRef colorSpaceInfo = CGImageGetColorSpace(imageRef);
CGContextRef bitmap = CGBitmapContextCreate(NULL, rect.size.width, rect.size.height, CGImageGetBitsPerComponent(imageRef), CGImageGetBytesPerRow(imageRef), colorSpaceInfo, bitmapInfo);
if (originalImage.imageOrientation == UIImageOrientationLeft) {
CGContextRotateCTM (bitmap, radians(90));
CGContextTranslateCTM (bitmap, 0, -rect.size.height);
} else if (originalImage.imageOrientation == UIImageOrientationRight) {
CGContextRotateCTM (bitmap, radians(-90));
CGContextTranslateCTM (bitmap, -rect.size.width, 0);
} else if (originalImage.imageOrientation == UIImageOrientationUp) {
// NOTHING
} else if (originalImage.imageOrientation == UIImageOrientationDown) {
CGContextTranslateCTM (bitmap, rect.size.width, rect.size.height);
CGContextRotateCTM (bitmap, radians(-180.));
}
CGContextDrawImage(bitmap, CGRectMake(0, 0, rect.size.width, rect.size.height), imageRef);
CGImageRef ref = CGBitmapContextCreateImage(bitmap);
UIImage *resultImage=[UIImage imageWithCGImage:ref];
CGImageRelease(imageRef);
CGContextRelease(bitmap);
CGImageRelease(ref);
return resultImage;
}
It only crops the original image with the relative CropRect, although this method dosen't scale the image, but it is short and sweet for me. Just for reference :)
As craig said, this is an issue in the dev forums and apples regular discussion board. I did, however, find a way around it. I'm using a bit of code from:
Apple Dev Forums
This includes most of what you need, and takes care of all the camera orientation issues. I've added the following which will take in the editing info and use it to get the original cropping rect with this addition:
- (UIImage*)scaleImage:(UIImage*)anImage withEditingInfo:(NSDictionary*)editInfo{
UIImage *newImage;
UIImage *originalImage = [editInfo valueForKey:@"UIImagePickerControllerOriginalImage"];
CGSize originalSize = CGSizeMake(originalImage.size.width, originalImage.size.height);
CGRect originalFrame;
originalFrame.origin = CGPointMake(0,0);
originalFrame.size = originalSize;
CGRect croppingRect = [[editInfo valueForKey:@"UIImagePickerControllerCropRect"] CGRectValue];
CGSize croppingRectSize = CGSizeMake(croppingRect.size.width, croppingRect.size.height);
CGSize croppedScaledImageSize = anImage.size;
float scaledBarClipHeight = 80;
CGSize scaledImageSize;
float scale;
if(!CGSizeEqualToSize(croppedScaledImageSize, originalSize)){
scale = croppedScaledImageSize.width/croppingRectSize.width;
float barClipHeight = scaledBarClipHeight/scale;
croppingRect.origin.y -= barClipHeight;
croppingRect.size.height += (2*barClipHeight);
if(croppingRect.origin.y<=0){
croppingRect.size.height += croppingRect.origin.y;
croppingRect.origin.y=0;
}
if(croppingRect.size.height > (originalSize.height - croppingRect.origin.y)){
croppingRect.size.height = (originalSize.height - croppingRect.origin.y);
}
scaledImageSize = croppingRect.size;
scaledImageSize.width *= scale;
scaledImageSize.height *= scale;
newImage = [self cropImage:originalImage to:croppingRect andScaleTo:scaledImageSize];
}else{
newImage = originalImage;
}
return newImage;
}
I updated the call back method from the dev forums post to the following:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)img editingInfo:(NSDictionary *)editInfo {
[self dismissModalViewControllerAnimated:YES];
self.myImageView.userInteractionEnabled=YES;
CGRect imageFrame = myImageView.frame;
CGPoint imageCenter = myImageView.center;
UIImage *croppedImage;
NSMutableDictionary *imageDescriptor = [editInfo mutableCopy];
// CGFloat scaleSize = 400.0f;
CGFloat scaleSize = 640.0f;
switch ([picker sourceType]) {
//done
case UIImagePickerControllerSourceTypePhotoLibrary:
croppedImage = [self scaleImage:img withEditingInfo:editInfo];
[imageDescriptor setObject:croppedImage forKey:@"croppedImage"];
break;
case UIImagePickerControllerSourceTypeCamera: {
UIImageOrientation originalOrientation = [[editInfo objectForKey:UIImagePickerControllerOriginalImage] imageOrientation];
if (originalOrientation != UIImageOrientationUp) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
CGRect origRect;
[[editInfo objectForKey:UIImagePickerControllerCropRect] getValue:&origRect];
UIImage *rotatedImage = straightenAndScaleImage([editInfo objectForKey:UIImagePickerControllerOriginalImage], scaleSize);
CGFloat scale = scaleSize/1600.0f;
origRect.origin.x *= scale;
origRect.origin.y *= scale;
origRect.size.width *= scale;
origRect.size.height *= scale;
croppedImage = [self cropImage:rotatedImage to:origRect andScaleTo:CGSizeMake(320, 480)];
[imageDescriptor setObject:croppedImage forKey:@"croppedImage"];
[pool drain];
}
else {
croppedImage = [self scaleImage:img withEditingInfo:editInfo];
[imageDescriptor setObject:croppedImage forKey:@"croppedImage"];
}
}
break;
case UIImagePickerControllerSourceTypeSavedPhotosAlbum: {
UIImageOrientation originalOrientation = [[editInfo objectForKey:UIImagePickerControllerOriginalImage] imageOrientation];
if (originalOrientation != UIImageOrientationUp) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
CGRect origRect;
[[editInfo objectForKey:UIImagePickerControllerCropRect] getValue:&origRect];
UIImage *rotatedImage = straightenAndScaleImage([editInfo objectForKey:UIImagePickerControllerOriginalImage], scaleSize);
CGFloat scale = scaleSize/640.0f;
origRect.origin.x *= scale;
origRect.origin.y *= scale;
origRect.size.width *= scale;
origRect.size.height *= scale;
croppedImage = [self cropImage:rotatedImage to:origRect andScaleTo:CGSizeMake(320, 480)];
[imageDescriptor setObject:croppedImage forKey:@"croppedImage"];
[pool drain];
}
else {
croppedImage = [self scaleImage:img withEditingInfo:editInfo];
[imageDescriptor setObject:croppedImage forKey:@"croppedImage"];
}
}
break;
default:
break;
}
imageFrame.size = croppedImage.size;
myImageView.frame = imageFrame;
myImageView.image = [imageDescriptor objectForKey:@"croppedImage"];
myImageView.center = imageCenter;
}
Better late than never: here's the source for the orientationTransformForImage
function
CGAffineTransform orientationTransformForImage(UIImage *image, CGSize *newSize) { CGImageRef img = [image CGImage]; CGFloat width = CGImageGetWidth(img); CGFloat height = CGImageGetHeight(img); CGSize size = CGSizeMake(width, height); CGAffineTransform transform = CGAffineTransformIdentity; CGFloat origHeight = size.height; UIImageOrientation orient = image.imageOrientation; switch(orient) { /* EXIF 1 to 8 */ case UIImageOrientationUp: break; case UIImageOrientationUpMirrored: transform = CGAffineTransformMakeTranslation(width, 0.0f); transform = CGAffineTransformScale(transform, -1.0f, 1.0f); break; case UIImageOrientationDown: transform = CGAffineTransformMakeTranslation(width, height); transform = CGAffineTransformRotate(transform, M_PI); break; case UIImageOrientationDownMirrored: transform = CGAffineTransformMakeTranslation(0.0f, height); transform = CGAffineTransformScale(transform, 1.0f, -1.0f); break; case UIImageOrientationLeftMirrored: size.height = size.width; size.width = origHeight; transform = CGAffineTransformMakeTranslation(height, width); transform = CGAffineTransformScale(transform, -1.0f, 1.0f); transform = CGAffineTransformRotate(transform, 3.0f * M_PI / 2.0f); break; case UIImageOrientationLeft: size.height = size.width; size.width = origHeight; transform = CGAffineTransformMakeTranslation(0.0f, width); transform = CGAffineTransformRotate(transform, 3.0f * M_PI / 2.0f); break; case UIImageOrientationRightMirrored: size.height = size.width; size.width = origHeight; transform = CGAffineTransformMakeScale(-1.0f, 1.0f); transform = CGAffineTransformRotate(transform, M_PI / 2.0f); break; case UIImageOrientationRight: size.height = size.width; size.width = origHeight; transform = CGAffineTransformMakeTranslation(height, 0.0f); transform = CGAffineTransformRotate(transform, M_PI / 2.0f); break; default: ; } *newSize = size; return transform; }