Published: November 24, 2021
43
344
1.7k

Lossless Image Compression in O(n) Time — introducing QOI, the Quite OK Image Format. 300 lines of C, single header library: https://phoboslab.org/log/2021...

Image in tweet by Dominic Szablewski

@phoboslab I love new image formats, but the compression ratio of this isn't great. For web-based delivery, we need very small size (webp is the best right now) as well as fast decode. PNG has the slowest decode of all web-compatible images because it is single-threaded. Avoid it always.

@BenHouston3D I agree. QOI is not meant for the web. It's more suitable as a replacement for things like stbi_image in indie games and such.

@phoboslab That's very impressive! Do you think it would be worth experimenting with non-RGB color transforms, especially the reversible ones because of their reduced complexity? Have you looked into chroma subsampling? Have compared it with GFWX? http://www.gfwx.org/

@awakecoding I previously tried YCoCg24 (https://stackoverflow.com/a/12... because it was an easy drop-in my current encoder (all three channels stay at 8bit wide). It helped with some images, but not others. I guess a lossy codec benefits much more from separating the luma channel.

@phoboslab I haven’t read the code, but if it has to refer to runs of previous pixels doesn’t that mean it must backtrack to identify them? In this case wouldn’t it be O(n^2)?

@lichtman_ben That would be correct, but QOI doesn't do that. Instead, it continuously inserts pixels into a "hash table" as it goes through them. See here specifically: #L317-L323 class="text-blue-500 hover:underline" target="_blank" rel="noopener noreferrer">https://github.com/phoboslab/q...

@phoboslab That's impressive! I have a question. If I have a sequence of two alternating colors who happen to have the same hash, they will not be saved as QOI_INDEX, right? The lookup will always return the .v of the previous color which will be different. It's that correct?

@redmagedev Yes, that's right. The new color will overwrite the old one at the same index. I didn't think too deeply about it, but you could probably forge an image that will force QOI to store all pixels as QOI_COLOR, resulting in a larger-than-uncompressed size.

@phoboslab Love your project! I had a similar idea leveraging Zstd a while back: https://github.com/catid/Zpng It also does same-as-left prediction similar to PNG but then uses Zstd instead of deflate to get better performance.

@phoboslab Very cool Dominic! Thanks for sharing this.

@phoboslab Quick! Tell us how it’s pronounced before it’s too late and everybody fights over it 😁

@phoboslab @aras_p The described method gives me vibes of the Amiga HAM mode... Modify a previous pixel, or load all-new-RGB values.

@phoboslab @bkaradzic Split image in macroblocks, like 32x32px or 64x64px and encode each block independently. It can be easily threaded.

@phoboslab Sounds like pcx++ :))

@phoboslab To decode a QOI, users have to know the number of channels. Number of channels could have been stored in the file header easily.

@phoboslab Here's a quick & dirty @rustlang port for whoever wants to toy with it :) https://gist.github.com/ChevyR...

@phoboslab Lovely work! I dabbled a bit into LZMA during a small break, and wrote a decompression library called minlzma on GH. Some of your encoding and tricks are quite similar to how LZMA works (which is not well documented anywhere!) — look into arithmetic coding for smaller sizes!

@phoboslab Turns out .qoi images are quite compressible. You can compress them with deflate to get tight/better results than .png overall (in my tests), or go deeper with lzma (or any other compressor of your choice). Neat! I guess pre-zmorton/hilbert could improve compression a bit even

@phoboslab I hope this format takes off! I was just looking for simple image formats a while ago (Something simple like PPM but with some kind of compression). This is just like what I was looking for. Even BMP (which I thought was supposed to be simple), is full of variants and flags.

@phoboslab @xotmatrix Wow! super fast and SAME compression size as PNG. Now that's something. Get this into every old computer, please.

@phoboslab Good work, don’t let the Old Boys Compression Club get to you.. Optimise a scalar solution, then SSE and then AVX2, and see where you are.. It’s exactly the same in audio land ;)

@phoboslab @richgel999 thought this might be interesting to you

@phoboslab This is a really nice experiment, and although I get the author was just tinkering, it does need to be said that the bloated file formats like PNG do have a lot of nice features (critically, things like gamma/chromaticity/ICC support, which are 100% must-have for an image format)

@phoboslab Amiga HAM6 mode back to life :)

@phoboslab Quite ok work here.

@phoboslab @pipelinec_hdl I imagine a nice conversion to a hardware implementation

@phoboslab I dimly remember early nasa and jpl image compression ? Similar ideas and constraints. The key addition is sending in bit-planes, (and gray coding). Close to a factor of two using RLE as the compressor for bit planes on Poisson distributed data.

@phoboslab Simple and elegant.

Share this thread

Read on Twitter

View original thread

Navigate thread

1/31