I managed to get the RLE implementation working quite well. The original code is adding an index information for EVERY pixel, which on a noisy image can double the size of the image instead of compressing it. This is pretty much a functional version:

... for (i = 1; i< lineLen; i++){ if (seq == 0){ seq++; } if (val>>CRANGE == curLine[i]>>CRANGE){ seq++; } else if (val>>CRANGE == curLine[i+1]>>CRANGE){ seq++; curLine[i] = val; } else { if (seq > 1){ comLine[indx] = seq | (0x80); comLine[indx+1] = val; indx +=2; } else { comLine[indx] = val; indx +=1; } seq=0; } if ((i == (lineLen - 1)) & (seq > 0)){ comLine[indx] = seq | (0x80); comLine[indx+1] = val; seq=0; indx +=2; } val = curLine[i]; } comLine[0] = indx >> 8; comLine[1] = indx & 0xff; ...

And the receiver:

```
...
index = 0;
for (y = 0; y < h; y++) {
x=0;
sz = ((imgRLEBuffer[index] << 8) | (imgRLEBuffer[index+1]));
if ((sz > 0) & (sz < w)){
for (z = 2; z < sz; z++){
if (imgRLEBuffer[index+z] > 0x7f){
seq = (imgRLEBuffer[index+z] & 0x7f);
z++;
y1 = ((imgRLEBuffer[index+z] << 1) & 0xff);
for (s = 0; s < seq; s++){
imgRaw.setRGB(x, y, (int)((y1 << 16) | (y1 << 8) | y1));
x++;
}
} else {
y1 = ((imgRLEBuffer[index+z] << 1) & 0xff);
imgRaw.setRGB(x, y, (int)((y1 << 16) | (y1 << 8) | y1));
x++;
}
}
}
index += sz;
}
canvasZoom.setImage(imgRaw, 1);
canvasZoom.repaint();
imgRaw.flush();
...
```

The new version is a bit smarter: will only add the index if is more than one adjacent pixel duplicated. Worse case: the final image is the same (and same size) with the original one, not bad huh?

The trick is to send 7 bits per pixel, and use the 8th pixel to identify the index byte.

Doing further filtering the result will be quite decent considering that I am using a simple MCU to do everything and will work on any camera. For a “clean” image I can get a 160 x 120 frame down to 2 Kbytes+ from the original 19 Kbytes. For a “noisy” one will go up to 15 Kbytes. In the capture below, the 5956 is the image size in bytes.

Next is to write simple implementation of LZW to run on the compressed image. I am really curious how “low” I can go…