PNG Support

Published on 2022-07-27 in Stage, a Tile and Sprite Engine.

../../../_images/192731658873601053.jpg

When I just started with the Stage library, I used BMP files for the graphics, mostly because they were uncompressed, so it seemed the easiest way. And it was good enough for a prototype, to confirm this is possible. But there are a lot of problems with BMP files, starting with their size, end ending with the fact that there isn’t really any official spec of them, and they have a lot of incompatible variants and versions. So while my code worked fine with images saved with GIMP, it didn’t with those created with other programs. And honestly, forcing people to use GIMP is just too cruel.

So for easier use, I decided to add GIF support. I took some work, as the compression algorithm is pretty tricky, but I got it done in pure Python, and with some restrictions, included it in the Stage library. GIF files are pretty much the same no matter what saves them, so that makes things a little bit easier for everyone. Or so I thought.

Unfortunately, when I looked at how people try to use this library at the recent EuroPython conference, I had to revise my conclusions. You see, for most people GIF is animated format. That means that most sprite-making software, when asked to save as GIF, will create an animation of your sprite’s frames, instead of an atlas. And that is very much not what Stage expects. The fact that you need to have at most 16 colors is also a problem, as many programs will happily add colors to your palette while handling or converting your GIFs, resulting in files that used to work stopping working when you edit them.

So what format should I be using? PNG is the most popular format for static pixel-art in the community, and most tools support exporting atlases of frames to that format. It’s also pretty well specified, so all the tools generate the same format. But the compression algorithm for PNG is even more complicated than for GIF, so what can I do? Turns out that the compression algorithm used by PNG, zlib deflate, is actually built-in into Python! And CircuitPython has an efficient C implementation of it available as a module too! So I don’t have to worry about the compression at all, I just need to handle the file structure, which is even simpler than in GIF.

So today I sat down, read the PNG specification, and wrote the ~50 lines of code needed to load the images. And it works! I even managed to fit the extra code and the zlib module on the PewPew M4 boards (I just had to nudge a bit the Japanese translation). Once the pull request merges, we will be able to use PNG images, and I will try to write a detailed tutorial.

Update: I had to remove the GIF support after all, to make room.