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

Laus ut Larry Wall.

Sages of cleansing knowledge.

As a humble scribe, I kneel in front of you, requesting - once more, I'm afraid - knowledge of what is yet unknown to me.

What I am trying to achieve is this : I have a picture, jpeg format, which is for a large part a certain color. I would like to be able to edit this picture and change that specific color to another (by let's say, RGB value).

I have dwelled through the monastery's vast library, exalted ones. I did not find. I am weary, covered in dust. Please lighten my burden.

Glory to the Gods.

-- Detonite

Replies are listed 'Best First'.
Re: Replace certain color in jpeg
by Roy Johnson (Monsignor) on Feb 15, 2005 at 13:50 UTC
    Your task is not at all straightforward. JPEG images are not stored in the RGB colorspace, but in the YUV colorspace. But that's not the difficulty. The encoding is akin to storing frequencies, which means that you're likely to have lots of slight variations even in regions that look to be solidly one color.

    The only module I know of that might be helpful is Image::Magick.


    Caution: Contents may have been coded under pressure.
Re: Replace certain color in jpeg
by Fletch (Bishop) on Feb 15, 2005 at 13:49 UTC

    I don't think you're going to be able to easily do this. JPEG isn't like GIF where there's a single palate of colors that you can just change in one place. You'd basically have to convert the JPEG into another format, change the color in the uncompressed image, and then re-compress back to JPEG. And due to the lossy nature of JPEG compression your going to get a worse (how bad depends on the quality setting used) converted picture.

    But yeah, Image::Magick and or GD's the stuff to look into. Or possibly script the Gimp.

      I understand. Your reply is useful though. Because of what you say about GIF, isn't it easier if I would use a GIF instead of a JPG? Anything but a .BMP... Thanks for the help!

      Detonite

Re: Replace certain color in jpeg
by phaylon (Curate) on Feb 15, 2005 at 13:42 UTC
    I don't know if that's helping, but CPAN knows (for example) Image::Magick, GD and Imlib2::Image. I think at least the both last have functions for palette-manipulation.

    hth,phay

    Ordinary morality is for ordinary people. -- Aleister Crowley
Re: Replace certain color in jpeg
by zentara (Cardinal) on Feb 15, 2005 at 14:21 UTC
    The Imager module has some good tools for this. For example check out batch rgb brightness and contrast adjustment. That script shows tinting, but you can probably find a way to replace just one color. Look thru the perldocs for Imager, there may be an example in there. I would think as a last resort, you could unpack the jpg to rgb values, then use a substitution regex on the color you want changed, then pack it back to binary.

    I'm not really a human, but I play one on earth. flash japh
Re: Replace certain color in jpeg
by zentara (Cardinal) on Feb 15, 2005 at 17:34 UTC
    Here is a little demo script which will show you how to do it from the different modules available. I will leave it to you to find which color you want to replace, and how to do the substitutuion. Look for getpixel and setpixel in the docs for the modules.
    #!/usr/bin/perl #None of these is fast, mainly because of the overhead of calling Perl + #code for each pixel. use strict; my $imagefile = shift or die "No file specified\n"; sub rgba2hex { sprintf "%02x%02x%02x%02x", map { $_ || 0 } @_; } { use Imager; my %colors; my $img = Imager->new(); $img->open( file => $imagefile ) or die $img->errstr; my ( $w, $h ) = ( $img->getwidth, $img->getheight ); for my $i ( 0 .. $w - 1 ) { for my $j ( 0 .. $h - 1 ) { my $color = $img->getpixel( x => $i, y => $j ); my $hcolor = rgba2hex $color->rgba(); print "$hcolor "; $colors{$hcolor}++; } } printf "Imager: Number of colours: %d\n", scalar keys %colors; } { use GD; my %colors; my $gd = GD::Image->new($imagefile) or die "GD::Image->new($imagef +ile)"; my ( $w, $h ) = $gd->getBounds(); for my $i ( 0 .. $w - 1 ) { for my $j ( 0 .. $h - 1 ) { my $index = $gd->getPixel( $i, $j ); my $hcolor = rgba2hex( $gd->rgb($index), 0 ); $colors{$hcolor}++; } } printf "GD: Number of colours: %d\n", scalar keys %colors; } { use Image::Magick; my %colors; my $img = Image::Magick->new(); my $rc = $img->Read($imagefile); die $rc if $rc; my ( $w, $h ) = $img->Get( 'width', 'height' ); for my $i ( 0 .. $w - 1 ) { for my $j ( 0 .. $h - 1 ) { my $color = $img->Get("pixel[$i,$j]"); my $hcolor = rgba2hex split /,/, $color; $colors{$hcolor}++; } } printf "Image::Magick: Number of colours: %d\n", scalar keys %colo +rs; }

    I'm not really a human, but I play one on earth. flash japh
Re: Replace certain color in jpeg
by RazorbladeBidet (Friar) on Feb 15, 2005 at 13:29 UTC
    I would suggest starting here with the JPEG (JFIF) specification.

    You'll have to uncompress and determine what makes up those RGB values.
    Not having specific knowledge in this domain I can't help you much more than this - I don't know if a package already exists for this or anything more.

    HTH
      I'll give that a shot. Learning's always good. (Except learning what pain is ;) ). Thanks for the help!
Re: Replace certain color in jpeg
by jbrugger (Parson) on Feb 15, 2005 at 14:22 UTC
    Could you do something using perl and gimp? image::magic can do a lot, but i don't think it's going to help you.
    1. Background
    One of the wonderful features of GIMP is that it all its functionality may be accessed through scripting. So far most of the script programming for Gimp has been done through Scheme through Script-Fu. Unfortunately the Scheme environment Gimp provides is very primitive, e.g. without any reasonable error handling. Furthermore, must users are not familiar with scheme as a language. Some users may therefore prefer to write scripts for the Gimp in Perl.

    A Tutorial for Perl Gimp Users