in reply to Re: Using text data in GD(or other)
in thread Using text data in GD(or other)

Here is what I have so far. It causes an gd-jpeg: JPEG library reports unrecoverable error: and crashes perl. Any ideas?
#!/usr/bin/perl -w use strict; use GD; use File::Slurp; my $width = 102; my $height = 123; my $truecolor; my $x; my $y; my $image = GD::Image->new([$width,$height],$truecolor); my $dbz1 = $image->colorAllocate(0,0,0); #-30 my $dbz2 = $image->colorAllocate(204,255,255); #-28 my $dbz3 = $image->colorAllocate(204,153,204); #-25 my $dbz4 = $image->colorAllocate(153,102,153); #-20 my $dbz5 = $image->colorAllocate(102,51,102); #-15 my $dbz6 = $image->colorAllocate(204,204,153); #-10 my $dbz7 = $image->colorAllocate(153,153,102); #-5 my $dbz8 = $image->colorAllocate(102,102,51); #0 my $dbz9 = $image->colorAllocate(102,255,255); #5 my $dbz10 = $image->colorAllocate(51,153,255); #10 my $dbz11 = $image->colorAllocate(0,0,255); #15 my $dbz12 = $image->colorAllocate(0,255,0); #20 my $dbz13 = $image->colorAllocate(0,204,0); #25 my $dbz14 = $image->colorAllocate(0,153,0); #30 my $dbz15 = $image->colorAllocate(255,255,0); #35 my $dbz16 = $image->colorAllocate(255,204,0); #40 my $dbz17 = $image->colorAllocate(255,104,0); #45 my $dbz18 = $image->colorAllocate(255,0,0); #50 my $dbz19 = $image->colorAllocate(204,51,0); #55 my $dbz20 = $image->colorAllocate(153,0,0); #60 my $dbz21 = $image->colorAllocate(255,0,255); #65 my $dbz22 = $image->colorAllocate(153,51,204); #70 my $dbz23 = $image->colorAllocate(255,255,255); #75 my $dbz24 = $image->colorAllocate(255,255,255); #80 print "$dbz1\n"; my @data = read_file('test_image.txt'); print "@data\n"; for($y=1;$y <= $height;$y++){ for($x=1;$x <= $width;$x++){ my $pixel = $x*$y-1; print "Pixel Value: $data[$pixel]\n"; if ($data[$pixel] == 0){ $image->setPixel($x,$y,$dbz1); } if ($data[$pixel] > 0 and $data[$pixel] <= 10){ $image->setPixel($x,$y,$dbz5); } if ($data[$pixel] > 10 and $data[$pixel] <= 20){ $image->setPixel($x,$y,$dbz10); } if ($data[$pixel] > 20 and $data[$pixel] <= 30){ $image->setPixel($x,$y,$dbz15); } } } my $jpeg = $image->jpeg(); open JPEG,'>','test_image.jpg' || die; print JPEG $jpeg; #~ my $gif = $image->gif(); #~ open GIF,'>','test_image2.gif' || die; #~ print GIF $gif; exit;

