位图文件分四部份数据块
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;
}