ronash
ronash

Reputation: 866

Modifying pixels in an image using Perl

Suppose I want to take one picture, move all of its pixels one pixel to the right and one to the left, and save it. I tried this code:

my $image_file = "a.jpg";
my $im = GD::Image->newFromJpeg($image_file);
my ($width, $height) = $im->getBounds();
my $outim = new GD::Image($width, $height);

foreach my $x (1..$width)
{
    foreach my $y (1..$height)
    {
        my $index = $im->getPixel($x-1,$y-1);
        my ($r,$g,$b) = $im->rgb($index);
        my $color = $outim->colorAllocate($r,$g,$b);
        $outim->setPixel($x,$y,$color);
    }
}
%printing the picture...

That doesn't do the trick; it draws all pixels, except those in which x=0 or y=0, in one color. Where am I going wrong?

Upvotes: 3

Views: 1459

Answers (4)

Carlsbad Raceway
Carlsbad Raceway

Reputation: 11

I realize that this is an old post, but this is a piece of code that I use GD:Thumb for creating resized images.

    sub png {
        my ($orig,$n) = (shift,shift);
        my ($ox,$oy) = $orig->getBounds();
        my $r = $ox>$oy ? $ox / $n : $oy / $n;
        my $thumb = GD::Image->newFromPng($ox/$r,$oy/$r,[0]);
        $thumb->copyResized($orig,0,0,0,0,$ox/$r,$oy/$r,$ox,$oy);
        return $thumb, sprintf("%.0f",$ox/$r), sprintf("%.0f",$oy/$r);
        }

Upvotes: 0

hobbs
hobbs

Reputation: 239881

Here's a solution using Imager because it's a very nice module and I'm more familiar with it, and it handles image transformations nicely.

use Imager;

my $image_file = "a.jpg";

my $src = Imager->new(file => $image_file) or die Imager->errstr;

my $dest = Imager->new(
    xsize => $src->getwidth() + 1,
    ysize => $src->getheight() + 1,
    channels => $src->getchannels
);

$dest->paste(left => 1, top => 1, src => $src);
$dest->write(file => "b.jpg") or die $dest->errstr;

Upvotes: 2

dgw
dgw

Reputation: 13646

Try reversing the direction of x and y - not from 1 to max but from max to 1. You are not sliding the colors but copying the same again and again.

Upvotes: 0

Marius Kjeldahl
Marius Kjeldahl

Reputation: 6824

Look in the docs:

Images created by reading JPEG images will always be truecolor. To force the image to be palette-based, pass a value of 0 in the optional $truecolor argument.

It's not indexed. Try adding a ,0 to your newFromJpeg call.

From the comments, it seems your next problem is the number of colors to allocate. By default, the indexed image is 8-bit, meaning a maximum number of 256 unique colors (2^8=256). The "simple" workaround is of course to use a truecolor image instead, but that depends on whether you can accept truecolor output.

If not, your next challenge will be to come up with "an optimal" set of 256 colors that will minimize the visible defects in the image itself (see http://en.wikipedia.org/wiki/Color_quantization). That used to be a whole topic in itself that we seldom have to worry about today. If you still have to worry about it, you are probably better off offloading that job to some specialized tool like Imagemagik or similar, rather than try to implement it yourself. Unless you like challenges of course.

Upvotes: 5

Related Questions