将字节数组转换并显示为图片

9

我正在制作一个程序,该程序从服务器获取图像的字节数组数据。我将这些数据转换成24位BMP格式(无论其是jpeg、png、bmp还是8-24-32bpp)。首先,我将其保存到我的硬盘上,然后将其加载到JLabel的图标中。虽然在某些情况下会出现以下异常:

java.io.EOFException at
javax.imageio.stream.ImageInputStreamImpl.readFully(ImageInputStreamImpl.java:353) at
com.sun.imageio.plugins.bmp.BMPImageReader.read24Bit(BMPImageReader.java:1188) at
com.sun.imageio.plugins.bmp.BMPImageReader.read(BMPImageReader.java:843) at
javax.imageio.ImageIO.read(ImageIO.java:1448) at 
javax.imageio.ImageIO.read(ImageIO.java:1308)

对于这行代码(第二行)

File imgFile = new File("d:/image.bmp");
BufferedImage image = ImageIO.read(imgFile);

在这些情况下:
  • 图片无法加载到JLabel中,但可以在我的硬盘上找到
  • 转换不正确,因为某些东西“滑动”了
  • 图片就像在Word文档中使用斜体字一样
起初,我以为可能是bpp的问题,然后我又想可能是图片太大了,但是对于这两个建议,我有时候会成功有时候会失败。我有点困惑,希望能得到一些想法。

1
你创建了那些图片吗?我能想到的是它们可能是使用某种 ImageIO 不支持的 BMP 格式创建的。也许你可以尝试编辑这些图片并重新保存。 - Piro
1
我认为问题在于一些图片没有EOF字节,这就是为什么你会得到“java.io.EOFException”的原因。我曾经在“jpeg”格式上遇到过同样的问题。如果你考虑文件的元数据包含有关文件长度的信息,那么这是有道理的,因此EOF不是必需的。这个事实解释了为什么你的文件可以在硬盘上找到(甚至可以打开),但在Java中却会出现异常。 - dic19
1
请查看这个链接,其中有我处理jpeg图像的经验分享,希望对您有所帮助。 - dic19
@dic19 谢谢你的想法!是的,它可以被打开,但不能用imageIO。然而,你的解决方案无法解决我的问题,但它很有用,因为现在我知道了那些文件并没有提到的EOF字节所引起的异常。 另外一件事,我把你代码中的system.arraycopy行替换成了arrays.copyof,因为我得到了参数错误。 - bajla
你能否在其他图像编辑软件中打开有问题的BMP文件?另外,你能否发布一个“损坏”的BMP链接?也许你可以尝试使用ImageIO来写入图像,而不是使用位图编码器?我认为问题可能出现在转换/写入BMP上,而不是读取上。 - Harald K
显示剩余3条评论
3个回答

7
  • 图片看起来像是在Word文档中使用斜体

我想我终于明白这个项目的意思了.. ;-)

以下是猜测的答案:

如果你写的图像看起来"倾斜",那么可能是由于缺少每列的填充,因为BMP格式规定了(或者BMP头文件中的宽度字段不正确)。然后我假设,你遇到EOF异常的图像,就是宽度不是4的倍数的图像。

尝试使用ImageIO编写BMPs以查看是否有帮助:

private static BufferedImage createRGBImage(byte[] bytes, int width, int height) {
    DataBufferByte buffer = new DataBufferByte(bytes, bytes.length);
    ColorModel cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), new int[]{8, 8, 8}, false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
    return new BufferedImage(cm, Raster.createInterleavedRaster(buffer, width, height, width * 3, 3, new int[]{0, 1, 2}, null), false, null);
}

...

byte[] bytes = ...; // Your image bytes
OutputStream stream = ...; // Your output

BufferedImage image = createRGBImage(bytes, width, height);

try {
    ImageIO.write(image, "BMP", stream);
}
finally {
    stream.close();
}

你很聪明,有问题的图像宽度为618、2671、598...而其他所有图像的宽度都是4的倍数。 - bajla
1
@bajla 很好。我现在更新了答案,加入了将RGB字节转换为“BufferedImage”的代码。你可以使用它,除非你已经弄清楚如何正确地填充图像数据(从我所理解的来看,Philipp C. Heckel的原始代码做得很好,但我只是粗略地浏览了一下)。 - Harald K
先生,这是绝对的获胜解决方案!感谢您的更新。我非常感激!这样图片显示更快,现在在所有情况下都可以正常工作!:) :) - bajla

2

按类名调用,例如 ClassName.byteArrayToImage(byte)

public static BufferedImage  byteArrayToImage(byte[] bytes){  
        BufferedImage bufferedImage=null;
        try {
            InputStream inputStream = new ByteArrayInputStream(bytes);
            bufferedImage = ImageIO.read(inputStream);
        } catch (IOException ex) {
            System.out.println(ex.getMessage());
        }
        return bufferedImage;
}

0
您可以使用此代码将输出图像转换为字节数组。
   Blob b = rs.getBlob(2);
   byte barr[] = new byte[(int)b.length()]; //create empty array
   barr = b.getBytes(1,(int)b.length());

   FileOutputStream fout = new FileOutputStream("D:\\sonoo.jpg");
   fout.write(barr);

我不想将图像转换为字节数组..第一行中的“rs”是什么?猜测它是一个图像,但我一开始就没有图像。 - bajla
rs是ResultSet对象。 - Mohsin Shaikh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接