如何更改 BufferedImage 类型?
How can i change the BufferedImage type?
我正在使用 ImageIO
导入图像以将图像组件(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 文档对我一点帮助都没有。
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,请使用按位运算符。
例如,如果我只想要红色,我可以使用位移运算符将位向右移动 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 之间。
我一直记得如何使用助记符来使用位运算符
"set-or clear-and"。这意味着使用 "or" 将位设置为 1。要将位清零,请使用 "and"。 “<<”和“>>”将位向左或向右移动由箭头右侧的操作数指定的次数。
修改后的答案(代码添加到问题后)
尽管出于性能和清晰度的原因不鼓励这样做,但栅格可以作为各种数组直接访问。在这些情况下,字节顺序遵循图像的类型和颜色模型。这是一个这样的例子:
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
,数组将是字节数组而不是整数数组。
我正在使用 ImageIO
导入图像以将图像组件(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 文档对我一点帮助都没有。
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,请使用按位运算符。
例如,如果我只想要红色,我可以使用位移运算符将位向右移动 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 之间。
我一直记得如何使用助记符来使用位运算符 "set-or clear-and"。这意味着使用 "or" 将位设置为 1。要将位清零,请使用 "and"。 “<<”和“>>”将位向左或向右移动由箭头右侧的操作数指定的次数。
修改后的答案(代码添加到问题后)
尽管出于性能和清晰度的原因不鼓励这样做,但栅格可以作为各种数组直接访问。在这些情况下,字节顺序遵循图像的类型和颜色模型。这是一个这样的例子:
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
,数组将是字节数组而不是整数数组。