January 25, 2025

compression

I spent a fair amount of time over the last few days looking at various compression libraries, trying to find a good balance of speed and compression ratio. I looked at general purpose algorithms and ones that are image-data specifific. I considered the idea of using a video compression algorithm because I intend to be able to stream dynamic overlay graphics, like the display on a scope. In the end, I randomly stumbled upon QOI. It seemed to be exactly what I needed, so I decided to try it out.

QOI is “The Quite OK Image Format for Fast, Lossless Compression.” First of all, I am enamored by the acronym and the way it deflates to a name with many more initials (like compression, get it?). But more importantly, it is lossless and the benchmarks show it to be quite fast. It is criticised as an actually useful image format because it doesn’t encode color space and such, but all I need is an array of RGBA pixels encoded, and that’s exactly what it excels at. It’s also a teeny tiny single-header library, and I always consider that a plus.

a table of file compression benchmarks, showing libpng to be the slowest and qoi the fastest in these tests

here seen excelling at ui-y stuff

In testing it out, I also discover that it works very well with the kind of images I’m most likely to be encoding, because module UI is usually a lot of flat color (Rack doesn’t even really support SVG gradients). Because of one aspect of the compression strategy (the full spec can be found here as a single-sheet pdf), those blocks of flat color collapse into a single value and a count of how many pixels in a row match. In addition, the way it keeps a running record of the previous 64 pixels and references them instead of storing new data works well with the limited color pallette of most modules, too. It seems ideal for my purposes.

So, let’s hook it up.

Much faster!

That’s 50,488 bytes (49k, 6.15% the size of the original!) in 46 chunks (vs 744), round trip in 709ms. Much better. For the panel graphics and occasional overlay updates for modules that don't change much, this is already pretty workable. But can I improve the performance enough to stream the overlay graphics at a reasonable framerate?

RTP works over UDP using the same packet size, maybe I can find some inspiration by looking into how it works. Or maybe I just end up learning how to use RTP. I have some ideas related to streaming audio as well.