位图(BMP)文件格式(一)

本文详细介绍了位图(BMP)文件的四个主要组成部分:位图文件头、位图信息头、调色板和位图数据。针对24位位图,重点讨论了没有调色板的情况以及字节对齐问题。通过实例计算了位图的宽度和总大小,并提供了读取和设置DIB位图到设备的函数StretchDIBits和SetDIBitsToDevice。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

位图文件分四部份数据块

1.位图文件头

BITMAPFILEHEADER

typedef struct tagBITMAPFILEHEADER {
        WORD    bfType;                //文件类型,对于位图格式,其值是'MB'19778, 由于字节存放次序问题的原故,实际为'BM'
        DWORD   bfSize;                //文件总大小
         WORD    bfReserved1;           //保留,置0
        WORD    bfReserved2;           //保留,置0
        DWORD   bfOffBits;             //位图数据偏移长度
} BITMAPFILEHEADER, FAR *LPBITMAPFILEHEADER, *PBITMAPFILEHEADER;

2.位图信息头

BITMAPINFOHEADER

typedef struct tagBITMAPINFOHEADER{
	DWORD      biSize;               //信息头大小,sizeof(BITMAPINFOHEADER)
	LONG       biWidth;              //图片宽度
	LONG       biHeight;             //图片高度
	WORD       biPlanes;             //面数,置1
	WORD       biBitCount;           //每一位像素占的位数,
	DWORD      biCompression;        //压缩,0比表示不压缩.BI_RGB
	DWORD      biSizeImage;          //图片大小,对24位来说,biWidth * biHeight * 3
         LONG       biXPelsPerMeter;      //分辨率,每米多少个像素
	LONG       biYPelsPerMeter;      //分辨率,每米多少个像素
	DWORD      biClrUsed;            //用到的颜色数
	DWORD      biClrImportant;       //重要的颜色
} BITMAPINFOHEADER, FAR *LPBITMAPINFOHEADER, *PBITMAPINFOHEADER;

3.调色版

typedef struct tagRGBQUAD {
 BYTE    rgbBlue;
 BYTE    rgbGreen;
 BYTE    rgbRed;
 BYTE    rgbReserved; //保留,置0
} RGBQUAD;
typedef RGBQUAD FAR* LPRGBQUAD;

 

4.位图数据

不同位数的数据格式不同,对24位位图来说,没有调色版,位图信息依次存放是BGR...

***********************************************************************************

另外两个数据结构,

//实际上OS/2的调色版,(1,4,8位)
typedef struct tagRGBTRIPLE  // rgbt 
{ 
      BYTE rgbtBlue ;        // blue level 
      BYTE rgbtGreen ;       // green level 
      BYTE rgbtRed ;         // red level 
} 
RGBTRIPLE ; 

 

//位图信息,(位图信息头 + 调色版)

typedef struct tagBITMAPINFO           // bmi 
{ 
      BITMAPINFOHEADER bmiHeader ;     // info-header structure 
      RGBQUAD       bmiColors[1] ;     // color table array 
} 
BITMAPINFO, * PBITMAPINFO ; 

 

对于24位位图来说,没有色彩对照表(调色版),
其位图数据是
       B                        G                    R
- - - - - - - -        - - - - - - - -       - - - - - - - -
也就是RGBTRIPLE结构

另外位图数据是自下而上.也就是说左下角为其第一个元素

 

关于字节对齐的问题,32位对齐也就是4个字节对节
对24位位图来说
由于存放数据时候时候,每像素3个节字,所以需要考虑对齐

//每行像素byte   

WIDTHBYTE(row)    ((row * 3 + 3 ) / 4 ) * 4

//更有效率一点 

WIDTHBYTE(row)    ((row * 24 + 31)>>5)<<2 


测试例子
QQ截一幅图55.bmp
属性如下:

         宽度              :847
         高度              :596
         水平分辨率 :96 DPI
         垂直分辨率 :96 DPI
         位深度          :24
         帧数              :1
图片大小:1516278 字节


有了前面这些.

手动计算 考虑对齐的问题,宽度 BYTE : ((847*3+3)/4)*4 =2544 (byte)
总大小 = 宽度 * 高度 + 文件头(14 bytes) + 信息头(40 bytes)
        =  2544 * 596 + 54 = 1516278 (bytes)

 

 

读图例子如下:

