0

I've written a program to modify images.

First, I get the image, and get its drawing context like this:

BufferedImage image;
try {
    image = ImageIO.read(inputFile);
} catch (IOException ioe) { /* exception handling ... */ }

Graphics g = image.createGraphics();

And then I modify the image like this:

for (int x = 0; x < image.getWidth(); x++) {
    for (int y = 0; y < image.getHeight(); y++) {
        g.setColor( /* calculate color ... */ );
        g.fillRect(x, y, 1, 1);
    }
}

After I've finished modifying the image, I save the image like this:

try {
    ImageIO.write(image, "PNG", save.getSelectedFile());
} catch (IOException ioe) { /* exception handling ... */ }

Now most of the time this works just fine.

However, when I tried recoloring this texture

enter image description here

to this

enter image description here

I get this instead:

enter image description here

Inside the debugger, though, the Graphics's color is the shade of pink I want it to be.

The comments seem to suggest that the image the user opens might have some color limitations, and since I'm drawing to the same image I'm reading from, my program has to abide by these limitations. The example image seems to be pretty grayscale-y, and apparently its bit depth is 8 bit. So maybe the pink I'm drawing on it is converted to grayscale, because the image has to stay 8-bit?

Marco13
  • 53,703
  • 9
  • 80
  • 159
  • 1
    Any chance to provide a setup (i.e. [MCVE] and example image) where it is possible to reproduce this? – Marco13 Nov 30 '17 at 23:45
  • 2
    The color model may not support the colors you are using – MadProgrammer Dec 01 '17 at 00:11
  • @Marco13 I added an example to my question. – Felix Klenk Dec 05 '17 at 08:49
  • @MadProgrammer do you mean I have to work with the limitations of the image the BufferedImage was read from? Like if it was read from a GIF, I have to work with the 256 colors it came with? – Felix Klenk Dec 05 '17 at 08:51
  • I’d be more worried about the target color model – MadProgrammer Dec 05 '17 at 09:02
  • @MadProgrammer There's only one BufferedImage in the program. I'm drawing to the same one I'm reading from. – Felix Klenk Dec 05 '17 at 09:08
  • So, if the original color model has a limited palette, it's possible that any color not found the palette might be converted to a "close" approximation, based on what's available in the color model – MadProgrammer Dec 05 '17 at 10:24
  • That kinda makes sense considering the results I've been getting. Thanks! From now on I'll use a separate output BufferedImage whenever I'm doing this sort of stuff. – Felix Klenk Dec 05 '17 at 14:01
  • Someone has downvoted this question. I'd actually consider upvoting this, because it can be a subtle caveat that may be relevant for others. But for this, it should be a bit "cleaned up" and more focussed on the point (maybe with code+images uploaded here). @MadProgrammer Do you think it's worth editing this? – Marco13 Dec 06 '17 at 22:28
  • @Marco13 The question is difficult to diagnose, as it does not provide any example (including code and source image/result image) from which deductions can be derived. While the OP can't post images, the code should be provided and more detail information about the source image should be provided - especially the image type and color model - this is just my opinion though – MadProgrammer Dec 06 '17 at 22:37
  • I changed it, I hope I made it better @Marco13 – Felix Klenk Dec 07 '17 at 20:25
  • @JoFelix Much better. The `FileChooser` stuff is not really relevant for the question, though. Do you mind if I edit it accordingly (and embed the images)? – Marco13 Dec 07 '17 at 23:22
  • @Marco13 feel free to do whatever improves my question. You seem to have much more experience with StackOverflow than me. – Felix Klenk Dec 09 '17 at 00:12

1 Answers1

0

As suggested in the comments, the main problem here indeed is the wrong color model. When you load the original image, and print some information about it...

BufferedImage image = ImageIO.read(
    new URL("https://i.stack.imgur.com/pSUFR.png"));
System.out.println(image);

it will say

BufferedImage@5419f379: type = 13 IndexColorModel: #pixelBits = 8 numComponents = 3 color space = java.awt.color.ICC_ColorSpace@7dc7cbad transparency = 1 transIndex   = -1 has alpha = false isAlphaPre = false ByteInterleavedRaster: width = 128 height = 128 #numDataElements 1 dataOff[0] = 0

The IndexColorModel does not necessarily support all the colors, but only a subset of them. (Basically, the image supports only the colors that it "needs", which allows for a more compact storage).

The solution here is to convert the image into one that has the appropriate color model. A generic method for this is shown in the following example:

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.URL;

import javax.imageio.ImageIO;

public class ImageColors
{
    public static void main(String[] args) throws IOException
    {
        BufferedImage image = ImageIO.read(
            new URL("https://i.stack.imgur.com/pSUFR.png"));

        // This will show that the image has an IndexColorModel.
        // This does not necessarily support all colors.
        System.out.println(image);

        // Convert the image to a generic ARGB image
        image = convertToARGB(image);

        // Now, the image has a DirectColorModel, supporting all colors
        System.out.println(image);

        Graphics2D g = image.createGraphics();
        g.setColor(Color.PINK);
        g.fillRect(50, 50, 50, 50);
        g.dispose();

        ImageIO.write(image, "PNG", new File("RightColors.png"));
    }

    public static BufferedImage convertToARGB(BufferedImage image)
    {
        BufferedImage newImage = new BufferedImage(
            image.getWidth(), image.getHeight(),
            BufferedImage.TYPE_INT_ARGB);
        Graphics2D g = newImage.createGraphics();
        g.drawImage(image, 0, 0, null);
        g.dispose();
        return newImage;
    }    
}
Marco13
  • 53,703
  • 9
  • 80
  • 159