JAVA Color[] 到 BufferedImage 到 Color[] 漂白输出

JAVA Color[] to BufferedImage to Color[] bleached output

我正在操作从 Color[] 数组生成输出图像的图像渲染器的代码,我的代码只是在保存之前用额外的东西更新它,也就是说当原始图像实际准备好时(准备好所有像素位置在该 Color[] 数组中填充 RGB 以备最终保存)。

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

出于这个原因 - 因为我没有 reach/access 用于原始准备好的 BufferedImage(但我可以访问创建它的实际 Color[])我不得不自己制作 class方法:

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

现在一切都像我预期的那样正常工作,除了一个我无法摆脱的非常烦人的事情:我更新的图像看起来非常 bleached-like/pale(几乎没有深度或阴影呈现)与原始无水印版本相比...

对我来说,在 image2color[] 转换之后(使用来自此处 Converting Image to Color array 的@stacker 解决方案),有些东西 wrong/is 不对,所以颜色变得苍白,我没有任何东西知道为什么。

这是我的代码中有问题的主要部分:

            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 到原始图像,包括。我在那张图片上的文字。

但正如我所说,当它被发送以进行渲染时,它变成了 bleached/pale 这是我正在努力解决的问题。

BTW 我一开始以为可能是Graphics2D的加法,所以我试了一下没有加它,结果还是一样的,就是bleached/pale版本。

尽管我的过程和代码完全不同,但输出图像基本上受到与本主题完全相同的影响(仍未解决)

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

正如所怀疑的那样,问题是在将 RGB 值设置为 BufferedImage 时,您将颜色值从线性 RGB 转换为 gamma-corrected/sRGB 值,但反向转换(返回线性 RGB)当您将值放回 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();

可以说,这更 "correct"(因为 AWT 将值视为 sRGB 颜色 space,无论如何),但我相信第一个版本更快,并且颜色不同可以忽略不计。所以我可能会先尝试第一个建议的修复方法,然后使用它,除非你遇到颜色不正确的情况。