-
Bmp格式
DigitalImage图像类设计
- 图像加载函数,通过bmp图片路径,加载图像数据,通过类构造函数来实现。
DigitalImage::DigitalImage(LPCTSTR lpszPath)
{StrCpy(m_FilePath, lpszPath);CFile RdBmp;if (!RdBmp.Open(m_FilePath, CFile::modeRead | CFile::shareDenyWrite)){return;}// 为位图文件头分配空间,并初始化为0m_lpBmpFileHeader = (LPBITMAPFILEHEADER)new BYTE[sizeof(BITMAPFILEHEADER)];memset(m_lpBmpFileHeader, 0, sizeof(BITMAPFILEHEADER));// 读取位图文件头int nCount = RdBmp.Read((void *)m_lpBmpFileHeader, sizeof(BITMAPFILEHEADER));if (nCount != sizeof(BITMAPFILEHEADER)){return;}if (m_lpBmpFileHeader->bfType == 0x4d42)// 判断此文件是不是位图文件(“0x4d42”代表“BM”){// 是位图文件// 计算除位图文件头的空间大小,分配空间并初始化为0DWORD dwDibSize = RdBmp.GetLength() - sizeof(BITMAPFILEHEADER);m_lpNotBmpFileHenderData = new BYTE[dwDibSize];memset(m_lpNotBmpFileHenderData, 0, dwDibSize);// 读取除位图文件头的所有数据RdBmp.Read(m_lpNotBmpFileHenderData, dwDibSize);// 关闭位图文件RdBmp.Close();// 设置位图信息指针m_lpBmpInfo = (LPBITMAPINFO)m_lpNotBmpFileHenderData;// 设置位图信息头指针m_lpBmpInfoHeader = (LPBITMAPINFOHEADER)m_lpNotBmpFileHenderData;// 设置位图颜色表指针m_lpRgbQuad = (LPRGBQUAD)(m_lpNotBmpFileHenderData + m_lpBmpInfoHeader->biSize);// 如果位图没有设置位图使用的颜色数,设置它if (m_lpBmpInfoHeader->biClrUsed == 0){if (m_lpBmpInfoHeader->biBitCount < 9){UINT dwNumOfColor = (UINT)pow(2, m_lpBmpInfoHeader->biBitCount);m_lpBmpInfoHeader->biClrUsed = dwNumOfColor;}}// 计算颜色表长度DWORD dwRgbQuadLength = 0;if (m_lpBmpInfoHeader->biClrUsed > 256)dwRgbQuadLength = 0;elsedwRgbQuadLength = m_lpBmpInfoHeader->biClrUsed * sizeof(RGBQUAD);// 设置位图数据指针m_lpData = m_lpNotBmpFileHenderData + m_lpBmpInfoHeader->biSize + dwRgbQuadLength;// 判断是否有颜色表if (m_lpRgbQuad == (LPRGBQUAD)m_lpData){m_lpRgbQuad = NULL; // 将位图颜色表指针置空m_bHasRgbQuad = FALSE; // 无颜色表}else{m_bHasRgbQuad = TRUE; // 有颜色表//删除旧的调色板对象if (m_hPalette != NULL){DeleteObject(m_hPalette);m_hPalette = NULL;}// 申请缓冲区,初始化为0DWORD dwSize = 2 * sizeof(WORD) + m_lpBmpInfoHeader->biClrUsed * sizeof(PALETTEENTRY);LPLOGPALETTE lpLogPalette = (LPLOGPALETTE) new BYTE[dwSize];memset(lpLogPalette, 0, dwSize);// 生成逻辑调色板lpLogPalette->palVersion = 0x300;lpLogPalette->palNumEntries = m_lpBmpInfoHeader->biClrUsed;LPRGBQUAD lpRgbQuad = (LPRGBQUAD)m_lpRgbQuad;for (int i = 0; i < m_lpBmpInfoHeader->biClrUsed; i++){lpLogPalette->palPalEntry[i].peRed = lpRgbQuad->rgbRed;lpLogPalette->palPalEntry[i].peGreen = lpRgbQuad->rgbGreen;lpLogPalette->palPalEntry[i].peBlue = lpRgbQuad->rgbBlue;lpLogPalette->palPalEntry[i].peFlags = 0;lpRgbQuad++;}// 创建逻辑调色板m_hPalette = CreatePalette(lpLogPalette);// 释放缓冲区delete[] lpLogPalette;// 设置位图大小(因为很多位图文件都不设置此项)if (m_lpBmpInfoHeader->biSizeImage == 0){m_lpBmpInfoHeader->biSizeImage = m_lpBmpInfoHeader->biWidth*m_lpBmpInfoHeader->biHeight;}// 位图有效m_bValid = TRUE;}}else{//非位图m_bValid = FALSE;}
}
2.图片的显示,通过两种方式显示,通过StretchDIBits函数;
BOOL DigitalImage::Draw(CDC *pDC, CPoint origin, CSize size)
{// 位图无效,无法绘制,返回错误if (!m_bValid){return FALSE;}// 旧的调色板句柄HPALETTE hOldPalette = NULL;// 如果位图指针为空,则返回FALSEif (m_lpNotBmpFileHenderData == NULL){return FALSE;}// 如果位图有调色板,则选进设备环境中if (m_hPalette != NULL){hOldPalette = SelectPalette(pDC->GetSafeHdc(), m_hPalette, TRUE);}// 设置位图伸缩模式pDC->SetStretchBltMode(COLORONCOLOR);// 将位图在pDC所指向的设备上进行显示StretchDIBits(pDC->GetSafeHdc(), origin.x, origin.y, size.cx, size.cy,0, 0, m_lpBmpInfoHeader->biWidth, m_lpBmpInfoHeader->biHeight, m_lpData, m_lpBmpInfo, DIB_RGB_COLORS, SRCCOPY);// 恢复旧的调色板if (hOldPalette != NULL){SelectPalette(pDC->GetSafeHdc(), hOldPalette, TRUE);}return TRUE;
}
3.通过SetPixel逐像素显示。
BOOL DigitalImage::DrawPixel(CDC * pDC, CPoint origin)
{ for (int i = m_lpBmpInfoHeader->biHeight-1; i>=0; i--){for (int j = 0; j < m_lpBmpInfoHeader->biWidth; j++){int index = i*m_lpBmpInfoHeader->biWidth + j;int indexcolor = m_lpData[index];COLORREF color;color = RGB(m_lpRgbQuad[indexcolor].rgbRed, m_lpRgbQuad[indexcolor].rgbGreen, m_lpRgbQuad[indexcolor].rgbBlue);pDC->SetPixel(i, j, color);}}return TRUE;
}
4.运行结果:
对于逐像素显示的函数,颜色数据解析存在不足,显示如下,对于存在的错误,还需继续专研。