[WIP] 1-bit Image Compressor for Arduboy


I have just finished the first public beta version (0.9) of the encoder to compress 1-bit images, also there is a library to draw these compressed images. Here is a zip with the readme, encoder, lib and samples:

Moblynx image compressor(beta 0.9)

- Features:

  • Compressor supports JPG, PNG, GIF (also animated gifs)
  • Better image compression (10-20% less size than Cabi)
  • Fast drawCompressed method (20-30 ms to draw 128x64pix images) -> 30-50 fps
  • Allows image mirroring (horizontal and vertical with no performance penalty) and image alignment
  • Experimental drawCompressedResized method (2-3x slower than drawCompressed) but can be useful to do some realtime stuff.

I will publish the code (java) of the encoder in a few days (I need to clean a lot of things).
Anyway, I will keep working a bit more in this lib to release a final version.

Please, give me feedback or ideas to improve the lib. Also I will help anyone who want to integrate this into their games. Thanks a lot!

I did a demo game to test the performance of the library, I think you can do great things with it on your Arduboys… :wink:


Just curious, how large is you decompress code in bytes? Can’t wait to get my hands on!

1 Like

The drawCompressed method could be between 500-1100 bytes, it depends of the parameters used on the skectch, the compiler can remove automatically part of the code if not used or optimize code if some conditions are happening.

I will work this days on optimizing more the code. I hope to make the library more configurable according to the needs of the game (fast draws, small code size, mirrored draws,…).
I’m sure I can improve the lib more but I need that devs give me feedback and ideas. :slight_smile:


That’s crazy! I can’t wait to tinker with this!

1 Like

Some time ago I published a game called Fatsche. It is also using compression. I am no expert on this topic but I helped me at that time to squeeze all the graphics into the memory. As far as I remember horizontal mirrorring was also part of it.
If you want you can check it out. It is by far not as versatile as yours or the TeamARG code but maybe worth a look.

Btw, nice game!


Hi @veritazz ,

Thanks for the info. I have checked your compression algorithm and works really well. I have tested 2 images of your game and your results are only a bit worse:
main_screen: 585 bytes (601 bytes)
help_screen: 524 bytes (530 bytes)

Anyway, maybe I can take some ideas of your algorithm and improve even more my compressor. Thanks again for your feedback! :wink:

1 Like

Oh wow I am really excited to see where you get. Actually I think my decompression is not as efficient as yours in terms of code size and speed. Maybe I will give your code a try in my next game. Looks very promising! :smile:


Cool. How does it compare to TEAMarg’s drawCompress implementation ( https://github.com/TEAMarg/drawCompressed )? (in terms of speed of drawing, and compression amount) (this is the same as the one included in arduboy2 as drawCompressed, IIRC)

1 Like

Hi, I have tested with some images and I can see an improvement of between 10-20% of the size. Speed is ~50% faster right now (even with mirror options). But best thing is that you test it and give me feedback about your results. This would really help me to keep working on this lib. :wink:

Now, I’m improving a lot the speed and size code of the “resized draw” of the images. The actual code is unnecessarily too complex. Also, I could include a faster draw & drawResized methods (with mirroring options) for uncompressed images (a good idea of @JO3RI) :sunglasses:

1 Like

@igvina I remember now that our version of drawCompress was made for images WITH masking.
Could you test an image with a mask and see how the separate and total ratio is for an image with a mask compared with your library?

I see that Cabi also compress the mask, but I didn’t find the drawCompress method with mask support.
Is this the correct link?


@igvina You have to draw twice … old way . first mask, than the image

ok, do you have a reference PNG for test? I think that mask should compress in a similar way on both compressors. I will test both with the team arg logo png and I will give you feedback about size & draw times.

Yeah, mmmm a reference image, that would be a good idea, because we both know compression depends on:

  • size
  • simplicity or complexity of the image
  • repetition of image parts
  • clutter

I would suggest some images of blob attack + the games splash screen, because that is the game we’ve used the compression for?



1 Like

Thanks for the PNGs @JO3RI.
I have tested 2 images:

splashScreen.png (with no mask):

  • size: (815b vs 663b) -> 0,81%
  • draw time: (52ms vs 32ms)

elfPauseWand.png (with mask):

  • size: (234b(164+70) vs 194b(136+58)) -> 0,82%
  • draw time: (17ms vs 12ms)

Also, I have tested my recoded “drawCompressedResized” function with splashScreen.png and worst result (0.99x resize) is about 60ms, not bad for a doing cool realtime stuff.
Anyway, I keep working on improving this and also I hope to release an early preview of the Voice lib. I’m trying that it can work at the same time as “4 channel Music”, but I have problems configuring a different timer (only working ok on Timer4). :cry:

*** UPDATED ***
I have created the same mirror/resize methods for uncompressed bitmaps and these are the results:

Draw time of splashScreen.png (with no mask):

  • No mirror: 1ms
  • Mirror horizontal and vertical: 3 ms
  • Resized (worst case): 30 ms
1 Like

I am using the TeamARG tool to compress images. What is the Mask it produces? I cannot see how the drawCompressed function can use this? I would love a drawCompressedWithMask() function!

The mask is for use with functions in the Sprites class.

Thanks @MLXXXp … but how does it work. Below is a sample image that has produced a mask. The image is compressed and it looks like the mask is as well. Which functions in the Sprite class accept compressed images?

const uint8_t PROGMEM samplef[] = {
// bytes:104 ratio: 0.354

const uint8_t PROGMEM sample_mask[] = {
// bytes:5 ratio: 0.017
1 Like

None. Perhaps Team A.R.G. has enhanced their tool for new functions that they’re using in Arduventure?

Another possibility is that you call drawCompressed() twice; once with the mask as the bitmap and then again with the bitmap itself, both at the same X/Y location. You could wrap the two calls into your own function (call it drawCompressedWithMask() if you like) that accepts both the bitmap and mask as arguments.

1 Like