From c74438e37776b825b6d27510eee045c87d00182c Mon Sep 17 00:00:00 2001 From: Scott Allen Date: Wed, 8 Jul 2020 10:27:22 -0400 Subject: [PATCH] Rewrite Cabi README.md with more details Also added file sample.png in the cabi directory, which is used for the example sketch in the Cabi README.md file Also added a note referring to Cabi in the documentation for drawCompressed() --- extras/cabi/README.md | 254 +++++++++++++++++++++++++++++++---------- extras/cabi/sample.png | Bin 0 -> 280 bytes src/Arduboy2.h | 15 ++- 3 files changed, 201 insertions(+), 68 deletions(-) create mode 100644 extras/cabi/sample.png diff --git a/extras/cabi/README.md b/extras/cabi/README.md index f7e83fb..b6b8462 100644 --- a/extras/cabi/README.md +++ b/extras/cabi/README.md @@ -1,75 +1,203 @@ -# Cabi -Arduboy encoder: -Monochrome rle encoding by [Zep @lexaloffle](https://twitter.com/lexaloffle) +# Cabi - Compress Arduboy Image -This tool is used for creating a compressed array from an image (png) +A command line program to read a PNG (Portable Network Graphics) file +containing a bitmap image, compress it using RLE encoding and convert it to +C/C++ code suitable for use with the Team A.R.G. *drawCompressed()* function. +This function is included in the Arduboy2 library. -The function to decompress in Arduino (Arduboy) can be found here: +Written by zep -https://github.com/TEAMarg/drawCompressed +https://www.lexaloffle.com/bbs/?uid=1 -to build: -```Bash -gcc cabi.c lodepng/lodepng.c -o cabi +https://twitter.com/lexaloffle + +Contributed to Team A.R.G. + +This program uses code from the LodePNG project by Lode Vandevenne to read +and decode PNG files. + +https://github.com/lvandeve/lodepng + +This version of Cabi is maintained as part of the Arduboy2 library so that it +remains available since the demise of Team A.R.G. + +## Building the program + +Pre-built executable code is not provided due to the difficulty of maintaining +versions for all the many operating systems that it could be run on. + +The code is written in C and should compile properly using any ANSI C99 +compatible compiler, such as (but not limited to) gcc or clang. + +### Build examples + +To build from a copy of the cabi directory tree provided, while in the base +directory containing cabi.c use: + +`gcc cabi.c lodepng/lodepng.c -o cabi` + +or + +`clang cabi.c lodepng/lodepng.c -o cabi` + + +For Windows, it may be more desirable to name the program `CABI.EXE` by using: + +`-o CABI.EXE` + +Compiler options for optimization, etc. (such as -O2 or -Os) can be added if +desired but likely won't make much difference for most uses. + +## Usage + +The binary executable file (cabi or CABI.EXE) should be placed somewhere in the +path for executables on the operating system used, or else include the path as +part of the command given. + +Running Cabi without any parameters will just output a brief program +description and the usage syntax: + +```text +cabi - Compress Arduboy Image +Convert a PNG file into RLE encoded C/C++ source +for use with Arduboy2 drawCompressed() + +usage: cabi in.png [array_name_prefix] ``` -to use: -```Bash -cabi input_file.png [array_name_prefix] -``` +For `in.png` substitute the name of the PNG file to be converted. If the file +isn't in the current directory, the full path and name can be specified. -Look at the compress ratio, before using the compressed data, it might be worse in some cases (above 1 is bad) +For `[array_name_prefix]` an optional prefix for the names of the arrays created +can be given. If this parameter isn't provided, `compressed_image` will be used +for the prefix. -ouput: -```C++ -// input_file.png width: 128 height: 48 -const uint8_t PROGMEM array_name_prefix[] = { - 0x7f,0x2f,0x30,0x68,0xb7,0xdb,0xed,0xdb,0x53,0x9f,0xfa,0x73,0x97,0xbb,0xd5,0xe7, - 0x2e,0x77,0xb9,0xcb,0x5d,0x6e,0xbb,0xbd,0xdc,0xe5,0x2e,0x77,0xb9,0xcb,0x5d,0xee, - 0x72,0x97,0x5b,0x2b,0xbb,0xdc,0x6e,0xb7,0xdb,0xed,0x76,0xbb,0xdd,0x6e,0xb7,0xdb, - 0xed,0x76,0xbb,0xdd,0x6e,0xb7,0xca,0xae,0x43,0x57,0x76,0xbb,0x5d,0x6e,0xb7,0xdb, - 0xed,0x76,0xbb,0xdd,0x6e,0xb7,0xdb,0xad,0xb2,0xdb,0x75,0xd8,0x5a,0x2a,0xb9,0xdd, - 0x6e,0xb7,0xeb,0x75,0x74,0xd9,0xe5,0x72,0xf9,0xfd,0xdf,0xea,0x72,0x57,0x77,0x75, - 0x97,0x3b,0x6d,0x95,0x93,0xca,0x2a,0xbb,0x0e,0xbf,0x6d,0x6f,0x75,0xab,0xed,0xb9, - 0x5c,0x77,0x2a,0xcf,0x9f,0x76,0xda,0xd5,0xad,0x4e,0xf7,0xaa,0x57,0xe9,0x74,0x3a, - 0x9d,0xbb,0xa4,0xc2,0xd1,0x76,0xb6,0xb4,0xd3,0x2e,0x9f,0x5e,0x5a,0x85,0xbc,0x74, - 0x3a,0x9d,0x4e,0xa7,0x3b,0x67,0x57,0x5b,0xaf,0x93,0x4a,0xb9,0x9d,0x52,0xca,0x2d, - 0x97,0xdb,0x74,0x6c,0x49,0xe5,0x9c,0x92,0x4a,0x2a,0xa9,0xa4,0x53,0x84,0xe9,0xf4, - 0xea,0x53,0xbf,0x56,0x2a,0x65,0xed,0x6e,0xa7,0x94,0x52,0x4a,0x46,0x9f,0x5e,0xaf, - 0x97,0xcb,0x6d,0xbc,0x4b,0xe7,0x5c,0xff,0x13,0x7a,0x9f,0xde,0xce,0xbe,0xd6,0xb9, - 0xee,0xd4,0xae,0x3b,0xb5,0x6e,0x7b,0xab,0x5b,0x8d,0x24,0x25,0x4b,0x29,0x95,0x4a, - 0x76,0x56,0x3a,0x1d,0xdb,0xce,0xcd,0x96,0x4e,0xa7,0xd3,0xe9,0xec,0x4e,0x4a,0xe9, - 0xec,0x08,0xdb,0x3a,0x67,0xe7,0x52,0xb3,0x29,0x2d,0xf5,0xa8,0x4b,0xa7,0xd3,0xe9, - 0x74,0xce,0xb9,0x5b,0x2f,0xdd,0x6a,0x87,0xac,0xa4,0x2a,0x25,0x95,0x54,0x52,0x49, - 0x25,0xed,0x36,0xa4,0xed,0xdc,0x64,0x49,0xa5,0x64,0xc8,0x5a,0x2a,0x1d,0xda,0xc2, - 0x1b,0x11,0x06,0xb9,0x2a,0x95,0x4c,0x55,0x2a,0xa2,0xc6,0xd5,0xea,0x56,0xb7,0xdd, - 0x6e,0xb7,0x4a,0x4a,0x55,0xa5,0x2a,0x95,0x52,0x2a,0x55,0xc9,0x54,0xaa,0x92,0xa9, - 0x54,0x25,0x53,0x29,0xa5,0xdd,0xf4,0x69,0x25,0xa5,0x54,0xed,0x5c,0xe7,0x3a,0xe7, - 0x9c,0x73,0x4a,0x2a,0x3b,0x15,0x51,0x52,0xf1,0x79,0xa5,0xd3,0x49,0x25,0x95,0xdc, - 0x6e,0xb7,0xdb,0xed,0x36,0x9d,0xce,0x6e,0xff,0xff,0xd3,0xa7,0x75,0x3a,0x1d,0xd9, - 0xce,0x39,0xe7,0x1c,0xd3,0xce,0x39,0xe7,0x9c,0xeb,0x5c,0xe7,0x9c,0x73,0x6e,0xf2, - 0xa4,0x54,0x52,0x2a,0xbb,0xdd,0x6e,0x2f,0xad,0xb4,0xd2,0xf9,0xb4,0x72,0x4e,0x6e, - 0x63,0x95,0xce,0x39,0xa9,0x3e,0xf5,0x6f,0x8f,0x08,0x87,0x64,0xc9,0x54,0x32,0xa2, - 0xb6,0xdb,0xed,0xea,0x56,0xb7,0x3d,0x9d,0x4e,0xa7,0x5b,0x5d,0x77,0x4a,0xb9,0xfe, - 0xa7,0x4a,0xd6,0xd2,0x29,0xd5,0x5d,0xab,0x63,0xeb,0x55,0xaf,0xf2,0x4a,0x72,0xef, - 0xdc,0x76,0xbb,0x5d,0x6e,0xb7,0x4a,0x2a,0xe7,0x56,0x3b,0x19,0xd1,0x76,0x2e,0x65, - 0xb7,0xdb,0xd5,0xbd,0xea,0x5c,0xe7,0x3a,0x9d,0xdd,0x6e,0xb7,0x5b,0x25,0x9d,0xb3, - 0xe9,0x94,0x54,0x52,0x49,0x25,0x95,0x54,0xaa,0x94,0x2a,0x25,0x95,0x54,0xd2,0x59, - 0x75,0xdb,0xed,0xae,0x5e,0x75,0xae,0x73,0x9d,0xeb,0xd4,0xa7,0x3e,0xf5,0xb9,0xda, - 0xee,0xa4,0xb4,0xca,0x6e,0xb7,0xdb,0xad,0x73,0xee,0xda,0x39,0xbb,0xba,0xb7,0x53, - 0x25,0x95,0xdc,0x2e,0x95,0x53,0xf6,0x72,0x97,0x93,0x4a,0x3a,0xa9,0xa4,0x3a,0xa5, - 0x7a,0x95,0xfa,0x5c,0xa7,0xd3,0x69,0xae,0xed,0x2a,0xa9,0x64,0x25,0x95,0x4e,0xa7, - 0xd3,0xe9,0xd0,0x97,0x5e,0x67,0xb7,0xa1,0x69,0x9d,0x1d,0xcb,0xe9,0xed,0x36,0x34, - 0xea,0x74,0x3a,0x9d,0x56,0x4a,0x2a,0xa9,0x94,0x4e,0xa7,0x53,0x44,0x4a,0x56,0xa9, - 0xaa,0x54,0x2a,0x25,0x75,0x5a,0x6d,0x95,0x74,0xeb,0x74,0xe7,0x8a,0x4a,0xc9,0x2a, - 0x55,0x95,0x4a,0xa5,0xa4,0x56,0xd2,0x39,0xe7,0xb6,0xdb,0xed,0xf6,0xed,0x29,0x59, - 0xc9,0x4a,0x2a,0xe2,0x74,0xb4,0xe9,0xd0,0xb5,0xce,0x8e,0xfd,0x74,0x3a,0xb4,0x01 +If the program is unable to produce proper output, an error message will be +given and a non-zero exit code will be returned. + +## Input file decoding + +The input file should be a PNG file containing the image to be converted. The +image will be translated to a raw array of 32 bit RGBA (Red, Green, Blue, Alpha) +pixels internally before being processed to output. Ideally, pixels that are to +be drawn (represented as a 1 in the image output) should be fully white. +Non-drawn (0) pixels should be fully black. Pixels intended to be masked out of +the image (represented as a 0 in both the image and mask output), should be +fully transparent and their color doesn't matter. + +However, after translation to RGBA, any pixel with an alpha (opaqueness) value +of 127 or less will be set as non-drawn (0) for both the image and the mask. +For the image, after the alpha value is first taken into account, pixels with a +red color value greater than 127 will be set as drawn (1) and others will be +set as non-drawn (0). For the mask, only the alpha value is used and red is +ignored. Green and blue color values are ignored for both image and mask. + +### To summarize: + +For the image: + +Green and blue are ignored. + +| Alpha | Red | Output | +|:------:|:-------:|:------:| +| <= 127 | <= 127 | 0 | +| <= 127 | > 127 | 0 | +| > 127 | <= 127 | 0 | +| > 127 | > 127 | 1 | + +For the mask: + +Red, green and blue are ignored. + +| Alpha | Output | +|:------:|:------:| +| <= 127 | 0 | +| > 127 | 1 | + +## Output + +Cabi will send all output to `stdout`, which is usually the console unless +redirected. To save the output, you may be able to copy and paste it into your +editor, or you can redirect `stdout` to a file for importing. For example: + +`cabi PlayerSprite.png PlayerSprite > PlayerSprite.out` + +If conversion is successful, the output will be text representing C/C++ code +for two arrays, an image and a mask, that can be included in a sketch for use +by the *drawCompressed()* function. The image array will be named the same as +the prefix. The mask name will be the prefix with `_mask` appended to it. + +Along with the actual array text, a comment will be included before each array +giving the input file name used and the dimensions of the image. A comment +included after each array will give the size of the array and the compression +ratio compared to the non-compressed equivalent (although the ratio is based +on the compressed array including two bytes for the bitmap dimensions compared +to a non-compressed array without bitmap dimensions). + +Note that it's possible that the "compressed" array will actually end up +larger than the equivalent non-compressed one would. This is indicated by +a compression ratio greater than 1. The ratio should be noted and taken into +account when determining whether using Cabi compressed bitmaps is suitable for +the intended purpose. + +If masking isn't required, the mask array can be ignored or deleted. + +Note that the usage message or any error message will also be sent to `stdout`, +rather than `stderr`. Therefore, if you redirect the output to a file, in this +case the file will contain only that text. + +## Using the output with *drawCompressed()* + +The Arduboy2 *drawCompressed()* function doesn't natively handle a mask for +"transparent" pixels in an image. However, masking can be accomplished by +calling *drawCompressed()* twice with the same coordinates. The first call +specifies the mask array and the color BLACK. The second call specifies the +image array and the color WHITE. + +An example PNG bitmap named `sample.png` is included with the program. Here is +an example Arduboy sketch that draws this bitmap with masking, using the Cabi +output imported into the sketch. + +```cpp +#include + +Arduboy2 arduboy; + +// ===== Cabi output ===== +// sample.png width: 32 height: 32 +const PROGMEM uint8_t sample[] = { +0x1f,0x1f,0x68,0x93,0xca,0x39,0xe5,0x9c,0x72,0xca,0xe9,0x74,0x4b,0x25,0x95,0xdc, +0x6e,0xb7,0xdb,0xed,0x56,0x49,0x65,0xb7,0x4a,0x3a,0xa9,0xac,0x92,0x4e,0x3a,0xa9, +0x74,0x94,0x8c,0x6a,0xbb,0xdd,0x6e,0xb7,0x8c,0x76,0xbb,0xdd,0x6e,0xb7,0xdb,0xed, +0x76,0xbb,0xdd,0xf2,0xf1,0xa6,0xb7,0x52,0x79,0xc5,0xa4,0xbc,0x92,0x76,0x1d,0x2f, +0x9f,0xdd,0x6e,0xb7,0xdb,0xed,0x76,0xbb,0xdd,0x6e,0xb7,0x8c,0xf4,0xd9,0x15,0x23, +0x65,0x5a,0x49,0x27,0x9d,0x54,0x56,0x49,0x27,0x95,0xdd,0x2a,0xa9,0xec,0x76,0xbb, +0xdd,0x6e,0x97,0x4a,0x2a,0xb9,0x54,0xce,0x39,0xe5,0x94,0x73,0xca,0x39,0x25,0xa3, +0x05 }; -// bytes:640 ratio: 0.833 +// bytes:113 ratio: 0.883 - -const uint8_t PROGMEM array_name_prefix_mask[] = { - 0x7f,0x2f,0x81,0xff,0x17 +const PROGMEM uint8_t sample_mask[] = { +0x1f,0x1f,0x68,0x93,0xca,0x39,0x25,0x95,0xdc,0xa6,0xd3,0xa1,0x35,0x9d,0x4e,0x6f, +0x95,0x54,0xd2,0x39,0xa9,0x74,0x94,0xe8,0xb4,0xdb,0xed,0x76,0xbb,0xdd,0x6e,0xb7, +0xdb,0xed,0x16,0x8f,0x8a,0x49,0xe1,0xd1,0x6e,0xb7,0xdb,0xed,0x76,0xbb,0xdd,0x6e, +0xb7,0x5b,0x74,0x52,0xa6,0x95,0x74,0x4e,0x2a,0xa9,0xec,0x3a,0x9d,0x0e,0xad,0xe9, +0x74,0x76,0xa9,0xa4,0x72,0x4e,0xc9,0x68,0x01 }; -// bytes:5 ratio: 0.007 +// bytes:73 ratio: 0.570 +// ======================= + +void setup() { + arduboy.begin(); +} + +void loop() { + arduboy.clear(); + + arduboy.drawCompressed(20, 10, sample_mask, BLACK); + arduboy.drawCompressed(20, 10, sample, WHITE); + + arduboy.display(); +} ``` + diff --git a/extras/cabi/sample.png b/extras/cabi/sample.png new file mode 100644 index 0000000000000000000000000000000000000000..be58c404daf0855cbf828ba0bfd2ffe2778a24f5 GIT binary patch literal 280 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?3oVGw3ym^DWND0s@# z#W5t}@Z0H*d<_O1EW3~Vub1>!yT#PBa0`3&*2Lx9LJr(AX=&$e89p3ynf4-FqDJs~ zQq~$VmOY0U!$T!FTQ=!#Z&-RGCAMQ@e!WV|{R|{{>;Z^LMUGJEtwI*W5Mq!t-=BM2!=dHeJb~^KD bRUMPnl|Iep