PNG Manipulation in Ruby
A few years ago, I was working on a project building an internal App Store for a client. The backend was written using Ruby on Rails. I was giving a demo to some other engineers in the company when I noticed that app icons were failing to load. When I started digging into it I noticed that this only happened in Chrome — Safari loaded and displayed the images just fine.
Knowing a bit about the PNG optimizations Xcode performs, I started looking into the images. Sure enough, the root cause was that the images I was extracting from the
.ipa files as part of the build upload process had their channels swapped. Safari, for whatever reason, knew how to reverse the process; Chrome did not (not that I blame it — good on it for refusing to load random files masquerading as PNGs).
I kicked around several potential approaches for fixing the problem. The most foolproof solution was to use Xcode’s version of
pngcrush to reverse the optimizations (as it would presumably be kept in lockstep with any changes to the iOS SDK). The problem was it would require a server running OS X.
Another option was to use something like ImageMagick to do the work. I don’t exactly recall why I didn’t go that route (Couldn’t do what I need to at the time? Didn’t want to pull in the additional dependency?), but I started to wonder if I could just use Ruby.
Now, I’m not naïve — I know Ruby isn’t known for its performance. This project was very small and wouldn’t be seeing hordes of traffic, so a few extra seconds to process images from an uploaded build was negligible. Beyond the benefits of not adding another dependency, I also wanted to learn about the internals of PNGs.
After several hours of reading the PNG spec and cobbling together a Ruby port of some similar scripts in other languages this is the end result:
Reinventing the wheel is one of my pet peeves, but I have to admit that it was terribly interesting to dive into the PNG spec and learn how these files are structured. I would never use the above script to do serious image manipulation, but it was really rewarding to see a properly-formatted PNG come out the other end and load properly in Chrome. All without leaving Ruby-land.
What have you dug into recently?