#include <afx.h>
int main()
{
 	char *pbuf = NULL;
 	BITMAPFILEHEADER bfh={0};
 	BITMAPINFOHEADER bih={0};

 	CFile file;
 	file.Open("55.bmp",CFile::modeRead);
 	int nLen  = file.GetLength();
 	pbuf = new char[nLen+1];
 	file.ReadHuge(pbuf , nLen);
 	file.Close();

 	bfh = *(LPBITMAPFILEHEADER)pbuf;
 	bih = *(LPBITMAPINFOHEADER)(pbuf + sizeof(BITMAPFILEHEADER));

 	delete []pbuf;
 	return 0;
}
//结果如下:
//文件头
//BITMAPFILEHEADER bfh
//bfType          = 19778      //'MB'
//bfSize           = 1516278
//bfReserved1      = 0
//bfReserved2      = 0
//bfOffBits        = 54
//信息头
//BITMAPINFOHEADER bih
//biWidth          = 847
//biHeight         = 596
//biPlanes         = 1
//biBitCount       = 24
//biCompression    = 0         //BI_RGB
//biSizeImage      = 1516224   // bfSize - bfOffBits
//biXPelsPerMeter  = 3780
//biYPelsPerMeter  = 3780
//biClrUsed        = 0
//biClrImportant   = 0

//
//显示图片
//最原始的用SetPixel来显示图片
//例子
//单文档工程中.CBmpView...
//成员变量
public:
 char * m_pBuf;//整个文件缓存
 char * m_pBits;//位图数据
 int m_nWidth;//宽度
 int m_nHeight;//高度
 int m_nRowBytes;//每行的节字数
 LPBITMAPFILEHEADER m_pbfh;//文件头指针
 LPBITMAPINFOHEADER m_pbih;//信息头指针
//构造函数中
CBmpView::CBmpView()
{
 // TODO: add construction code here
 m_pBuf = NULL;
 m_pBits = NULL;
 m_pbfh = NULL;
 m_pbih = NULL;
 
//读数据
 CFile file;
 file.Open("55.bmp",CFile::modeRead);
 int nLen = file.GetLength();
 m_pBuf = new char[nLen+1];
 file.ReadHuge(m_pBuf,nLen);
 file.Close();
 m_pbfh = LPBITMAPFILEHEADER(m_pBuf);//文件头
 int nOffBits = m_pbfh->bfOffBits;//真实位图数据位移大小
 m_pbih = LPBITMAPINFOHEADER(m_pBuf + sizeof(BITMAPFILEHEADER));//信息头
 m_pBits = m_pBuf +  nOffBits;//位图数据
 m_nWidth = m_pbih->biWidth;    //宽度
 m_nHeight = m_pbih->biHeight;  //高度
 m_nRowBytes = ((m_nWidth*3+3)/4) * 4;//每行的节字大小
}

 

//显示图片
void CBmpView::OnDraw(CDC* pDC)
{
 CBmpDoc* pDoc = GetDocument();
 ASSERT_VALID(pDoc);
 // TODO: add draw code for native data here

 RGBTRIPLE *rgb = (RGBTRIPLE *)(m_pBits);
 char *pRow = (char *)rgb;

 int nXOff = 20;
 int nYoff = 20;
//从下往上显示
 for(int y = m_nHeight-1 ; y > 0  ; y--)
 {
  for(int x = 0 ; x < m_nWidth ; x++)
  {
   BYTE r = rgb[x].rgbtRed;
   BYTE g = rgb[x].rgbtGreen;
   BYTE b = rgb[x].rgbtBlue;
   COLORREF clr = RGB(r,g,b);//取颜色
   pDC->SetPixel( nXOff + x , nYoff + y ,clr);
  }
  pRow += m_nRowBytes;//指向下一行
  rgb = (RGBTRIPLE *)pRow;//指向下一行
 }
}

//,常规方法.更为简便,速度的方法
int StretchDIBits(
  HDC hdc,                    // handle to DC
  int XDest,                    // x-coord of destination upper-left corner
  int YDest,                    // y-coord of destination upper-left corner
  int nDestWidth,          // width of destination rectangle
  int nDestHeight,         // height of destination rectangle
  int XSrc,                       // x-coord of source upper-left corner
  int YSrc,                       // y-coord of source upper-left corner
  int nSrcWidth,             // width of source rectangle
  int nSrcHeight,            // height of source rectangle
  CONST VOID *lpBits,      // bitmap bits
  CONST BITMAPINFO *lpBitsInfo, // bitmap data
  UINT iUsage,                  // usage options
  DWORD dwRop              // raster operation code
);

