Question

I am getting UIimages from the camera and assigning them to UIImageViews to be displayed. When I do this the camera gives me a 1200 x 1600 pixel image which I then assign to a UIImageView in my Application. The image is displayed as expected in the image view under this condition. However, when I attempt to RESIZE the retrieved UIImage before assigning it to the UIImageView, the image is resizing as expected but there IS a problem in that somewhere (in the RESIZING code?) my UIImage is getting ROTATED... As a result, when I assign the resized UIImage to a UIImageView the image is rotated 90 degrees and appears stretched as the aspect ratio (1200 x 1600 pixels) was unchanged...

I am using this to get a UIImage from the Camera:

- (void) imagePickerController:(UIImagePickerController*)picker didFinishPickingMediaWithInfo:(NSDictionary*)info
{

        myImg = [info objectForKey:@"UIImagePickerControllerOriginalImage"];
        myResizedImg = [self resizeImage:myImg width:400 height:533];
        [myImageView setImage:myResizedImg];

}

I am using this to resize it:

-(UIImage *)resizeImage:(UIImage *)anImage width:(int)width height:(int)height
{

    CGImageRef imageRef = [anImage CGImage];

    CGImageAlphaInfo alphaInfo = CGImageGetAlphaInfo(imageRef);

    if (alphaInfo == kCGImageAlphaNone)
    alphaInfo = kCGImageAlphaNoneSkipLast;


    CGContextRef bitmap = CGBitmapContextCreate(NULL, width, height, CGImageGetBitsPerComponent(imageRef), 4 * width, CGImageGetColorSpace(imageRef), alphaInfo);

    CGContextDrawImage(bitmap, CGRectMake(0, 0, width, height), imageRef);

    CGImageRef ref = CGBitmapContextCreateImage(bitmap);
    UIImage *result = [UIImage imageWithCGImage:ref];

    CGContextRelease(bitmap);
    CGImageRelease(ref);

    return result;  
}

QUESTION: How do I RESIZE a UIImage pulled from the Camera WITHOUT rotating the pixels?

Was it helpful?

Solution

The reason your code doesn't work is because the imageOrientation on the code that you have is not being taken into account. Specifically, if the imageOrientation is right/left, then you need to both rotate the image and swap width/height. Here is some code to do this:

-(UIImage*)imageByScalingToSize:(CGSize)targetSize
{
    UIImage* sourceImage = self; 
    CGFloat targetWidth = targetSize.width;
    CGFloat targetHeight = targetSize.height;

    CGImageRef imageRef = [sourceImage CGImage];
    CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef);
    CGColorSpaceRef colorSpaceInfo = CGImageGetColorSpace(imageRef);

    if (bitmapInfo == kCGImageAlphaNone) {
        bitmapInfo = kCGImageAlphaNoneSkipLast;
    }

    CGContextRef bitmap;

    if (sourceImage.imageOrientation == UIImageOrientationUp || sourceImage.imageOrientation == UIImageOrientationDown) {
        bitmap = CGBitmapContextCreate(NULL, targetWidth, targetHeight, CGImageGetBitsPerComponent(imageRef), CGImageGetBytesPerRow(imageRef), colorSpaceInfo, bitmapInfo);

    } else {
        bitmap = CGBitmapContextCreate(NULL, targetHeight, targetWidth, CGImageGetBitsPerComponent(imageRef), CGImageGetBytesPerRow(imageRef), colorSpaceInfo, bitmapInfo);

    }   

    if (sourceImage.imageOrientation == UIImageOrientationLeft) {
        CGContextRotateCTM (bitmap, radians(90));
        CGContextTranslateCTM (bitmap, 0, -targetHeight);

    } else if (sourceImage.imageOrientation == UIImageOrientationRight) {
        CGContextRotateCTM (bitmap, radians(-90));
        CGContextTranslateCTM (bitmap, -targetWidth, 0);

    } else if (sourceImage.imageOrientation == UIImageOrientationUp) {
        // NOTHING
    } else if (sourceImage.imageOrientation == UIImageOrientationDown) {
        CGContextTranslateCTM (bitmap, targetWidth, targetHeight);
        CGContextRotateCTM (bitmap, radians(-180.));
    }

    CGContextDrawImage(bitmap, CGRectMake(0, 0, targetWidth, targetHeight), imageRef);
    CGImageRef ref = CGBitmapContextCreateImage(bitmap);
    UIImage* newImage = [UIImage imageWithCGImage:ref];

    CGContextRelease(bitmap);
    CGImageRelease(ref);

    return newImage; 
}

