Java 的当前发行版并不正式支持在 Java 应用程序中读取 Microsoft Windows 位图文件但别担心我们有办法解决这个问题!这篇技巧将说明如何完成这一任务 我们首先说明读取 Microsoft Windows 文件格式的基本步骤
Windows DIB(设备独立的位图)文件格式比较简单与纯位图格式不同DIB 格式保留着用于在内存中存储图像的明确信息问题是图像格式的变体如此之多( 位 位 位和 位以及其他格式)本篇 Java 技巧中提供的解决方案只处理 位和 位两种格式这两种格式代表了最常见的变体
不管是哪种 Windows DIB 子类型这种文件格式总是由 位文件头和 位信息头组成这两个标头精确包含有关文件的存储内容和存储次序的信息有关标头中每一项的确切含义请参考 Microsoft Software Development Kit (SDK)文件其余部分的内容随信息头中数据的不同而不同
我们看一下本文要处理的两种子类型 位格式很简单RGB(红绿蓝)颜色值( 个字节并按 BGR 排序)紧接在信息头之后但是每个扫描行都被补足到 个字节按照说明文档(请参阅 Microsoft SDK)的说法这种补足是为了优化 Windows 位图绘图 API同时底部的扫描行是文件中的第一项内容 因此相对普通的图形坐标系统(其矢量方向的正向分别为向下和向右)而言必须从后向前读取图像
位子类型由于在信息头和象素数据之间插入调色板信息而复杂化因此每个象素条目只是进入 位 RGB 颜色的调色板数组的一个 位索引在象素信息中每个扫描行同样被补足到 个字节
请注意本文提供的位图图像加载方法不支持对压缩位图图像进行解压缩实际上这个例程甚至不寻求这种可能性!如果遇到压缩 Windows DIB 文件该例程肯定会产生异常Windows SDK 中有对压缩 Windows DIB 格式的说明
至于性能在运行 Microsoft Windows 的 DXMHz 系统上该例程读取 位 x 的文件(大约 千字节)所需的时间不超过 秒使用 BufferedInputStream 而不是 FileInputStream 可明显提高性能
以下例程读取两种文件格式中的任一种并生成一个 Image 图像以下代码并未包含全面的错误和异常处理以避免使该例程更加复杂您总可用 Windows Paint 程序对不支持的 Windows DIB 子类型进行转换
/**
loadbitmap() 方法由 Windows C 代码转换而来
只能读取未压缩的 位和 位图像已在
Windows 上用 Microsoft Paint 保存的图像
对它进行了测试如果图像不是 位或 位图像
该程序拒绝进行任何尝试我猜测如果先用
然后用 对字节执行掩码操作则也可将 位
图像包括在内我实际上对这些图像不感兴趣
如果尝试读取压缩图像该例程可能失败并产生
一个 IOException 异常如果变量 ncompression
不为 则表示已经过压缩
参数
sdir 和 sfile 是 FileDialog 的
getDirectory() 和 getFile() 方法的结果
返回值
Image 对象切记要检查 (Image)null !!!!
*/
public Image loadbitmap (String sdir String sfile)
{
Image image;
Systemoutprintln(loading:+sdir+sfile);
try
{
FileInputStream fs=new FileInputStream(sdir+sfile);
int bflen=; // 字节 BITMAPFILEHEADER
byte bf[]=new byte[bflen];
fsread(bfbflen);
int bilen=; // 字节 BITMAPINFOHEADER
byte bi[]=new byte[bilen];
fsread(bibilen);
// 解释数据
int nsize = (((int)bf[]&xff)< < )
| (((int)bf[]&xff)< < )
| (((int)bf[]&xff)< < )
| (int)bf[]&xff;
Systemoutprintln(File type is :+(char)bf[]+(char)bf[]);
Systemoutprintln(Size of file is :+nsize);
int nbisize = (((int)bi[]&xff)< < )
| (((int)bi[]&xff)< < )
| (((int)bi[]&xff)< < )
| (int)bi[]&xff;
Systemoutprintln(Size of bitmapinfoheader is :+nbisize);
int nwidth = (((int)bi[]&xff)< < )
| (((int)bi[]&xff)< < )
| (((int)bi[]&xff)< < )
| (int)bi[]&xff;
Systemoutprintln(Width is :+nwidth);
int nheight = (((int)bi[]&xff)< < )
| (((int)bi[]&xff)< < )
| (((int)bi[]&xff)< < )
| (int)bi[]&xff;
Systemoutprintln(Height is :+nheight);
int nplanes = (((int)bi[]&xff)< < ) | (int)bi[]&xff;
Systemoutprintln(Planes is :+nplanes);
int nbitcount = (((int)bi[]&xff)< < ) | (int)bi[]&xff;
Systemoutprintln(BitCount is :+nbitcount);
// 查找表明压缩的非零值
int ncompression = (((int)bi[])< < )
| (((int)bi[])< < )
| (((int)bi[])< < )
| (int)bi[];
Systemoutprintln(Compression is :+ncompression);
int nsizeimage = (((int)bi[]&xff)< < )
| (((int)bi[]&xff)< < )
| (((int)bi[]&xff)< < )
| (int)bi[]&xff;
Systemoutprintln(SizeImage is :+nsizeimage);
int nxpm = (((int)bi[]&xff)< < )
| (((int)bi[]&xff)< < )
| (((int)bi[]&xff)< < )
| (int)bi[]&xff;
Systemoutprintln(XPixels per meter is :+nxpm);
int nypm = (((int)bi[]&xff)< < )
| (((int)bi[]&xff)< < )
| (((int)bi[]&xff)< < )
| (int)bi[]&xff;
Systemoutprintln(YPixels per meter is :+nypm);
int nclrused = (((int)bi[]&xff)< < )
| (((int)bi[]&xff)< < )
| (((int)bi[]&xff)< < )
| (int)bi[]&xff;
Systemoutprintln(Colors used are :+nclrused);
int nclrimp = (((int)bi[]&xff)< < )
| (((int)bi[]&xff)< < )
| (((int)bi[]&xff)< < )
| (int)bi[]&xff;
Systemoutprintln(Colors important are :+nclrimp);
if (nbitcount==)
{
// 位格式不包含调色板数据但扫描行被补足到
// 个字节
int npad = (nsizeimage / nheight) nwidth * ;
int ndata[] = new int [nheight * nwidth];
byte brgb[] = new byte [( nwidth + npad) * * nheight];
fsread (brgb (nwidth + npad) * * nheight);
int nindex = ;
for (int j = ; j <nheight; j++)
{
for (int i = ; i <nwidth; i++)
{
ndata [nwidth * (nheight j ) + i] =
(&xff)< <
| (((int)brgb[nindex+]&xff)< < )
| (((int)brgb[nindex+]&xff)< < )
| (int)brgb[nindex]&xff;
// Systemoutprintln(Encoded Color at (
+i++j+)is:+nrgb+ (RGB)= (
+((int)(brgb[]) & xff)+
+((int)brgb[]&xff)+
+((int)brgb[]&xff)+));
nindex += ;
}
nindex += npad;
}
image = createImage
( new MemoryImageSource (nwidth nheight
ndata nwidth));
}
else if (nbitcount == )
{
// 必须确定颜色数如果 clrsused 参数大于
// 则颜色数由它决定如果它等于 则根据
// bitsperpixel 计算颜色数
int nNumColors = ;
if (nclrused > )
{
nNumColors = nclrused;
}
else
{
nNumColors = (&xff)< < nbitcount;
}
Systemoutprintln(The number of Colors is+nNumColors);
// 某些位图不计算 sizeimage 域请找出
// 这些情况并对它们进行修正
if (nsizeimage == )
{
nsizeimage = ((((nwidth*nbitcount)+) & ~ ) >> );
nsizeimage *= nheight;
Systemoutprintln(nsizeimage (backup) is+nsizeimage);
}
// 读取调色板颜色
int npalette[] = new int [nNumColors];
byte bpalette[] = new byte [nNumColors*];
fsread (bpalette nNumColors*);
int nindex = ;
for (int n = ; n <nNumColors; n++)
{
npalette[n] = (&xff)< <
| (((int)bpalette[nindex+]&xff)< < )
| (((int)bpalette[nindex+]&xff)< < )
| (int)bpa