I was working on NetSketch last night and ran into an interesting problem. To optimize the display of thumbnail images, I decided to cache them at their display size and not at full size (320×380). It worked out really well and led to a huge performance boost at launch. The allocation of memory is so slow on the iPhone that leaving around a bunch of large images just isn’t an option – especially when they all need to be loaded at the same time.
I wrote a convenience function to do the heavy lifting, and I’ve posted the source below. Given a CGImageRef and a desired scale (1.0 being the same), it returns another CGImage of a different scale. Of course, for many scenarios you can just shove the full size image into a UIImage and let UIKit resize the image for you. That approach doesn’t perform anti-aliasing, though – and will give you a slightly more grainy result.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | CGImageRef CreateScaledCGImageFromCGImage(CGImageRef image, float scale) { // Create the bitmap context CGContextRef context = NULL; void * bitmapData; int bitmapByteCount; int bitmapBytesPerRow; // Get image width, height. We'll use the entire image. int width = CGImageGetWidth(image) * scale; int height = CGImageGetHeight(image) * scale; // Declare the number of bytes per row. Each pixel in the bitmap in this // example is represented by 4 bytes; 8 bits each of red, green, blue, and // alpha. bitmapBytesPerRow = (width * 4); bitmapByteCount = (bitmapBytesPerRow * height); // Allocate memory for image data. This is the destination in memory // where any drawing to the bitmap context will be rendered. bitmapData = malloc( bitmapByteCount ); if (bitmapData == NULL) { return nil; } // Create the bitmap context. We want pre-multiplied ARGB, 8-bits // per component. Regardless of what the source image format is // (CMYK, Grayscale, and so on) it will be converted over to the format // specified here by CGBitmapContextCreate. CGColorSpaceRef colorspace = CGImageGetColorSpace(image); context = CGBitmapContextCreate (bitmapData,width,height,8,bitmapBytesPerRow, colorspace,kCGImageAlphaNoneSkipFirst); CGColorSpaceRelease(colorspace); if (context == NULL) // error creating context return nil; // Draw the image to the bitmap context. Once we draw, the memory // allocated for the context for rendering will then contain the // raw image data in the specified color space. CGContextDrawImage(context, CGRectMake(0,0,width, height), image); CGImageRef imgRef = CGBitmapContextCreateImage(context); CGContextRelease(context); free(bitmapData); return imgRef; } |