Replies are listed 'Best First'.
Re^3: Using text data in GD(or other)
by BrowserUk (Patriarch) on Apr 22, 2009 at 00:02 UTC

    There are a few problems with your attempt.

    1. my $image = GD::Image->new([$width,$height],$truecolor);
      • $width & $height are parameters that should be passed directly, not wrapped in an anonymous subroutine.

        In the POD example: $image = GD::Image->new([$width,$height],[$truecolor]), the brackets [] are intended to indicate that the arguments are optional.

      • The parameter $truecolor should be passed as either 0 or 1. You never give the variable any value.
      my $image = GD::Image->new( $width, $height, 1 );
    2. for($y=1;$y <= $height;$y++){ for($x=1;$x <= $width;$x++){

      The pixels in an image (as with most arrays in computing) starts from 0. So your loops should run from 0 to width/height -1. You'll also be less likely to make out-by-one errors if you use Perl's counting loops with in-line variable declarations:

      for my $y ( 0 .. $height - 1 ){ for my $x ( 0 .. $width - 1 ){
    3. This 2D to 1D array mapping looks very wrong:         my $pixel = $x*$y-1;

      Even using your original 1-based indices, this mapping reuses several indices from the data, and completely omits others. In this example indices 1, 2 & 5 are reused; 4, 6 & 7 are never used:

      for my $y ( 1 .. 3 ) { for my $x ( 1 .. 3 ) { print "[$x:$y] => ", $x*$y-1; } } [1:1] => 0 [2:1] => 1 [3:1] => 2 [1:2] => 1 [2:2] => 3 [3:2] => 5 [1:3] => 2 [2:3] => 5 [3:3] => 8

      Using 0-based indices, you probably want something like:

      my $pixel = ( $y * $width ) + $x;
    4. if( $data[ $pixel ] == 0 ){ $image->setPixel( $x, $y, $dbz1 ); } if( $data[ $pixel ] > 0 and $data[$pixel] <= 10){ $image->setPixel($x,$y,$dbz5); } if ($data[$pixel] > 10 and $data[$pixel] <= 20){ $image->setPixel($x,$y,$dbz10); } if ($data[$pixel] > 20 and $data[$pixel] <= 30){ $image->setPixel($x,$y,$dbz15); }

      Whilst the way you have that coded will work, you are making more work for yourself (having to specify the lower bounds of the if statements), and more work for your program (having to test 7 conditions for every pixel). Better to use an if/elsif cascade:

      if( $data[ $pixel ] == 0 ){ $image->setPixel( $x, $y, $dbz1 ); } elsif( $data[ $pixel ] <= 10 ){ $image->setPixel( $x, $y, $dbz5 ); } elsif( $data[ $pixel ] <= 20 ){ $image->setPixel( $x, $y, $dbz10 ); } elsif( $data[ $pixel ] <= 30 ){ $image->setPixel( $x, $y, $dbz15 ); } else { ## What do you want to do if the value is greater than 30? +? }

      In this way, the later conditions are only tested if the earlier ones have failed, and because of that, you do not need to test the lower bounds.

    5. open JPEG,'>','test_image.jpg' || die; print JPEG $image->jpeg();

      Several problems here:

      • Either use parens on your open open( JPEG,'>','test_image.jpg' ) || die; or use the low-precedence or keyword: open JPEG,'>','test_image.jpg' or die;. I favour the latter. See the docs for the reasons.
      • If you are going to die, at least do yourself the favour of printing $! so you know why you died.
      • It's a good idea to binmode files used for binary data.
        binmode JPEG;
      • It's a good idea to explicitly close files:

    Putting that all together you end up with something like:

    #!/usr/bin/perl -w use strict; use GD; use File::Slurp; my $width = 102; my $height = 123; my $image = GD::Image->new( $width, $height, 1 ); my $dbz1 = $image->colorAllocate(0,0,0); #-30 my $dbz2 = $image->colorAllocate(204,255,255); #-28 my $dbz3 = $image->colorAllocate(204,153,204); #-25 my $dbz4 = $image->colorAllocate(153,102,153); #-20 my $dbz5 = $image->colorAllocate(102,51,102); #-15 my $dbz6 = $image->colorAllocate(204,204,153); #-10 my $dbz7 = $image->colorAllocate(153,153,102); #-5 my $dbz8 = $image->colorAllocate(102,102,51); #0 my $dbz9 = $image->colorAllocate(102,255,255); #5 my $dbz10 = $image->colorAllocate(51,153,255); #10 my $dbz11 = $image->colorAllocate(0,0,255); #15 my $dbz12 = $image->colorAllocate(0,255,0); #20 my $dbz13 = $image->colorAllocate(0,204,0); #25 my $dbz14 = $image->colorAllocate(0,153,0); #30 my $dbz15 = $image->colorAllocate(255,255,0); #35 my $dbz16 = $image->colorAllocate(255,204,0); #40 my $dbz17 = $image->colorAllocate(255,104,0); #45 my $dbz18 = $image->colorAllocate(255,0,0); #50 my $dbz19 = $image->colorAllocate(204,51,0); #55 my $dbz20 = $image->colorAllocate(153,0,0); #60 my $dbz21 = $image->colorAllocate(255,0,255); #65 my $dbz22 = $image->colorAllocate(153,51,204); #70 my $dbz23 = $image->colorAllocate(255,255,255); #75 my $dbz24 = $image->colorAllocate(255,255,255); #80 print "$dbz1\n"; my @data = read_file('test_image.txt'); print "@data\n"; for my $y ( 0 .. $height - 1 ){ for my $x ( 0 .. $width - 1 ){ my $pixel = ( $y * $width ) + $x; # print "Pixel Value: $data[$pixel]\n"; if( $data[ $pixel ] == 0 ){ $image->setPixel( $x, $y, $dbz1 ); } elsif( $data[ $pixel ] <= 10 ){ $image->setPixel( $x, $y, $dbz5 ); } elsif( $data[ $pixel ] <= 20 ){ $image->setPixel( $x, $y, $dbz10 ); } elsif( $data[ $pixel ] <= 30 ){ $image->setPixel( $x, $y, $dbz15 ); } else { ## What do you want to do if the value is greater than 30? +? } } } open JPEG,'>','test_image.jpg' or die $!; binmode( JPEG ); print JPEG $image->jpeg(); close JPEG; exit;

    Which may not produce exactly what you are after, but will run and should get a step forward.


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
Re^3: Using text data in GD(or other)
by Anonymous Monk on Apr 22, 2009 at 03:50 UTC
    You're already using File::Slurp, so
    write_file( 'test_image.jpg', {binmode => ':raw' }, $image->jpeg) ; write_file( 'test_image2.gif', {binmode => ':raw' }, $image->gif) ;