`
hzy3774
  • 浏览: 985594 次
  • 性别: Icon_minigender_1
  • 来自: 珠海
社区版块
存档分类
最新评论

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;
}

 

效果如图:



 

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

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

 

全部代码在附件中。

  • 大小: 210.7 KB
分享到:
评论

相关推荐

    DICOM图像相关文档

    DICOM医学图像文件格式解析与应用研究 WINDOWS环境下DICOM医学图像显示方法的初步研究 标准医学DICOM图像的转换实现 基于DICOM的数据组织及医学图像序列提取方法研究 用二叉树实现DICOM医学图像的编码 树型结构DICOM...

    《浩海网络多格式播放器》V3.9.4.4

    2,全新增加图片格式文件支持(*.bmp;*.jpg;*.gif;*.jpge;*.png 等)为V4.0播放器抛下伏笔3,全面解决V3.8系列播放器左上角在有些系统上出现视频窗口的严重BUG!4,全新的版权保护机制!彻底改善V3.8系列保护机制...

    《浩海网络多格式播放器》V3.9.4.5

    2,全新增加图片格式文件支持(*.bmp;*.jpg;*.gif;*.jpge;*.png 等)为V4.0播放器抛下伏笔3,全面解决V3.8系列播放器左上角在有些系统上出现视频窗口的严重BUG!4,全新的版权保护机制!彻底改善V3.8系列保护机制...

    《浩海网络多格式播放器》V3.9.4.1

    2,全新增加图片格式文件支持(*.bmp;*.jpg;*.gif;*.jpge;*.png 等)为V4.0播放器抛下伏笔3,全面解决V3.8系列播放器左上角在有些系统上出现视频窗口的严重BUG!4,全新的版权保护机制!彻底改善V3.8系列保护机制...

    《OceanX》播放器 Prv0.3

    2,全新增加图片格式文件支持(*.bmp;*.jpg;*.gif;*.jpge;*.png 等)为V4.0播放器抛下伏笔3,全面解决V3.8系列播放器左上角在有些系统上出现视频窗口的严重BUG!4,全新的版权保护机制!彻底改善V3.8系列保护机制...

    VC与Labview、Matlab编程论文资料

    基于VC_实现的实时数据监控和显示方法.pdf 基于VC_实现的数字与字母识别.pdf 基于VC_开发虚拟数字键盘ActiveX控件.pdf 基于VC_的1553B总线接口仿真软件设计.pdf 基于VC_的3G无线上网卡主功能设计与实现.pdf 基于VC_...

    《OceanX》播放器 Prv0.33

    2,全新增加图片格式文件支持(*.bmp;*.jpg;*.gif;*.jpge;*.png 等)为V4.0播放器抛下伏笔3,全面解决V3.8系列播放器左上角在有些系统上出现视频窗口的严重BUG!4,全新的版权保护机制!彻底改善V3.8系列保护机制...

    《OceanX》播放器 Prv0.34

    2,全新增加图片格式文件支持(*.bmp;*.jpg;*.gif;*.jpge;*.png 等)为V4.0播放器抛下伏笔3,全面解决V3.8系列播放器左上角在有些系统上出现视频窗口的严重BUG!4,全新的版权保护机制!彻底改善V3.8系列保护机制...

    VC与Labview、Matlab编程论文资料[2].rar

    基于VC_实现的实时数据监控和显示方法.pdf 基于VC_实现的数字与字母识别.pdf 基于VC_开发虚拟数字键盘ActiveX控件.pdf 基于VC_的1553B总线接口仿真软件设计.pdf 基于VC_的3G无线上网卡主功能设计与实现.pdf 基于VC_...

    VC与Labview、Matlab编程论文资料[4].rar

    基于VC_实现的实时数据监控和显示方法.pdf 基于VC_实现的数字与字母识别.pdf 基于VC_开发虚拟数字键盘ActiveX控件.pdf 基于VC_的1553B总线接口仿真软件设计.pdf 基于VC_的3G无线上网卡主功能设计与实现.pdf 基于VC_...

Global site tag (gtag.js) - Google Analytics