2024年2月7日发(作者:)

Eastmount制作

第二课 bmp图片格式解析

<一>.BMP格式定义

BMP文件格式是Windows操作系统推荐和支持的图像文件格式,是一种将内存或显示器的图像数据不经过压缩而直接按位存盘的文件格式,故称位图(bitmap),其扩展名为BMP。

BMP图像文件被分为4个部分:

a.位图文件头 b.位图信息头 c.颜色表 d.位图数据

Eastmount制作

a.颜色表中RGBQUAD结构数据的个数有biBitCount来确定:

当biBitCount=1,4,8时,分别有2,16,256个表项;

当biBitCount=24时,没有颜色表项。

位图信息头和颜色表组成位图信息,BITMAPINFO结构定义如下:

typedef struct tagBITMAPINFO {

BITMAPINFOHEADER bmiHeader; // 位图信息头

RGBQUAD bmiColors[1]; // 颜色表

} BITMAPINFO;

b.位图数据

位图数据记录了位图的每一个像素值,记录顺序是在扫描行内是从左到右,扫描行之间是从下到上。位图的一个像素值所占的字节数:

当biBitCount=1时,8个像素占1个字节;

当biBitCount=4时,2个像素占1个字节;

当biBitCount=8时,1个像素占1个字节;

当biBitCount=24时,1个像素占3个字节;

Windows规定一个扫描行所占的字节数必须是

4的倍数(即以long为单位),不足的以0填充,

biSizeImage = ((((h * ount) + 31) & ~31)

/ 8) * ht。

Eastmount制作

<二>.BMP图片在MFC工程中的定义

存在2个未解问题:

a. bmp结构时我定义成系统自带的结构,否则会多2个字节在图片最后为CD;

b. 在read中malloc只能申请4字节的空间,但fread(,m_nImage,)读入位图大小个。

第一步:添加BMP信息文件头

文件—新建—创建ImageStruct.h—包含BMP格式的文件头部分的结构。打开ImageStruct.h并添加代码:

重点注意:

结构头必须定义成BITMAPFILEHEADER_ 不能定义成BITMAPFILEHEADER;

因为在MFC中已存在BITMAPFILEHEADER的定义,在定义成它会显示重复定义。同时自己定义的在View.h和中注意引用#include “ImageStruct.h”。

2.在后面的引用bmp结构时我定义成系统自带的结构:

BITMAPFILEHEADER bfh;

BITMAPINFOHEADER bih;

而不是BITMAPFILEHEADER_ ,因为MFC中用自带的定义图片头文件信息是正确的,但在位图信息块总会在文件最后多出2字节并默认为CD(0x16进制)。原因可能是自定义的图片头文件少2字节,在后面补充了2字节。(未知)

/*******************************************************/

/* BMP位图文件包括4部分: */

/* 位图文件头结构BITMAPFILEHEADER */

/* 位图信息头结构BITMAPINFOHEADER */

/* 位图颜色表RGBQUAD */

/* 位图像素数据 */

/*******************************************************/

Eastmount制作

#ifndef _IMAGESTRUCT_

#define _IMAGESTRUCT_

/*14byte BMP文件头含有BMP文件的类型、大小、位图文件的保留字、位图数据距文件头的偏移量*/

typedef struct T_BITMAPFILEHEADER {

WORD bfType; //2byte 位图文件的类型,必须为BM 0x424d

DWORD bfSize; //4byte 位图文件的大小,以字节为单位

WORD bfReserved1; //2byte 位图文件保留字,必须为0

WORD bfReserved2; //2byte 位图文件保留字,必须为0

DWORD bfOffBits; //4byte 位图数据距文件头的偏移量(字节)

} BITMAPFILEHEADER_;

/*40byte BMP位图信息头用于说明位图的尺寸等信息*/

typedef struct T_BITMAPINFOHEADER {

DWORD biSize; //本结构所占用字节数

LONG biWidth; //位图的宽度,以像素为单位

LONG biHeight; //位图的高度,以像素为单位

WORD biPlanes; //目标设备的级别,必须为1

WORD biBitCount;

//每个像素所需的位数,必须是1(双色)、4(16色)、8(256色)或24(真彩色)之一

DWORD biCompression;

//位图压缩类型,必须是 0(不压缩)1(BI_RLE8压缩类型)或2(BI_RLE压缩类型)之一

DWORD biSizeImage; //位图的大小,以字节为单位

LONG biXPelsPerMeter; //位图水平分辨率,每米像素数

LONG biYPelsPerMeter; //位图垂直分辨率,每米像素数

DWORD biClrUsed; //位图实际使用的颜色表中的颜色数

DWORD biClrImportant; //位图显示过程中重要的颜色数

} BITMAPINFOHEADER_;

/*BMP位图颜色表*/

typedef struct T_RGBQUAD

{

BYTE rgbBlue;

BYTE rgbGreen;

BYTE rgbRed;

BYTE rgbReserved;

} RGBQUAD_;