This will resize your image and rotate it to the correct orientation. If you need the definition for radians, it is:

static inline double radians (double degrees) {return degrees * M_PI/180;}

The answer Daniel gave is also correct, but it suffers from the problem that it is not thread-safe, since you're using UIGraphicsBeginImageContext(). Since the above code only uses CG functions, you're all set. I also have a similar function to resize and do proper aspect fill on images - let me know if that's what you're looking for.

Note: I got the original function from this post, and did some modifications to make it work on JPEGs.

OTHER TIPS

I had this problem too with some of the code out there, i found this code that works, check it out, let me know what you find

+ (UIImage*)imageWithImage:(UIImage*)image 
               scaledToSize:(CGSize)newSize;
{
   UIGraphicsBeginImageContext( newSize );
   [image drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];
   UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
   UIGraphicsEndImageContext();

   return newImage;
}

Swift 3

I add this to didFinishPickingMediaWithInfo method and then use image without worrying for its rotation.

var image = info[UIImagePickerControllerOriginalImage] as! UIImage
if (image.imageOrientation != .up) {
  UIGraphicsBeginImageContextWithOptions(image.size, false, image.scale)
  image.draw(in: CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height))
  image = UIGraphicsGetImageFromCurrentImageContext()!
  UIGraphicsEndImageContext()
}

If you want to make a square image from a rectangle image (no matter horizontal or vertical) by cropping it by width or height in both sides, use my code. The difference is that I don't stretch, but I crop. I made it from the top code by modification:

//Cropping _image to fit it to the square by height or width

CGFloat a = _image.size.height;
CGFloat b = _image.size.width;
CGRect cropRect;

if (!(a==b)) {
    if (a<b) {
        cropRect = CGRectMake((b-a)/2.0, 0, a, a);
        b = a;
    }
    else if (b<a) {
        cropRect = CGRectMake(0, (a-b)/2.0, b, b);
        a = b;
    }

    CGImageRef imageRef = CGImageCreateWithImageInRect([_image CGImage], cropRect);

    UIImage* sourceImage = _image; 
    CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef);
    CGColorSpaceRef colorSpaceInfo = CGImageGetColorSpace(imageRef);
    CGContextRef bitmap;
    if (sourceImage.imageOrientation == UIImageOrientationUp || sourceImage.imageOrientation == UIImageOrientationDown) {
        bitmap = CGBitmapContextCreate(NULL, a, a, CGImageGetBitsPerComponent(imageRef), CGImageGetBytesPerRow(imageRef), colorSpaceInfo, bitmapInfo);

    } else {
        bitmap = CGBitmapContextCreate(NULL, a, a, CGImageGetBitsPerComponent(imageRef), CGImageGetBytesPerRow(imageRef), colorSpaceInfo, bitmapInfo);
    }

    if (sourceImage.imageOrientation == UIImageOrientationLeft) {
        CGContextRotateCTM (bitmap, radians(90));
        CGContextTranslateCTM (bitmap, 0, -a);

    } else if (sourceImage.imageOrientation == UIImageOrientationRight) {
        CGContextRotateCTM (bitmap, radians(-90));
        CGContextTranslateCTM (bitmap, -a, 0);

    } else if (sourceImage.imageOrientation == UIImageOrientationUp) {
        // NOTHING
    } else if (sourceImage.imageOrientation == UIImageOrientationDown) {
        CGContextTranslateCTM (bitmap, a, a);
        CGContextRotateCTM (bitmap, radians(-180.));
    }

    CGContextDrawImage(bitmap, CGRectMake(0, 0, a, a), imageRef);
    CGImageRef ref = CGBitmapContextCreateImage(bitmap);
    _image = [UIImage imageWithCGImage:ref];
    CGImageRelease(imageRef);
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top