BMP格式文件初步解析和显示

    BMP取自位图BitMaP的缩写,也称为DIB(与设备无关的位图),是微软视窗图形子系统(Graphics Device Interface)内部使用的一种位图图形格式,它是微软视窗平台上的一个简单的图形文件格式。

详细介绍可以参考维基百科:http://zh.wikipedia.org/wiki/BMP

    学习的目的是解析一个为图文件并显示位图。在位图图像数据之前,有文件头和信息头,Windows环境下wingdi.h中提供了相应的数据结构。

文件头结构体:

typedef struct tagBITMAPFILEHEADER
{
	WORD bfType;//位图文件的类型,必须为BM(1-2字节)
	DWORD bfSize;//位图文件的大小,以字节为单位(3-6字节,低位在前)
	WORD bfReserved1;//位图文件保留字,必须为0(7-8字节)
	WORD bfReserved2;//位图文件保留字,必须为0(9-10字节)
	DWORD bfOffBits;//位图数据的起始位置,以相对于位图(11-14字节,低位在前)
	//文件头的偏移量表示,以字节为单位
}BITMAPFILEHEADER;

 信息头结构体:

typedef struct tagBITMAPINFOHEADER{
	DWORD biSize;//本结构所占用字节数(15-18字节)
	LONG biWidth;//位图的宽度,以像素为单位(19-22字节)
	LONG biHeight;//位图的高度,以像素为单位(23-26字节)
	WORD biPlanes;//目标设备的级别,必须为1(27-28字节)
	WORD biBitCount;//每个像素所需的位数,必须是1(双色),(29-30字节)
	//4(16色),8(256色)16(高彩色)或24(真彩色)之一
	DWORD biCompression;//位图压缩类型,必须是0(不压缩),(31-34字节)
	//1(BI_RLE8压缩类型)或2(BI_RLE4压缩类型)之一
	DWORD biSizeImage;//位图的大小(其中包含了为了补齐行数是4的倍数而添加的空字节),以字节为单位(35-38字节)
	LONG biXPelsPerMeter;//位图水平分辨率,每米像素数(39-42字节)
	LONG biYPelsPerMeter;//位图垂直分辨率,每米像素数(43-46字节)
	DWORD biClrUsed;//位图实际使用的颜色表中的颜色数(47-50字节)
	DWORD biClrImportant;//位图显示过程中重要的颜色数(51-54字节)
}BITMAPINFOHEADER;

 全部实例代码:

/*
 * bmptest.c
 *
 *  Created on: 2014-10-27
 *      Author: HZY
 */

#include <stdio.h>

#include "GL/freeglut.h"

static BYTE* buffer = NULL;
static BITMAPINFOHEADER infoHeader;

//BGR转RGB:对于每个点,第一字节和第三字节交换
void bgrToRgb(BYTE* buffer, int size) {
	int i = 0;
	int j = 0;
	BYTE temp = 0;
	int blueIdx = 0;
	int rowBytes = size / infoHeader.biHeight;

	for (i = 0; i < infoHeader.biHeight; i++) {
		for (j = 0; j < infoHeader.biWidth; j++) {
			blueIdx = i * rowBytes + j * 3;
			temp = buffer[blueIdx];
			buffer[blueIdx] = buffer[blueIdx + 2];
			buffer[blueIdx + 2] = temp;
		}
	}
}

//获取每一行所用的字节数,需要凑足4的倍数
int getRowBytes(int width){
	//刚好是4的倍数
	if((width * 3) % 4 == 0){
		return width * 3;
	}else{
		return ((width * 3) / 4 + 1) * 4;
	}
}

void printFileHeader(BITMAPFILEHEADER* h) {
	printf("$fileHeader: offbits[%ld], size[%ld], type[%d]\n", h->bfOffBits,
			h->bfSize, h->bfType);
}

void printInfoHeader(BITMAPINFOHEADER* h) {
	printf("$infoHeader: size[%ld], width[%ld], height[%ld], planes[%d]\n\t"
			"bitcount[%d], compression[%ld], sizeImage[%ld]\n\t"
			"XpixPerM[%ld], YpixPerM[%ld], colors[%ld], impColors[%ld]\n",
			h->biSize, h->biWidth, h->biHeight, h->biPlanes, h->biBitCount,
			h->biCompression, h->biSizeImage, h->biXPelsPerMeter,
			h->biYPelsPerMeter, h->biClrUsed, h->biClrImportant);
}

void parseBmp() {
	FILE* fp = NULL;
	BITMAPFILEHEADER fileHeader;
	int realBytes = 0;

	//打开文件
	fp = fopen("test.bmp", "rb");
	if (fp == NULL) {
		printf("file open error!\n");
		exit(EXIT_FAILURE);
	}
	//读取文件头
	fread(&fileHeader, sizeof(BITMAPFILEHEADER), 1, fp);
	printFileHeader(&fileHeader);
	//读取信息头
	fread(&infoHeader, sizeof(BITMAPINFOHEADER), 1, fp);
	printInfoHeader(&infoHeader);
	//只处理24位非压缩位图
	switch (infoHeader.biBitCount) {
	case 24:
		realBytes = infoHeader.biWidth * infoHeader.biHeight * 3;
		printf("image realBytes[%d]\n", realBytes);
		//一些图片编辑软件得到的biSizeImage为0,
		//这样的图片手动计算biSizeImage
		if (infoHeader.biSizeImage < realBytes) {
			infoHeader.biSizeImage = getRowBytes(infoHeader.biWidth) * infoHeader.biHeight;
			printf("Calculated biSizeImage[%ld]\n", infoHeader.biSizeImage);
		}
		//获取堆空间
		buffer = malloc(infoHeader.biSizeImage);
		//读数据到内存
		fread(buffer, infoHeader.biSizeImage, 1, fp);
		//bmp中保存的是BGR,转成RGB,方便显示
		bgrToRgb(buffer, infoHeader.biSizeImage);
		break;
	default:
		printf("not 24 bit bitmap!\n");
		fclose(fp);
		exit(EXIT_FAILURE);
		break;
	}
	fclose(fp);
}

//opengl显示图片
void myDisplay(){
	glClear(GL_COLOR_BUFFER_BIT);
	glDrawPixels(infoHeader.biWidth, infoHeader.biHeight, GL_RGB, GL_UNSIGNED_BYTE, buffer);
	glFlush();
}

int main(int c, char** v){
	parseBmp();

	glutInit(&c, v) ;
	glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
	glutInitWindowPosition(100, 100);
	glutInitWindowSize(infoHeader.biWidth, infoHeader.biHeight);
	glutCreateWindow("hello bmp");
	glutDisplayFunc(&myDisplay);
	glutMainLoop();

	free(buffer);
	return 0;
}

 

效果如图:


BMP格式文件初步解析和显示_第1张图片
 

显示图片采用opengl来渲染,使用了freeglut:

工程是用eclipse中cdt使用mingw编译:

 

全部代码在附件中。

你可能感兴趣的:(文件)