#endif

//蓝色的亮度(值范围为0~255)

//绿色的亮度(值范围为0~255)

//红色的亮度(值范围为0~255)

//保留,必须为0

Eastmount制作

第二步:在..View.h中添加共有成员变量和成员函数

1.找到..View.h头文件添加:#include "ImageStruct.h"

2.在Class CBmpDrawView : public Cview中的public中添加成员变量函数:

public:

//用来保存bmp格式图片

bool SaveBmp(LPCSTR lpFileName);

//用来读取bmp图片

bool ReadBmp();

//用来显示指定位图jpg、gif的函数

bool ShowJpgGif(CDC* pDC,CString strPath, int x, int y);

//用来显示指定位图bmp的函数

void ShowBitmap(CDC* pDC,CString BmpName);

/*CBitmap m_bitmaplin; 创建临时位图对象进行处理*/

CBitmap m_bitmap; //创建位图对象

CString EntName; //保存图像文件扩展名

CString BmpName; //保存图像文件文件名

int m_nWidth; //图像实际宽度

int m_nHeight; //图像实际高度

int m_nDrawWidth; //图像显示宽度

int m_nDrawHeight; //图像显示高度

DWORD m_nImage; //图像数据的字节数 只含位图 DWORD相当于long int

DWORD m_nSize; //图像文件大小

int m_nLineByte; //图像一行所占字节数

int m_nBitCount; //图像每个像素所占位数

int m_nPalette; //位图实际使用的颜色表中的颜色数

/*注意:信息头必须条用系统bmp的结构BITMAPFILEHEADER 否则会多2字节*/

BITMAPFILEHEADER bfh; //全局变量文件头

BITMAPINFOHEADER bih; //全局变量信息头

RGBQUAD *m_pPal; //颜色表指针

BYTE *m_pImage; //读入图片数据后的指针 BYTE相当于 unsigned char

virtual ~CBmpDrawView();

Eastmount制作

第三步:添加readbmp函数

添加函数的方法:

a.在View.h的public中直接添加函数bool ReadBmp()像第二步中一样;然后在中添加函数:bool CBmpDrawView::ReadBmp(){}。

b.选中ClassView区--选中View类右键--增加成员变量函数—函数类型为bool—函数名为ReadBmp()—函数Access为public。程序会自动在中添加函数:bool CBmpDrawView::ReadBmp(){}。

c.添加代码:

//************************写入bmp格式图片过程***************************//

bool CBmpDrawView::ReadBmp()

{

FILE *fp = fopen(BmpName,"rb"); //读取bmp图片 BmpName为图片的绝对路径

if(fp==0) { AfxMessageBox("无法打开文件!",MB_OK,0); return 0; }

/*读取文件头 全局变量bfh BITMAPFILEHEADER 定义在ImageStruct中*/

/*解决BMP格式倒置的方法 (CSDN) fread(&bfh,sizeof(BITMAPFILEHEADER),1,fp);倒置*/

fread(&,sizeof(WORD),1,fp);

fread(&,sizeof(DWORD),1,fp);

fread(&rved1,sizeof(WORD),1,fp);

fread(&rved2,sizeof(WORD),1,fp);

fread(&its,sizeof(DWORD),1,fp);

m_nSize = ; //图像文件的总字节数

/*判断是否是bmp格式图片 'BM'*/

if(!=0x4d42) { AfxMessageBox("不是BMP格式图片!",MB_OK,0); return 0; }

/*读取信息头*/

/*解决BMP格式倒置的方法fread(&bih,sizeof(BITMAPINFOHEADER),1,fp);倒置*/

fread(&,sizeof(DWORD),1,fp);

fread(&h,sizeof(LONG),1,fp);

fread(&ht,sizeof(LONG),1,fp);

fread(&es,sizeof(WORD),1,fp);

Eastmount制作

fread(&ount,sizeof(WORD),1,fp);

fread(&ression,sizeof(DWORD),1,fp);

fread(&Image,sizeof(DWORD),1,fp);

fread(&sPerMeter,sizeof(LONG),1,fp);

fread(&sPerMeter,sizeof(LONG),1,fp);

fread(&sed,sizeof(DWORD),1,fp);

fread(&mportant,sizeof(DWORD),1,fp);

if(!=sizeof(bih)) { AfxMessageBox("本结构所占用字节数出现错误"); return 0; }

/*位图压缩类型:必须是0(不压缩)、1(BI_RLE8压缩类型)、2(BI_RLE压缩类型)之一*/

if(ression == BI_RLE8 || ression == BI_RLE4)

{ AfxMessageBox("位图被压缩!"); return 0; }

/*获取图像高宽和每个像素所占位数*/

m_nHeight = ht;

m_nWidth = h;

m_nDrawHeight = ht;

m_nDrawWidth = h;

m_nBitCount = ount; //每个像素所占位数

/*计算图像每行像素所占的字节数(必须是4字节的倍数) 2种方法*/

//m_nLineByte = (m_nWidth*m_nBitCount/8+3)/4*4;

m_nLineByte = (m_nWidth*m_nBitCount+31)/32*4;

/*计算图片位图的大小 长*宽*3为24位bmp位图大小3表示rgb*/

m_nImage = m_nLineByte * m_nHeight;

/*位图实际使用的颜色表中的颜色数 biClrUsed 注:24位bmp不用改参数*/

m_nPalette = 0;

if(sed) m_nPalette = sed;

/*申请位图空间 大小为位图大小 m_nImage*/

/*注意:malloc只能申请4字节的空间(未知) 但fread(,m_nImage,)读入位图大小个*/

m_pImage=(BYTE*)malloc(m_nImage);

fread(m_pImage,m_nImage,1,fp);

/*注意:要关闭fp*/

fclose(fp);

return true;

}

