JAVA Color[] 到 BufferedImage 到 Color[] 漂白输出
JAVA Color[] to BufferedImage to Color[] bleached output
我正在操作从 Color[] 数组生成输出图像的图像渲染器的代码,我的代码只是在保存之前用额外的东西更新它,也就是说当原始图像实际准备好时(准备好所有像素位置在该 Color[] 数组中填充 RGB 以备最终保存)。
我这样做的原因是能够插入描述我的渲染的文本,而不需要另一个外部图形程序来执行此操作(我想一次性完成所有操作!不需要另一个外部图形程序的操作应用程序)。
出于这个原因 - 因为我没有 reach/access 用于原始准备好的 BufferedImage(但我可以访问创建它的实际 Color[])我不得不自己制作 class方法:
- 将原始 Color[] 转换为我自己的临时 BufferedImage
- 更新那个温度。 BufferedImage 与我的东西通过 Graphics2D(向图像添加一些文本)
- 将我的结果(带 Graphics2D 的临时 BufferedImage)转换回颜色[]
- 将最终的 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,无论如何),但我相信第一个版本更快,并且颜色不同可以忽略不计。所以我可能会先尝试第一个建议的修复方法,然后使用它,除非你遇到颜色不正确的情况。
我正在操作从 Color[] 数组生成输出图像的图像渲染器的代码,我的代码只是在保存之前用额外的东西更新它,也就是说当原始图像实际准备好时(准备好所有像素位置在该 Color[] 数组中填充 RGB 以备最终保存)。
我这样做的原因是能够插入描述我的渲染的文本,而不需要另一个外部图形程序来执行此操作(我想一次性完成所有操作!不需要另一个外部图形程序的操作应用程序)。
出于这个原因 - 因为我没有 reach/access 用于原始准备好的 BufferedImage(但我可以访问创建它的实际 Color[])我不得不自己制作 class方法:
- 将原始 Color[] 转换为我自己的临时 BufferedImage
- 更新那个温度。 BufferedImage 与我的东西通过 Graphics2D(向图像添加一些文本)
- 将我的结果(带 Graphics2D 的临时 BufferedImage)转换回颜色[]
- 将最终的 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,无论如何),但我相信第一个版本更快,并且颜色不同可以忽略不计。所以我可能会先尝试第一个建议的修复方法,然后使用它,除非你遇到颜色不正确的情况。