Looks like no one’s replied in a while. To start the conversation again, simply ask a new question.

Roate UIImage help

Hi,

Any image taken with the camera and saved as a UIImage doesn't seem to come out right, orientation wise that is. Does anyway have a solution on how to rotate the image to it's proper state?

Many Thanks
Dave

Macbook Pro, Mac OS X (10.4.6)

Posted on May 27, 2008 8:44 PM

Reply
Question marked as Best reply

Posted on May 27, 2008 9:59 PM

i struggled quite a bit with this... the trick is the UIImage.imageOrientation flag. i also figured out that the size returned by the camera doesn't seem to be right, to get the right size, i had to do:


CGImageRef imgRef = theImage.CGImage;
orient = theImage.imageOrientation;

CGFloat width = CGImageGetWidth(imgRef);
CGFloat height = CGImageGetHeight(imgRef);


from here, i created a context and put that through a series of Affine transformations. if you just want to show the image on a UIImageView, you can use the following:


UIImage *imageCopy = [[UIImage alloc]initWithCGImage:theImage.CGImage];
switch (orient) {
case UIImageOrientationLeft:
imageBackground.transform = CGAffineTransformMakeRotation(3.0 * M_PI / 2.0);
break;
case UIImageOrientationRight:
imageBackground.transform = CGAffineTransformMakeRotation(M_PI / 2.0);
break;
case UIImageOrientationDown: //EXIF = 3
imageBackground.transform = CGAffineTransformMakeRotation(M_PI);
default:
break;
}
imageBackground.image = imageCopy;


where image background is a UIImageView object. as you can see, i set the image to a copy of the UIImage passed in... so i'm guessing either i'm doing something wrong, or there is some trouble with the camera in the image picker.

this all seems to work... if you want to save the image, it gets more complicated, but i think you can use the general principles above to work that out.
22 replies
Question marked as Best reply

May 27, 2008 9:59 PM in response to davtian

i struggled quite a bit with this... the trick is the UIImage.imageOrientation flag. i also figured out that the size returned by the camera doesn't seem to be right, to get the right size, i had to do:


CGImageRef imgRef = theImage.CGImage;
orient = theImage.imageOrientation;

CGFloat width = CGImageGetWidth(imgRef);
CGFloat height = CGImageGetHeight(imgRef);


from here, i created a context and put that through a series of Affine transformations. if you just want to show the image on a UIImageView, you can use the following:


UIImage *imageCopy = [[UIImage alloc]initWithCGImage:theImage.CGImage];
switch (orient) {
case UIImageOrientationLeft:
imageBackground.transform = CGAffineTransformMakeRotation(3.0 * M_PI / 2.0);
break;
case UIImageOrientationRight:
imageBackground.transform = CGAffineTransformMakeRotation(M_PI / 2.0);
break;
case UIImageOrientationDown: //EXIF = 3
imageBackground.transform = CGAffineTransformMakeRotation(M_PI);
default:
break;
}
imageBackground.image = imageCopy;


where image background is a UIImageView object. as you can see, i set the image to a copy of the UIImage passed in... so i'm guessing either i'm doing something wrong, or there is some trouble with the camera in the image picker.

this all seems to work... if you want to save the image, it gets more complicated, but i think you can use the general principles above to work that out.

May 28, 2008 6:45 PM in response to johne-dm

