BufferedImage.setRGB像素颜色错误

时间:2017-03-13 02:26:59

标签: java bufferedimage graphics2d javax.imageio

尝试做一些相对简单的事情,给定512x512 png的地图,我试图绘制点。我的代码相当简单,我尝试使用setRGB函数和createGraphics函数返回的Graphics2D对象。我必须忽略一些简单的事情。编辑:我应该提到我不打算创建一个新的BufferedImage,我正在寻找修改现有的BufferedImage,因为连续的库调用将继续修改我正在使用的BufferedImage。 (在下面的示例代码中,我从文件中读取了BufferedImage,这是一种复制问题的简单方法。

            File outputImage = new File("before.png");
            BufferedImage img = ImageIO.read(outputImage);


            img.setRGB(255, 255, new Color(0f, 1f, 0).getRGB());

            File after = new File("after.png");
            ImageIO.write(img, "png", after);

如果你放大得到的像素,它不是绿色,而是一些深灰色。由于这种行为与Graphics2D一致,我希望解决这个问题也能解决这个问题。

before.png after.png

2 个答案:

答案 0 :(得分:3)

BufferedImage的色彩空间必定会导致问题。

在下面的代码中,我使用原始图像并将其绘制为具有指定色彩空间的BufferedImage:

import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.swing.*;
import java.io.*;
import javax.imageio.*;
import java.net.*;

public class SSCCE extends JPanel
{
    SSCCE()
    {
        try
        {
            BufferedImage original = ImageIO.read( new File("map.png") );
            int width = original.getWidth(null);
            int height = original.getHeight(null);
            int size = 100;
            BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            Graphics2D g2d = bi.createGraphics();
            g2d.drawImage(original, 0, 0, null);

            int color = new Color(0f, 1f, 0f).getRGB();
            bi.setRGB(10, 10, color);
            bi.setRGB(10, 11, color);
            bi.setRGB(11, 10, color);
            bi.setRGB(11, 11, color);
            add( new JLabel( new ImageIcon(bi) ) );
        }
        catch(Exception e2) {}
    }

    private static void createAndShowGUI()
    {
        JFrame frame = new JFrame("SSCCE");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(new SSCCE());
        frame.pack();
        frame.setLocationByPlatform( true );
        frame.setVisible( true );
    }

    public static void main(String[] args)
    {
        EventQueue.invokeLater( () -> createAndShowGUI() );
/*
        EventQueue.invokeLater(new Runnable()
        {
            public void run()
            {
                createAndShowGUI();
            }
        });
*/
    }
}

答案 1 :(得分:1)

以下是根据评论中的讨论,尝试描述一些可以解决问题的方法:

问题是原始图像使用IndexColorModel(或颜色贴图或“调色板”,如果您愿意)。没有绿色完全与您指定的颜色匹配,因此颜色模型会进行查找以获得“最接近”颜色到您指定的颜色(您可以不同意这种颜色是最接近的匹配,但它给出了使用的算法)。

如果将颜色设置为与图像颜色匹配的颜色,则可以使用该颜色进行绘制。对于浅绿色的,请尝试new Color(0.8f, 0.9019608f, 0.6392157f)或RGB值0xffcce6a3。使用new Color(0.6392157f, 0.8f, 1f)0xffa3ccff作为浅蓝色。

如果您想知道我是如何找到这些值的,这就是解释。假设colorModelIndexColorModel,您可以使用:

int[] rgbs = new int[colorModel.getMapSize()]; 
colorModel.getRGBs(rgbs); 

...获取颜色图中的颜色。选择其中一种颜色应始终有效。

现在,如果你的“库”(你没有透露太多细节)使用固定的调色板来生成这些图像,那么你很好,并且可以使用我提到的颜色之一,或者使用所描述的方法获取颜色,并选择合适的颜色。如果没有,您需要动态找到最佳颜色。如果你真的没有运气,可能根本就没有合适的颜色(即,你的地图瓷砖都是海洋,唯一可用的颜色是海蓝色,不可能绘制绿点)。然后除了修改库之外别无他法解决这个问题。

一种完全不同的方法,可以类似于@ camickr的解决方案,您可以暂时将图像转换为真彩色(BufferedImage.TYPE_INT_RGBTYPE_3BYTE_BGR),将您的更改绘制到此临时图像上,然后绘制图像回到原始。这个可能更好地工作的原因是,组合机制将使用抖动和更好的颜色查找算法。但是你仍然会遇到与上一段所述的可用颜色相关的问题。

这是一个代码示例,使用暖黄色和输出:

Color color = new Color(0.89411765f, 0.5686275f, 0.019607844f);
int argb = color.getRGB();

Graphics2D g = image.createGraphics();
try {
    g.setColor(color);
    g.fillRect(10, 10, 50, 50);
}
finally {
    g.dispose();
}

image with yellow rectangle