Using LibPNG To Encode Spooky Eye Data

Sclera array and bitmap

Emily and I thought it would be cool to have the Spooky Eye visualization running on platforms in addition to Teensy and Adafruit SAMD boards. The first target: a Raspberry Pi zero. Reading through the project documentation and source code gave us a good idea how the data is encoded, but the best test is always to make use of that data and see if it turns out as I expected.

This would be a new coding experiment, so a new Github repository was created. I added the header files for various eyeballs then I started looking for ways to use that data. Since the header files are in C, it made sense to look for a C library to do something. I decided to output data to PNG bitmap files. Verifying the output looks correct would be as simple as opening the bitmap in an image viewer.

The canonical reference library for PNG image compression is libpng. Since I expect my use to be fairly mainstream, I skipped over the official documentation that covers all the corner cases a full application would need to consider. In the spirit of a quick hack prototype, I looked for sample code to modify. I found one by Dr. Andrew Greensted that looked simple and amenable to this project.

I fired up my Ubuntu 18.04 WSL and installed gcc and libpng-dev as per instructions. The sample failed to compile at first with this error:

/tmp/ccT3r4xP.o: In function `writeImage':
makePNG.c:(.text+0x36f): undefined reference to `setRGB'
collect2: error: ld returned 1 exit status

Since there were a lot of references to this sample code, I thought this wouldn’t be a new problem. A web search on “makePNG undefined reference to setRGB” sent me to this page on Stackoverflow, which indicated there was a problem with use of C keyword inline. There were two options to get around this problem: either remove inline or use the -Ofast compiler option to bypass some standards compliance. I chose to remove inline.

That was enough to get baseline sample code up and running, and modification begins. The first act is to #include "defaultEye.h" and see if that even compiles… it did not.

In file included from makePNG.c:20:0:
defaultEye.h:4:7: error: unknown type name ‘uint16_t’

Again this was a fairly straightforward fix to #include <stdint.h> which takes care of defining standard integer type uint16_t.

Once everything compiled, the makePNG sample code for generating a fractal was removed, as was the code to translate the fractal’s floating point value into color. The image data was replaced with data from Spooky Eye header files. If all works well, I should have a PNG bitmap. The first few efforts generated odd-looking images because there were bugs in my code to covert Spooky Eyes image array, encoded in 16-bit RGB565 format, to be written out in 24-bit RGB888 format. Once my bitwise manipulation errors were fixed, I had my eyeballs!

Looking Under The Hood Of Adafruit Spooky Eyes

Sclera array and bitmap

Adafruit’s Hallowing was easily the most memorable part of the 2018 Superconference attendee gift bag. Having a little moving blinking eye looking around is far more interesting than a blinking LED. It is so cool, in fact, that Emily has ambition to put the same visual effect on other devices.

Since the Hallowing was one of the headline platforms that supported CircuitPython, the original hope was that it would be very easy to translate to a Raspberry Pi. Sadly, it turns out “Spooky Eyes” is actually a sketch created using Arduino IDE for a Teensy board that also ran on the Hallowing.

As I found out in my own Nyan cat project for Superconference 2018 badge, modern image compression algorithms are a tough fit for small micro controllers. And just as I translated an animated GIF into raw byte data for my project, Spooky Eyes represented their image data in the form of raw bytes in a header file.

Adafruit always has excellent documentation, so of course there’s a page describing what these bytes represent and where they came from for the purposes of letting people create their own eye bitmaps. Apparently this project came from this forum thread. I was a little grumpy the Adafruit page said “from the Github repository” without providing a link, but the forum thread pointed here for the Python script tablegen.py.

There was a chance the source bitmaps would be on Github as well, but I had no luck finding them. They certainly weren’t in the same repository as tablegen.py or the Arduino sketches I examined. Still, the data is there, we just need to figure out what format would be most useful for putting the eye on another project.

As a first step, I’ll try to extract and translate them into a more familiar lossless bitmap format. Something that can be directly usable by more powerful devices like a Raspberry Pi. A successful translation would confirm I understand the eyeball data format correctly, which would be good to know for any future projects that might want to encode that data into different formats as needed for other devices.