imho arithmetic coding is overkill for this.
just playing a bit with the lucida picture, i changed it to 12 x 560 so that width and height are multiples of 2,which means you have tiles of 2x2 and then i simply built a "dictionary" from them ... out of 1680 tiles around 16 tiles total around 950 occurances
So you could probably have some kind of hybrid encoding where you make a 16 or 32 tile dictionary, and use the last palette entry as "tile not in dictionary" and then have 1680x4 bit , followed by the remaining tiles tiles.
In the picture above, we have 543 unique tiles and we have a 6 x 280 tile set = 1680 tiles x 2 bytes per tile = 3360 bytes
If you prepare a 15 tile "dictionary" where the 15 most common tiles show up 950 times (not the actual number, but close enough) then the picture is already reduced to :
15 x 2 bytes = 30 bytes + 1680 x 4 bit = 840 bytes + (1680-950) x 2 bytes = 1460 bytes ... so total = 2330 bytes
or if you add a bit map (1 bit if tile is in dictionary or not)
15x 2 bytes = 30 bytes + 1680/8 = 210 bytes + 950 tiles x 4 bit = 475 bytes + (1680-950) x 2 bytes = 1460 bytes => total = 2175 bytes
This can be further compressed with some basic LZW, LZ77, whatever ...
some php code i made as i wrote this to illustrate
<?php
$dictionary = [];
$blocks = [];
$pic = imagecreatefrompng(__DIR__ .'/picture.png');
for ($y=0;$y<280;$y++) {
for ($x=0;$x<6; $x++) {
$a = imagecolorat($pic,$x,$y); // actually the index in color palette
$b = imagecolorat($pic,$x+1,$y);
$c = imagecolorat($pic,$x,$y+1);
$d = imagecolorat($pic,$x+1,$y+1);
$block = $a * 4096 + $b * 256 + $c * 16 +$d;
//echo $block.' ';
if (isset($dictionary[$block])===FALSE) $dictionary[$block]=[$a,$b,$c,$d,0];
$dictionary[$block][4]++;
}
}
$dictionary_sorted = [];
$i=0;
foreach ($dictionary as $block => $value) {
$dictionary_sorted[$i] = $value;
$i++;
}
$sorted = FALSE;
while ($sorted==FALSE) {
$sorted=TRUE;
for ($i=0;$i<count($dictionary_sorted)-1;$i++) {
if ($dictionary_sorted[$i][4]<$dictionary_sorted[$i+1][4]) {
$temp = $dictionary_sorted[$i];
$dictionary_sorted[$i] = $dictionary_sorted[$i+1];
$dictionary_sorted[$i+1] = $temp;
$sorted = FALSE;
}
}
}
foreach ($dictionary_sorted as $index => $pair){
echo $index.','.json_encode($pair)."\n";
};
?>
the output :
0,[9,9,9,9,526]
1,[9,9,0,0,83]
2,[0,0,9,9,69]
3,[9,0,9,0,60]
4,[0,9,0,9,45]
5,[9,9,9,0,33]
6,[9,0,9,9,33]
7,[0,9,9,9,14]
8,[9,9,0,9,13]
9,[0,0,0,9,11]
10,[9,9,9,5,10]
11,[9,3,9,9,10]
12,[9,9,9,3,9]
13,[9,9,9,7,8]
14,[9,9,3,9,8]
15,[3,9,9,9,8]
16,[9,9,10,0,8]
17,[9,9,9,11,8]
18,[9,11,9,9,7]
19,[9,13,9,9,6]
20,[0,0,9,0,6]
21,[9,12,9,9,5]
22,[9,9,9,15,5]
23,[9,9,5,10,5]
24,[9,2,9,9,5]
25,[4,0,9,9,5]
26,[9,4,9,0,5]
27,[0,2,9,9,4]
28,[7,9,9,9,4]
29,[13,0,9,9,4]
30,[9,9,0,10,4]
31,[0,10,9,9,4]
[...]