How to create square thumbnails using iPhone SDK / CG Quartz 2D

Today I wrote a useful Objective-C method which uses Quartz 2D from the iPhone SDK to dynamically generate square thumbnails from any portfolio or landscape UIImage. I failed to find helpful results on Google for the various CGContextClipToRect/CGContextTranslateCTM/CGContextScaleCTM Quartz functions so after a lot of trial and error I managed to get the results I was after with a fairly efficient script – shown below.

So, if for example you want to get a 32×32 pixel square thumbnail, you can pass 32 as the ‘length’ parameter in the function below. For portfolio images the code will take a full square from the original image from the centre using the full width of your original portfolio image. Likewise, for a landscape image the script will use all the height available, clipping the right and left sides.

I think the most import thing I learned when writing this script is that when you call UIGraphicsBeginImageContext(CGSize) make sure that the size you pass in is the size you want your final image to be. Otherwise you end up having to call UIGraphicsEndImageContext() and UIGraphicsBeginImageContext() multiple times with different CGSize instances which I’m sure isn’t an optimised way to achieve the same results.

– (UIImage *)thumbWithSideOfLength:(float)length {

NSString *subdir = @”my/images/directory”;
NSString *filename = @”myOriginalImage.png”;
NSString *fullPathToThumbImage = [subdir stringByAppendingPathComponent:[NSString stringWithFormat:@”%dx%d%@”,(int) length, (int) length,filename];
NSString *fullPathToMainImage = [subdir stringByAppendingPathComponent:filename];

UIImage *thumbnail;

NSFileManager *fileManager = [NSFileManager defaultManager];

if ([fileManager fileExistsAtPath:fullPathToThumbImage] == YES) {
thumbnail = [UIImage imageWithContentsOfFile:fullPathToThumbImage];

}
else {
//couldn’t find a previously created thumb image so create one first…
UIImage *mainImage = [UIImage imageWithContentsOfFile:fullPathToMainImage];

UIImageView *mainImageView = [[UIImageView alloc] initWithImage:mainImage];

BOOL widthGreaterThanHeight = (mainImage.size.width > mainImage.size.height);
float sideFull = (widthGreaterThanHeight) ? mainImage.size.height : mainImage.size.width;

CGRect clippedRect = CGRectMake(0, 0, sideFull, sideFull);

//creating a square context the size of the final image which we will then
// manipulate and transform before drawing in the original image
UIGraphicsBeginImageContext(CGSizeMake(length, length));
CGContextRef currentContext = UIGraphicsGetCurrentContext();

CGContextClipToRect( currentContext, clippedRect);

CGFloat scaleFactor = length/sideFull;

if (widthGreaterThanHeight) {
//a landscape image – make context shift the original image to the left when drawn into the context
CGContextTranslateCTM(currentContext, -((mainImage.size.width – sideFull) / 2) * scaleFactor, 0);

}
else {
//a portfolio image – make context shift the original image upwards when drawn into the context
CGContextTranslateCTM(currentContext, 0, -((mainImage.size.height – sideFull) / 2) * scaleFactor);

}
//this will automatically scale any CGImage down/up to the required thumbnail side (length) when the CGImage gets drawn into the context on the next line of code
CGContextScaleCTM(currentContext, scaleFactor, scaleFactor);

[mainImageView.layer renderInContext:currentContext];

thumbnail = UIGraphicsGetImageFromCurrentImageContext();

UIGraphicsEndImageContext();
NSData *imageData = UIImagePNGRepresentation(thumbnail);

[imageData writeToFile:fullPathToThumbImage atomically:YES];

thumbnail = [UIImage imageWithContentsOfFile:fullPathToThumbImage];
}
return thumbnail;
}

So if, for example your original image looked like this:

finn

Using the method above you could request a 100×100 pixel thumbnail which would result in this:

finn_thumb

Get Lippy!: iPhone Application

Get Lippy! is a fun entertainment Application that I built for the iPhone earlier this year (2009).

This silly iPhone App automatically records when users talk into the microphone. Then it trims the sound input and plays back the speech either like a Chipmonk or Barry White: the App enables you to control the pitch adjustment.

You can choose pictures from your iPhone library or take your own on the fly and then select from 4 comic talking mouths that you can resize/reposition to overlay your photos. When the app plays back a recording it animates the lips fast or slow depending on the pitch as it detects audio levels.

New functionality in version 1.1 includes the ability for users to submit their animated recordings to the Get Lippy Gallery and send them to their mates.

www.getlippy.net

Download Get Lippy! from the App Store

Update (4th October 09): Recently I was chosen as one of the 3 minute wonders to speak at Flash on the Beach ’09 conference. My presentation was about the iPhone Development Workflow from a Flash Developer’s perspective. You can see the video and a few more details here.

Getting 0,0 for multiple touches on iPhone?

It’s taken a while for me to discover the simple solution as to why one of my 2 UITouch objects when grabbing the allTouches set from the iPhone SDK touchesMoved event always resulted in 0,0 co-ordinates in my view…

NSSet *allTouches = [event allTouches];

Solution: you need to switch on the multipleTouchEnabled property of the view you want to get multiple touch events from!! ie:

[self.view setMultipleTouchEnabled:YES];

Hope this post helps others…

iPhone Development: initial thoughts and suggestions

I’ve recently started work developing a new iPhone Application and have found it fairly straight forward to get up and running with Xcode, Objective-C and the iPhone SDK. I thought I’d share some of my initial experiences and recommendations to other Developers to get up and running with iPhone Development:

If, like me, you’re already comfortable with Object Oriented Programming and MVC patterns then the first thing I’d suggest you read is Apple’s Object-C Primer page here:

http://developer.apple.com/iphone/gettingstarted/docs/objectivecprimer.action

(You may need to create a free developer login with Apple first to read this)

This page is enough to get you up to speed with the basic Object-C syntax – how instance and static methods are written, how each class need a m and a h (header, like an Interface file in Flex).

Download Apple’s examples

The iPhone Dev Center contains a whole bunch over very useful examples that make it very quick work to get up and running building iPhone apps that make use of the components that come bundled with the iPhone SDK. These are the ones I found most helpful for my table/ tab navigator type application:

TableViewSuite – I initially downloaded this example and found it a good starting point for understanding tables and how to create data providers/sources and table delegates.

The Elements – This has been the most useful example I’ve downloaded and used so far. I’ve used this as a base for how I’ve developed my own application. It doesn’t use a single xib/nib file and to be honest I found the whole Interface Builder development made things more confusing than they needed to be. If you don’t like Interface Builder and you want to learn how to build a Table based app without it this is the example you need!

I’m loving this iPhone Development. Might have to start reselling myself as an iPhone Developer 🙂