Fixing PNGs

One of my hobbies is poking around in the application bundles of software that I did not write. The extent of my curiosity ranges from aiming to find the identify of an uncredited developer, to disassembling and examining the technical approaches that were taken in the code. But usually I just like to take a quick survey and see if anything catches my interest.

For Mac apps, it’s as easy as control-clicking the application in the Finder and selecting “Show Package Contents.” For iOS apps, it’s a bit tricker, but easy enough when you realize that the “.ipa” files in your Music/iTunes/Mobile Applications folder are actually zip archives and can be easily unpackaged by first changing their names to end in .zip, or by direct command line invocation:

% unzip -d Goodies "MarsEdit Touch.ipa"
% cd "Goodies/PayLoad/MarsEdit Touch.app"

At this point exploration from the Finder or Terminal is similar to browsing a Mac application, except the structure for iOS apps is a little flatter and, blast it all, none of the images are viewable. That seriously dampens my enjoyment of the bundles.

The reason most PNG images in iOS apps are not viewable is because Apple applies special, non-standard optimizations to the images to improve performance on iOS devices. This renders the images useless to all other apps that normally work with PNG files, including the Finder’s Quick Look feature.

Years ago, I discovered a handy tool called iPhonePNG that was assembled by David Watanabe. Essentially, the authors of this tool figured out the optimizations that Apple were doing, and reversed the steps to convert them back into standard PNG images. The tool relied upon a compiled-in version of the libpng library.

Recently when I went to use this tool again, I noticed that it did not work reliably. It dumped lots of memory errors and complained of “extra compressed data” in the input files. I then proceeded to spend too many hours trying to fix it, bashing my head against libpng, before my friend Tom Harrington alerted me to an Xcode-bundled tool that can do the job reliably:

iPhoneOS.platform/Developer/usr/bin/pngcrush

This Apple-modified version of the pngcrush utility accepts a “-revert-iphone-optimizations” option to do exactly the chore I’m looking to have done. But remembering the path to this tool and the long option name was not working for me, so I threw together a handy pair of zsh functions. Now when I’m bundle-surfing and want to peek at an iOS-optimized PNG, it’s easy:

% fixpng ./RedSweater.png
Writing fixed PNG to RedSweater-fixed.png
% open RedSweater-fixed.png

Or if I want to browse a whole folder full:

% fixpngs *.png

If you use zsh, or would like to adapt the functions to your preferred shell, you can download them here. Enjoy!

Updates: I was alerted by Kelvin Owers to an impressive, free tool called ImageOptim. The author argues that his optimization technique for PNGs results in smaller, faster-loading images than Apple’s, while conforming with the PNG standard. I ran some of my PNGs through the tool and it shaved 30-40% off the size. I’m going to strongly consider using this tool, and disabling Apple’s PNG optimization for my projects.

I was also informed by Jordan Breeding and Clark Cox that the “xcrun” command line tool makes a nicer method of invoking the magic Apple-customized pngcrush tool:

% xcrun -sdk iphoneos pngcrush -revert-iphone-optimizations

From the point of view of making the whole bundle-browsing process seamless, Christopher Bowns pointed me to atPeek for examining app bundles, and the associated, free Quick Look plugin for automatically decoding the PNGs.

Thanks for all the useful feedback!