Pretty looking thumbnails in iOS 3.2 with CoreGraphics

As Beast Boxing 3D wraps up, I’ve been brushing up my iOS SDK chops by working through the Big Nerd Ranch Guide to iPhone Programming, a great book that takes a fundamentals-based approach to learning how to operate well within Apple’s SDKs. In Chapter 16, there’s a cool challenge where they ask you to take a relatively simple method of converting an image to a thumbnail, and make it prettier. I spent some time researching it and ended up with a method I’m pretty satisfied with that uses CoreGraphics clipping paths and gradients to do the job. As I’m working on iPad apps next, iOS 3.2 is my target, so I take advantage of UIBezierPath, an iOS 3.2 addition, in this sample. Without further ado, here’s the code. Enjoy!

- (void)setThumbnailDataFromImage:(UIImage *)image
{
// Release old data
[thumbnailData release];
[thumbnail release];

// Create an empty image of size 70 x 70
CGRect imageRect = CGRectMake(0, 0, 70, 70);
// Create an offscreen graphics context to draw into
UIGraphicsBeginImageContext(imageRect.size);

CGContextRef c = UIGraphicsGetCurrentContext();
UIBezierPath *bp = [UIBezierPath bezierPathWithRoundedRect:imageRect cornerRadius:10.0];
CGPathRef path = [bp CGPath];
CGContextAddPath(c, path);
CGContextClip(c);
// Render the big image onto the image context
[image drawInRect:imageRect];


// Render a glossy gradient on top!
CGGradientRef glossGradient;
CGColorSpaceRef rgbColorSpace;
size_t num_locations = 2;
CGFloat locations[2] = {
 0.0, 1.0
};
CGFloat components[8] = {
 1.0, 1.0, 1.0, 0.85, // Start color
1.0, 1.0, 1.0, 0.05 // End color
};
rgbColorSpace = CGColorSpaceCreateDeviceRGB();
glossGradient = CGGradientCreateWithColorComponents(rgbColorSpace, components, locations, num_locations);

CGPoint topCenter = CGPointMake(CGRectGetMidX(imageRect), 0.0);
CGPoint topQuarterBoundary = CGPointMake(CGRectGetMidX(imageRect), imageRect.size.height * 0.35);

CGContextDrawLinearGradient(c, glossGradient, topCenter, topQuarterBoundary, 0);

CGGradientRelease(glossGradient);


// Render a shadow gradient down low
CGGradientRef shadowGradient;

CGFloat shadowLocations[2] = {
0.0, 1.0
};
CGFloat shadowComponents[8] =  {
0.0, 0.0, 0.0, 0.65, // Start color
0.0, 0.0, 0.0, 0.00 // End color
};
rgbColorSpace = CGColorSpaceCreateDeviceRGB();
shadowGradient = CGGradientCreateWithColorComponents(rgbColorSpace, shadowComponents, shadowLocations, num_locations);

CGPoint bottomCenter = CGPointMake(CGRectGetMidX(imageRect), imageRect.size.height);
CGPoint bottomQuarterBoundary = CGPointMake(CGRectGetMidX(imageRect), imageRect.size.height * 0.85);

CGContextDrawLinearGradient(c, shadowGradient, bottomCenter, bottomQuarterBoundary, 0);

CGGradientRelease(shadowGradient);
CGColorSpaceRelease(rgbColorSpace);


// Make a new one from the image context
thumbnail = UIGraphicsGetImageFromCurrentImageContext();

// Retain the new one
[thumbnail retain];

// Clean up image context resources
UIGraphicsEndImageContext();

// Make a new data object from the image
thumbnailData = UIImageJPEGRepresentation(thumbnail, 0.5);

// You may get malloc warnings on the simulator from this line,
// it is a bug in the simulator

// Retain it
[thumbnailData retain];

}