I have a UIImage
that is UIImageOrientationUp
(portrait) that I would like to rotate counter-clockwise by 90 degrees (to landscape). I don't want to use a CGAffineTransform
. I want the pixels of the UIImage
to actually shift position. I am using a block of code (shown below) originally intended to resize a UIImage
to do this. I set a target size as the current size of the UIImage
but I get an error:
(Error): CGBitmapContextCreate: invalid data bytes/row: should be at least 1708 for 8 integer bits/component, 3 components, kCGImageAlphaPremultipliedLast.
(I don't get an error whenever I provide a SMALLER size as the target size BTW). How can I ROTATE my UIImage
90 degrees CCW using just core graphics functions while preserving the current size?
-(UIImage*)reverseImageByScalingToSize:(CGSize)targetSize:(UIImage*)anImage
{
UIImage* sourceImage = anImage;
CGFloat targetWidth = targetSize.height;
CGFloat targetHeight = targetSize.width;
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, targetHeight, targetWidth, CGImageGetBitsPerComponent(imageRef), CGImageGetBytesPerRow(imageRef), colorSpaceInfo, bitmapInfo);
} else {
bitmap = CGBitmapContextCreate(NULL, targetWidth, targetHeight, CGImageGetBitsPerComponent(imageRef), CGImageGetBytesPerRow(imageRef), colorSpaceInfo, bitmapInfo);
}
if (sourceImage.imageOrientation == UIImageOrientationRight) {
CGContextRotateCTM (bitmap, radians(90));
CGContextTranslateCTM (bitmap, 0, -targetHeight);
} else if (sourceImage.imageOrientation == UIImageOrientationLeft) {
CGContextRotateCTM (bitmap, radians(-90));
CGContextTranslateCTM (bitmap, -targetWidth, 0);
} else if (sourceImage.imageOrientation == UIImageOrientationDown) {
// NOTHING
} else if (sourceImage.imageOrientation == UIImageOrientationUp) {
CGContextRotateCTM (bitmap, radians(90));
CGContextTranslateCTM (bitmap, 0, -targetHeight);
}
CGContextDrawImage(bitmap, CGRectMake(0, 0, targetWidth, targetHeight), imageRef);
CGImageRef ref = CGBitmapContextCreateImage(bitmap);
UIImage* newImage = [UIImage imageWithCGImage:ref];
CGContextRelease(bitmap);
CGImageRelease(ref);
return newImage;
}
What about something like:
I had trouble with ll of the above, including the approved answer. I converted Hardy's category back into a method since all i wanted was to rotate an image. Here's the code and usage:
And the usage:
Thanks Hardy!
I like the simple elegance of
Peter Sarnowski
's answer, but it can cause problems when you can't rely onEXIF
metadata and the like. In situations where you need to rotate the actual image data I would recommend something like this:The above code takes an image whose orientation is
Landscape
(can't remember if it'sLandscape Left
orLandscape Right
) and rotates it intoPortrait
. It is an example which can be modified for your needs.The key arguments you would have to play with are
CGContextRotateCTM(context, M_PI_2)
where you decide how much you want to rotate by, but then you have to make sure the picture still draws on the screen usingCGContextTranslateCTM(context, 0, -640)
. This last part is quite important to make sure you see the image and not a blank screen.For more info check out the source.
For Swift: Here is a simple extension to UIImage:
(Source)
Use it with:
The former will rotate an image and flip it if flip is set to true.
Check out the simple and awesome code of Hardy Macia at: cutting-scaling-and-rotating-uiimages
Just call
Thanks Hardy Macia!
Header:
Since the link may die, here's the complete code
Minor change to the other answers that are based on Hardy Macia's code. There is no need to create a whole
UIView
object simply to calculate the bounding rectangle of the rotated image. Just apply a rotate transform to the image rectangle usingCGRectApplyAffineTransform
.