vc 位图操作 BITMAPINFO 赋值


vc 位图操作 BITMAPINFO 赋值

BMP 文件结构分成以下几个部分:
1 BITMAP FILEHEADER (BMP 文件头)
2 BITMAP INFOHEADER (BMP 文件信息头)
3 RGBQUAD (BMP 文件调色板)
4 BITMAP DATA (BMP 文件数据)

Windows 中位图有两种格式:
设备相关位图 Device Depend Bitmap DDB
设备无关位图 Device Independ Bitmap DIB

DDB 位图格式 ------------ BITMAP(结构体) CBitmap(MFC类) HBITMAP(HANDLE)
由 BITMAP 数据类型的结构 + 图像数据构成。
因为DDB没有保存位图的调色板,在不同类设备显示时可能造成完全失真。

DIB 位图格式 ----------- BITMAPINFO
BITMAP INFOHEADER (BMP 文件信息头) + RGBQUAD (BMP 文件调色板) + BITMAP DATA (BMP 文件数据) 三部分构成
它实际就是BMP文件去掉BITMAP FILEHEADER (BMP 文件头),即一个BITMAPINFO结构后面接上调色板再加上图像数据。

BMP文件的显示 ---- DIB
首先将BMP读成DIB格式,当显示时直接DIB显示,只要读入BITMAPINFO结构和图像数据即可。

BMP文件的显示 ---- DDB
首先要先将DIB位图转化为DDB位图,再由MFC的CBitmap类显示。

总结: 统一使用DIB显示,即 BITMAPINFO;//个人意见
不要使用以下:BITMAP(结构体) CBitmap(MFC类) HBITMAP(HANDLE)//个人意见

//**********************************************
重点说说 BITMAPINFO MFC中的定义如下:
typedef struct tagBITMAPINFO {
    BITMAPINFOHEADER    bmiHeader;
    RGBQUAD             bmiColors[1];
} BITMAPINFO, FAR *LPBITMAPINFO, *PBITMAPINFO;

这个结构体定义很奇怪,大概的意思是兼容没有调色板的情况,不看它的写法,
依据BITMAPINFO的大小为 sizeof(BITMAPINFOHEADER) + numQuad * sizeof(RGBQUAD)       采用如下赋值方法

   CFile file;
   BITMAPFILEHEADER FILE_HEADER; //文件头
BITMAPINFOHEADER INFO_HEADER; //信息头
   file.Open("d:\demo.bmp", CFile::modeRead);

   file.Read(&FILE_HEADER, sizeof(BITMAPFILEHEADER));
   if(FILE_HEADER.bfType != 0x4d42)
   {
    file.Close();
    AfxMessageBox("原图象不为BMP图象!");
    return;
   }

   file.Read(&INFO_HEADER,sizeof(BITMAPINFOHEADER));

   // 调色板数目
   int numQuad = 0;
   if(INFO_HEADER.biBitCount < 24)
   {
    numQuad = 1 << INFO_HEADER.biBitCount; //1右移?位 = 2的?次方
   }

   BITMAPINFO *pBMP_INFO = (BITMAPINFO*)HeapAlloc(GetProcessHeap(),0,
    sizeof(BITMAPINFOHEADER) + numQuad * sizeof(RGBQUAD));
   memcpy(pBMP_INFO, &INFO_HEADER, sizeof(BITMAPINFOHEADER));
   RGBQUAD *quad = (RGBQUAD*)((BYTE*)pBMP_INFO + sizeof(BITMAPINFOHEADER));
   if(numQuad != 0)
   {
    file.Read(quad, sizeof(RGBQUAD) * numQuad);
   }

   int sizeBuf = FILE_HEADER.bfSize - FILE_HEADER.bfOffBits;
   BYTE *bmpBuf = new BYTE[sizeBuf];
   file.Read(bmpBuf, sizeBuf);
   file.Close();

   CDC *pDC = GetDC();
   Graphics gdiDC(pDC->GetSafeHdc());
   Bitmap *pBmp = Bitmap::FromBITMAPINFO(pBMP_INFO, bmpBuf);//GDI+从BITMAPINFO生成bmp的方法
   gdiDC.DrawImage(pBmp, 0, 0);
   ReleaseDC(pDC);

//====================BITMAPINFO 说明=====================================

typedef struct tagBITMAPINFO {
    BITMAPINFOHEADER    bmiHeader;
    RGBQUAD             bmiColors[1];
} BITMAPINFO, FAR *LPBITMAPINFO, *PBITMAPINFO;

在一个结构体定义
RGBQUAD bmiColors[1];
是很危险也非常巧妙的不得已的办法,它的存在只为照顾bmp文件而存在;
因此使用BITMAPINFO有很多限制:
限制一 RGBQUAD bmiColors[1];此类设置只能存在1个,且必在最后
限制二 RGBQUAD类型必为4字节的整倍数
限制三 虽然sizeof(BITMAPINFO) = 40 + 4 = 44;
       但为BITMAPINFO申请内存时必须是40 + 4 * 调色板个数,否则内存越界
       也就是在使用BITMAPINFO时申请的字节数可能为40或大于44的某个数,总之一定不是44,如果为44会报错
bmp文件的字节是连续的(当然任何文件都是连续的),在文件中,紧随BITMAPINFOHEADER之后是调色板,如果没有调色板,紧随BITMAPINFOHEADER之后是数据,注意如果没有调色板,在BITMAPINFOHEADER与数据之间没有任何字节存在,为了照顾bmp文件BITMAPINFO被设计成这样,bmiColors[1]是个数组,它存放了数组的第1个元素,也就是bmiColors[0],接下来一定是bmiColors[1](此bmiColors[1]表示RGBQUAD数组的第2个元素,而BITMAPINFO中RGBQUAD bmiColors[1];则表示定义一个类型,是一个数组,因为数组是连续存储的,这样设计才能保证与bmp文件结构吻合),好乱~

