BMP 全解

本文总结了BMP格式的相关知识,包括DDB和DIB的区别,以及解码过程中遇到的问题:如信息头结构体对齐、宽度4字节对齐、像素起点位置、颜色格式转换等。此外,详细介绍了1bit到32bit不同位深BMP的解码方法,包括调色板索引、颜色格式转换等,并提到4bit和8bit的RLE压缩情况。

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

好久没写东西咯,最近一种忙图片效果,这两天吧BMP做了,总想记录下东西下来吧,所以总结了下。本想把之前的TGA,PNG,GIF的都再一起重新总结一下,可惜时间不多,那就暂时先把BMP总结咯,位图的资料网上有很多,我只总结下自己在解码过程中遇到的几个问题。

BMP格式

   BMP格式是常见的格式,早期windows3.0以前,底层图片基本上都使用BMP,所以叫DDB(device depande BMP),windows3.0以后开始脱离BMP,叫DIB(device indepande BMP).

解码过程中遇到的几个问题:

1. 信息头54个字节,在定义信息头结构体的时候要注意所在的平台,注意int是4个字节还是2个字节,往往会因为结构体自动对齐的问题使得头信息结构体算出长度为56,此时就需要将结构体声明为2字节对齐,方法是使用#pragma pack(2) ;

2. 注意在读取数据的时候,BMP的宽是使用4字节对齐,所以可能会出现“补位”的情况,这时,在计算宽的时候可以使用公式 padbytes =(长像素%4) ?(4 - (长像素%4) : 0);

3. 很多格式的图片解码出来的图片像素的起始点是在左下角,所以需要从下往上一排一排的将像素换行,即第一行和最后一行交换,以此类推。

4. 关于解码出来的是BGRA是否需要转化为RGBA,网上说是需要转化的,其实是根据具体平台参考,例如我用的linux平台就不需要再转化为RGB。

5. 现在具体说说不同位的BMP图片的解码:

 1bit 和 4bit 

     之所以把它们和在一起是因为它们的解压方式十分相近,都是采用调色盘索引的方式,1bit就是只能索引0和1,即只有黑白两种颜色,4bit是可以有2^4种索引,为16色。

它们需要注意的是一个字节表示几个像素点,分别是8个和2两个,所以解码的时候一个字节要对应存几次。

 8bit 

 8bit其实和前面的两种很相似咯,同样是使用调色板索引表,只是一个字节对应一个像素点,相对更简单点。其实通过文件头和8位都可以判断,其索引表都是256个字节的。

 16bit 

 16位的稍微麻烦点,需要先通过文件头的压缩方式来判定,0是555格式,3是565格式,它们在转化位24bit或者32bit时使用的掩码是不同的,具体网上很多。分别是将提取出的颜色分量放在低5位,这样颜色失真一般比较严重,所以再做个均匀映射255的可以吧颜色补正。

  在调试的过程中发现,原来16位BMP转24位或者32位还是很简单的,只需要稍微修改信息头的类型,文件大小,再将其存储位.bmp文件 即可。

 24bit 

     24位如果绘图直接是使用RGB接很简单咯,直接解码出数据返回即可,如果是绘图图层是32位的,还需要给ALPHA位补255,buf分配空间因该是 waith * hight * 4 。

 32bit

     我本来就是使用的32位图层,所以32位解码是最简单的,去掉文件头,其余数据直接返回 OK :)

至此,BMP基本告一段落,其实还有一种情况没有考虑,就是4bit和8bit可能还带RLE压缩,虽然实际这种情况很少见,我这里暂时没有做RLE的加压工作。

void CExample10View::OnSave555BiBitfields() { // TODO: Add your command handler code here if(lpBmpDataBuf==NULL) { MessageBox("当前没有打开的图"); return; } BYTE r,g,b; LPBYTE lpDest,lpSrc; int i,j; int nheapSize; CFileDialog filesavebox(FALSE,"bmp","BI_BITFIELDS.bmp",OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,"files(*.bmp)|*.bmp|",NULL); CFile file; CString strPathname; if(m_bmi.biBitCount!=24) { MessageBox("当前打开的图不是24图"); return; } memcpy(&m_newbmf,&m_bmf,sizeof(BITMAPFILEHEADER)); memcpy(&m_newbmi,&m_bmi,sizeof(BITMAPINFOHEADER)); m_newbmi.biBitCount=16; m_newbmi.biCompression=BI_BITFIELDS;//即3 m_newbmi.biSizeImage=WIDTHBYTES(m_newbmi.biWidth,m_newbmi.biBitCount)*m_newbmi.biHeight; m_newbmf.bfSize=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+sizeof(DWORD)*3 +WIDTHBYTES(m_newbmi.biWidth,m_newbmi.biBitCount)*m_newbmi.biHeight; m_newbmf.bfOffBits=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+sizeof(DWORD)*3; nheapSize=sizeof(BITMAPINFOHEADER)+sizeof(DWORD)*3 +WIDTHBYTES(m_newbmi.biWidth,m_newbmi.biBitCount)*m_newbmi.biHeight; if(lpnewBmpDataBuf!=NULL) { delete []lpnewBmpDataBuf; lpnewBmpDataBuf=NULL; } lpnewBmpDataBuf=new BYTE[nheapSize]; memcpy(lpnewBmpDataBuf,&m_newbmi,sizeof(BITMAPINFOHEADER)); DWORD* lp=(DWORD*)(lpnewBmpDataBuf+sizeof(BITMAPINFOHEADER)); *lp++=0x00007c00; *lp++=0x000003e0; *lp =0x0000001f; for(i=0;i<m_newbmi.biHeight;i++) { for(j=0;j<m_newbmi.biWidth;j++) { lpSrc=lpBmpDataBuf+sizeof(BITMAPINFOHEADER) +WIDTHBYTES(m_bmi.biWidth,m_bmi.biBitCount)*(m_bmi.biHeight-1-i) +j*3; lpDest=lpnewBmpDataBuf+sizeof(BITMAPINFOHEADER)+sizeof(DWORD)*3 +WIDTHBYTES(m_newbmi.biWidth,m_newbmi.biBitCount)*(m_newbmi.biHeight-1-i) +j*2; b=*lpSrc++; b&=0xf8; g=*lpSrc++; g&=0xf8; r=*lpSrc++; r&=0xf8; WORD* lp=(WORD*)lpDest; *lp=0; *lp=r<<7; *lp+=(g<>3); } } if(filesavebox.DoModal()!=IDOK) return; strPath
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值