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.