The best method I could think of that wouldn't take you forever to program would follow an algorithm something like this:
1) Create a block of color*
2) Move over the width of ^ and repeat until the whole row is filled.
3) Move down the maximum height in ^ row and repeat until max height is filled.
So now you have a file that when converted back would be a lattice of colorblocks and holes. Now, however, we can start systematically filling in the holes with your previously used method.
4) Print a code to show that the end of blockcoding has been reached
5) Find first hole and print out line encoding
6) Do the same for all remaining holes
And just as the encoding program is able to figure out where the holes are after the blocks are created, the decoding algorithm can do the very same. This will be more memory intensive, but should save much more space.
Now, to make this better, you could limit the maximum size of each block. this way, no supertall blocks force the rest of the code to be written the old way. You would also want to run size checks from all four directions and not just two, in order to optimize, again.
*Also i was bored so I wrote a possible blockmaking code. Edit my post in order to see that it tually does have decent spacing and such.
x = 0;
y = 0;
i = 0;
while (true) {
//Gather Data
t = 1;
n = 0;
a = 0;
while (true) {
while (true) {
if (c[x,y]==c[x+t,y+n]) {
a = 1;
tw++;
if (x+tw > maxwidth) {
a = 0;
tw = maxwidth-x;
break;
}
} else {
tw--;
if (a==1) {
a = 0;
break;
}
if (tw<0) {
a = 0;
break;
}
}
}
if (t<0) {
m=n;
break;
)
t[n] = t;
n++;
}
//Find 'Optimum' Rectangle
n = 0;
r = 0;
while (m>n) {
if (t[r]*r<t[n]*n) {
r = n;
}
n ++
}
//output the characteristics of block as a datastructure
p = DataPelletConstruct(c[x,y],t[r],r);
i++;
//move over to the next item
x += t[r];
if (x>maxwidth) {
break;
}
}