I decided to take a break from my normal rock and roll lifestyle (ha!) this evening to get some work done on Cocoalicious, with an eye toward doing a new release sometime next week. Specifically, I’ve been working on integrating and tweaking Eric Blair’s lovely favicon support patch.
In the course of polishing the favicon support, it occurred to me that we could improve performance a lot by pre-sizing the cached version of each favicon on download, instead of always resizing them on display (as it turns out, favicons in the wild come in all kinds of sizes). So I set to work changing the code to do just that, only to run up against a lot of confusion about just how to resize an image using NSImage.
At first glance it seems like the task is fairly straightforward. NSImage has a method called setSize, which the documentation says “sets the width and height of the image.” It seems like one should be able to simply read the data into the image, set its size, get the TIFF representation, and write that to disk.
Not so. As it turns out, setSize() only specifies how the image is displayed when it’s drawn–it does nothing to the underlying data. The most straightforward way to actually resize the data is to create another NSImage with the new size, lock focus on it, draw the source image into the new image, and then get the TIFF representation of the new, scaled image.
This may be obvious to some, but it certainly wasn’t to me, and I had trouble finding illuminating examples or explanations through Google, so I thought I’d post my code here to help anyone else who is similarly befuddled. If anyone has anything interesting to add on the subject, do let us know in the comments…
NSData *sourceData ... // Get your data from a file, URL, etc.
float resizeWidth = 13.0;
float resizeHeight = 13.0;
NSImage *sourceImage = [[NSImage alloc] initWithData: sourceData];
NSImage *resizedImage = [[NSImage alloc] initWithSize: NSMakeSize(resizeWidth, resizeHeight)];
NSSize originalSize = [sourceImage size];
[resizedImage lockFocus];
[sourceImage drawInRect: NSMakeRect(0, 0, resizeWidth, resizeHeight) fromRect: NSMakeRect(0, 0, originalSize.width, originalSize.height) operation: NSCompositeSourceOver fraction: 1.0];
[resizedImage unlockFocus];
NSData *resizedData = [resizedImage TIFFRepresentation];
[sourceImage release];
[resizedImage release];