Wednesday, April 08, 2009

Extract UIKit artwork

While writing an iPhone application (more about it on this blog soon), I wanted to tint my UIAlertView with the same color I tinted my other controls. Maybe this is not a good idea, but I wanted to try anyway. Unfortunately, only UISearchBar, UISegmentedControl, UINavigationBar and UIToolbar have the tintColor property. So I started digging into UIKit. The first place to look was obviously the -(void)[UIAlertView(Private) drawRect:] method. To draw its background, a UIAlertView calls _popupAlertBackground which in turn call _UIImageWithName(@"UIPopupAlertSheetBackground.png"). This file probably lies inside the UIKit.framework would think a Mac developer. In fact it is not there. Only two pngs are there: DefaultWallpaper-iPhone.png and DefaultWallpaper-iPod.png. So, where is it?

It is in fact somehow embedded in the Other.artwork file which contains UIKit artwork. This file is memory mapped at application startup, probably for performance reasons and the content is easily accessed with the private _UIImageWithName() function. _UIImageWithName looks up in a dictionary that associates a file name to some memory location that contains the actual image data.

Now, it would be cool to extract all this content to see what artwork UIKit contains. It turns out to be quite easy. The only trick is to find a reference to the dictionary containing all the file names. Check my UIKit Artwork Extractor project on github to see how it works.

In an attempt to encourage comments, I'm offering a beer at NSConference to the first person who will clearly explain how to find the magic address of the images dictionary (except for Nicolas who knows the answer already) and I'm offering two beers to the one who provides a cleaner way to obtain a reference to the dictionary that is not UIKit version specific ;-)

Edit: I have updated the code so that it is not UIKit version specific, so I won the beers myself that I'm going to drink right away.

20 comments:

nst said...

The dictionary address is 0x31a2dd70 in SDK 3.0 b2.

Anonymous said...

Thanks! This saved me a whole bunch of arsing around with photoshop recreating images that are already there on the phone.

All I wanted to do was use UITabBarItems with the system graphics and my own label :/

BeSweeet said...

So you haven't found a way to actually extract the files from within UIKit into their individual PNG files? I need to figure out how Winterboard does it...

Cédric Luthi said...

1. I did find a way to actually extract individual PNG files, read the blog post once again and follow the UIKit Artwork Extractor link.

2. http://svn.saurik.com/repos/menes/trunk/winterboard/

Anonymous said...

I am trying to extract the iPhone 4 Shared.artwork so that I can retrieve some of the @2x files. I checked out your UIKit-Artwork-Extractor link but I am lost as to how it works! Do I have to have an iPhone SDK and then compile it myself or something? Is there an already compiled app that you have available so I can install it on my phone? Please advise, Thanks!

Cédric Luthi said...

Yes, you must have the iPhone SDK installed and compile it yourself. There is no compiled binary.

Anonymous said...

Alright well I guess I will research on how to do all that. In the mean time would you happen to know of a source who has the iPhone 4 Shared.artwork extracted? Or if it wouldn't be too much trouble would you mind extracting it for me and emailing me the link to xenonkilla@yahoo.com

I would appreciate it if you can. Probably save me hours of trouble and hassle of getting a SDK just to compile your app and extract that file. Thanks!

Anonymous said...

can some one please do a quick tut on how to compile this? i tried every way i know but failed.

Anonymous said...

Can someone compile this for the ipad?

Joe said...

To get the 2x quality images on the iPhone 4, you have to run the app on your device (the Simulator doesn't appear to have the hi-res images built-in). I found that replacing the saveImage: method in ArtworkViewController.m to have it save an image to your Photo Library saved a lot of time in extracting single images. I wouldn't try extracting them all at once though... Here's the code I used:


- (void) saveImage:(NSDictionary *)imageInfo
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
UIImage *image = [imageInfo objectForKey:@"image"];
#if TARGET_IPHONE_SIMULATOR
AppDelegate *appDelegate = [UIApplication sharedApplication].delegate;
NSString *imageName = [imageInfo objectForKey:@"name"];
NSString *bundleName = [[imageInfo objectForKey:@"bundleName"] stringByReplacingOccurrencesOfString:@"." withString:@" "];
NSString *imagePath = [[appDelegate saveDirectory:bundleName] stringByAppendingPathComponent:pathWithScale(imageName, [image scale])];
[UIImagePNGRepresentation(image) writeToFile:imagePath atomically:YES];
[self performSelectorOnMainThread:@selector(incrementSaveCounter) withObject:nil waitUntilDone:YES];
#else
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);
#endif
[pool drain];
}

Cédric Luthi said...

@Joe You can extract @2x images in the iPhone simulator. I have updated the README with instructions.

Diziet said...

Holy cow thank you for this. Now I just need to figure out how the hell the delete button with an image works in the mail.app and replicate that! Or wedge tabbar icons with badges into toolbars... :P

neowinston said...

Great! Thanks a lot for your work that saved a LOT of time!

Anonymous said...

I think you're pretty cute =D, however you're not gay :(.

skantner said...

This code is absolutely awesome! Thank you!

Agos said...

Thank you, this code saved me hours of painful image editing. *hug*

puls200 said...

I just came across this tool. Excellent job, congratulations! :-)

4ki1 said...

Hi 0xced,

I used your Artwork extractor tool for iOS 6 beta 4, it worked fine. But I found one artwork file called: languageCache@2x~iphone.artwork.

It located in System --> Library --> PrivateFrameworks --> Preferences.framework.

Would you mind to help to extract this file?

Thanks in advance

Anonymous said...

Hi Cedric, thank you so much,Artwork extractor rocks!
Leo

kl94 said...

Is there a way to extract UIKit Resouces Localized strings (just like you extract UIKit Resouces images) ? I can't find a way to do it. Thanks by advance, good work.