绘制到 BufferedImage 有时但始终会产生错误的颜色
Drawing to a BufferedImage sometimes, but consistently, yields wrong colors
我写了一个修改图片的程序。
首先,我获取图像,并获取其绘图上下文,如下所示:
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 ... */ }
现在大部分时间都可以正常工作。
但是,当我尝试重新着色此纹理时
至此
我改为:
不过,在调试器内部,Graphics
的颜色是我想要的粉红色。
这些评论似乎表明用户打开的图像可能有一些颜色限制,并且由于我绘制的图像与我正在阅读的图像相同,所以我的程序必须遵守这些限制。示例图像似乎是非常灰度的,显然它的位深度是 8 位。所以也许我在上面画的粉红色被转换为灰度,因为图像必须保持 8 位?
正如评论中所建议的,这里的主要问题确实是错误的颜色模型。当您加载原始图像并打印有关它的一些信息时...
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
不一定支持所有的颜色,只是其中的一个子集。 (基本上,图像只支持它 "needs" 的颜色,这样可以更紧凑地存储)。
此处的解决方案是将图像转换为具有适当颜色模型的图像。下面的示例显示了一个通用方法:
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;
}
}
我写了一个修改图片的程序。
首先,我获取图像,并获取其绘图上下文,如下所示:
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 ... */ }
现在大部分时间都可以正常工作。
但是,当我尝试重新着色此纹理时
至此
我改为:
不过,在调试器内部,Graphics
的颜色是我想要的粉红色。
这些评论似乎表明用户打开的图像可能有一些颜色限制,并且由于我绘制的图像与我正在阅读的图像相同,所以我的程序必须遵守这些限制。示例图像似乎是非常灰度的,显然它的位深度是 8 位。所以也许我在上面画的粉红色被转换为灰度,因为图像必须保持 8 位?
正如评论中所建议的,这里的主要问题确实是错误的颜色模型。当您加载原始图像并打印有关它的一些信息时...
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
不一定支持所有的颜色,只是其中的一个子集。 (基本上,图像只支持它 "needs" 的颜色,这样可以更紧凑地存储)。
此处的解决方案是将图像转换为具有适当颜色模型的图像。下面的示例显示了一个通用方法:
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;
}
}