📄 dibapi.cpp
字号:
} else { // 象素的大小 DWORD dwBmBitsSize; // 大小为Width * Height dwBmBitsSize = WIDTHBYTES((lpBI->biWidth)*((DWORD)lpBI->biBitCount)) * lpBI->biHeight; // 计算出DIB真正的大小 dwDIBSize += dwBmBitsSize; // 更新biSizeImage(很多BMP文件头中biSizeImage的值是错误的) lpBI->biSizeImage = dwBmBitsSize; } // 计算文件大小:DIB大小+BITMAPFILEHEADER结构大小 bmfHdr.bfSize = dwDIBSize + sizeof(BITMAPFILEHEADER); // 两个保留字 bmfHdr.bfReserved1 = 0; bmfHdr.bfReserved2 = 0; // 计算偏移量bfOffBits,它的大小为Bitmap文件头大小+DIB头大小+颜色表大小 bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + lpBI->biSize + PaletteSize((LPSTR)lpBI); // 尝试写文件 TRY { // 写文件头 file.Write((LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER)); // 写DIB头和象素 file.WriteHuge(lpBI, dwDIBSize); } CATCH (CFileException, e) { // 解除锁定 ::GlobalUnlock((HGLOBAL) hDib); // 抛出异常 THROW_LAST(); } END_CATCH // 解除锁定 ::GlobalUnlock((HGLOBAL) hDib); // 返回TRUE return TRUE;}/************************************************************************* * * 函数名称: * ReadDIBFile() * * 参数: * CFile& file - 要读取得文件文件CFile * * 返回值: * HDIB - 成功返回DIB的句柄,否则返回NULL。 * * 说明: * 该函数将指定的文件中的DIB对象读到指定的内存区域中。除BITMAPFILEHEADER * 外的内容都将被读入内存。 * *************************************************************************/HDIB WINAPI ReadDIBFile(CFile& file){ BITMAPFILEHEADER bmfHeader; DWORD dwBitsSize; HDIB hDIB; LPSTR pDIB; // 获取DIB(文件)长度(字节) dwBitsSize = file.GetLength(); // 尝试读取DIB文件头 if (file.Read((LPSTR)&bmfHeader, sizeof(bmfHeader)) != sizeof(bmfHeader)) { // 大小不对,返回NULL。 return NULL; } // 判断是否是DIB对象,检查头两个字节是否是"BM" if (bmfHeader.bfType != DIB_HEADER_MARKER) { // 非DIB对象,返回NULL。 return NULL; } // 为DIB分配内存 hDIB = (HDIB) ::GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, dwBitsSize); if (hDIB == 0) { // 内存分配失败,返回NULL。 return NULL; } // 锁定 pDIB = (LPSTR) ::GlobalLock((HGLOBAL) hDIB); // 读象素 if (file.ReadHuge(pDIB, dwBitsSize - sizeof(BITMAPFILEHEADER)) != dwBitsSize - sizeof(BITMAPFILEHEADER) ) { // 大小不对。 // 解除锁定 ::GlobalUnlock((HGLOBAL) hDIB); // 释放内存 ::GlobalFree((HGLOBAL) hDIB); // 返回NULL。 return NULL; } // 解除锁定 ::GlobalUnlock((HGLOBAL) hDIB); // 返回DIB句柄 return hDIB;}/************************************************************************* * * 函数名称: * DIBToPCX256() * * 参数: * LPSTR lpDIB - 指向DIB对象的指针 * CFile& file - 要保存的文件 * * 返回值: * BOOL - 成功返回True,否则返回False。 * * 说明: * 该函数将指定的256色DIB对象保存为256色PCX文件。 * *************************************************************************/BOOL WINAPI DIBToPCX256(LPSTR lpDIB, CFile& file){ // 循环变量 LONG i; LONG j; // DIB高度 WORD wHeight; // DIB宽度 WORD wWidth; // 中间变量 BYTE bChar1; BYTE bChar2; // 指向源图像象素的指针 BYTE * lpSrc; // 指向编码后图像数据的指针 BYTE * lpDst; // 图像每行的字节数 LONG lLineBytes; // 重复像素计数 int iCount; // 缓冲区已使用的字节数 DWORD dwBuffUsed; // 指向DIB象素指针 LPSTR lpDIBBits; // 获取DIB高度 wHeight = (WORD) DIBHeight(lpDIB); // 获取DIB宽度 wWidth = (WORD) DIBWidth(lpDIB); // 找到DIB图像象素起始位置 lpDIBBits = FindDIBBits(lpDIB); // 计算图像每行的字节数 lLineBytes = WIDTHBYTES(wWidth * 8); //************************************************************************* // PCX文件头 PCXHEADER pcxHdr; // 给文件头赋值 // PCX标识码 pcxHdr.bManufacturer = 0x0A; // PCX版本号 pcxHdr.bVersion = 5; // PCX编码方式(1表示RLE编码) pcxHdr.bEncoding = 1; // 像素位数(256色为8位) pcxHdr.bBpp = 8; // 图像相对于屏幕的左上角X坐标(以像素为单位) pcxHdr.wLeft = 0; // 图像相对于屏幕的左上角Y坐标(以像素为单位) pcxHdr.wTop = 0; // 图像相对于屏幕的右下角X坐标(以像素为单位) pcxHdr.wRight = wWidth - 1; // 图像相对于屏幕的右下角Y坐标(以像素为单位) pcxHdr.wBottom = wHeight - 1; // 图像的水平分辨率 pcxHdr.wXResolution = wWidth; // 图像的垂直分辨率 pcxHdr.wYResolution = wHeight; // 调色板数据(对于256色PCX无意义,直接赋值为0) for (i = 0; i < 48; i ++) { pcxHdr.bPalette[i] = 0; } // 保留域,设定为0。 pcxHdr.bReserved = 0; // 图像色彩平面数目(对于256色PCX设定为1)。 pcxHdr.bPlanes = 1; // 图像的宽度(字节为单位),必须为偶数。// if ((wWidth & 1) == 0)// { pcxHdr.wLineBytes = wWidth;// }// else// {// pcxHdr.wLineBytes = wWidth + 1;// } // 图像调色板的类型,1表示彩色或者单色图像,2表示图像是灰度图。 pcxHdr.wPaletteType = 1; // 制作该图像的屏幕宽度(像素为单位) pcxHdr.wSrcWidth = 0; // 制作该图像的屏幕高度(像素为单位) pcxHdr.wSrcDepth = 0; // 保留域,取值设定为0。 for (i = 0; i < 54; i ++) { pcxHdr.bFiller[i] = 0; } // 写入文件头 file.Write((LPSTR)&pcxHdr, sizeof(PCXHEADER)); //******************************************************************************* // 开始编码 // 开辟一片缓冲区(2被原始图像大小)以保存编码结果 lpDst = new BYTE[wHeight * wWidth * 2]; // 指明当前已经用了多少缓冲区(字节数) dwBuffUsed = 0; // 每行 for (i = 0; i < wHeight; i++) { // 指向DIB第i行,第0个象素的指针 lpSrc = (BYTE *)lpDIBBits + lLineBytes * (wHeight - 1 - i); // 给bChar1赋值 bChar1 = *lpSrc; // 设置iCount为1 iCount = 1; // 剩余列 for (j = 1; j < wWidth; j ++) { // 指向DIB第i行,第j个象素的指针 lpSrc++; // 读取下一个像素 bChar2 = *lpSrc; // 判断是否和bChar1相同并且iCount < 63 if ((bChar1 == bChar2) && (iCount < 63)) { // 相同,计数加1 iCount ++; // 继续读下一个 } else { // 不同,或者iCount = 63 // 写入缓冲区 if ((iCount > 1) || (bChar1 >= 0xC0)) { // 保存码长信息 lpDst[dwBuffUsed] = iCount | 0xC0; // 保存bChar1 lpDst[dwBuffUsed + 1] = bChar1; // 更新dwBuffUsed dwBuffUsed += 2; } else { // 直接保存该值 lpDst[dwBuffUsed] = bChar1; // 更新dwBuffUsed dwBuffUsed ++; } // 重新给bChar1赋值 bChar1 = bChar2; // 设置iCount为1 iCount = 1; } } // 保存每行最后一部分编码 if ((iCount > 1) || (bChar1 >= 0xC0)) { // 保存码长信息 lpDst[dwBuffUsed] = iCount | 0xC0; // 保存bChar1 lpDst[dwBuffUsed + 1] = bChar1; // 更新dwBuffUsed dwBuffUsed += 2; } else { // 直接保存该值 lpDst[dwBuffUsed] = bChar1; // 更新dwBuffUsed dwBuffUsed ++; } } // 写入编码结果 file.WriteHuge((LPSTR)lpDst, dwBuffUsed); // 释放内存 delete lpDst; //************************************************************************** // 写入调色板信息 // 指向BITMAPINFO结构的指针(Win3.0) LPBITMAPINFO lpbmi; // 指向BITMAPCOREINFO结构的指针 LPBITMAPCOREINFO lpbmc; // 表明是否是Win3.0 DIB的标记 BOOL bWinStyleDIB; // 开辟一片缓冲区以保存调色板 lpDst = new BYTE[769]; // 调色板起始字节 * lpDst = 0x0C; // 获取指向BITMAPINFO结构的指针(Win3.0) lpbmi = (LPBITMAPINFO)lpDIB; // 获取指向BITMAPCOREINFO结构的指针 lpbmc = (LPBITMAPCOREINFO)lpDIB; // 判断是否是WIN3.0的DIB bWinStyleDIB = IS_WIN30_DIB(lpDIB); // 读取当前DIB调色板 for (i = 0; i < 256; i ++) { if (bWinStyleDIB) { // 读取DIB调色板红色分量 lpDst[i * 3 + 1] = lpbmi->bmiColors[i].rgbRed; // 读取DIB调色板绿色分量 lpDst[i * 3 + 2] = lpbmi->bmiColors[i].rgbGreen; // 读取DIB调色板蓝色分量 lpDst[i * 3 + 3] = lpbmi->bmiColors[i].rgbBlue; } else { // 读取DIB调色板红色分量 lpDst[i * 3 + 1] = lpbmc->bmciColors[i].rgbtRed; // 读取DIB调色板绿色分量 lpDst[i * 3 + 2] = lpbmc->bmciColors[i].rgbtGreen; // 读取DIB调色板蓝色分量 lpDst[i * 3 + 3] = lpbmc->bmciColors[i].rgbtBlue; } } // 写入调色板信息 file.Write((LPSTR)lpDst, 769); // 返回 return TRUE;}/************************************************************************* * * 函数名称: * ReadPCX256() * * 参数: * CFile& file - 要读取的文件 * * 返回值: * HDIB - 成功返回DIB的句柄,否则返回NULL。 * * 说明: * 该函数将读取指定的256色PCX文件。将读取的结果保存在一个未压缩 * 编码的DIB对象中。 * *************************************************************************/HDIB WINAPI ReadPCX256(CFile& file){ // PCX文件头 PCXHEADER pcxHdr; // DIB大小(字节数) DWORD dwDIBSize; // DIB句柄 HDIB hDIB; // DIB指针 LPSTR pDIB; // 循环变量 LONG i; LONG j; // 重复像素计数 int iCount; // DIB高度 WORD wHeight; // DIB宽度 WORD wWidth; // 图像每行的字节数 LONG lLineBytes; // 中间变量 BYTE bChar; // 指向源图像象素的指针 BYTE * lpSrc; // 指向编码后图像数据的指针 BYTE * lpDst; // 临时指针 BYTE * lpTemp; // 尝试读取PCX文件头 if (file.Read((LPSTR)&pcxHdr, sizeof(PCXHEADER)) != sizeof(PCXHEADER)) { // 大小不对,返回NULL。 return NULL; } // 判断是否是256色PCX文件,检查第一个字节是否是0x0A, if ((pcxHdr.bManufacturer != 0x0A) || (pcxHdr.bBpp != 8) || (pcxHdr.bPlanes != 1)) { // 非256色PCX文件,返回NULL。 return NULL; } // 获取图像高度 wHeight = pcxHdr.wBottom - pcxHdr.wTop + 1; // 获取图像宽度 wWidth = pcxHdr.wRight - pcxHdr.wLeft + 1; // 计算图像每行的字节数 lLineBytes = WIDTHBYTES(wWidth * 8); // 计算DIB长度(字节) dwDIBSize = sizeof(BITMAPINFOHEADER) + 1024 + wHeight * lLineBytes; // 为DIB分配内存 hDIB = (HDIB) ::GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, dwDIBSize); if (hDIB == 0) { // 内存分配失败,返回NULL。 return NULL; } // 锁定 pDIB = (LPSTR) ::GlobalLock((HGLOBAL) hDIB); // 指向BITMAPINFOHEADER的指针 LPBITMAPINFOHEADER lpBI; // 赋值 lpBI = (LPBITMAPINFOHEADER) pDIB; // 给lpBI成员赋值 lpBI->biSize = 40; lpBI->biWidth = wWidth; lpBI->biHeight = wHeight; lpBI->biPlanes = 1; lpBI->biBitCount = 8; lpBI->biCompression = BI_RGB; lpBI->biSizeImage = wHeight * lLineBytes; lpBI->biXPelsPerMeter = pcxHdr.wXResolution; lpBI->biYPelsPerMeter = pcxHdr.wYResolution; lpBI->biClrUsed = 0; lpBI->biClrImportant = 0; // 分配内存以读取编码后的象素 lpSrc = new BYTE[file.GetLength() - sizeof(PCXHEADER) - 769]; lpTemp = lpSrc; // 读取编码后的象素 if (file.ReadHuge(lpSrc, file.GetLength() - sizeof(PCXHEADER) - 769) != file.GetLength() - sizeof(PCXHEADER) - 769 ) { // 大小不对。 // 解除锁定 ::GlobalUnlock((HGLOBAL) hDIB); // 释放内存 ::GlobalFree((HGLOBAL) hDIB); // 返回NULL。 return NULL; } // 计算DIB中像素位置 lpDst = (BYTE *) FindDIBBits(pDIB); // 一行一行解码 for (j = 0; j <wHeight; j++) { i = 0; while (i < wWidth) { // 读取一个字节 bChar = *lpTemp; lpTemp++; if ((bChar & 0xC0) == 0xC0) { // 行程 iCount = bChar & 0x3F; // 读取下一个字节 bChar = *lpTemp; lpTemp++; // bChar重复iCount次保存 memset(&lpDst[(wHeight - j - 1) * lLineBytes + i], bChar, iCount); // 已经读取像素的个数加iCount i += iCount; } else { // 保存当前字节 lpDst[(wHeight - j - 1) * lLineBytes + i] = bChar; // 已经读取像素的个数加1 i += 1; } } } // 释放内存 delete lpSrc; //************************************************************* // 调色板 // 读调色板标志位 file.Read(&bChar, 1); if (bChar != 0x0C) { // 出错 // 解除锁定 ::GlobalUnlock((HGLOBAL) hDIB); // 释放内存 ::GlobalFree((HGLOBAL) hDIB); // 返回NULL。 return NULL; } // 分配内存以读取编码后的象素 lpSrc = new BYTE[768]; // 计算DIB中调色板的位置 lpDst = (BYTE *) pDIB + sizeof(BITMAPINFOHEADER); // 读取调色板 if (file.Read(lpSrc, 768) != 768) { // 大小不对。 // 解除锁定 ::GlobalUnlock((HGLOBAL) hDIB); // 释放内存 ::GlobalFree((HGLOBAL) hDIB); // 返回NULL。 return NULL; } // 给调色板赋值 for (i = 0; i < 256; i++) { lpDst[i * 4] = lpSrc[i * 3 + 2]; lpDst[i * 4 + 1] = lpSrc[i * 3 + 1]; lpDst[i * 4 + 2] = lpSrc[i * 3]; lpDst[i * 4 + 3] = 0; } // 释放内存 delete lpSrc; // 解除锁定 ::GlobalUnlock((HGLOBAL) hDIB); // 返回DIB句柄 return hDIB;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -