Home > Perl/mod_perl > Changing Pixel Colors With ImageMagick

Changing Pixel Colors With ImageMagick

ImageMagick

ImageMagick

On List Central, users will be able to choose from a selection of themes for their main page. The themes available only vary by color. To make this happen I have several sets of CSS files; when the user logs in, the system checks which theme s/he selected, and serves the appropriate CSS files. These sets of CSS files are automatically created from a base set of CSS files when a them is created in the List Central Administration.

Aside from the CSS files, there are several images on the users’ main page that vary depending on what theme is selected. In the name of saving time in the future, I set out to figure out a way to create these images automatically as well. I really don’t like busy work, and I’m willing to go to great lengths to find a way around having to do any!

My general approach was, for each image, go through each and every pixel in the image, and see if it is one of the colors I want to change. If it is, then I change it, else, I don’t do anything with it. I’m assuming that the image will only have the colors I want to change in it. The code can easily be modified to handle this case differently.

On with the code!

my @BaseColors = (‘#ffffff’, ‘#0000ff’, ‘#00ff00′, ‘#ff0000′, ‘#000000′);
my @NewColors = (‘#ffffff’, ‘#121d52′, ‘#1d687a’, ‘#bdeaff’, ‘#f8f8ff’);

my $imSrcImg = new Image::Magick;
my $imagefile = ‘source_image.png’;
my $warn = $imSrcImg->Read($imagefile);
print ‘READ WARN: $warn’;

my ($width, $height) = $imSrcImg->Get(‘width’, ‘height’);
print ‘GET WARN: $warn’;

my $size = $width . ‘x’ . $height;
my $iMagickNew = new Image::Magick(size=>$size);
$warn = $iMagickNew->ReadImage(‘NULL:white’);
print ‘ReadImage WARN: $warn’);

# Iterate over every pixel in the image and change
for my $y (0..($height-1)){
   for my $x (0..($width-1)){

      my (@pixel) = split(/,/, $imSrcImg->Get(‘pixel[$x,$y]‘));

      my $red = DecToHex($pixel[0]);
      my $green = DecToHex($pixel[1]);
      my $blue = DecToHex($pixel[2]);

      my $color = ‘#’ . $red . $green . $blue;

      # Check all of the colors we are going to be changing
       for(my $i = 0; $i < @BaseColors; $i++ ) {

         # Change pixel color if the pixel is the color of one
         # of our base colors but not if it's the color we
         # want to change it to already to save a fraction
         # of a moment
         if($color eq $BaseColors[$i] && $color ne $NewColors[$i]){

               # Pull out the red, green, & blue components
               my $r; my $g; my $b;
               my $changeToColor = $NewColors[$i];
               if($changeToColor =~ m/#([wd]{2})([wd]{2})([wd]{2})/){
                  $r = $1; $g = $2; $b = $3;
               }

               # Convert to hex
               my $red = HexToDec($r);
               my $green = HexToDec($g);
               my $blue = HexToDec($b);

               my $toColorHex = '#'.$r.$g.$b;
               my $toColorDec = '$red, $green, $blue';

               my $x2 = $x + 1; my $y2 = $y + 1;
               my $warn = $iMagickNew->Draw(fill=>$toColorHex, primitive=>’point’, points=>’$x,$y’);
               print ‘Changing pixl [$x,$y] from $color to $toColorHex ($toColorDec)nWARN: $warn’;
            }
         }
      }
}

# Write the new image, then we are done
my $newImage = ‘new_image.png’;
my $warn = $iMagickNew->Write($newImage);
print ‘WARN: $warn’;

# Converts a decimal number to a hexidecimal number
sub DecToHex {
   my $dec = shift;

   my $hex = sprintf(‘%X’, $dec);
   if($hex =~ m/^([wd]{2})/){
      $hex = $1;
   }

   $hex = lc($hex);
   return $hex;
}

# Converts a hexidecimal number to a decimal number
sub HexToDec {
   my $hex = shift;

   my $dec = hex($hex);

   return $dec;
}

WARNING: This code will not work as is. There are apostrophes that should be double apostrophes and other such aesthetic changes.

I’ve played around with ImageMagick in the past, so it was the logical choice for my image manipulation package.

I had one major sticking point in trying to get my pixels to change color, which all stemmed from the lack of quality documentation available for the ImageMagick perl package. I love PerlMagick! It is super powerful! It has always baffled me how poor the documentation is. Hopefully my sharing this tidbit will help some other poor soul out there who is struggling with Perl Magick.

Here’s the crux of it: You cannot get a pixel to display in a certain color with:

$iMagick->Set(‘pixel[49,49]‘=>’red’);

as you might assume from the documentation. You have to use the ‘Draw’ subroutine like this:

$iMagick->Draw(fill=>red, primitive=>’point’, points=>’49,49);

It took me hours to figure that out!

I hope my future users like the whole theme selection business on List Central after all of this effort! It was fun to make it happen though! Its a win win!

You might also like...

  1. May 8th, 2009 at 19:24 | #1

    w already includes d

  1. No trackbacks yet.