Eastmount制作

第四步:添加保存menu控件和函数

a.查看--建立类导向(Ctrl+W)--CpictureXSView(类名)--ID_FILE_SAVE(IDs列表)--COMMAND(Messages列表)--默认成员函数名为OnFileSave

--Member Functions(成员函数)中双击该函数进入函数编辑。

b.注意:Ctrl+W把另存为也设置成与保存相同的函数。

ID_FILE_SAVE_AS--COMMAN--函数OnFileSaveAs改名为OnFileSave。

c.添加代码:

//******************文件保存*****************//

void CBmpDrawView::OnFileSave()

{

// TODO: Add your command handler code here

CString filter;

filter="所有文件(*.*)|*.bmp;*.jpg;*.gif;*.tiff| BMP(*.bmp)|*.bmp| JPG(*.jpg)|*.jpg|

GIF(*.gif)|*.gif| TIFF(*.tiff)|*.tiff||";

/*重点:1-文件打开 0-文件保存*/

CFileDialog dlg(0,NULL,NULL,OFN_HIDEREADONLY,filter,NULL); //产生保存对话框

}

/*按下确定按钮*/

if( l() == IDOK )

{

CString str;

CString strName;

CString filename;

}

str = hName(); //获取文件的路径

filename = eTitle(); //获取文件名

int nFilterIndex=dlg.m_rIndex;

if( nFilterIndex == 2 ) //当用户选择文件过滤器为".BMP"时

{

str = str + ".bmp"; //自动加扩展名.bmp

SaveBmp(str); //保存bmp图片 就是一个写出图片的过程

AfxMessageBox("图片保存成功",MB_OK,0);

}

Eastmount制作

第五步:添加保存函数SaveBmp

添加函数原理同第三步添加Readbmp函数,在添加下列代码:

/*保存bmp格式图片 写出图片的过程 只处理24像素的图片 该图片无调色板*/

bool CBmpDrawView::SaveBmp(LPCTSTR lpFileName)

{

}

/*lpFileName为位图文件路径名*/

//AfxMessageBox(lpFileName);

FILE *fpo = fopen(BmpName,"rb");

FILE *fpw = fopen(lpFileName,"wb");

fread(&bfh,sizeof(BITMAPFILEHEADER),1,fpo);

fread(&bih,sizeof(BITMAPINFOHEADER),1,fpo);

fwrite(&bfh,sizeof(BITMAPFILEHEADER),1,fpw);

fwrite(&bih,sizeof(BITMAPINFOHEADER),1,fpw);

/*malloc只能申请4字节的空间 (未知)*/

m_pImage=(BYTE*)malloc(m_nImage);

fread(m_pImage,m_nImage,1,fpo);

fwrite(m_pImage,m_nImage,1,fpw);

fclose(fpo);

fclose(fpw);

return true;

Eastmount制作

第六步:在word1中的修改

a. 在void CPictureMapView::ShowBitmap(CDC* pDC,CString

BmpName)中实现图片可以压缩伸展显示的功能:

//***************************************************************************//

/*图片显示调用函数BitBlt变成StretchBlt */

//pDC->BitBlt(0,0,m_h,m_ht,&dcBmp,0,0,SRCCOPY);

if(m_nDrawWidth<650 && m_nDrawHeight<650)

pDC->StretchBlt(0,0,m_nDrawWidth,m_nDrawHeight,&dcBmp,0,0,m_h,m_ht,SRCCOPY); //显示原图

else

pDC->StretchBlt(0,0,640,640,&dcBmp,0,0,m_h,m_ht,SRCCOPY);

//显示大小横为640*640

//***************************************************************************//

b. 在void CPictureMapView::OnDraw(CDC* pDC)函数中添加ReadBmp读取图片:

//***************************************************************************//

if( e(_T("bmp")) == 0 ) //bmp格式

{

ReadBmp(); //图片信息保存如全局变量

ShowBitmap(pDC,BmpName); //显示图片

}

//***************************************************************************//