Java BuffereImage.setRGB像素颜色错误

Java BuffereImage.setRGB像素颜色错误,java,bufferedimage,graphics2d,javax.imageio,Java,Bufferedimage,Graphics2d,Javax.imageio,尝试做一些相对简单的事情,给定512x512 png的地图,我尝试绘制点。我的代码非常简单,我尝试使用setRGB函数和createGraphics函数返回的Graphics2D对象。我一定忽略了一些简单的事情。编辑:我应该提到,我不是要创建新的BuffereImage,而是要修改现有的BuffereImage,因为连续的库调用将继续修改我正在使用的BuffereImage。在下面的示例代码中,我从文件中读取了BuffereImage,这是一种复制问题的简单方法 File

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

            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是一致的,所以我希望解决这个问题也能解决这个问题


缓冲区图像的颜色空间一定是造成问题的原因

在下面的代码中,我使用原始图像并使用指定的颜色空间将其绘制到BuffereImage:

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();
            }
        });
*/
    }
}

BuffereImage的颜色空间一定是造成问题的原因

在下面的代码中,我使用原始图像并使用指定的颜色空间将其绘制到BuffereImage:

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();
            }
        });
*/
    }
}

根据评论中的讨论,这里尝试描述一些解决问题的方法:


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

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

如果你想知道我是如何找到这些值的,下面是解释。假设colorModel是IndexColorModel,则可以使用:

int[] rgbs = new int[colorModel.getMapSize()]; 
colorModel.getRGBs(rgbs); 
…以获取颜色贴图中的颜色。选择这些颜色中的一种应该总是有效的

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

一种完全不同的方法,可能类似于@camickr的解决方案,即临时将图像转换为真彩色BuffereImage.TYPE_INT_RGB或TYPE_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();
}

根据评论中的讨论,这里尝试描述一些解决问题的方法:


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

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

如果你想知道我是如何找到这些值的,下面是解释。假设colorModel是IndexColorModel,则可以使用:

int[] rgbs = new int[colorModel.getMapSize()]; 
colorModel.getRGBs(rgbs); 
…以获取颜色贴图中的颜色。选择这些颜色中的一种应该总是有效的

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

一种完全不同的方法,也可能是类似的 对于@camickr的解决方案,您可以临时将图像转换为真彩色BuffereImage.TYPE_INT_RGB或TYPE_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();
}

问题是原始图像正在使用IndexColorModel或颜色贴图或调色板(如果您愿意)。没有与指定的颜色匹配的绿色,因此颜色模型会进行查找,以获得与指定颜色最接近的颜色@camickr的解决方案应该可以很好地工作,尽管问题在于颜色模型而不是颜色空间,它们都是RGB-问题是原始图像正在使用IndexColorModel或颜色贴图或调色板(如果您愿意)。没有与指定的颜色匹配的绿色,因此颜色模型会进行查找,以获得与指定颜色最接近的颜色@camickr的解决方案应该可以很好地工作,尽管问题在于颜色模型而不是颜色空间,它们都是RGB-谢谢,但是有没有办法用现有的BuffereImage实现这一点?没有创建一个新的?我正在从库调用中获取BuffereImage,需要修改它,而不是创建一个新的。@ParthMehrotra,我给了你我能想到的最好的解决方案。我不知道色彩空间是如何工作的,也不知道如何在两者之间转换。阅读BuffereImage API并查看ColorSpace类。也许你能想出办法。您的要求是将图像保存到文件中。我看不出是否先创建原始图像的副本有多重要。重要的是,带有更改的图像被保存到一个文件中。我的要求是绘制多个点,我从来没有真正提到过将任何内容保存到一个文件中。谢谢你告诉我这个问题是由颜色空间引起的,这是我可以进一步研究的。但是,不幸的是,这并不能解决我的问题。我对你的答案投了更高的票,因为它帮助了我,也许它将来也会帮助别人,但被接受的答案必须与给定的BuffereImage一起工作。今晚我将试着提供一个被接受的答案。@haraldK,谢谢你理解我的建议。无论这个图书馆是什么,OP都在谈论。库可以在将图像加载到库中时转换图像,然后访问库图像的任何其他进程都将使用相同的转换图像。谢谢,但是有没有任何方法可以使用现有的BuffereImage执行此操作?没有创建一个新的?我正在从库调用中获取BuffereImage,需要修改它,而不是创建一个新的。@ParthMehrotra,我给了你我能想到的最好的解决方案。我不知道色彩空间是如何工作的,也不知道如何在两者之间转换。阅读BuffereImage API并查看ColorSpace类。也许你能想出办法。您的要求是将图像保存到文件中。我看不出是否先创建原始图像的副本有多重要。重要的是,带有更改的图像被保存到一个文件中。我的要求是绘制多个点,我从来没有真正提到过将任何内容保存到一个文件中。谢谢你告诉我这个问题是由颜色空间引起的,这是我可以进一步研究的。但是,不幸的是,这并不能解决我的问题。我对你的答案投了更高的票,因为它帮助了我,也许它将来也会帮助别人,但被接受的答案必须与给定的BuffereImage一起工作。今晚我将试着提供一个被接受的答案。@haraldK,谢谢你理解我的建议。无论这个图书馆是什么,OP都在谈论。库可以在将图像加载到库中时转换图像,然后访问库图像的任何其他进程都将使用相同的转换图像。