Here are two code snippets for rotating and resizing UIImage’s without using UIGraphicsBeginImageContext(), because it is not thread-safe and can lead to weird behavior.
In my case the camera-preview when taking a picture in an app I was writing, turned black from time to time. The problem was that I was rotating and resizing the images using UIGraphicsBeginImageContext().
Here’s some code I’ve found and tweaked to resize images:
- (UIImage *)imageByScalingToSize:(CGSize)targetSize
{
UIImage *newImage = nil;
CGFloat targetWidth = targetSize.width;
CGFloat targetHeight = targetSize.height;
CGContextRef bitmap = CGBitmapContextCreate(NULL,
targetWidth,
targetHeight,
CGImageGetBitsPerComponent(self.CGImage),
4 * targetWidth, CGImageGetColorSpace(self.CGImage),
(CGBitmapInfo)kCGImageAlphaNoneSkipLast);
CGContextDrawImage(bitmap, CGRectMake(0, 0, targetWidth, targetHeight), self.CGImage);
CGImageRef ref = CGBitmapContextCreateImage(bitmap);
newImage = [UIImage imageWithCGImage:ref];
if(newImage == nil) NSLog(@"could not scale image");
CGContextRelease(bitmap);
return newImage ;
}
And here’s how to rotate them:
- (UIImage*)rotateInRadians:(CGFloat)radians
{
CGImageRef cgImage = self.CGImage;
const CGFloat originalWidth = CGImageGetWidth(cgImage);
const CGFloat originalHeight = CGImageGetHeight(cgImage);
const CGRect imgRect = (CGRect){.origin.x = 0.0f, .origin.y = 0.0f,
.size.width = originalWidth, .size.height = originalHeight};
const CGRect rotatedRect = CGRectApplyAffineTransform(imgRect, CGAffineTransformMakeRotation(radians));
CGContextRef bmContext = NYXImageCreateARGBBitmapContext(rotatedRect.size.width, rotatedRect.size.height, 0);
if (!bmContext)
return nil;
CGContextSetShouldAntialias(bmContext, true);
CGContextSetAllowsAntialiasing(bmContext, true);
CGContextSetInterpolationQuality(bmContext, kCGInterpolationHigh);
CGContextTranslateCTM(bmContext, +(rotatedRect.size.width * 0.5f), +(rotatedRect.size.height * 0.5f));
CGContextRotateCTM(bmContext, radians);
CGContextDrawImage(bmContext, (CGRect){.origin.x = -originalWidth * 0.5f, .origin.y = -originalHeight * 0.5f,
.size.width = originalWidth, .size.height = originalHeight}, cgImage);
CGImageRef rotatedImageRef = CGBitmapContextCreateImage(bmContext);
UIImage* rotated = [UIImage imageWithCGImage:rotatedImageRef];
CGImageRelease(rotatedImageRef);
CGContextRelease(bmContext);
return rotated;
}
Because the above takes radians, convert using something like this:
CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI / 180;};
Just put these methods into a category on UIImage.
P.S.: You can follow me on Twitter.
Lukas Z's Blog