天天看点

位图文件结构及平滑缩放

BMP位图文件结构及平滑缩放

----   用普通方法显示BMP位图,占内存大,速度慢,在图形缩小时,失真严重,在低颜色位数的设备上显示高颜色位数的图形时失真大。本文采用视频函数显示BMP位图,可以消除以上的缺点。

----   一、BMP文件结构

----   1.   BMP文件组成

----   BMP文件由文件头、位图信息头、颜色信息和图形数据四部分组成。

----   2.   BMP文件头

----   BMP文件头数据结构含有BMP文件的类型、文件大小和位图起始位置等信息。

----   其结构定义如下:

typedef   struct   tagBITMAPFILEHEADER

{

WORDbfType;   //   位图文件的类型,必须为BM

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

WORDbfReserved1;   //   位图文件保留字,必须为0

WORDbfReserved2;   //   位图文件保留字,必须为0

DWORD   bfOffBits;   //   位图数据的起始位置,以相对于位图

//   文件头的偏移量表示,以字节为单位

}   BITMAPFILEHEADER;

----   3.   位图信息头 ----

BMP位图信息头数据用于说明位图的尺寸等信息。

typedef   struct   tagBITMAPINFOHEADER{

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

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

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

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

WORD   biBitCount;  //  每个像素所需位数,1(双色), 4(16色),8(256色)或24(真彩色)等DWORD   biCompression;   //   位图压缩类型,必须是0(不压缩),或1(BI_RLE8压缩类型)  

或 (BI_RLE4压缩类型)之一                                                                                    

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

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

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

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

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

}   BITMAPINFOHEADER;

----   4.   颜色表

----   颜色表用于说明位图中的颜色,它有若干个表项,每一个表项是一个RGBQUAD类型的结构,定义一种颜色。RGBQUAD结构的定义如下:

typedef   struct   tagRGBQUAD   {

BYTErgbBlue;//   蓝色的亮度(值范围为0-255)

BYTErgbGreen;   //   绿色的亮度(值范围为0-255)

BYTErgbRed;   //   红色的亮度(值范围为0-255)

BYTErgbReserved;//   保留,必须为0

}   RGBQUAD;

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

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

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

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

typedef   struct   tagBITMAPINFO   {

BITMAPINFOHEADER   bmiHeader;   //   位图信息头

RGBQUAD   bmiColors[1];   //   颜色表

}   BITMAPINFO;

----   5.   位图数据

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

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

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

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

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

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

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

一个扫描行所占的字节数计算方法:

DataSizePerLine=   (biWidth*   biBitCount+31)/8;  

//   一个扫描行所占的字节数

DataSizePerLine=   DataSizePerLine/4*4;   //   字节数必须是4的倍数

位图数据的大小(不压缩情况下):

DataSize=   DataSizePerLine*   biHeight;

----   二、BMP位图一般显示方法

----   1.   申请内存空间用于存放位图文件

----   GlobalAlloc(GHND,FileLength);

----   2.   位图文件读入所申请内存空间中

----   LoadFileToMemory(   mpBitsSrc,mFileName);

----   3.   在OnPaint等函数中用创建显示用位图

----   用CreateDIBitmap()创建显示用位图,用CreateCompatibleDC()创建兼容DC,

----   用SelectBitmap()选择显示位图。

----   4.   用BitBlt或StretchBlt等函数显示位图

----   5.   用DeleteObject()删除所创建的位图

----   以上方法的缺点是:   1)显示速度慢;   2)   内存占用大;   3)   位图在缩小显示时图形失真大,(可通过安装字体平滑软件来解决);   4)   在低颜色位数的设备上(如256显示模式)显示高颜色位数的图形(如真彩色)失真严重。

----   三、BMP位图缩放显示

----   用DrawDib视频函数来显示位图,内存占用少,速度快,而且还可以对图形进行淡化(Dithering)处理。淡化处理是一种图形算法,可以用来在一个支持比图像所用颜色要少的设备上显示彩色图像。BMP位图显示方法如下:

----   1.   打开视频函数DrawDibOpen(),一般放在在构造函数中

----   2.   申请内存空间用于存放位图文件

----   GlobalAlloc(GHND,FileLength);

----   3.   位图文件读入所申请内存空间中

----   LoadFileToMemory(mpBitsSrc,mFileName);

----   4.   在OnPaint等函数中用DrawDibRealize(),DrawDibDraw()显示位图

----   5.   关闭视频函数DrawDibClose(),一般放在在析构函数中

----   以上方法的优点是:   1)显示速度快;   2)   内存占用少;   3)   缩放显示时图形失真小,4)   在低颜色位数的设备上显示高颜色位数的图形时失真小;   5)   通过直接处理位图数据,可以制作简单动画。

----   四、CViewBimap类编程要点

----   1.   在CViewBimap类中添加视频函数等成员

HDRAWDIB   m_hDrawDib;   //   视频函数

HANDLEmhBitsSrc;   //   位图文件句柄(内存)

LPSTR   mpBitsSrc;   //   位图文件地址(内存)

BITMAPINFOHEADER   *mpBitmapInfo;   //   位图信息头

----   2.   在CViewBimap类构造函数中添加打开视频函数

----   m_hDrawDib=   DrawDibOpen();

----   3.   在CViewBimap类析构函数中添加关闭视频函数

if(   m_hDrawDib   !=   NULL)

{

DrawDibClose(   m_hDrawDib);

m_hDrawDib   =   NULL;

}

----   4.   在CViewBimap类图形显示函数OnPaint中添加GraphicDraw()

voidCViewBitmap::OnPaint()

{

CPaintDC   dc(this);   //   device   context   for   painting

GraphicDraw(   );

}

voidCViewBitmap::GraphicDraw(   void   )

{

CClientDC   dc(this);   //   device   context   for   painting

BITMAPFILEHEADER   *pBitmapFileHeader;

ULONG   bfoffBits=   0;

CPoint   Wid;

//   图形文件名有效   (=0   BMP)

if(   mBitmapFileType   <   ID_BITMAP_BMP   )   return;

//   图形文件名有效   (=0   BMP)

//   准备显示真彩位图

pBitmapFileHeader=   (BITMAPFILEHEADER   *)   mpBitsSrc;

bfoffBits=   pBitmapFileHeader-> bfOffBits;

//   使用普通函数显示位图

if(   m_hDrawDib   ==   NULL   ||   mDispMethod   ==   0)

{

HBITMAP   hBitmap=::CreateDIBitmap(dc.m_hDC,

mpBitmapInfo,   CBM_INIT,   mpBitsSrc+bfoffBits,

(LPBITMAPINFO)   mpBitmapInfo,DIB_RGB_COLORS);  

//   建立位图

HDC   hMemDC=::CreateCompatibleDC(dc.m_hDC);//   建立内存

HBITMAP   hBitmapOld=   SelectBitmap(hMemDC,   hBitmap);   //   选择对象

//   成员CRect   mDispR用于指示图形显示区域的大小.

//   成员CPoint   mPos用于指示图形显示起始位置坐标.

if(   mPos.x   >   (mpBitmapInfo-   > biWidth   -   mDispR.Width()   ))

mPos.x=   mpBitmapInfo-> biWidth   -   mDispR.Width()   ;

if(   mPos.y   >   (mpBitmapInfo-   > biHeight-   mDispR.Height()))

mPos.y=   mpBitmapInfo-   > biHeight-   mDispR.Height();

if(   mPos.x   <   0   )   mPos.x=   0;

if(   mPos.y   <   0   )   mPos.y=   0;

if(   mFullViewTog   ==   0)

{

//   显示真彩位图

::BitBlt(dc.m_hDC,0,0,   mDispR.Width(),   mDispR.Height(),

hMemDC,mPos.x,mPos.y,   SRCCOPY);

}   else   {

::StretchBlt(dc.m_hDC,0,0,   mDispR.Width(),   mDispR.Height(),

hMemDC,0,0,   mpBitmapInfo-   > biWidth,   mpBitmapInfo-

> biHeight,   SRCCOPY);

}

//   结束显示真彩位图

::DeleteObject(SelectObject(hMemDC,hBitmapOld));  

//   删   除   位   图

}   else   {

//   使用视频函数显示位图

if(   mPos.x   >   (mpBitmapInfo-   > biWidth   -   mDispR.Width()   ))

mPos.x=   mpBitmapInfo-   > biWidth   -   mDispR.Width()   ;

if(   mPos.y   >   (mpBitmapInfo-   > biHeight-   mDispR.Height()))

mPos.y=   mpBitmapInfo-   > biHeight-   mDispR.Height();

if(   mPos.x   <   0   )   mPos.x=   0;

if(   mPos.y   <   0   )   mPos.y=   0;

//   显示真彩位图

DrawDibRealize(   m_hDrawDib,   dc.GetSafeHdc(),   TRUE);

if(   mFullViewTog   ==   0)

{

Wid.x=   mDispR.Width();

Wid.y=   mDispR.Height();

//   1:1   显示时,   不能大于图形大小

if(   Wid.x   >   mpBitmapInfo-   > biWidth   )

Wid.x   =   mpBitmapInfo-   > biWidth;

if(   Wid.y   >   mpBitmapInfo-   > biHeight)

Wid.y   =   mpBitmapInfo-   > biHeight;

DrawDibDraw(m_hDrawDib, dc.GetSafeHdc()

,   0,   0,   Wid.x,   Wid.y,

mpBitmapInfo,   (LPVOID)   (mpBitsSrc+bfoffBits),

mPos.x,   mPos.y,   Wid.x,   Wid.y,   DDF_BACKGROUNDPAL);

}   else   {

DrawDibDraw(   m_hDrawDib,   dc.GetSafeHdc(),

0,   0,   mDispR.Width(),   mDispR.Height(),

mpBitmapInfo,   (LPVOID)   (mpBitsSrc+bfoffBits),

0,   0,   mpBitmapInfo-   > biWidth,   mpBitmapInfo-   > biHeight,

DDF_BACKGROUNDPAL);

}

}

return;

}

----   五、使用CViewBimap类显示BMP位图

----   1.   在Visual   C++5.0中新建一个名称为mymap工程文件,类型为MFC   AppWizard[exe]。在编译运行通过后,在WorkSpace(如被关闭,用Alt_0打开)点击ResourceView,点击Menu左侧的+符号展开Menu条目,双击IDR_MAINFRAME条目,进入菜单资源编辑,在 '“查看(V)”下拉式菜单(英文版为View下拉式菜单)的尾部添加“ViewBitmap”条目,其ID为ID_VIEW_BITMAP。

----   2.   在Visual   C++5.0中点击下拉式菜单Project-   > Add   To   project-   > Files...,将Bitmap0.h和Bitmap0.cpp添加到工程文件中。

----   3.   在Visual   C++5.0中按Ctrl_W进入MFC   ClassWizard,选择类名称为CMainFrame,ObjectIDs:   ID_VIEW_BITMAP,Messages选择Command,然后点击Add   Fucction按钮

继续阅读