用Java编写ICO解码器

时间:2016-10-07 14:42:01

标签: java bitmap bufferedimage bmp ico

我正在尝试用Java编写ICO解码器,因此我能够显示来自网站的favicon。我第一次使用image4j库,但发现它没有解码我扔给它的所有favicon。因此经过一些调查后,我意识到image4j只能解码包含PNG图像的ICO文件或标题大小为40 which turns out to be bitmaps with the header type BITMAPINFOHEADER的BMP图像。由于Windows Vista大多数位图包含BITMAPV5HEADER或其他类似BITMAPV4HEADER的内容,因此image4j不适合我。

我尝试编写自己的ICO解码器,现在可以正常工作,但唯一的问题是从数据中重新构造BufferedImage。根据维基百科,PNG图像完全存储在其中,并且BMP图像也完全存储在其中但没有文件头。而不是为每个压缩,图像格式编写解码例程......我注意到ImageIO API支持大多数Windows位图标题(8位,16位位图和Adobe除外)。但是有一个小问题,为了使用ImageIO.read(Inputstream input),BMP图像需要一个可以看到here的文件头。所以我要做的是为BMP图像重新创建the file header,从ICO文件追加BMP数据并尝试使用ImageIO.read(Inputstream stream)读取它。目前我得到一个EOF异常,我认为它必须在文件头中声明图像数据偏移,但也可能是我写错了数据。

下面是一些显示我正在做的事情的代码:

final BitmapInfoHeader infoHeader = new BitmapInfoHeader(data);//decodes bitmapheader to figure out amount of color palette entries
final int fileHeaderSize = 14;
final int offset = fileHeaderSize + infoHeader.headerSize + infoHeader.clrImportant * 4;// offset = 54
final int fileSize = offset + data.length + fileHeaderSize;// file size = 1196
final ByteBuffer BMPFile = ByteBuffer.allocate(fileSize).order(ByteOrder.LITTLE_ENDIAN);
//BMPFile.putChar('B');//when doing this file header is 16 bytes long
//BMPFile.putChar('M');
BMPFile.put((byte) 'B');//when doing this file header is 14 bytes long
BMPFile.put((byte) 'M');
BMPFile.putInt(fileSize);
BMPFile.putInt(0); //Reserved
BMPFile.putInt(offset);
BMPFile.put(data); //Data from ICO file

final byte[] imageData = BMPFile.array();
System.out.println("File header + data: " + Arrays.toString(imageData));

final BufferedImage favIcon = ImageIO.read(new ByteArrayInputStream(imageData));//Throws EOF exception

输出:

  

/ *******阅读ICO文件******* /

     

图片类型:1 - > .ICO

     

参赛作品数量:2

     

条目#1-> 16X16 |调色板:0 |保留:0 |飞机:0 |格式:32 |   数据大小:1128 |数据偏移:38

     

条目#2-> 32X32 |调色板:0 |保留:0 |飞机:0 |格式:32 |   数据大小:4264 |数据偏移:1166

     

数据输入#1:(1128) - > [40,0,0,0,16,0,0,0,32,0,0,0,1,0,   32,0,0,0,0,0,64,4 ......

     

/ *******阅读BITMAP HEADER ******* /

     

HeaderSize:40
  [BITMAPINFOHEADER]
  宽度:16 |身高:32 |   colorPlanes:1 | bitsPerPixel:32 |压缩:0 |图像大小:1088   | xPelsPerMeter:0 | yPelsPerMeter:0 | clrUsed:0 | clrImportant:0

     

/ *******创建BITMAP文件标题******* /

     

文件头+数据:[66,77,0,0,4,-84,0,0,0,0,0,0,04,   40,0,0,0,16,0,0,0,32,0,0,0,1,0,32,0,0,0,0,0,64,   4,...

当使用字节表示幻数时重新构造文件头时,文件头大小为14个字节:

BMPFile.put((byte) 'B');
BMPFile.put((byte) 'M');
                 "B" "M"                             | 14 bytes
     

文件头+数据:[66,77,0,0,4,-84,0,0,0,0,0,0,04,   40,0,0,0,16,0,0,0,32,0,0,0,1,0,32,0,0,0,0,0,64,   4,...

但是当使用putChar作为幻数时,文件头大小为16字节:

BMPFile.putChar('B');
BMPFile.putChar('M');
                 --B-- --M--                              | 16 bytes 
     

文件头+数据:[0,66,0,77,0,0,4,-84,0,0,0,0,0,0,04,50,0,0,0, 16,0,0,0,32,0,0,0,1,0,32,0,0,0,0,0,64,4,

欢迎所有帮助:)

0 个答案:

没有答案