DigitalImage::DigitalImage(LPCTSTR lpszPath)
{
StrCpy(m_FilePath, lpszPath);
CFile RdBmp;
if (!RdBmp.Open(m_FilePath, CFile::modeRead | CFile::shareDenyWrite))
{
return;
}
// 为位图文件头分配空间,并初始化为0
m_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”)
{
// 是位图文件
// 计算除位图文件头的空间大小,分配空间并初始化为0
DWORD 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;
else
dwRgbQuadLength = 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;
}
// 申请缓冲区,初始化为0
DWORD 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;
// 如果位图指针为空,则返回FALSE
if (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.运行结果:
对于逐像素显示的函数,颜色数据解析存在不足,显示如下,对于存在的错误,还需继续专研。