【发布时间】:2015-01-08 14:58:16
【问题描述】:
我正在尝试从一些图像数据创建一个 BufferedImage,它是一个字节数组。图像是 RGB 格式,每个像素 3 个样本 - R、G 和 B,每个样本 32 位(对于每个样本,不是所有 3 个样本)。
现在我想从这个字节数组创建一个 BufferedImage。这就是我所做的:
ColorModel cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), new int[] {32, 32, 32}, false, false, Transparency.OPAQUE, DataBuffer.TYPE_INT);
Object tempArray = ArrayUtils.toNBits(bitsPerSample, pixels, samplesPerPixel*imageWidth, endian == IOUtils.BIG_ENDIAN);
WritableRaster raster = cm.createCompatibleWritableRaster(imageWidth, imageHeight);
raster.setDataElements(0, 0, imageWidth, imageHeight, tempArray);
BufferedImage bi = new BufferedImage(cm, raster, false, null);
上面的代码适用于每个样本 RGB 图像 24 位,但不是每个样本 32 位。生成的图像是垃圾,显示在图像的右侧。它应该像图像的左侧。
注意:我机器上唯一可以读取此图像的图像阅读器是 ImageMagick。所有其他显示的结果与下图右侧的垃圾类似。
ArrayUtils.toNBits() 只是将字节数组转换为具有正确字节序的 int 数组。我确定这个是正确的,因为我已经与其他方法进行了交叉检查以生成相同的 int 数组。
我猜这个问题可能源于我使用所有 32 位 int 来表示包含负值的颜色。看起来我需要 long 数据类型,但是 long 没有 DataBuffer 类型。
使用传输类型创建的 ComponentColorModel 实例 DataBuffer.TYPE_BYTE、DataBuffer.TYPE_USHORT 和 DataBuffer.TYPE_INT 具有被视为无符号整数的像素样本值 价值观。
以上引用来自 ComponentColorModel 的 Java 文档。这意味着 32 位样本确实被视为无符号整数值。那么问题可能出在其他地方。
有没有人遇到过类似的问题并找到了解决方法,或者我可能在这里做错了什么?
Update2:“真正的”问题在于,当使用 32 位样本时,ComponentColorModel 的算法将 1 向左移动 0 次(1
更新:根据 HaraldK 和 cmets 的回答,我们终于同意问题出在 Java 的 ComponentColorModel 没有正确处理 32 位样本。 HaraldK 提出的修复方案也适用于我的情况。以下是我的版本:
import java.awt.Transparency;
import java.awt.color.ColorSpace;
import java.awt.image.ComponentColorModel;
import java.awt.image.DataBuffer;
public class Int32ComponentColorModel extends ComponentColorModel {
//
public Int32ComponentColorModel(ColorSpace cs, boolean alpha) {
super(cs, alpha, false, alpha ? Transparency.TRANSLUCENT : Transparency.OPAQUE, DataBuffer.TYPE_INT);
}
@Override
public float[] getNormalizedComponents(Object pixel, float[] normComponents, int normOffset) {
int numComponents = getNumComponents();
if (normComponents == null || normComponents.length < numComponents + normOffset) {
normComponents = new float[numComponents + normOffset];
}
switch (transferType) {
case DataBuffer.TYPE_INT:
int[] ipixel = (int[]) pixel;
for (int c = 0, nc = normOffset; c < numComponents; c++, nc++) {
normComponents[nc] = ipixel[c] / ((float) ((1L << getComponentSize(c)) - 1));
}
break;
default: // I don't think we can ever come this far. Just in case!!!
throw new UnsupportedOperationException("This method has not been implemented for transferType " + transferType);
}
return normComponents;
}
}
【问题讨论】:
-
new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR);或其他类型常量之一,尤其是 TYPE_INT_RGB? -
@JoopEggen:BufferedImage.TYPE_4BYTE_ABGR 仅适用于每个样本 8 位。我的是每个样本 32 位。
-
我明白了,仍在使用 TIFF 阅读器。 ;-) 看起来有点像负面形象?可能是颜色模型问题?通过对我自己的 TIFFImageReader(尚不支持 RGB [32、32、32])进行一些快速更改,我读到了一张看起来就像你在右边的图像......
-
@haraldK:你敢打赌。我还尝试了 jai-imageio,它显示的和右边的一样。但无法弄清楚出了什么问题。
标签: java image rgb bufferedimage 32-bit