申请内存也可这样写:
BITMAPINFO *pBMP_INFO = (BITMAPINFO*)malloc(sizeof(BITMAPINFOHEADER) + numQuad * sizeof(RGBQUAD));

BITMAPINFO *pBMP_INFO = new BITMAPINFO[sizeof(BITMAPINFOHEADER) + numQuad * sizeof(RGBQUAD)];

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这是一个用于C++ MFC开发的Bitmap图片操作类,在文件中叫CBitmapEx,可用于放大,缩小,翻转,过渡和其他有用的功能,有兴趣的朋友可以下载看看。 部分public method: // // void Create(long width, long height); // void Create(CBitmapEx& bitmapEx); // void Load(LPTSTR lpszBitmapFile); // void Save(LPTSTR lpszBitmapFile); // void Scale(long horizontalPercent=100, long verticalPercent=100); // void Rotate(long degrees=0, _PIXEL bgColor=_RGB(0,0,0)); // void FlipHorizontal(); // void FlipVertical(); // void MirrorLeft(); // void MirrorRight(); // void MirrorTop(); // void MirrorBottom(); // void Clear(_PIXEL clearColor=_RGB(0,0,0)); // void Negative(); // void Grayscale(); // void Sepia(long depth=34); // void Emboss(); // void Engrave(); // void Pixelize(long size=4); // void Draw(HDC hDC); // void Draw(long dstX, long dstY, long width, long height, // CBitmapEx& bitmapEx, long srcX, long srcY); // void Draw(long dstX, long dstY, long width, long height, // CBitmapEx& bitmapEx, long srcX, long srcY, long alpha); // void Draw(long dstX, long dstY, long dstWidth, long dstHeight, // CBitmapEx& bitmapEx, long srcX, long srcY, long srcWidth, long srcHeight); // void Draw(long dstX, long dstY, long dstWidth, long dstHeight, CBitmapEx& bitmapEx, // long srcX, long srcY, long srcWidth, long srcHeight, long alpha); // void DrawTransparent(long dstX, long dstY, long width, long height, // CBitmapEx& bitmapEx, long srcX, long srcY, _PIXEL transparentColor=_RGB(0,0,0)); // void DrawTransparent(long dstX, long dstY, long width, long height, // CBitmapEx& bitmapEx, long srcX, long srcY, long alpha, // _PIXEL transparentColor=_RGB(0,0,0)); // void DrawTransparent(long dstX, long dstY, long dstWidth, long dstHeight, // CBitmapEx& bitmapEx, long srcX, long srcY, long srcWidth, long srcHeight, // _PIXEL transparentColor=_RGB(0,0,0)); // void DrawTransparent(long dstX, long dstY, long dstWidth, long dstHeight, // CBitmapEx& bitmapEx, long srcX, long srcY, long srcWidth, long srcHeight, // long alpha, _PIXEL transparentColor=_RGB(0,0,0)); // LPBI
以下是将MFC 24位图转换为单色位图的示例代码: CBitmap bmp24; bmp24.LoadBitmap(IDB_BITMAP24); //加载24位图 BITMAPINFO bmi24; ZeroMemory(&bmi24, sizeof(BITMAPINFO)); //清空结构体 bmi24.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bmp24.GetBitmap(&bmi24.bmiHeader, sizeof(BITMAPINFOHEADER)); //获取24位图像素信息 //创建单色位图 BITMAPINFO bmi1; ZeroMemory(&bmi1, sizeof(BITMAPINFO)); bmi1.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bmi1.bmiHeader.biWidth = bmi24.bmiHeader.biWidth; bmi1.bmiHeader.biHeight = bmi24.bmiHeader.biHeight; bmi1.bmiHeader.biPlanes = 1; bmi1.bmiHeader.biBitCount = 1; bmi1.bmiHeader.biCompression = BI_RGB; //计算单色位图像素信息 BYTE* pBits24 = new BYTE[bmi24.bmiHeader.biSizeImage]; bmp24.GetBitmapBits(bmi24.bmiHeader.biSizeImage, pBits24); BYTE* pBits1 = new BYTE[bmi1.bmiHeader.biSizeImage]; int rowWidth24 = ((bmi24.bmiHeader.biWidth * 24 + 31) / 32) * 4; int rowWidth1 = ((bmi1.bmiHeader.biWidth * 1 + 31) / 32) * 4; for (int y = 0; y < bmi24.bmiHeader.biHeight; y++) { for (int x = 0; x < bmi24.bmiHeader.biWidth; x++) { int index24 = y * rowWidth24 + x * 3; int index1 = y * rowWidth1 + x / 8; BYTE gray = (BYTE)(0.299 * pBits24[index24 + 2] + 0.587 * pBits24[index24 + 1] + 0.114 * pBits24[index24]); //计算灰度值 BYTE bit = gray > 128 ? 0 : 1; //将灰度值转为二值图像 pBits1[index1] |= (bit << (7 - x % 8)); //将二值图像写入单色位图 } } //创建单色位图 CBitmap bmp1; bmp1.CreateBitmapIndirect(&bmi1, pBits1); //释放内存 delete[] pBits24; delete[] pBits1; //显示单色位图 CDC* pDC = GetDC(); CDC memDC; memDC.CreateCompatibleDC(pDC); CBitmap* pOldBmp = memDC.SelectObject(&bmp1); pDC->BitBlt(0, 0, bmi1.bmiHeader.biWidth, bmi1.bmiHeader.biHeight, &memDC, 0, 0, SRCCOPY); memDC.SelectObject(pOldBmp); ReleaseDC(pDC);

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值