Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Most Enlightened Monks to Whom This is But A Trivial Task,

What I'd like to do is take an black & white (I mean monocrome, not the game) image (Currently BMP but can be converted) and convert it to 'text'. Basically, a white pixel becomes whitespace, and a black one becomes an asterix. This seems like the kind of thing that could be done in one (obfusicated) line of Perl.
My questions are:

  1. Is Perl the ideal tool? Is there a better way?
  2. Within Perl, is there a premade function which does the majority of the work for me?
  3. How does one use Perl to say "Ah, yes, the pixel at co-ordinate (X,Y) is black"?
Thank you for your time,
Anonymous Monk

Replies are listed 'Best First'.
(ar0n) Re: Perl BMP -- Text
by ar0n (Priest) on Jun 06, 2001 at 18:59 UTC
    If you're allowed to convert it to png, jpg or xpm, you can use GD. And access the color at $x, $y with
    my @rgb = $img->rgb( $img->getPixel($x, $y) ); if ( 3 == grep !$_, @rgb ) { print "*"; } else { print " "; }


    ar0n ]

Re: Perl BMP -- Text
by knobunc (Pilgrim) on Jun 06, 2001 at 19:35 UTC

    There is an ASCII-Art mode in The Gimp, but that does more than you want (it can handle greyscale and color).

    Image::Magick has a perl interface so you can get the image information (width and height) then loop through the pixels.

    www.wotsit.org has links to the different file formats. There are a couple of BMP formats depending on the windows version, or it may be an X bitmap, you were not very clear there. Once you know the format you can get the dimensions and then play games with pack and unpack.

    If this is an infrequent thing and you don't care about extreme speed then I would go the Image::Magick route.

    -ben

Re: Perl BMP -- Text
by bikeNomad (Priest) on Jun 06, 2001 at 19:35 UTC
    If you can use XPM, here's a solution that doesn't require any external packages:

    #!/usr/bin/perl -w use strict; # reads a 2-color XPM; outputs space for white, asterisk for black my @lines = map { tr/",//d; $_ } grep {!m{^/\*|[{}]}} <>; my ($header, @c) = splice(@lines, 0, 3); my @dims = $header =~ m{(\d+)}g; die "has too many colors or is in wrong format\n" if $dims[2] > 2 || $ +dims[3] > 1; my $text = join('', @lines); # process colormap my ($w, $b); foreach (@c) { m{^\s*(\S).*#(\S+)\s*$}; hex($2) ? $w = $1 : $b = $1 } eval "\$text =~ tr/$w$b/ */"; print $text;

    And, in case the prior was too readable, here's a regex-based version of the above...

    #!/usr/bin/perl -w # reads a 2-color XPM; outputs space for white, asterisk for black use strict; $/ = undef; my $text = <>; $text =~ s{^[^"]*\n}{}gm; # remove noise lines $text =~ s{^\s*"\s*([^"]*\S)\s*"\s*,\s*$}{$1}gm; # unquote others $text =~ s{^\d+\s+\d+\s+(\d+)\s+(\d+)\n # dimensions (.)\s+c\s+\#([0-9a-fA-F]+)\n # colormap 0 (.)\s+c\s+\#([0-9a-fA-F]+)\n }{}mx; # colormap 1 die "has too many colors or is in wrong format\n" if $1 > 2 || $2 > 1; my ($w, $b) = hex($4) > hex($6) ? ( $3,$5 ) : ( $5,$3 ); eval "\$text =~ tr/$w$b/ */"; print $text;
    update: shortened code a bit, added second version
      Any chance this could be done with GIFs or BMPs???
        Not mine, but ar0n's method using GD should work with any image format that GD can read (this depends on how you compile it, of course). GD supports WBMP images. However, its author reacted1 to the Unisys patent flap by removing GIF support from GD. So you'd have to convert your GIFs to something else before using GD.

        1 some people would say he overreacted, but it's his business what to provide. There are people who would be glad to see patches to GD that would allow GIF manipulation.