我正在尝试通过套接字发送BufferedImage
,我是通过将图像转换为byte[]
然后在Base64中对其进行编码后将其发送来实现的。我发送超过2个BufferedImages,其中一个是“满”,另一个是大约50%透明。我遇到的问题是,当它们到达时,第二个图像仍然在视觉上透明,但是当我通过Raster获取数据数组时,它已被更改。
我制作了一个小测试代码来证明问题;
BufferedImage levelBufferedOriginal = ...
BufferedImage backgroundBufferedOriginal = ...
byte[] levelDataOriginal = ((DataBufferByte) levelBufferedOriginal.getRaster().getDataBuffer()).getData();
byte[] backgroundDataOriginal = ((DataBufferByte) backgroundBufferedOriginal.getRaster().getDataBuffer()).getData();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] temp = null, temp2=null;
try {
ImageIO.write(levelBufferedOriginal, "png", baos);
baos.flush();
temp = baos.toByteArray();
baos.close();
baos=new ByteArrayOutputStream();
ImageIO.write(backgroundBufferedOriginal, "png", baos);
baos.flush();
temp2 = baos.toByteArray();
baos.close();
} catch (IOException e1) {
e1.printStackTrace();
}
BufferedImage levelBufferedNew = null;
BufferedImage backgroundBufferedNew = null;
try {
levelBufferedNew = ImageIO.read(new ByteArrayInputStream(temp));
backgroundBufferedNew = ImageIO.read(new ByteArrayInputStream(temp2));
} catch (IOException e) {
e.printStackTrace();
}
byte[] levelDataNew = ((DataBufferByte) levelBufferedNew.getRaster().getDataBuffer()).getData();
byte[] backgroundDataNew = ((DataBufferByte) backgroundBufferedNew.getRaster().getDataBuffer()).getData();
System.out.println("LEVEL: " + Arrays.equals(levelDataOriginal, levelDataNew));
System.out.println("BACKGROUND: " + Arrays.equals(backgroundDataOriginal, backgroundDataNew));
我在这里所做的只是将BufferedImage
转换为byte[]
,然后返回,并比较我从DataBufferByte
获得的数据。输出是
LEVEL:false
背景:真的
背景是“完整”图像,而Level是具有一些透明像素的图像。
如果一般的想法是错误的,我想听到另一个想法,我想要的是能够完全重建2个缓冲图像。
答案 0 :(得分:1)
编辑:到目前为止我们已经建立了什么:
byte
s)。后映像在此索引处具有不同的值,这是不透明的。这导致结论是ImageIO PNGImageWriter在写入时重新排列颜色映射中的条目,从而产生不同的像素数据/颜色映射。
这基本上给我们留下了两个选择:
以不同方式序列化图像数据,以确保不修改色彩映射/像素数据。可以发送像素数据阵列以及颜色映射阵列和图像的高度/宽度,然后在客户端准确地重新创建图像。这是相当多的代码,可能还有关于SO的其他问题。
不要依赖像素数据/颜色图相同。使用((IndexColorModel) levelBufferedNew.getColorModel()).getTransparentPixel()
的值来测试/设置透明度而不是硬编码值-1
。这几乎不需要对代码进行其他更改。
注意:这些解决方案仅适用于TYPE_BYTE_INDEXED(13)图像。
对于更通用(但可能更慢)的方法,使用原始答案中的代码设置透明部分,并使用(levelBufferedNew.getRGB(x, y) >> 24) == 0
测试透明度。这应该适用于TYPE_INT_ARGB或TYPE_4BYTE_ABGR。
原始回答:
为什么不尝试使用普通的Java2D,而不是在字节数组级别摆弄图像? ; - )
类似的东西:
Graphics2D g = levelBufferedNew.createGraphics();
try {
g.setComposite(AlphaComposite.Clear);
g.fillOval(x, y, w, h); // The area you want to make transparent
}
finally {
g.dispose();
}
......应该有用。
PS:由于图片使用IndexColorModel
,您可以使用getTransparentPixel()
获取透明像素索引,而不是依赖于某个索引(-1/255)。然后你仍然可以在字节数组级别进行操作。 ; - )