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

2016-02-19 15:33 5 1 收藏

今天图老师小编要向大家分享个BMP位图文件结构及平滑缩放教程,过程简单易学,相信聪明的你一定能轻松get!

【 tulaoshi.com - 编程语言 】

  -- 用普通方法显示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;  // 本结构所占用字节数
   LONGbiWidth; // 位图的宽度,以像素为单位
   LONGbiHeight; // 位图的高度,以像素为单位
   WORD  biPlanes; // 目标设备的级别,必须为1
   WORD  biBitCount// 每个像素所需的位数,必须是1(双色),
  // 4(16色),8(256色)或24(真彩色)之一
   DWORD biCompression;  // 位图压缩类型,必须是 0(不压缩),
  // 1(BI_RLE8压缩类型)或2(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填充,

(本文来源于图老师网站,更多请访问https://www.tulaoshi.com/bianchengyuyan/)

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

  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; // 位图文件地址(内存)

(本文来源于图老师网站,更多请访问https://www.tulaoshi.com/bianchengyuyan/)

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

来源:https://www.tulaoshi.com/n/20160219/1609879.html

延伸阅读
标签: flash教程
Flash各种实例剖析我们都看过不少,不过你有没有想过swf文件内部到底是怎样的结构呢?不少闪客都想制作自己的Flash播放器,除了对控件的掌握和使用,更需要我们对swf文件的结构有深入的了解。于是我用WinHex分别打开一个swf文件和由它生成的exe文件,经过仔细分析对比后,我不仅发现了swf文件转变成exe可执行文件的秘密,并且将Flash自...
学习Java的朋友应该都知道Java从刚开始的时候就打着平台无关性的旗号,说“一次编写,到处运行”,其实说到无关性,Java平台还有另外一个无关 性那就是语言无关性,要实现语言无关性,那么Java体系中的class的文件结构或者说是字节码就显得相当重要了,其实Java从刚开始的时候就有两套 规范,一个是Java语言规范,另外一个是Java虚拟机规范,Ja...
flywolf(mailto:flywolf@ynmail.com) 最近,我偶然发现了一个超星 - BMP的方法。 首先,请下载最新的超星3.4Beta 7,安装后,运行Delphi5,选择Component-Import ActiveX Control,然后,你会发现Import ActiveX中有一个选择为Pdg2 Type Library(Version 1.0).....,剩下的事不用我说了吧。 我的方法: procedure TMa...
最近,我偶然发现了一个超星 - BMP的方法。 首先,请下载最新的“超星3.4Beta 7”,安装后,运行Delphi5,选择Component-Import ActiveX Control,然后,你会发现“Import ActiveX”中有一个选择为“Pdg2 Type Library(Version 1.0)”.....,剩下的事不用我说了吧。 我的方法: procedure TMainForm.PdgToBmp(FPdgN...
标签: 服务器
linux下怎么用tree命令以树形结构显示文件目录结构?   今天小编来给分享Linux 系统下一个非常有用的命令的使用:tree命令可以以树形结构显示文件目录结构,它非常适合于我们给别人介绍我们的文件目录的组成框架,同时该命令使用适当的参数也可以将命令结果输出到文本文件中。小编的这个建议只适合于10.10之前版本的ubuntu系统,后面...

经验教程

402

收藏

82
微博分享 QQ分享 QQ空间 手机页面 收藏网站 回到头部