Created
March 11, 2014 17:36
-
-
Save jyliang/9490870 to your computer and use it in GitHub Desktop.
vImageScaledImage
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Method: vImageScaledImage:(UIImage*) sourceImage withSize:(CGSize) destSize | |
// Returns even better scaling than drawing to a context with kCGInterpolationHigh. | |
// This employs the vImage routines in Accelerate.framework. | |
// For more information about vImage, see https://developer.apple.com/library/mac/#documentation/performance/Conceptual/vImage/Introduction/Introduction.html#//apple_ref/doc/uid/TP30001001-CH201-TPXREF101 | |
// Large quantities of memory are manually allocated and (hopefully) freed here. Test your application for leaks before and after using this method. | |
+ (UIImage*) vImageScaledImage:(UIImage*) sourceImage withSize:(CGSize) destSize; | |
{ | |
UIImage *destImage = nil; | |
if (sourceImage) | |
{ | |
// First, convert the UIImage to an array of bytes, in the format expected by vImage. | |
// Thanks: http://stackoverflow.com/a/1262893/1318452 | |
CGImageRef sourceRef = [sourceImage CGImage]; | |
NSUInteger sourceWidth = CGImageGetWidth(sourceRef); | |
NSUInteger sourceHeight = CGImageGetHeight(sourceRef); | |
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); | |
unsigned char *sourceData = (unsigned char*) calloc(sourceHeight * sourceWidth * 4, sizeof(unsigned char)); | |
NSUInteger bytesPerPixel = 4; | |
NSUInteger sourceBytesPerRow = bytesPerPixel * sourceWidth; | |
NSUInteger bitsPerComponent = 8; | |
CGContextRef context = CGBitmapContextCreate(sourceData, sourceWidth, sourceHeight, | |
bitsPerComponent, sourceBytesPerRow, colorSpace, | |
kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Big); | |
CGContextDrawImage(context, CGRectMake(0, 0, sourceWidth, sourceHeight), sourceRef); | |
CGContextRelease(context); | |
// We now have the source data. Construct a pixel array | |
NSUInteger destWidth = (NSUInteger) destSize.width; | |
NSUInteger destHeight = (NSUInteger) destSize.height; | |
NSUInteger destBytesPerRow = bytesPerPixel * destWidth; | |
unsigned char *destData = (unsigned char*) calloc(destHeight * destWidth * 4, sizeof(unsigned char)); | |
// Now create vImage structures for the two pixel arrays. | |
// Thanks: https://github.com/dhoerl/PhotoScrollerNetwork | |
vImage_Buffer src = { | |
.data = sourceData, | |
.height = sourceHeight, | |
.width = sourceWidth, | |
.rowBytes = sourceBytesPerRow | |
}; | |
vImage_Buffer dest = { | |
.data = destData, | |
.height = destHeight, | |
.width = destWidth, | |
.rowBytes = destBytesPerRow | |
}; | |
// Carry out the scaling. | |
vImage_Error err = vImageScale_ARGB8888 ( | |
&src, | |
&dest, | |
NULL, | |
kvImageHighQualityResampling | |
); | |
// The source bytes are no longer needed. | |
free(sourceData); | |
// Convert the destination bytes to a UIImage. | |
CGContextRef destContext = CGBitmapContextCreate(destData, destWidth, destHeight, | |
bitsPerComponent, destBytesPerRow, colorSpace, | |
kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Big); | |
CGImageRef destRef = CGBitmapContextCreateImage(destContext); | |
// Store the result. | |
destImage = [UIImage imageWithCGImage:destRef]; | |
// Free up the remaining memory. | |
CGImageRelease(destRef); | |
CGColorSpaceRelease(colorSpace); | |
CGContextRelease(destContext); | |
// The destination bytes are no longer needed. | |
free(destData); | |
if (err != kvImageNoError) | |
{ | |
NSString *errorReason = [NSString stringWithFormat:@"vImageScale returned error code %d", err]; | |
NSDictionary *errorInfo = [NSDictionary dictionaryWithObjectsAndKeys: | |
sourceImage, @"sourceImage", | |
[NSValue valueWithCGSize:destSize], @"destSize", | |
nil]; | |
NSException *exception = [NSException exceptionWithName:@"HighQualityImageScalingFailureException" reason:errorReason userInfo:errorInfo]; | |
@throw exception; | |
} | |
} | |
return destImage; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment