位图文件结构及平滑缩放

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.  
BitBltStretchBlt等函数显示位图


----   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”条目,其IDID_VIEW_BITMAP

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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值