Hmm... this is what I was putting together, I guess I need to have a UIImage at the end =(


+(UIImage *)rotateImage:(UIImage *)image {
int orient = image.imageOrientation;
UIImageView *imageView = [[UIImageView alloc] init];
UIImage *imageCopy = [[UIImage alloc] initWithCGImage:image.CGImage];
switch (orient) {
case UIImageOrientationLeft:
imageView.transform = CGAffineTransformMakeRotation(3.0 * M_PI / 2.0);
break;
case UIImageOrientationRight:
imageView.transform = CGAffineTransformMakeRotation(M_PI / 2.0);
break;
case UIImageOrientationDown: //EXIF = 3
imageView.transform = CGAffineTransformMakeRotation(M_PI);
default:
break;
}
imageView.image = imageCopy;
return (imageView.image);
}

May 28, 2008 6:52 PM in response to davtian

well... this might be a bug or something, but i think that you then have to jump through a bunch more hoops... i haven't tried in beta 6, so if it is a bug, then you could try and see if it has been fixed magically.

otherwise, the hoops i jump through (which could be totally wrong approach) is:


- (void)scaleAndRotateImage {
CGImageRef imgRef = self.image.CGImage;
CGFloat width = CGImageGetWidth(imgRef);
CGFloat height = CGImageGetHeight(imgRef);
if (width <= kMaxResolution && height <= kMaxResolution && orient == UIImageOrientationUp) {
return;
}

CGAffineTransform transform = CGAffineTransformIdentity;
CGRect bounds = CGRectMake(0, 0, width, height);
if (width > kMaxResolution || height > kMaxResolution) {
CGFloat ratio = width/height;
if (ratio > 1) {
bounds.size.width = kMaxResolution;
bounds.size.height = bounds.size.width / ratio;
}
else {
bounds.size.height = kMaxResolution;
bounds.size.width = bounds.size.height * ratio;
}
}

CGFloat scaleRatio = bounds.size.width / width;
CGSize imageSize = CGSizeMake(CGImageGetWidth(imgRef), CGImageGetHeight(imgRef));
CGFloat boundHeight;
switch(orient) {

case UIImageOrientationUp: //EXIF = 1
transform = CGAffineTransformIdentity;
break;

case UIImageOrientationUpMirrored: //EXIF = 2
transform = CGAffineTransformMakeTranslation(imageSize.width, 0.0);
transform = CGAffineTransformScale(transform, -1.0, 1.0);
break;

case UIImageOrientationDown: //EXIF = 3
transform = CGAffineTransformMakeTranslation(imageSize.width, imageSize.height);
transform = CGAffineTransformRotate(transform, M_PI);
break;

case UIImageOrientationDownMirrored: //EXIF = 4
transform = CGAffineTransformMakeTranslation(0.0, imageSize.height);
transform = CGAffineTransformScale(transform, 1.0, -1.0);
break;

case UIImageOrientationLeftMirrored: //EXIF = 5
boundHeight = bounds.size.height;
bounds.size.height = bounds.size.width;
bounds.size.width = boundHeight;
transform = CGAffineTransformMakeTranslation(imageSize.height, imageSize.width);
transform = CGAffineTransformScale(transform, -1.0, 1.0);
transform = CGAffineTransformRotate(transform, 3.0 * M_PI / 2.0);
break;

case UIImageOrientationLeft: //EXIF = 6
boundHeight = bounds.size.height;
bounds.size.height = bounds.size.width;
bounds.size.width = boundHeight;
transform = CGAffineTransformMakeTranslation(0.0, imageSize.width);
transform = CGAffineTransformRotate(transform, 3.0 * M_PI / 2.0);
break;

case UIImageOrientationRightMirrored: //EXIF = 7
boundHeight = bounds.size.height;
bounds.size.height = bounds.size.width;
bounds.size.width = boundHeight;
transform = CGAffineTransformMakeScale(-1.0, 1.0);
transform = CGAffineTransformRotate(transform, M_PI / 2.0);
break;

case UIImageOrientationRight: //EXIF = 8
boundHeight = bounds.size.height;
bounds.size.height = bounds.size.width;
bounds.size.width = boundHeight;
transform = CGAffineTransformMakeTranslation(imageSize.height, 0.0);
transform = CGAffineTransformRotate(transform, M_PI / 2.0);
break;

default:
[NSException raise:NSInternalInconsistencyException format:@"Invalid image orientation"];

}

UIGraphicsBeginImageContext(bounds.size);
CGContextRef context = UIGraphicsGetCurrentContext();
if (orient == UIImageOrientationRight || orient == UIImageOrientationLeft) {
CGContextScaleCTM(context, -scaleRatio, scaleRatio);
CGContextTranslateCTM(context, -height, 0);
}
else {
CGContextScaleCTM(context, scaleRatio, -scaleRatio);
CGContextTranslateCTM(context, 0, -height);
}

CGContextConcatCTM(context, transform);

CGContextDrawImage(UIGraphicsGetCurrentContext(), CGRectMake(0, 0, width, height), imgRef);
UIImage *imageCopy = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

self.image = imageCopy;
}


this code also scales the image, which you may not need.

Jun 2, 2008 8:57 AM in response to davtian

really, you should be able to just set the imageView's image to the orignially passed in image and it should rotate and scale for you. i haven't tried this with beta 6 yet, but as of beta 5, the image came out funny if you took the picture in "portrait" mode.

all this mess of code should just be a work-around until the issue is fixed... in beta 5, i couldn't even get the size of the image when it came from the camera.

Jun 5, 2008 3:26 PM in response to davtian

With a couple of changes I was able to get your method turned into a usable function for application wherever needed:


UIImage *scaleAndRotateImage(UIImage *image)
{
int kMaxResolution = 320; // Or whatever

CGImageRef imgRef = image.CGImage;

CGFloat width = CGImageGetWidth(imgRef);
CGFloat height = CGImageGetHeight(imgRef);


CGAffineTransform transform = CGAffineTransformIdentity;
CGRect bounds = CGRectMake(0, 0, width, height);
if (width > kMaxResolution || height > kMaxResolution) {
CGFloat ratio = width/height;
if (ratio > 1) {
bounds.size.width = kMaxResolution;
bounds.size.height = bounds.size.width / ratio;
}
else {
bounds.size.height = kMaxResolution;
bounds.size.width = bounds.size.height * ratio;
}
}

CGFloat scaleRatio = bounds.size.width / width;
CGSize imageSize = CGSizeMake(CGImageGetWidth(imgRef), CGImageGetHeight(imgRef));
CGFloat boundHeight;
UIImageOrientation orient = image.imageOrientation;
switch(orient) {

case UIImageOrientationUp: //EXIF = 1
transform = CGAffineTransformIdentity;
break;

case UIImageOrientationUpMirrored: //EXIF = 2
transform = CGAffineTransformMakeTranslation(imageSize.width, 0.0);
transform = CGAffineTransformScale(transform, -1.0, 1.0);
break;

case UIImageOrientationDown: //EXIF = 3
transform = CGAffineTransformMakeTranslation(imageSize.width, imageSize.height);
transform = CGAffineTransformRotate(transform, M_PI);
break;

case UIImageOrientationDownMirrored: //EXIF = 4
transform = CGAffineTransformMakeTranslation(0.0, imageSize.height);
transform = CGAffineTransformScale(transform, 1.0, -1.0);
break;

case UIImageOrientationLeftMirrored: //EXIF = 5
boundHeight = bounds.size.height;
bounds.size.height = bounds.size.width;
bounds.size.width = boundHeight;
transform = CGAffineTransformMakeTranslation(imageSize.height, imageSize.width);
transform = CGAffineTransformScale(transform, -1.0, 1.0);
transform = CGAffineTransformRotate(transform, 3.0 * M_PI / 2.0);
break;

case UIImageOrientationLeft: //EXIF = 6
boundHeight = bounds.size.height;
bounds.size.height = bounds.size.width;
bounds.size.width = boundHeight;
transform = CGAffineTransformMakeTranslation(0.0, imageSize.width);
transform = CGAffineTransformRotate(transform, 3.0 * M_PI / 2.0);
break;

case UIImageOrientationRightMirrored: //EXIF = 7
boundHeight = bounds.size.height;
bounds.size.height = bounds.size.width;
bounds.size.width = boundHeight;
transform = CGAffineTransformMakeScale(-1.0, 1.0);
transform = CGAffineTransformRotate(transform, M_PI / 2.0);
break;

case UIImageOrientationRight: //EXIF = 8
boundHeight = bounds.size.height;
bounds.size.height = bounds.size.width;
bounds.size.width = boundHeight;
transform = CGAffineTransformMakeTranslation(imageSize.height, 0.0);
transform = CGAffineTransformRotate(transform, M_PI / 2.0);
break;

default:
[NSException raise:NSInternalInconsistencyException format:@"Invalid image orientation"];

}

UIGraphicsBeginImageContext(bounds.size);

CGContextRef context = UIGraphicsGetCurrentContext();

if (orient == UIImageOrientationRight || orient == UIImageOrientationLeft) {
CGContextScaleCTM(context, -scaleRatio, scaleRatio);
CGContextTranslateCTM(context, -height, 0);
}
else {
CGContextScaleCTM(context, scaleRatio, -scaleRatio);
CGContextTranslateCTM(context, 0, -height);
}

CGContextConcatCTM(context, transform);

CGContextDrawImage(UIGraphicsGetCurrentContext(), CGRectMake(0, 0, width, height), imgRef);
UIImage *imageCopy = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

return imageCopy;
}

Jun 5, 2008 4:41 PM in response to davtian

i'm letting the user set that in settings and defaulting to 800x600, but i'm sure i'll regret that.

remember... 3G phones next week, so make sure you don't punish the 3G people for the edge people. i think pulling it from a setting is prolly your best bet... i put a couple common resolutions in my settings:


<dict>
<key>DefaultValue</key>
<integer>800</integer>
<key>Title</key>
<string>Max Resolution</string>
<key>Key</key>
<string>maxResolution</string>
<key>Type</key>
<string>PSMultiValueSpecifier</string>
<key>Titles</key>
<array>
<string>640 x 480</string>
<string>800 x 600</string>
</array>
<key>Values</key>
<array>
<integer>640</integer>
<integer>800</integer>
</array>
</dict>

Jul 28, 2008 1:24 PM in response to BadPirate

Am I the only one receiving "EXC BADACCESS" when using this code?

It seems something bad happen in 'camera_callback' (which is not in my code) after I display the /rotated/scaled UIImage returned from scaleAndRotateImage function.

Here is my code:

// in main code:

if ( [UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera] )
{
picker = [[UIImagePickerController alloc] init];
picker.sourceType = UIImagePickerControllerSourceTypeCamera;
picker.delegate = self;
picker.allowsImageEditing = NO;

myVew addSubview:picker.view ;
}

// Picker image delegate

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)image editingInfo:(NSDictionary *)editingInfo
{
image = scaleAndRotateImage( image );

currentPhoto = [UIImage imageWithCGImage:image.CGImage];

// Remove the picker interface and release the picker object.
picker.view removeFromSuperview;
picker release ;

// Redraw the screen, with updated background picture
myView performSelectorOnMainThread:@selector(setNeedsDisplay) withObject:nil waitUntilDone:NO;
}

// inside main code

-(void)drawRect:(CGRect)rect
{
currentPhoto drawAtPoint:CGPointMake(0,0);

super drawRect:rect;
}


=> if I comment the line in picketImage delegate
image = scaleAndRotateImage( image );
everything works fine (except the image is huge and with bad orientation), else, the right image is displayed in drawRect (correctly scaled and rotated), but soon after the “EXC BADACCESS” signal is received (in function CoreSurfaceClientBufferGetID)

Can someone please tell me what's wrong in previous code?

Please note that I'm using addSubview to display the imagePicker, instead of presentModalViewController: could it be the reason of the problem?
(I'm not using a UIViewController, which is why I'm calling addSubView)

Thanks for any suggestion.

Roate UIImage help

Welcome to Apple Support Community
A forum where Apple customers help each other with their products. Get started with your Apple ID.