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

CGContextRef c = UIGraphicsGetCurrentContext();
UIBezierPath *bp = [UIBezierPath bezierPathWithRoundedRect:imageRect cornerRadius:10.0];
CGPathRef path = [bp CGPath];
CGContextAddPath(c, path);
// 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);


// 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);


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

// Retain the new one
[thumbnail retain];

// Clean up image context resources

// 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];


3 thoughts on “Pretty looking thumbnails in iOS 3.2 with CoreGraphics

  1. Hi,

    Nice work!

    But I was wondering why is the retain necessary at the end of:
    UIBezierPath *bp = [[UIBezierPath bezierPathWithRoundedRect:imageRect cornerRadius:10.0] retain];

    It’s true it doesn’t work without it, but I can’t see why the retain count must be incremented here…


  2. Hi Victor,

    Good catch, the retain is unnecessary because the bezierPathWithRoundedRect:imageRect:cornerRadius call is a convenience function, and should return an autoreleased UIBezierPath object. I’ll update the code to remove that retain call as well as the corresponding release further down. Since I don’t use the path outside of this function, the retain/release is unnecessary, as it will be cleaned up the next time through the run loop. :)


  3. Hi thank you for great piece of code but I am newbie and cannot understand what is :thumbnailData?

Comments are closed.