Image conversion and algorithm

A project log for IoT thermal grayscale printer shield

Arduino shield (will work standalone also) which would print on a thermal paper. Serial, USB and Ethernet communication, open source.

lukasz.iwaszkiewiczlukasz.iwaszkiewicz 08/18/2014 at 13:070 Comments

To print a row on the head, I have to send a stream of 832 bits via HDAT line. I am considering only a graphic data, i.e. printer won't generate any fonts for itself (at least for now). So for purpose of printing any color image in any format, some preprocessing on the host must be undertaken. Steps to do:

Surprisingly the task was not as easy as I thought. It turns out, that the topic is quite complicated. For example look at those pages listed below, how many detailed information they contain:

The last one may give you idea what tool I am using. It is a standard command line Swiss army knife for graphics manipulation available (often by default) on any *nix system. BTW my system is a Ubuntu 14.04, 64bit running on i5 and i7. After lots of tweaking (3 evenings or more) I came up with satisfactory solution:

1. Generate a "color palette". In my case only 4 shades : black, white and two grays:

convert -size 1x4 gradient:black ~/gradient_levels.png

2a. Perform steps 1-5 in one go, and output the result in form of viewable PNG image (for easy inspection):

convert IMG_7245.JPG -resize 832 -colorspace sRGB -set colorspace RGB -colorspace Gray -dither FloydSteinberg -remap ~/gradient_levels.png -depth 2 ~/franek.png

2b. Or alternatively output in raw format (notice the output image extension):

convert IMG_7245.JPG -resize 832 -colorspace sRGB -set colorspace RGB -colorspace Gray -dither FloydSteinberg -remap ~/gradient_levels.png -depth 2 ~/franek.gray

3. Make a *.h file (huge):

xxd -i ~/franek.gray > /home/iwasz/workspace/test07/src/franek.h

Resulting *.h file can be quite huge. Look at this for example. Every byte contains 4 pixels, each 2 bits wide. Black ones has value of 0x0, dark gray is 0x1, light gray is 0x2 and white is 0x3. So draft algorithm may look like that :

bit monochrome[832];

for each line

    for k = 0; k < number of colors - 1 (i.e. 3); ++k

        for each 2 bit pixel (color)

            if color <= k

                set corresponding bit in monochrome array to 1;

        transfer monochrome array;

        issue the DST signal;

In other words I spit the DST signal duration (let it be D ms) to 3 durations. First I turn on all black pixels, turn on the heat and wait D/3 ms. Then I turn on dark gray ones (black are still on) and after turning on the heat I wait another D/3 ms. Finally I add light gray pixels to the ones already switched on and repeat the heating for D/3 ms. This coarse description is implemented here.