如何更改BufferedImage类型?

时间:2016-06-21 20:08:14

标签: java image graphics bufferedimage

我正在使用ImageIO导入图像以将图像组件(alpha,red,green,blue)存储在字节数组中。后来我需要读取这个字节数组,但我不知道组件的顺序(我不知道第一个元素是alpha,第二个是红色......还是不在数组中)存储,甚至存储alpha?

是否有默认序列?或者有没有办法将序列改为ABGR或ARGB等所需的序列。

获取数组中组件的当前代码。

    BufferedImage temp;

    try{
        temp = ImageIO.read(new File(path));
        ImageArray = ((DataBufferByte)temp.getRaster().getDataBuffer()).getData();
    }catch(IOException ex){
        ex.printStackTrace();
    }

java文档根本没有帮助我。

1 个答案:

答案 0 :(得分:4)

java中的BufferedImage对象有两个相关的方法:

int getRGB(int x, int y)

void setRGB(int x, int y, int rgb)

在这两种情况下,无论图像如何设置,像素通道都会遵循相同的方案。 int rgb是一个四字节整数。

最左边的字节是alpha,然后是红色,然后是蓝色,然后是绿色。也就是说,argb。由于一个字节可以容纳从0到255的小整数。每个字节具有256个不同的个体强度。实际位看起来像这样:

aaaaaaaarrrrrrrrggggggggbbbbbbbb

要提取您想要访问的颜色或alpha,请使用按位运算符。

如果我只想要红色例如,我可以使用bitshift操作符将位移16位,然后用十六进制值来提取该通道:

int rgb = image.getRGB(x, y);
int a = (rgb >> 24) & 0x000000ff;
int r = (rgb >> 16) & 0x000000ff;
int g = (rgb >>  8) & 0x000000ff;
int b =       (rgb) & 0x000000ff;

让我们看看它是如何发挥作用的。假设我们已经有了颜色:

rgb -> the binary 00101011 10101010 11111111 00000000

然后让它向右移16位:

00000000 00000000 00101011 10101010

注意,现在alpha还在那里......我们不想要它。因此,除了红色位之外,我们将清除所有内容:

    00000000 00000000 00101011 10101010
and 00000000 00000000 00000000 11111111
  = 00000000 00000000 00000000 10101010

这只是颜色10101010的红色成分。

您也可以使用相同的思路反过来设置所有三个位通道:

int rgb = (a << 24) | (r << 16) | (g << 8) | b;

...假设每个频道已经在0-255之间。

我总是记得如何使用助记符来使用按位运算符 “设置或清除 - ”。这意味着将位设置为1使用“或”。要清除一点为0,请使用“和”。 “&lt;&lt;&lt;&lt;和“&gt;&gt;”将位向左或向右移动箭头右侧操作数指定的次数。

修改后的答案(代码被添加到问题后)

即使因性能和清晰度原因而不鼓励,也可以直接将栅格作为各种数组进行访问。在这些情况下,字节的顺序遵循图像的类型和颜色模型。这是一个这样的例子:

BufferedImage img = new BufferedImage(100, 100, BufferedImage.TYPE_3BYTE_BGR);
// If we swap the type, what we put in our for loop will vary greatly
DataBufferByte dbb = ((DataBufferByte)img.getRaster().getDataBuffer());
byte[] bytes = dbb.getData();
for (int i = 0; i < bytes.length; i++) {
  // modify byte array here with bytes[i];
}
try {
  SampleModel sampleModel = new ComponentSampleModel(DataBuffer.TYPE_BYTE, 100, 100, 3, 100*3, new int[]{2, 1, 0});
  DataBuffer dataBuffer = new DataBufferByte(bytes, bytes.length);
  Raster raster = Raster.createRaster(sampleModel, dataBuffer, null);
  img.setData(raster);
} catch stuff......

如果您要将TYPE_3BYTE_BGR更改为TYPE_3BYTE_RGB,则上述示例中每隔三个字节(3n)将为红色而不是蓝色;另外,每三个加两个(3n + 2)字节将是蓝色而不是红色。这基本上只是交换红色和蓝色字节。

如果TYPE_3BYTE...BYTE更改为INT,则数组将是一个字节数组而不是整数。