90: Resize an image using CGImage and CGContext Example

Question: how to resize or scale an image from one size to another.


Basic Approach

Create a CGImageSourceRef using the method CGImageSourceCreateWithURL.

Create the CGImage using CGImageSourceCreateImageAtIndex.

Create a CGContext for a bitmap of the desired output size.

Use CGContextDrawImage to draw the CGImage into that context.

Use CGBitmapContextCreateImage to create the output image.

Write the output to file using CGImageDestinationRef methods CGImageDestinationCreateWithURL, CGImageDestinationAddImage and CGImageDestinationFinalize.


Download

This XCode 3.2.6 project exists as a 2.6 MB download.


Coding

Create a new XCode Cocoa application project. Call it CGImageResize.
In the Groups and Files collumn select CGImageResize and click Info.
Under the build tab scroll down to Objective-C-Garbage-Collection and make it Required.
We are going to use a mixed memory management approach.
Make CGImageResizeAppDelegate.h look as follows:

Note: if one uses CGBitmapContextCreate(NULL,.... instead of CGBitmapContextCreate then Quartz will allocate and manage the memory for the bitmap. From the docs In iOS 4.0 and later, and Mac OS X v10.6 and later, you can pass NULL if you want Quartz to allocate memory for the bitmap. This frees you from managing your own memory, which reduces memory leak issues.

// CGImageResizeAppDelegate.h #import @interface CGImageResizeAppDelegate : NSObject { NSWindow *window; void * voidPtrToBitmap; } @property (assign) IBOutlet NSWindow *window; @property (assign) void * voidPtrToBitmap; -(NSURL *)makeNSURLForFilename:(NSString*)pFilename; -(CGContextRef)makeContextOfSize:(CGSize)pSize; @end

Make CGImageResizeAppDelegate.m look like this:

// CGImageResizeAppDelegate.m @import "CGImageResizeAppDelegate.h" @implementation CGImageResizeAppDelegate @synthesize window; @synthesize voidPtrToBitmap; - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { // note: we are running with Garbage Collection enabled // but use memory management for CG objects NSURL * zNSURLInputFile = [self makeNSURLForFilename:@"inputFile.tiff"]; CGImageSourceRef zCgImageSourceRef = CGImageSourceCreateWithURL((CFURLRef)zURLInputFile,NULL); CGImageRef zCgImageInput = CGImageSourceCreateImageAtIndex(zCgImageSourceRef,0,NULL); CFRelease(zCgImageSourceRef); // no longer needed size_t zSiztHalfWidth = CGImageGetWidth(zCgImageInput) / 2; size_t zSiztHalfHeight = CGImageGetHeight(zCgImageInput) / 2; CGSize zCGSizeOutputImage = CGSizeMake(zSiztHalfWidth,zSiztHalfHeight); CGContextRef zContextOutImage = [self makeContextOfSize:zCGSizeOutputImage]; CGRect zRectOutputImage = CGRectMake(0.0,0.0,zSiztHalfWidth,zSiztHalfHeight); CGContextDrawImage (zContextOutImage,zRectOutputImage,zCgImageInput); CGImageRelease (zCgImageInput); // no longer needed CGImageRef zCGImageOutput = CGBitmapContextCreateImage(zContextOutImage); // output the image NSURL * zURLOutputFile = [self makeNSURLForFilename:@"outputFile.tiff"]; CGImageDestinationRef zCGImageDestRef = CGImageDestinationCreateWithURL ( (CFURLRef)zURLOutputFile, kUTTypeTIFF, 1, NULL ); CGImageDestinationAddImage (zCGImageDestRef, zCGImageOutput, NULL ); CGImageDestinationFinalize(zCGImageDestRef); // final memory management CGImageRelease (zCGImageOutput); CGContextRelease(zContextOutImage); CFRelease(zCGImageDestinationRef); } // end applicationDidFinishLaunching -(NSURL *)makeNSURLForFilename:(NSString*)pFilename { NSString * zStrUrl = [NSString stringWithFormat:@"../../../%@",pFilename]; NSURL * zURL = [NSURL fileURLWithPath:zStrUrl]; if(zURL == nil) { NSLog(@"ERROR makeNSURLForFilenameRoot %@",zStrUrl); exit(1); } // end if return zURL; } // end makeNSURLForFilename -(CGContextRef)makeContextOfSize:(CGSize)pSize { NSInteger zIntBitmapBytesPerRow = pSize.width * 4; // rgb alpha NSInteger zIntBitmapTotalBytes = zIntBitmapBytesPerRow * pSize.height; self.voidPtrToBitmap = malloc(zIntBitmapTotalBytes); if (self.voidPtrToBitmap == NULL) { NSLog(@"makeContext error on malloc"); exit(1); } // end if CGContextRef zBitmapContextRef = CGBitmapContextCreate( self.voidPtrToBitmap, pSize.width, pSize.height, 8, zIntBitmapBytesPerRow, CGColorSpaceCreateDeviceRGB(), kCGImageAlphaNoneSkipFirst ); return zBitmapContextRef; } // end makeContextOfSize @end

Build and run.

CGImage before

CGImage after being resized by 50 percent

CGImage before and after a 50 percent resize


Download

This XCode 3.2.6 project exists as a 2.6 MB download.



Please send me your comments

If you include your e-mail I may reply!  

Page last modified: 11:57 Monday 7th. November 2011