StretchDIBits(pDC->GetSafeHdc(),
 nXOff,nYoff,m_nWidth,m_nHeight,
 0,0,m_nWidth,m_nHeight,
 m_pBits,(LPBITMAPINFO)m_pbih,DIB_RGB_COLORS,SRCCOPY);


 

int SetDIBitsToDevice(
  HDC hdc,                 // handle to DC
  int XDest,               // x-coord of destination upper-left corner
  int YDest,               // y-coord of destination upper-left corner
  DWORD dwWidth,           // source rectangle width
  DWORD dwHeight,          // source rectangle height
  int XSrc,                // x-coord of source lower-left corner
  int YSrc,                // y-coord of source lower-left corner
  UINT uStartScan,         // first scan line in array
  UINT cScanLines,         // number of scan lines
  CONST VOID *lpvBits,     // array of DIB bits
  CONST BITMAPINFO *lpbmi, // bitmap information
  UINT fuColorUse          // RGB or palette indexes
);

SetDIBitsToDevice(
 pDC->GetSafeHdc(),
 nXOff,nYoff,m_nWidth,m_nHeight,
 0,0,0,m_nHeight,
 m_pBits,(LPBITMAPINFO)m_pbih,DIB_RGB_COLORS);

 

-*******************************************

//文件的保存

(24位)文件的保存

void CBmpView::OnFullscreen() 
{
	// TODO: Add your command handler code here
	HDC hdc,hmemDC;
	HBITMAP hBitmap,hOldBitmp;
	//屏幕DC,长度,宽度
	hdc = CreateDC("DISPLAY",NULL,NULL,NULL);
	int cx  = GetDeviceCaps(hdc,HORZRES);
	int cy  = GetDeviceCaps(hdc,VERTRES);

	//兼容DC,兼容位图
	hmemDC  = CreateCompatibleDC(hdc);
	hBitmap = CreateCompatibleBitmap(hdc,cx,cy);
	hOldBitmp =(HBITMAP)SelectObject(hmemDC,hBitmap);
	BitBlt(hmemDC,0,0,cx,cy,hdc,0,0,SRCCOPY);
	hBitmap = (HBITMAP)SelectObject(hmemDC,hOldBitmp);
	DeleteDC(hdc);
	DeleteObject(hOldBitmp);

	//基本长度,宽度
	BITMAP bm;
	GetObject(hBitmap,sizeof(bm),&bm);
	int nWidth = bm.bmWidth;
	int nHeight = bm.bmHeight;

	//像素数据大小(byte)
	DWORD dwBmBitsSize = ((nWidth*24+31)/32)*4*nHeight;
	
	BITMAPFILEHEADER bfh={0};
	BITMAPINFOHEADER bih={0};

	//文件头信息
	bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
	bfh.bfReserved1 = 0;
	bfh.bfReserved2 = 0;
	bfh.bfSize = bfh.bfOffBits + dwBmBitsSize;
	bfh.bfType = 'MB';

	//信息头信息
	bih.biBitCount     = 24;
	bih.biCompression  = BI_RGB;
	bih.biHeight       = nHeight;
	bih.biWidth        = nWidth;
	bih.biPlanes       = 1;
	bih.biSize         = sizeof(BITMAPINFOHEADER);
	bih.biSizeImage    = dwBmBitsSize;
	bih.biClrImportant = 0;
	bih.biClrUsed      = 0;
	bih.biXPelsPerMeter= 0;
	bih.biYPelsPerMeter= 0;

	//位图数据
	char *pBits = new char[dwBmBitsSize];
	memset(pBits , 0 , dwBmBitsSize);
	GetDIBits(hmemDC,hBitmap,0,nHeight,pBits,(LPBITMAPINFO)&bih,DIB_RGB_COLORS);
	DeleteDC(hmemDC);
	DeleteObject(hBitmap);

	//写文件
	CFile file;
	file.Open("1.bmp",CFile::modeCreate | CFile::modeWrite);
	file.Write(&bfh,14);
	file.Write(&bih,40);
	file.Write(pBits,dwBmBitsSize);
	file.Close();
	delete []pBits;
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值