BMP(DIB)图片格式

Windows中有两种位图格式,一种是GDI位图对象,另一种就是设备无关位图DIB(Device Independent Bitmap),扩展名为BMP。

一、BMP图片格式

1、当DIB存储成文件时(即后缀为BMP的图片文件),它的格式如下图:
在这里插入图片描述
特别说明:
1位、4位、8位位图才有Color Table颜色表,像素位表示颜色表数组的索引
16位、24位、32位位图是没有Color Table的,像素位直接就是RGB数据

不过现在计算机中的位图几乎都是24位或32位的了。

2、文件头的定义如下:

typedef struct tagBITMAPFILEHEADER {
	WORD    bfType;      // 文件类型,0x4d42即"BM",小端
    DWORD   bfSize;		 // 文件大小
    WORD    bfReserved1; // 保留字段1,总为0
    WORD    bfReserved2; // 保留字段2,总为0
    DWORD   bfOffBits;	 // 像素位距离文件头的偏移,字节
} BITMAPFILEHEADER;

用二进制方式打开BMP文件分析文件头:
在这里插入图片描述
bfType: 0x42 4d即"BM"
bfSize: 0x36 00 03 00,注意这里是小端模式,即文件大小为196662(0x30036)字节
bfOffBits:0x36 00 00 00,像素数据从文件开始偏移54字节,即BITMAPFILEHEADER和BITMAPINFOHEADER刚好54字节,不包含颜色表

3、信息头的定义如下:

typedef tagBITMAPINFOHEADER {
	DWORD      biSize;		  // 结构体大小
    LONG       biWidth;		  // BMP图片宽,像素
    LONG       biHeight;	  // BMP图片高,像素
    WORD       biPlanes;	  // 总是1
    WORD       biBitCount;	  // 用多少比特表示一个像素即位深
    DWORD      biCompression; // 通常为BI_RGB,表示未经压缩
    DWORD      biSizeImage;	  // 像素数据大小
    LONG       biXPelsPerMeter; // 实际水平分辨率,没什么用
    LONG       biYPelsPerMeter; // 实际垂直分辨率,没什么用
    DWORD      biClrUsed;	    // 用到的颜色数
    DWORD      biClrImportant;  // 重要的颜色数
} BITMAPINFOHEADER;

注意:
biHeight为负数表示自上而下存储
biHeight为正数表示自下而上存储,这种情况图片显示出来是倒着的

用二进制方式打开BMP文件分析信息头:
在这里插入图片描述
biSize:0x28 00 00 00,结构体大小为40字节
biWidth: 0x00 01 00 00,图片宽256像素
biHeight:0x00 01 00 00,图片高256像素
biPlanes:0x01 00
biBitCount:0x18 00,每像素24比特

二、DIB位图的内存表示

把BMP文件加载到内存中,我们用BITMAPINFO结构的指针来指向这块内存,从信息头开始读取,不包括文件头。

typedef struct tagBITMAPINFO {
    BITMAPINFOHEADER    bmiHeader;
    RGBQUAD             bmiColors[1];
} BITMAPINFO;

typedef struct tagRGBQUAD {
        BYTE    rgbBlue;
        BYTE    rgbGreen;
        BYTE    rgbRed;
        BYTE    rgbReserved;
} RGBQUAD;

颜色表就是RGBQUAD结构的数组,且biBitCount字段不大于8才有颜色表
从RGBQUAD结构也可以看到实际存储的时候是以BGR顺序存的

三、 处理DIB位图的重要API

1、给颜色表RGBQUAD赋值

UINT GetDIBColorTable(
  __in   HDC hdc,
  __in   UINT uStartIndex,
  __in   UINT cEntries,
  __out  RGBQUAD *pColors
);

2、显示DIB位图

int SetDIBitsToDevice(
  __in  HDC hdc,
  __in  int XDest,
  __in  int YDest,
  __in  DWORD dwWidth,
  __in  DWORD dwHeight,
  __in  int XSrc,
  __in  int YSrc,
  __in  UINT uStartScan,
  __in  UINT cScanLines,
  __in  const VOID *lpvBits,
  __in  const BITMAPINFO *lpbmi,
  __in  UINT fuColorUse
);
int StretchDIBits( // 可拉伸,图片会失真
  __in  HDC hdc,
  __in  int XDest,
  __in  int YDest,
  __in  int nDestWidth,
  __in  int nDestHeight,
  __in  int XSrc,
  __in  int YSrc,
  __in  int nSrcWidth,
  __in  int nSrcHeight,
  __in  const VOID *lpBits,
  __in  const BITMAPINFO *lpBitsInfo,
  __in  UINT iUsage,
  __in  DWORD dwRop
);

如果要重复多次显示同一张位图最好不用这两个函数,效率较低,可以先把DIB位图转换为GDI位图对象再进行显示

3、根据DIB位图创建GDI位图对象

HBITMAP CreateDIBitmap(
  __in  HDC hdc,
  __in  const BITMAPINFOHEADER *lpbmih,
  __in  DWORD fdwInit,
  __in  const VOID *lpbInit,
  __in  const BITMAPINFO *lpbmi,
  __in  UINT fuUsage
);

4、创建内存DIB位图

HBITMAP CreateDIBSection(
  __in   HDC hdc,
  __in   const BITMAPINFO *pbmi,
  __in   UINT iUsage,
  __out  VOID **ppvBits,
  __in   HANDLE hSection,
  __in   DWORD dwOffset
);

四、自己写的一个练手小项目

实现的功能有:
1.显示BMP图片
2.从BMP图片中提取RGB数据,保存成.rgb文件
可以用RGB播放器打开该.rgb文件,验证是否和BMP图片显示的一样。
3.屏幕截图
<使用方法>
a.按住鼠标左键拖动鼠标选择截图区域,释放鼠标左键完成截图
b.按下CTRL+A可以全屏截图
c.按下Esc键取消截图
d.鼠标双击图片可以另存为BMP文件

所有功能全部用Win32 API实现,不调用其他库。
rgb文件查看工具借用了雷霄骅(雷神)的YUV/RGB播放器:https://blog.csdn.net/leixiaohua1020/article/details/50466201

项目截图:在这里插入图片描述
源码链接:https://download.csdn.net/download/weixin_37853880/12460951

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值