【问题标题】:JAVA Color[] to BufferedImage to Color[] bleached outputJAVA Color[] to BufferedImage to Color[] 漂白输出
【发布时间】:2016-10-27 23:24:56
【问题描述】:

我正在处理从 Color[] 数组生成输出图像的图像渲染器的代码,我的代码只是在保存之前用其他内容更新它,即实际准备原始图像时(所有像素位置都准备好填充了该 Color[] 数组中的 RGB,准备最终保存)。

我这样做的原因是能够插入描述我的渲染的文本,而无需另一个可以执行此操作的外部图形程序(我想一次性完成所有操作!无需另一个外部应用程序) .

出于这个原因 - 因为我无法访问/访问原始准备的 BufferedImage(但我可以访问创建它的实际 Color[]),所以我必须创建自己的类方法:

  1. 将原来的 Color[] 转换为我自己的临时 BufferedImage
  2. 更新该温度。 BufferedImage 与我的东西通过 Graphics2D(添加一些文本到图像)
  3. 将我的结果(带有 Graphics2D 的 temp.BufferedImage)转换回 Color[]
  4. 将最终的 Color[] 发送回原始图像渲染方法 这实际上会使它成为渲染出来的最终图像 并保存为 png

现在一切正常,除了我无法摆脱的一件非常烦人的事情:我更新的图像看起来非常漂白/苍白(几乎没有深度或阴影)原始无水印版本...

在我看来,在 image2color[] 转换之后(使用 @stacker 的解决方案,从这里 Converting Image to Color array)出现问题/不正确,所以颜色变得苍白,我不知道为什么。

这是我的代码的主要部分:

            BufferedImage sourceImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

            // Color[] to BufferedImage
            for (int k = 0; k < multiArrayList.size(); k++) {

                // PREPARE...
                int x = (int) multiArrayList.get(k)[0];
                int y = (int) multiArrayList.get(k)[1];
                int w = (int) multiArrayList.get(k)[2];
                int h = (int) multiArrayList.get(k)[3];
                Color[] data = (Color[]) multiArrayList.get(k)[4];
                int border = BORDERS[k % BORDERS.length];

                for (int by = 0; by < h; by++) {
                    for (int bx = 0; bx < w; bx++) {
                        if (bx == 0 || bx == w - 1) {
                            if (5 * by < h || 5 * (h - by - 1) < h) {
                                sourceImage.setRGB(x + bx, y + by, border);
                            }
                        } else if (by == 0 || by == h - 1) {
                            if (5 * bx < w || 5 * (w - bx - 1) < w) {
                                sourceImage.setRGB(x + bx, y + by, border);
                            }
                        }
                    }
                }
                // UPDATE...
                for (int j = 0, index = 0; j < h; j++) {
                    for (int i = 0; i < w; i++, index++) {
                        sourceImage.setRGB(x + i, y + j, data[index].copy().toNonLinear().toRGB());
                    }
                }
            }

            Graphics2D g2d = (Graphics2D) sourceImage.getGraphics();

            // paints the textual watermark
            drawString(g2d, text, centerX, centerY, sourceImage.getWidth());

            // when saved to png at this point ALL IS JUST FINE
            ImageIO.write(sourceImage, "png", new File(imageSavePath));
            g2d.dispose();

            // BufferedImage to Color array
            int[] dt = ((DataBufferInt) sourceImage.getRaster().getDataBuffer()).getData();

            bucketFull = new Color[dt.length];
            for (int i = 0; i < dt.length; i++) {
                bucketFull[i] = new Color(dt[i]);
            }

            // update and repaint output image - THIS OUTPUT IS ALREADY BLEACHED/PALE
            d.ip(0, 0, width, height, renderThreads.length + 1);
            d.iu(0, 0, width, height, bucketFull);

            // reset objects
            g2d = null;
            sourceImage = null;
            bucketFull = null;
            multiArrayList = new ArrayList<>();

我已经测试(通过在添加 Graphics2D 后立即将其保存到另一个 .png 文件),在它进行第二次转换之前,它看起来绝对可以 1:1 到原始图像,包括。我在那张图片上的文字。

但正如我所说,当它发送渲染时,它会变白/苍白,这是我要解决的问题。

顺便说一句我一开始以为可能是添加了 Graphics2D,所以我确实尝试了没有它,但结果是一样的,那就是漂白/苍白的版本。

虽然我的流程和代码完全不同,但输出图像基本上与本主题完全相同(仍未解决)BufferedImage color saturation

这是我的 2 个示例 - 第一个原始,第二个更新(漂白/苍白)

【问题讨论】:

  • 您使用的Color 类是什么?好像不是java.awt.Color...更具体地说,data[index].copy().toNonLinear().toRGB() 是做什么的?似乎您在将颜色值传递给BufferedImage 之前对其进行了转换。但是你不要在任何地方做相反的事情。我怀疑这是问题所在。
  • @haraldK 它使用 float 0-1 而不是 int 0-255,data[index].copy().toNonLinear().toRGB() 取自原始代码不太清楚它到底是什么确实如此,但我认为它可以纠正/操纵伽玛...无论如何:我现在在没有“.copy().toNonLinear()”部分和 WOW: NOW IT RENDERS OK 的情况下对其进行了测试 - 非常感谢!您想将此作为独立建议发布,以便我可以将其作为正确答案签名吗? ;-)
  • 好!我已经添加了一个答案。 :-)

标签: java image colors rendering bufferedimage


【解决方案1】:

正如怀疑的那样,问题是在将 RGB 值设置为BufferedImage 时,您将颜色值从线性 RGB 转换为伽马校正/sRGB 值,但在您将值放回 Color 数组中。

要么换行(在双 for 循环内):

sourceImage.setRGB(x + i, y + j, data[index].copy().toNonLinear().toRGB());

sourceImage.setRGB(x + i, y + j, data[index].toRGB());

(您不再需要 copy(),因为您不再使用 toNonLinear() 改变值)。

这完全避免了转换。


...或者您可以也可能更改设置值的行,来自:

bucketFull[i] = new Color(dt[i]);

bucketFull[i] = new Color(dt[i]).toLinear();

可以说,这更“正确”(因为 AWT 将值视为在 sRGB 颜色空间中,无论如何),但我相信第一个版本更快,颜色差异可以忽略不计。所以我可能会先尝试第一个建议的修复,然后使用它,除非您遇到颜色不亮的情况。

【讨论】:

  • 是的,就是这样:“bucketFull[i] = new Color(dt[i]).toLinear();”
猜你喜欢
  • 2012-11-11
  • 2022-07-28
  • 2022-12-02
  • 2020-03-26
  • 2022-12-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多