Just a short proof of principle thing, badly coded and terribly slow, but it works :-)
Images must be converted to the RAW PPM format using e.g. GIMP. If you think of using ImageMagick and convert: doesn’t work properly !
Here is an example of a small image in this format.
P6 # feep.ppm 4 4 15 0 0 0 0 0 0 0 0 0 15 0 15 0 0 0 0 15 7 0 0 0 0 0 0 0 0 0 0 0 0 0 15 7 0 0 0 15 0 15 0 0 0 0 0 0 0 0 0
Short description of the lines starting from 1:
- ASCII: Identifier
- ASCII: Comment
- ASCII: x-resolution space y-resolution
- ASCII: max color value
- HEX: sequential data: R,G,B,R,G,B …
If you look at such a RAW PPM image with a hex editor it might look like this:
00000000 50 36 0a 23 20 43 52 45 41 54 4f 52 3a 20 47 49 |P6.# CREATOR: GI| 00000010 4d 50 20 50 4e 4d 20 46 69 6c 74 65 72 20 56 65 |MP PNM Filter Ve| 00000020 72 73 69 6f 6e 20 31 2e 31 0a 38 20 38 0a 32 35 |rsion 1.1.8 8.25| 00000030 35 0a 00 00 ab 00 00 ab 00 00 a4 00 00 43 07 07 |5............C..| 00000040 4a 00 00 a0 00 00 ab 00 00 ab 00 00 ab 00 00 ab |J...............| 00000050 03 03 86 42 3f 35 4c 4c 4a 00 00 64 00 00 ab 00 |...B?5LLJ..d....| 00000060 00 ab 00 00 ab 00 00 ab 02 02 89 dc b2 20 b5 9b |............. ..| 00000070 43 08 08 49 00 00 ab 00 00 ab 00 00 ab 00 00 aa |C..I............| 00000080 43 43 74 f3 f3 f3 f4 f4 f4 2e 2e 2f 00 00 78 00 |CCt......../..x.| 00000090 00 ab 00 00 ab 03 03 78 cb cb cb fd fd fd ff ff |.......x........| 000000a0 ff a2 a2 a2 04 04 15 00 00 a9 07 05 a5 7d 65 3a |.............}e:| 000000b0 d4 d0 c0 f9 f9 f9 ff ff ff bb ae 83 2c 24 09 07 |............,$..| 000000c0 05 a3 a5 84 4b ff d1 31 c0 9d 1d ee ed eb d8 d8 |....K..1........| 000000d0 d8 ce a7 26 fa ca 26 79 63 6f 33 27 86 73 59 5b |...&..&yco3'.sY[| 000000e0 a0 7a 3a 12 0c 62 00 00 69 80 5e 3d 65 4d 67 04 |.z:..b..i.^=eMg.| 000000f0 03 a8 |..| 000000f2
( space = 0x20 (hex), n = 0x0A (hex) )
This is an image of ... TUX (of course) !
Such an image is easy to read and process in Perl:
#!/usr/bin/perl -W -T
use strict;
use Device::SerialPort;
use Time::HiRes qw(sleep);
my $separator = "n"; # 0x0A
my $start_byte = "n"; # 0x0A
my $stop_byte = "r"; # 0x0D
my $image_id = "P6"; # ID for .ppm image
my $color_scaler = 8;
my $port = "/dev/ttyUSB0"; # <-- find right port !
my $link = Device::SerialPort->new($port) || die("could not open port: $port - $!"); # <-- match to right com port
$link->databits(8);
$link->baudrate(19200); # <-- match to arduino settings
$link->parity("none");
$link->stopbits(1);
$| = 1; # buffers disabled
open(FILE, "< $ARGV[0]"); # open .ppm image
my @image = ; # load the data in an array
close(FILE);
my $tmp = $image[0]; # get .ppm ID from image
$tmp =~ s/n//; # remove n
shift @image; #remove ID line
if ( $tmp ne $image_id ) { print "nnot .ppm image!nn"; exit; }
$tmp = $image[0];
if ( $tmp =~ m/^#.*/ ) { # comment line ?
shift @image; # remove comment line
}
my $x_res = $image[0];
$x_res =~ m/^(d*) /;
$x_res = $1;
my $y_res = $image[0];
$y_res =~ m/^d* (d*)/;
$y_res = $1;
my $c_max = $image[1];
shift @image; # remove X x Y line
shift @image; # remove color line
if ( ($x_res > 8) || ($y_res > 8) ) { print "n($x_res x $y_res)nimage larger than 8x8nn"; exit; }
print "x_res: ",$x_res,"n";
print "y_res: ",$y_res,"n";
print "c_max: ",$c_max,"n";
@image = split('',$image[0]); # put every single character into a new line --> access it c-style
my $row;
my $led;
for ($row = 0; $row < 8; $row++) {
for ($led = 0; $led < 8; $led++) {
$link->write($start_byte);
$link->write(pack("C",$row));
$link->write(pack("C",$led));
$link->write(pack("C",unpack("C",$image[$row*3*8+$led*3+0])/$color_scaler));
$link->write(pack("C",unpack("C",$image[$row*3*8+$led*3+1])/$color_scaler));
$link->write(pack("C",unpack("C",$image[$row*3*8+$led*3+2])/$color_scaler));
$link->write($stop_byte);
sleep(0.035);
}
}
The pack() and unpack() functions are used to determine how Perl interprets the raw data. It’s too difficult a thing to explain here, so just a link.
Here’s the code/example: show_ppm.tgz
I updated the code a bit and improved transfer speed quite a lot:
- upped serial speed to 57600
- transmit one row in one go, reduce start/stop byte overhead
- tweaked delay times in Perl
Here’s the improved code: show_ppm_v2.tgz
And another update. Here’s an animation stored in PROGMEM.
Here’s the code: show_ppm_v3.tgz
Related posts:





