有时候绘制到BufferedImage,但始终如一,会产生错误的颜色

时间:2017-11-30 23:33:34

标签: java graphics bufferedimage

我写了一个修改图像的程序。

首先,我得到图像,并得到它的绘图上下文:

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

Graphics g = image.createGraphics();

然后我像这样修改图像:

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);
    }
}

完成图像修改后,我将图像保存为:

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

现在大部分时间这都很好。

然而,当我尝试重新着色此纹理时

enter image description here

到这个

enter image description here

我得到了这个:

enter image description here

在调试器内部,Graphics的颜色是我想要的粉红色。

评论似乎表明用户打开的图像可能有一些颜色限制,而且由于我正在绘制我正在阅读的相同图像,因此我的程序必须遵守这些限制。示例图像似乎是非常灰度级的,显然它的位深度是8位。也许我正在绘制的粉红色转换为灰度,因为图像必须保持8位?

1 个答案:

答案 0 :(得分:0)

正如评论中所建议的,这里的主要问题确实是错误的颜色模型。加载原始图像时,打印一些有关它的信息......

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

它会说

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

IndexColorModel不一定支持所有颜色,只支持其中的一部分。 (基本上,图像仅支持“需要”的颜色,这样可以实现更紧凑的存储)。

此处的解决方案是将图像转换为具有适当颜色模型的图像。以下示例显示了一种通用方法:

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;
    }    
}