DIB函数注释

来源:互联网 发布:js call apply 区别 编辑:程序博客网 时间:2024/06/18 16:25
《数字图像处理》老师非要用MFC做实验,所以我被迫接触了一些window api 。一开始看的很辛苦,不过本着不会就查,再不会再查的递归解决思想,我也解决了一些问题,不过MFC的机制我还是一无所知,我的本心也不想知道,只能是要用多少就学多少吧。在这里我给DIB函数写了一些注释,或许能给那些和我一样刚刚接触Windows编程的人,或是凑巧要做图像处理作业的人一些帮助。// ************************************************************************//  文件名:dibapi.cpp////  DIB(Independent Bitmap) API函数库:////  PaintDIB()          - 绘制DIB对象//  CreateDIBPalette()  - 创建DIB对象调色板//  FindDIBBits()       - 返回DIB图像象素起始位置//  DIBWidth()          - 返回DIB宽度//  DIBHeight()         - 返回DIB高度//  PaletteSize()       - 返回DIB调色板大小//  DIBNumColors()      - 计算DIB调色板颜色数目//  CopyHandle()        - 拷贝内存块////  SaveDIB()           - 将DIB保存到指定文件中//  ReadDIBFile()       - 重指定文件中读取DIB对象////  DIBToPCX256()- 将指定的256色DIB对象保存为256色PCX文件//  ReadPCX256()- 读取256色PCX文件//// ************************************************************************#include "stdafx.h"#include "dibapi.h"#include <io.h>#include <errno.h>#include <math.h>#include <direct.h>//目录/* * Dib文件头标志(字符串"BM",写DIB时用到该常数) */#define DIB_HEADER_MARKER   ((WORD) ('M' << 8) | 'B')//这是在构造“BM”在内存中的表示,‘M’的ascii码是77,它的二进制是01001101,左移八位为 0100 1101 0000 0000‘B’的ascii码是66,它的二进制是01000010, 0100 1101 0000 0000|0000 0000 0100 0010=0100 1101 0100 0010结果就是BM在内存中的表示/************************************************************************* * * 函数名称: *   PaintDIB() * * 参数: *   HDC hDC            - 输出设备DC//HDC是一个结构体指针,结构体内只有一个名为unused的int变量 *   LPRECT lpDCRect    - 绘制矩形区域//LPRECT是一个指向tagRECT结构体的指针,//struct  tagRECT  //  {    //LONG left;    //LONG top;    //LONG right;    //LONG bottom;    //}//LONG是long的别名,为什么它要取一个这么没有用的别名?????? *   HDIB hDIB          - 指向DIB对象的指针//HDIB的类型同HDC,但是它不是//Windows内置的别名,要自己用DECLARE_HANDLE()宏定义 *   LPRECT lpDIBRect   - 要输出的DIB区域//同上 *   CPalette* pPal     - 指向DIB对象调色板的指针//CPalette是一个封装了Window//调色板的类,Windows调色板是一个设备借口,应用程序利用这个接口,使用设备的颜//色处理能力 * * 返回值: *   BOOL               - 绘制成功返回TRUE,否则返回FALSE。 * * 说明: *   该函数主要用来绘制DIB对象。其中调用了StretchDIBits()或者 * SetDIBitsToDevice()来绘制DIB对象。输出的设备由由参数hDC指 * 定;绘制的矩形区域由参数lpDCRect指定;输出DIB的区域由参数 * lpDIBRect指定。 * ************************************************************************/BOOL WINAPI PaintDIB(HDC     hDC,LPRECT  lpDCRect,HDIB    hDIB,LPRECT  lpDIBRect,//应该指在lpDCRect中的区域吧?CPalette* pPal){LPSTR    lpDIBHdr;            // BITMAPINFOHEADER指针,LPSTR是char*的别//名LPSTR    lpDIBBits;           // DIB象素指针BOOL     bSuccess=FALSE;      // 成功标志HPALETTE hPal=NULL;           // DIB调色板,HPALETTE是一个结构体指针,结//构体内只有一个int 名为unusedHPALETTE hOldPal=NULL;        // 以前的调色板// 判断DIB对象是否为空if (hDIB == NULL){// 返回return FALSE;}// 锁定DIBlpDIBHdr  = (LPSTR) ::GlobalLock((HGLOBAL) hDIB);//HGLOBAL是一个void*,只有锁定了一块内存才能操作它,其实这个语句,把位图的这块内存的地址放在了lpDIBHdr,这样每次移动刚好是一个字节// 找到DIB图像象素起始位置lpDIBBits = ::FindDIBBits(lpDIBHdr);//找到位图信息的开始地址// 获取DIB调色板,并选中它if (pPal != NULL){hPal = (HPALETTE) pPal->m_hObject;//这个数据成员是一个句柄集包含很多绑定到对象的句柄// 选中调色板hOldPal = ::SelectPalette(hDC, hPal, TRUE);//该函数选择指定的逻辑调色板到一个设备环境中,并给这个逻辑调色板映射一个物理调色板}// 设置显示模式::SetStretchBltMode(hDC, COLORONCOLOR);设置显示设备环境中的位图拉伸模式,COLORONCOLOR:删除像素。该模式删除所有消除的像素行,不保留其信息。// 判断是调用StretchDIBits()还是SetDIBitsToDevice()来绘制DIB对象if ((RECTWIDTH(lpDCRect)  == RECTWIDTH(lpDIBRect)) &&   (RECTHEIGHT(lpDCRect) == RECTHEIGHT(lpDIBRect)))//#define RECTWIDTH(lpRect)     ((lpRect)->right - (lpRect)->left),//#define RECTHEIGHT(lpRect)    ((lpRect)->bottom - (lpRect)->top),这是两个宏定义函数,获得矩形的宽度,获得矩形的高度。//如果绘图区域大小和位图图像大小一样,则不用拉伸{// 原始大小,不用拉伸。bSuccess = ::SetDIBitsToDevice(hDC,                    // hDC,输出的设备   lpDCRect->left,             // DestX,绘图区域的坐标   lpDCRect->top,              // DestY,同上   RECTWIDTH(lpDCRect),        // nDestWidth,绘图区域的宽度,调用了一个宏函数   RECTHEIGHT(lpDCRect),       // nDestHeight,绘图区域的高度,调用了一个宏函数   lpDIBRect->left,            // SrcX,位图起始坐标,这个坐标在左下,这和位图在内存中是由左//到右由下到上储存有关   (int)DIBHeight(lpDIBHdr) -  lpDIBRect->top -  RECTHEIGHT(lpDIBRect),   // SrcY,y坐标不知道怎么来的?????   0,                          // nStartScan//绘图区域开始扫描的行   (WORD)DIBHeight(lpDIBHdr),  // nNumScans//扫描位图的行数,从起始行开始扫描   lpDIBBits,                  // lpBits//位图内存的起始位置   (LPBITMAPINFO)lpDIBHdr,     // lpBitsInfo//把位图文件的内存直接转换为指向位图信息头的指针,就可以获 //得想要的内存块?//typedef struct tagBITMAPINFO { //  BITMAPINFOHEADER    bmiHeader;   // RGBQUAD             bmiColors[1];}   DIB_RGB_COLORS);            // wUsage表示颜色表包含原义的RGB值//如何理解这个函数:以上都是个人看法}    else{// 非原始大小,拉伸。bSuccess = ::StretchDIBits(hDC,                          // hDC   lpDCRect->left,                 // DestX   lpDCRect->top,                  // DestY   RECTWIDTH(lpDCRect),            // nDestWidth   RECTHEIGHT(lpDCRect),           // nDestHeight   lpDIBRect->left,                // SrcX   lpDIBRect->top,                 // SrcY   RECTWIDTH(lpDIBRect),           // wSrcWidth   RECTHEIGHT(lpDIBRect),          // wSrcHeight   lpDIBBits,                      // lpBits   (LPBITMAPINFO)lpDIBHdr,         // lpBitsInfo   DIB_RGB_COLORS,                 // wUsage   SRCCOPY);                       // dwROP}    // 解除锁定::GlobalUnlock((HGLOBAL) hDIB);// 恢复以前的调色板if (hOldPal != NULL){::SelectPalette(hDC, hOldPal, TRUE);}// 返回return bSuccess;}/************************************************************************* * * 函数名称: *   CreateDIBPalette() * * 参数: *   HDIB hDIB          - 指向DIB对象的指针 *   CPalette* pPal     - 指向DIB对象调色板的指针 * * 返回值: *   BOOL               - 创建成功返回TRUE,否则返回FALSE。 * * 说明: *   该函数按照DIB创建一个逻辑调色板,从DIB中读取颜色表并存到调色板中, * 最后按照该逻辑调色板创建一个新的Windows调色板,并返回该调色板的句柄。这样 * 可以用最好的颜色来显示DIB图像。 * ************************************************************************/BOOL WINAPI CreateDIBPalette(HDIB hDIB, CPalette* pPal){// 指向逻辑调色板的指针LPLOGPALETTE lpPal;// 逻辑调色板的句柄HANDLE hLogPal;// 调色板的句柄HPALETTE hPal = NULL;// 循环变量int i;// 颜色表中的颜色数目WORD wNumColors;// 指向DIB的指针LPSTR lpbi;// 指向BITMAPINFO结构的指针(Win3.0)LPBITMAPINFO lpbmi;// 指向BITMAPCOREINFO结构的指针LPBITMAPCOREINFO lpbmc;// 表明是否是Win3.0 DIB的标记BOOL bWinStyleDIB;// 创建结果BOOL bResult = FALSE;// 判断DIB是否为空if (hDIB == NULL){// 返回FALSEreturn FALSE;}// 锁定DIBlpbi = (LPSTR) ::GlobalLock((HGLOBAL) hDIB);// 获取指向BITMAPINFO结构的指针(Win3.0)lpbmi = (LPBITMAPINFO)lpbi;// 获取指向BITMAPCOREINFO结构的指针lpbmc = (LPBITMAPCOREINFO)lpbi;// 获取DIB中颜色表中的颜色数目wNumColors = ::DIBNumColors(lpbi);if (wNumColors != 0){// 分配为逻辑调色板内存hLogPal = ::GlobalAlloc(GHND, sizeof(LOGPALETTE)+ sizeof(PALETTEENTRY)* wNumColors);// 如果内存不足,退出if (hLogPal == 0){// 解除锁定::GlobalUnlock((HGLOBAL) hDIB);// 返回FALSEreturn FALSE;}lpPal = (LPLOGPALETTE) ::GlobalLock((HGLOBAL) hLogPal);// 设置版本号lpPal->palVersion = PALVERSION;// 设置颜色数目lpPal->palNumEntries = (WORD)wNumColors;// 判断是否是WIN3.0的DIBbWinStyleDIB = IS_WIN30_DIB(lpbi);// 读取调色板for (i = 0; i < (int)wNumColors; i++){if (bWinStyleDIB){// 读取红色分量lpPal->palPalEntry[i].peRed = lpbmi->bmiColors[i].rgbRed;// 读取绿色分量lpPal->palPalEntry[i].peGreen = lpbmi->bmiColors[i].rgbGreen;// 读取蓝色分量lpPal->palPalEntry[i].peBlue = lpbmi->bmiColors[i].rgbBlue;// 保留位lpPal->palPalEntry[i].peFlags = 0;}else{// 读取红色分量lpPal->palPalEntry[i].peRed = lpbmc->bmciColors[i].rgbtRed;// 读取绿色分量lpPal->palPalEntry[i].peGreen = lpbmc->bmciColors[i].rgbtGreen;// 读取红色分量lpPal->palPalEntry[i].peBlue = lpbmc->bmciColors[i].rgbtBlue;// 保留位lpPal->palPalEntry[i].peFlags = 0;}}// 按照逻辑调色板创建调色板,并返回指针bResult = pPal->CreatePalette(lpPal);// 解除锁定::GlobalUnlock((HGLOBAL) hLogPal);// 释放逻辑调色板::GlobalFree((HGLOBAL) hLogPal);}// 解除锁定::GlobalUnlock((HGLOBAL) hDIB);// 返回结果return bResult;}/************************************************************************* * * 函数名称: *   FindDIBBits() * * 参数: *   LPSTR lpbi         - 指向DIB对象的指针 * * 返回值: *   LPSTR              - 指向DIB图像象素起始位置 * * 说明: *   该函数计算DIB中图像象素的起始位置,并返回指向它的指针。 * ************************************************************************/LPSTR WINAPI FindDIBBits(LPSTR lpbi){return (lpbi + *(LPDWORD)lpbi + ::PaletteSize(lpbi));//这一句的逻辑是认为位图图像是不包含BITMAPFILEHEADER的,大概句柄不包含FILEHEADER了吧!}/************************************************************************* * * 函数名称: *   DIBWidth() * * 参数: *   LPSTR lpbi         - 指向DIB对象的指针 * * 返回值: *   DWORD              - DIB中图像的宽度 * * 说明: *   该函数返回DIB中图像的宽度。对于Windows 3.0 DIB,返回BITMAPINFOHEADER * 中的biWidth值;对于其它返回BITMAPCOREHEADER中的bcWidth值。 * ************************************************************************/DWORD WINAPI DIBWidth(LPSTR lpDIB){// 指向BITMAPINFO结构的指针(Win3.0)LPBITMAPINFOHEADER lpbmi;// 指向BITMAPCOREINFO结构的指针LPBITMAPCOREHEADER lpbmc;// 获取指针lpbmi = (LPBITMAPINFOHEADER)lpDIB;//竟然可以这样获取指针,好智能啊!!!!lpbmc = (LPBITMAPCOREHEADER)lpDIB;// 返回DIB中图像的宽度if (IS_WIN30_DIB(lpDIB)){// 对于Windows 3.0 DIB,返回lpbmi->biWidthreturn lpbmi->biWidth;}else{// 对于其它格式的DIB,返回lpbmc->bcWidthreturn (DWORD)lpbmc->bcWidth;//位图宽四个字节}}/************************************************************************* * * 函数名称: *   DIBHeight() * * 参数: *   LPSTR lpDIB        - 指向DIB对象的指针 * * 返回值: *   DWORD              - DIB中图像的高度 * * 说明: *   该函数返回DIB中图像的高度。对于Windows 3.0 DIB,返回BITMAPINFOHEADER * 中的biHeight值;对于其它返回BITMAPCOREHEADER中的bcHeight值。我觉得大部分都是3.0 * ************************************************************************/DWORD WINAPI DIBHeight(LPSTR lpDIB){// 指向BITMAPINFO结构的指针(Win3.0)LPBITMAPINFOHEADER lpbmi;// 指向BITMAPCOREINFO结构的指针LPBITMAPCOREHEADER lpbmc;// 获取指针lpbmi = (LPBITMAPINFOHEADER)lpDIB;lpbmc = (LPBITMAPCOREHEADER)lpDIB;// 返回DIB中图像的宽度if (IS_WIN30_DIB(lpDIB)){// 对于Windows 3.0 DIB,返回lpbmi->biHeightreturn lpbmi->biHeight;}else{// 对于其它格式的DIB,返回lpbmc->bcHeightreturn (DWORD)lpbmc->bcHeight;}}//只考虑3.0就好了/************************************************************************* * * 函数名称: *   PaletteSize() * * 参数: *   LPSTR lpbi         - 指向DIB对象的指针 * * 返回值: *   WORD               - DIB中调色板的大小 * * 说明: *   该函数返回DIB中调色板的大小。对于Windows 3.0 DIB,返回颜色数目× * RGBQUAD的大小;对于其它返回颜色数目×RGBTRIPLE的大小。 * ************************************************************************/WORD WINAPI PaletteSize(LPSTR lpbi){// 计算DIB中调色板的大小if (IS_WIN30_DIB (lpbi)){//返回颜色数目×RGBQUAD的大小return (WORD)(::DIBNumColors(lpbi) * sizeof(RGBQUAD));//只考虑这种情况就好了}else{//返回颜色数目×RGBTRIPLE的大小return (WORD)(::DIBNumColors(lpbi) * sizeof(RGBTRIPLE));}}/************************************************************************* * * 函数名称: *   DIBNumColors() * * 参数: *   LPSTR lpbi         - 指向DIB对象的指针 * * 返回值: *   WORD               - 返回调色板中颜色的种数 * * 说明: *   该函数返回DIB中调色板的颜色的种数。对于单色位图,返回2, * 对于16色位图,返回16,对于256色位图,返回256;对于真彩色 * 位图(24位),没有调色板,返回0。 * ************************************************************************/WORD WINAPI DIBNumColors(LPSTR lpbi){WORD wBitCount;// 对于Windows的DIB, 实际颜色的数目可以比象素的位数要少。// 对于这种情况,则返回一个近似的数值。// 判断是否是WIN3.0 DIBif (IS_WIN30_DIB(lpbi)){DWORD dwClrUsed;// 读取dwClrUsed值dwClrUsed = ((LPBITMAPINFOHEADER)lpbi)->biClrUsed;if (dwClrUsed != 0){// 如果dwClrUsed(实际用到的颜色数)不为0,直接返回该值,如果为0,表示全部都用到了,或者没有全部用到,但是没有记录要的数目return (WORD)dwClrUsed;}}// 读取象素的位数if (IS_WIN30_DIB(lpbi)){// 读取biBitCount值wBitCount = ((LPBITMAPINFOHEADER)lpbi)->biBitCount;}else{// 读取biBitCount值wBitCount = ((LPBITMAPCOREHEADER)lpbi)->bcBitCount;}// 按照象素的位数计算颜色数目switch (wBitCount){case 1:return 2;case 4:return 16;case 8:return 256;default:return 0;}}//只考虑window 3.0的情况就可以了/************************************************************************* * * 函数名称: *   DIBBitCount() * * 参数: *   LPSTR lpbi         - 指向DIB对象的指针 * * 返回值: *   WORD               - 返回调色板中颜色的种数 * * 说明: *   该函数返回DIBBitCount。 * ************************************************************************/WORD WINAPI DIBBitCount(LPSTR lpbi){WORD wBitCount;// 读取象素的位数if (IS_WIN30_DIB(lpbi)){// 读取biBitCount值wBitCount = ((LPBITMAPINFOHEADER)lpbi)->biBitCount;}else{// 读取biBitCount值wBitCount = ((LPBITMAPCOREHEADER)lpbi)->bcBitCount;}// 返回wBitCountreturn wBitCount;}//返回像素值位数/************************************************************************* * * 函数名称: *   CopyHandle() * * 参数: *   HGLOBAL h          - 要复制的内存区域 * * 返回值: *   HGLOBAL            - 复制后的新内存区域 * * 说明: *   该函数复制指定的内存区域。返回复制后的新内存区域,出错时返回0。 * ************************************************************************/HGLOBAL WINAPI CopyHandle (HGLOBAL h)//HGLOBAL是void*类型{if (h == NULL)return NULL;// 获取指定内存区域大小DWORD dwLen = ::GlobalSize((HGLOBAL) h);// 分配新内存空间,GHND标志分配的内存是可以移动的,且初始化为0,返回一个句柄。HGLOBAL hCopy = ::GlobalAlloc(GHND, dwLen);// 判断分配是否成功if (hCopy != NULL){// 锁定内存,获得指针void* lpCopy = ::GlobalLock((HGLOBAL) hCopy);void* lp     = ::GlobalLock((HGLOBAL) h);// 复制memcpy(lpCopy, lp, dwLen);//内存拷贝函数,向指定内存起始地址拷贝从指定内存地址开始的指定字节内存内容// 解除锁定::GlobalUnlock(hCopy);::GlobalUnlock(h);}return hCopy;//返回新内存块的句柄}/************************************************************************* * * 函数名称: *   SaveDIB() * * 参数: *   HDIB hDib          - 要保存的DIB *   CFile& file        - 保存文件CFile * * 返回值: *   BOOL               - 成功返回TRUE,否则返回FALSE或者CFileException * * 说明: *   该函数将指定的DIB对象保存到指定的CFile中。该CFile由调用程序打开和关闭。 * *************************************************************************/BOOL WINAPI SaveDIB(HDIB hDib, CFile& file){// Bitmap文件头BITMAPFILEHEADER bmfHdr;// 指向BITMAPINFOHEADER的指针LPBITMAPINFOHEADER lpBI;// DIB大小DWORD dwDIBSize;if (hDib == NULL){// 如果DIB为空,返回FALSEreturn FALSE;}// 读取BITMAPINFO结构,并锁定lpBI = (LPBITMAPINFOHEADER) ::GlobalLock((HGLOBAL) hDib);//获得这个结构体的指针的方法,直接锁定位图文件的内存,再把它//强制类型转换为BITMAPINFOHEADER指针即可,真是匪夷所思。if (lpBI == NULL){// 为空,返回FALSEreturn FALSE;}// 判断是否是WIN3.0 DIBif (!IS_WIN30_DIB(lpBI))//都什么时代了还再考虑win3.0的事情。{// 不支持其它类型的DIB保存// 解除锁定::GlobalUnlock((HGLOBAL) hDib);// 返回FALSEreturn FALSE;}// 填充文件头// 文件类型"BM"bmfHdr.bfType = DIB_HEADER_MARKER;//DIB_HEADER_MARKER是一个宏定义的操作//构造了 BM 这两个字符在内存中的表示,前文已述,它不是字符串。// 计算DIB大小时,最简单的方法是调用GlobalSize()函数。但是全局内存大小并// 不是DIB真正的大小,它总是多几个字节。这样就需要计算一下DIB的真实大小。// 文件头大小+颜色表大小// (BITMAPINFOHEADER和BITMAPCOREHEADER结构的第一个DWORD都是该结构的大小)dwDIBSize = *(LPDWORD)lpBI + ::PaletteSize((LPSTR)lpBI);//这里强调了,dib文件的大小没有包含文件头。// 计算图像大小if ((lpBI->biCompression == BI_RLE8) || (lpBI->biCompression == BI_RLE4))//对于压缩类型无法计算{// 对于RLE位图,没法计算大小,只能信任biSizeImage内的值dwDIBSize += lpBI->biSizeImage;}else{// 象素的大小DWORD dwBmBitsSize;// 大小为Width * HeightdwBmBitsSize = WIDTHBYTES((lpBI->biWidth)*((DWORD)lpBI->biBitCount)) * lpBI->biHeight;//WIDTHBYTES,这个宏计算行的字节数,这个宏要求的参数是行的位数。// 计算出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);//直接写就可了吗,或许MFC已经为CFILE绑定好了文件。}CATCH (CFileException, e){// 解除锁定::GlobalUnlock((HGLOBAL) hDib);// 抛出异常THROW_LAST();}END_CATCH// 解除锁定::GlobalUnlock((HGLOBAL) hDib);// 返回TRUEreturn TRUE;}/************************************************************************* * * 函数名称: *   ReadDIBFile() * * 参数: *   CFile& file        - 要读取得文件文件CFile * * 返回值: *   HDIB               - 成功返回DIB的句柄,否则返回NULL。 * * 说明: *   该函数将指定的文件中的DIB对象读到指定的内存区域中。除BITMAPFILEHEADER * 外的内容都将被读入内存。 * *************************************************************************/HDIB WINAPI ReadDIBFile(CFile& file){BITMAPFILEHEADER bmfHeader;DWORD dwBitsSize;HDIB hDIB;LPSTR pDIB;//char*类型// 获取DIB(文件)长度(字节)dwBitsSize = file.GetLength();//这个是全部DIB的大小// 尝试读取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);//为DIB分配内存,分配的内存多余要求//这个内存是可动的,初始化为0if (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;}//总结,//读dib位图文件,先把BITMAPFILEHEADER随便读到内存中来,判断这是否是一个位图图//像,如果是位图文件,//这分配一段内存,把剩下的文件全部读进来,//可见,位图句柄所指向的内存//包含位图信息头,调色板信息,位图内容,不包含位图文件头。/************************************************************************* * * 函数名称: *   DIBToPCX256() * * 参数: *   LPSTR lpDIB        - 指向DIB对象的指针 *   CFile& file        - 要保存的文件 * * 返回值: *   BOOL               - 成功返回True,否则返回False。 * * 说明: *   该函数将指定的256色DIB对象保存为256色PCX文件。 * *************************************************************************///以下两个函数似乎没有用到,暂时不研究了。BOOL WINAPI DIBToPCX256(LPSTR lpDIB, CFile& file){// 循环变量LONGi;LONGj;// DIB高度WORDwHeight;// DIB宽度WORDwWidth;// 中间变量BYTEbChar1;BYTEbChar2;// 指向源图像象素的指针BYTE *lpSrc;// 指向编码后图像数据的指针BYTE *lpDst;// 图像每行的字节数LONGlLineBytes;// 重复像素计数intiCount;// 缓冲区已使用的字节数DWORDdwBuffUsed;// 指向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为1iCount = 1;// 剩余列for (j = 1; j < wWidth; j ++){// 指向DIB第i行,第j个象素的指针lpSrc++;// 读取下一个像素bChar2 = *lpSrc;// 判断是否和bChar1相同并且iCount < 63if ((bChar1 == bChar2) && (iCount < 63)){// 相同,计数加1iCount ++;// 继续读下一个}else{// 不同,或者iCount = 63// 写入缓冲区if ((iCount > 1) || (bChar1 >= 0xC0)){// 保存码长信息lpDst[dwBuffUsed] = iCount | 0xC0;// 保存bChar1lpDst[dwBuffUsed + 1] = bChar1;// 更新dwBuffUseddwBuffUsed += 2;}else{// 直接保存该值lpDst[dwBuffUsed] = bChar1;// 更新dwBuffUseddwBuffUsed ++;}// 重新给bChar1赋值bChar1 = bChar2;// 设置iCount为1iCount = 1;}}// 保存每行最后一部分编码if ((iCount > 1) || (bChar1 >= 0xC0)){// 保存码长信息lpDst[dwBuffUsed] = iCount | 0xC0;// 保存bChar1lpDst[dwBuffUsed + 1] = bChar1;// 更新dwBuffUseddwBuffUsed += 2;}else{// 直接保存该值lpDst[dwBuffUsed] = bChar1;// 更新dwBuffUseddwBuffUsed ++;}}// 写入编码结果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的DIBbWinStyleDIB = 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大小(字节数)DWORDdwDIBSize;// DIB句柄HDIBhDIB;// DIB指针LPSTRpDIB;// 循环变量LONGi;LONGj;// 重复像素计数intiCount;// DIB高度WORDwHeight;// DIB宽度WORDwWidth;// 图像每行的字节数LONGlLineBytes;// 中间变量BYTEbChar;// 指向源图像象素的指针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);// 已经读取像素的个数加iCounti += iCount;}else{// 保存当前字节lpDst[(wHeight - j - 1) * lLineBytes + i] = bChar;// 已经读取像素的个数加1i += 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;}

0 0