5

I'm wondering if there is a more efficient method for replacing colors in a BufferedImage. At the moment I use the following method:

I fill an array with colors to be replaced and the colors to replace them with, including transparency. Then I loop through every pixel in the image. If it matches one of the colors in the array I replace it with the new color from the array. Here is the code:

  Graphics2D g2;
  g2 = img.createGraphics();
  int x, y, i,clr,red,green,blue;

  for (x = 0; x < img.getWidth(); x++) {
    for (y = 0; y < img.getHeight(); y++) {

      // For each pixel in the image
      // get the red, green and blue value
      clr = img.getRGB(x, y);
      red = (clr & 0x00ff0000) >> 16;
      green = (clr & 0x0000ff00) >> 8;
      blue = clr & 0x000000ff;

      for (i = 1; i <= Arraycounter; i++) {
        // for each entry in the array
        // if the red, green and blue values of the pixels match the values in the array
        // replace the pixels color with the new color from the array
        if (red == Red[i] && green == Green[i] && blue == Blue[i])
        {
          g2.setComposite(Transparency[i]);
          g2.setColor(NewColor[i]);
          g2.fillRect(x, y, 1, 1);
        }
      }
    }

The images I'm working with are small, 20x20 pixels or so. Nevertheless It seems there must be a more efficient way to do this.

Rene
  • 10,391
  • 5
  • 33
  • 46
  • maybe if you explain the original problem we could help more – mohdajami Mar 03 '10 at 10:07
  • The code creates images to be used as a legend in a map. We have a set of template images with four colors. black, red, green and blue. Depending on the thematic representation in the map the template images must get the correct color. Black will be converted to the background color, red the correct border color, green a hash pattern and blue areas will become transparent. – Rene Mar 03 '10 at 10:35

4 Answers4

10

Instead of changing the value of the image pixels you can modify the underlying ColorModel. Much faster that way and no need to iterate over the whole image so it scales well.

objects
  • 8,637
  • 4
  • 30
  • 38
  • 1
    `ColorMap` isn't a class in the Java API. How is he supposed to do that? – uckelman Mar 03 '10 at 10:19
  • 2
    Thats was a typo (which had already been fixed), down voting seems a bit harsh – objects Mar 03 '10 at 10:20
  • And the technique works well, have used it for medical imagery viewer where the contrast of an image needed to be adjusted in real time. Changing individual pixel values is just too slow. – objects Mar 03 '10 at 10:22
  • 2
    Thanks, I've had a look at the java documentation for Colormodel but must confess that I'm having great difficulties with the level of abstraction of all these classes. – Rene Mar 03 '10 at 13:05
  • ColorModel maps pixel values to colors. So by changing the mapping in the ColorModel for a value you avoid having to change the pixel values in the image. Will see if I can dig up a good example for you. – objects Mar 04 '10 at 00:15
  • 1
    an example here http://helpdesk.objects.com.au/java/changing-the-colormodel-of-a-bufferedimage – objects Mar 06 '10 at 02:54
  • 1
    The example shows how I can create an image with a new ColorModel, but how would I create a color model to replace the image with an arbitraty image, which could have an arbitrary ColorModel? – Thayne Jul 15 '16 at 05:25
3

Use a HashMap<Color,Color>. The key should be the original color, and the value the replacement. If the get returns null, do nothing.

Matthew Flaschen
  • 278,309
  • 50
  • 514
  • 539
3

It looks like the idiomatic way to do this is to implement a LookupOp and then apply this operation to create a new target BufferedImage. There is a great answer here.

Community
  • 1
  • 1
Adamski
  • 54,009
  • 15
  • 113
  • 152
  • What I need to do is to convert red, green, blue and black pixels all to their own new color. Can this be done using LookupOp? It seems works on each color component individually. – Rene Mar 03 '10 at 10:27
  • I haven't used it but I'm faily sure it can. Looking at the answer I reference it seems like the LookupTable (constructed with a 2D array) is used to map source to destination colours. Check out LookupTable's lookupPixel method ... I'm fairly sure this is what will be called, typically with a 4-element src array containing the RGBA values (you should check this though). – Adamski Mar 03 '10 at 11:11
1

Have a look at BufferedImageFilter/BufferedImageOp to filter your image in the producer/consumer/observer paradigm.

Rahel Lüthy
  • 6,837
  • 3
  • 36
  • 51