1 2 Previous Next 22 Replies Latest reply: Feb 4, 2009 5:26 AM by YBC
davtian Level 1 Level 1 (0 points)
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)
  • 1. Re: Roate UIImage help
    johne-dm Level 1 Level 1 (25 points)
    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.
  • 2. Re: Roate UIImage help
    davtian Level 1 Level 1 (0 points)
    Thnak you for your help!!!
  • 3. Re: Roate UIImage help
    davtian Level 1 Level 1 (0 points)
    If you want to get the image from the UImageView at the end, wouldn't this work?



    UIImage *myfinalImage = [[UIImage alloc] init];
    myfinalImage = imageBackground.image;

  • 4. Re: Roate UIImage help
    johne-dm Level 1 Level 1 (25 points)
    i think that is gonna cause a leak... you are allocating an image, then changing the pointer to something else.

    i'm not sure that you aren't just going to get back the same thing you passed in.. unfortunately, i can't try that out right now cause i'm having another problem in that my code on my iphone isn't updating.
  • 5. Re: Roate UIImage help
    davtian Level 1 Level 1 (0 points)
    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);
    }

  • 6. Re: Roate UIImage help
    johne-dm Level 1 Level 1 (25 points)
    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.
  • 7. Re: Roate UIImage help
    davtian Level 1 Level 1 (0 points)
    It seems like I can't get this to work in SDK 6, there should be an easier way of rotating the images take from the camera =)

    Dave
  • 8. Re: Roate UIImage help
    davtian Level 1 Level 1 (0 points)
    My apologies, it does work in SDK 6, I had a small mistake in my code
  • 9. Re: Roate UIImage help
    johne-dm Level 1 Level 1 (25 points)
    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.
  • 10. Re: Roate UIImage help
    johne-dm Level 1 Level 1 (25 points)
    it looks like this code is no longer needed in beta 6. i think now, you can just create a context and drawRect and get the image to come out right... if you want to scale, just set the rect size and the size of the context to the appropriate new size.
  • 11. Re: Roate UIImage help
    johne-dm Level 1 Level 1 (25 points)
    oops.. might have spoke too soon... looks like setting the image of a UIImage view works, but the "drawInRect" into a bitmap context didn't seem to work so good... oh well... back to the drawing board.

    it is still worth re-checking with each new beta so you can reduce the amount of code you have to maintain, etc.
  • 12. Re: Roate UIImage help
    BadPirate Level 1 Level 1 (0 points)
    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;
    }
  • 13. Re: Roate UIImage help
    davtian Level 1 Level 1 (0 points)
    All credit goes to johne-dm for helping with this. The changes you have posted are identical to mine and it works like a champ, can't decide what a good kMaxResolution is over edge, since it's so slow.
  • 14. Re: Roate UIImage help
    johne-dm Level 1 Level 1 (25 points)
    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>
1 2 Previous Next