cdib.cpp
上传用户:panpan8800
上传日期:2013-06-29
资源大小:274k
文件大小:38k
源码类别:

图形图像处理

开发平台:

Visual C++

  1. // cdib.cpp
  2. #include "stdafx.h"
  3. #include "math.h"
  4. #include "process.h"
  5. #include "cdib.h"
  6. #include "GlobalApi.h"
  7. #ifdef _DEBUG
  8. #define new DEBUG_NEW
  9. #undef THIS_FILE
  10. static char THIS_FILE[] = __FILE__;
  11. #endif
  12. // 声明串行化过程
  13. IMPLEMENT_SERIAL(CDib, CObject, 0);
  14. /*************************************************************************
  15.  *
  16.  * 函数名称:
  17.  *   CDib()
  18.  *
  19.  * 输入参数:
  20.  * 无
  21.  *
  22.  * 返回值:
  23.  *   无
  24.  *
  25.  * 说明:
  26.  *   构造函数
  27.  *
  28.  ************************************************************************
  29.  */
  30. CDib::CDib()
  31. {
  32. m_hFile      = NULL;
  33. m_hBitmap    = NULL;
  34. m_hPalette   = NULL;
  35. m_nBmihAlloc = m_nImageAlloc = noAlloc;
  36. Empty();
  37. }
  38. /*************************************************************************
  39.  *
  40.  * 函数名称:
  41.  *   CDib()
  42.  *
  43.  * 输入参数:
  44.  * CSize size - 位图尺寸
  45.  * int nBitCount - 象素位数
  46.  *
  47.  * 返回值:
  48.  *   无
  49.  *
  50.  * 说明:
  51.  *   构造函数
  52.  *   根据给定的位图尺寸和象素位数构造CDib对象,并对信息头和调色板分配内存
  53.  *   但并没有给位图数据分配内存
  54.  *
  55.  ************************************************************************
  56.  */
  57. CDib::CDib(CSize size, int nBitCount)
  58. {
  59. m_hFile      = NULL;
  60. m_hBitmap    = NULL;
  61. m_hPalette   = NULL;
  62. m_nBmihAlloc = m_nImageAlloc = noAlloc;
  63. Empty();
  64. // 根据象素位数计算调色板尺寸
  65. ComputePaletteSize(nBitCount);
  66. // 分配DIB信息头和调色板的内存
  67. m_lpBMIH = (LPBITMAPINFOHEADER) new 
  68. char[sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * m_nColorTableEntries];
  69. // 设置信息头内存分配状态
  70. m_nBmihAlloc = crtAlloc;
  71. // 设置信息头中的信息
  72. m_lpBMIH->biSize = sizeof(BITMAPINFOHEADER);
  73. m_lpBMIH->biWidth = size.cx;
  74. m_lpBMIH->biHeight = size.cy;
  75. m_lpBMIH->biPlanes = 1;
  76. m_lpBMIH->biBitCount = nBitCount;
  77. m_lpBMIH->biCompression = BI_RGB;
  78. m_lpBMIH->biSizeImage = 0;
  79. m_lpBMIH->biXPelsPerMeter = 0;
  80. m_lpBMIH->biYPelsPerMeter = 0;
  81. m_lpBMIH->biClrUsed = m_nColorTableEntries;
  82. m_lpBMIH->biClrImportant= m_nColorTableEntries;
  83. // 计算图象数据内存的大小,并设置此DIB的调色板的指针
  84. ComputeMetrics();
  85. // 将此DIB的调色板初始化为0
  86. memset(m_lpvColorTable, 0, sizeof(RGBQUAD) * m_nColorTableEntries);
  87. // 暂时不分配图象数据内存
  88. m_lpImage = NULL; 
  89. }
  90. /*************************************************************************
  91.  *
  92.  * 函数名称:
  93.  *   ~CDib()
  94.  *
  95.  * 输入参数:
  96.  * 无
  97.  *
  98.  * 返回值:
  99.  *   无
  100.  *
  101.  * 说明:
  102.  *   析构函数,并释放所有分配的DIB内存
  103.  *
  104.  ************************************************************************
  105.  */
  106. CDib::~CDib()
  107. {
  108. Empty();
  109. }
  110. /*************************************************************************
  111.  *
  112.  * 函数名称:
  113.  *   GetDimensions()
  114.  *
  115.  * 输入参数:
  116.  *   无
  117.  *
  118.  * 返回值:
  119.  *   CSize - DIB的宽度和高度
  120.  *
  121.  * 说明:
  122.  *   返回以象素表示的DIB的宽度和高度
  123.  *
  124.  ************************************************************************
  125.  */
  126. CSize CDib::GetDimensions()
  127. {
  128. if(m_lpBMIH == NULL) return CSize(0, 0);
  129. return CSize((int) m_lpBMIH->biWidth, (int) m_lpBMIH->biHeight);
  130. }
  131. /*************************************************************************
  132.  *
  133.  * 函数名称:
  134.  *   AttachMapFile()
  135.  *
  136.  * 输入参数:
  137.  *   const char* strPathname - 映射文件的路径名
  138.  *   BOOL bShare - 如果文件以共享形式打开,设置为TRUE
  139.  * - 默认值为FALSE
  140.  *
  141.  * 返回值:
  142.  *   BOOL - 如果成功,则为TRUE 
  143.  *
  144.  * 说明:
  145.  *   以读模式打开内存映射文件,并将其与CDib对象进行关联。因为在文件使用之前并没有读入内存,
  146.  *   所以它立即返回。不过,当访问这个DIB的时候,可能会有一些延迟,因为文件是分页的。
  147.  *   DetachMapFile函数可以释放现有的已分配的内存,并关闭以前关联的任何内存映射文件。
  148.  *   用内存中的DIB与已有的CDib对象关联。此内存可能是程序的资源,或者是可能是剪贴板
  149.  *   或者OLE数据对象内存。内存可能已经由CRT堆栈用new运算符分配了,或者可能已经由
  150.  *   Windows堆栈用GlobalAlloc分配了。
  151.  *   如果打开相同的文件两次,则Windows以另一个文件来对待 
  152.  *
  153.  ************************************************************************
  154.  */
  155. BOOL CDib::AttachMapFile(const char* strPathname, BOOL bShare) // for reading
  156. {
  157. // 获取文件句柄,并设置打开模式为共享
  158. HANDLE hFile = ::CreateFile(strPathname, GENERIC_WRITE | GENERIC_READ,
  159. bShare ? FILE_SHARE_READ : 0,
  160. NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  161. ASSERT(hFile != INVALID_HANDLE_VALUE);
  162. // 获取文件的尺寸
  163. DWORD dwFileSize = ::GetFileSize(hFile, NULL);
  164. // 创建文件映射对象,并设置文件映射的模式为读写
  165. HANDLE hMap = ::CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 0, NULL);
  166. DWORD dwErr = ::GetLastError();
  167. if(hMap == NULL) {
  168. AfxMessageBox("Empty bitmap file");
  169. return FALSE;
  170. }
  171. // 映射整个文件,注意FILE_MAP_WRITE为读写模式
  172. LPVOID lpvFile = ::MapViewOfFile(hMap, FILE_MAP_WRITE, 0, 0, 0); // map whole file
  173. ASSERT(lpvFile != NULL);
  174. // 确认为bmp格式文件
  175. if(((LPBITMAPFILEHEADER) lpvFile)->bfType != 0x4d42) {
  176. AfxMessageBox("Invalid bitmap file");
  177. DetachMapFile();
  178. return FALSE;
  179. }
  180. // 将内存中的DIB与已有的CDib对象关联
  181. AttachMemory((LPBYTE) lpvFile + sizeof(BITMAPFILEHEADER));
  182. // 将这些有用的句柄设置为类数据成员
  183. m_lpvFile = lpvFile;
  184. m_hFile   = hFile;
  185. m_hMap    = hMap;
  186. // 返回
  187. return TRUE;
  188. }
  189. /*************************************************************************
  190.  *
  191.  * 函数名称:
  192.  *   CopyToMapFile()
  193.  *
  194.  * 输入参数:
  195.  *   const char* strPathname - 映射文件的路径名
  196.  *
  197.  * 返回值:
  198.  *   BOOL - 如果成功,则为TRUE 
  199.  *
  200.  * 说明:
  201.  *   该函数可以创建一个新的内存映射文件,并将现有的CDib数据复制到该文件的内存
  202.  *   释放以前的所有内存。并关闭现有的所有内存映射文件。实际上,直到新文件
  203.  *   关闭的时候,才将这个数据写到磁盘,但是,当CDib对象被重复使用或被破坏
  204.  *   时,也会发生写磁盘操作
  205.  *
  206.  ************************************************************************
  207.  */
  208. BOOL CDib::CopyToMapFile(const char* strPathname)
  209. {
  210. BITMAPFILEHEADER bmfh;
  211. // 设置文件头信息
  212. bmfh.bfType = 0x4d42;  
  213. bmfh.bfSize = m_dwSizeImage + sizeof(BITMAPINFOHEADER) +
  214. sizeof(RGBQUAD) * m_nColorTableEntries + sizeof(BITMAPFILEHEADER);
  215. bmfh.bfReserved1= bmfh.bfReserved2 = 0;
  216. bmfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) +
  217. sizeof(RGBQUAD) * m_nColorTableEntries;
  218. // 创建接收数据的文件
  219. HANDLE hFile = ::CreateFile(strPathname, GENERIC_WRITE | GENERIC_READ, 0, NULL,
  220. CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  221. ASSERT(hFile != INVALID_HANDLE_VALUE);
  222. // 计算文件的大小尺寸
  223. int nSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) +
  224. sizeof(RGBQUAD) * m_nColorTableEntries +  m_dwSizeImage;
  225. // 创建内存映射文件对象
  226. HANDLE hMap = ::CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, nSize, NULL);
  227. DWORD dwErr = ::GetLastError();
  228. ASSERT(hMap != NULL);
  229. // 映射整个文件
  230. LPVOID lpvFile = ::MapViewOfFile(hMap, FILE_MAP_WRITE, 0, 0, 0); 
  231. ASSERT(lpvFile != NULL);
  232. // 临时文件指针
  233. LPBYTE lpbCurrent = (LPBYTE) lpvFile;
  234. // 拷贝文件头信息到内存映射文件中
  235. memcpy(lpbCurrent, &bmfh, sizeof(BITMAPFILEHEADER)); 
  236. // 计算信息头在文件中的地址,并拷贝信息头信息
  237. lpbCurrent += sizeof(BITMAPFILEHEADER);
  238. LPBITMAPINFOHEADER lpBMIH = (LPBITMAPINFOHEADER) lpbCurrent;
  239. memcpy(lpbCurrent, m_lpBMIH,
  240. sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * m_nColorTableEntries); 
  241. // 计算调色板在文件中的地址,并拷贝调色板
  242. lpbCurrent += sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * m_nColorTableEntries;
  243. memcpy(lpbCurrent, m_lpImage, m_dwSizeImage); 
  244. // 暂时存放图象数据尺寸变量
  245. DWORD dwSizeImage = m_dwSizeImage;
  246. // 释放一起分配的所有内存
  247. Empty();
  248. // 设置图象数据尺寸并设置内存分配状态
  249. m_dwSizeImage = dwSizeImage;
  250. m_nBmihAlloc  = m_nImageAlloc = noAlloc;
  251. // 信息头指针重新指向文件中的位置
  252. m_lpBMIH = lpBMIH;
  253. // 图象数据指针重新指向文件中的数据地址
  254. m_lpImage = lpbCurrent;
  255. // 设置文件句柄
  256. m_hFile = hFile;
  257. // 设置映射对象句柄
  258. m_hMap = hMap;
  259. // 设置映射文件指针
  260. m_lpvFile = lpvFile;
  261. // 重新计算得到调色板尺寸
  262. ComputePaletteSize(m_lpBMIH->biBitCount);
  263. // 重新计算图象数据块大小,并设置调色板指针
  264. ComputeMetrics();
  265. // 如果调色板存在的话,读取并创建一个Windows调色板
  266. MakePalette();
  267. // 返回
  268. return TRUE;
  269. }
  270. /*************************************************************************
  271.  *
  272.  * 函数名称:
  273.  *   AttachMemory()
  274.  *
  275.  * 输入参数:
  276.  *   LPVOID lpvMem - 要关联的内存地址
  277.  *   BOOL bMustDelete - 如果CDib类负责删除这个内存,标记为TRUE
  278.  * - 默认值为FALSE
  279.  *   HGLOBAL hGlobal - 如果内存是通过Win32 GlobalAlloc得到的,
  280.  * - 则CDib对象必须保存该句柄,这样,以后
  281.  * - 可以释放句柄。这里假设bMustDelete设置为TRUE
  282.  *
  283.  * 返回值:
  284.  *   BOOL - 如果成功,则为TRUE 
  285.  *
  286.  * 说明:
  287.  *   用内存中的DIB与已有的CDib对象关联。此内存可能是程序的资源,或者是可能是剪贴板
  288.  *   或者OLE数据对象内存。内存可能已经由CRT堆栈用new运算符分配了,或者可能已经由
  289.  *   Windows堆栈用GlobalAlloc分配了。
  290.  *
  291.  ************************************************************************
  292.  */
  293. BOOL CDib::AttachMemory(LPVOID lpvMem, BOOL bMustDelete, HGLOBAL hGlobal)
  294. {
  295. // 首先释放已经分配的内存
  296. Empty();
  297. m_hGlobal = hGlobal;
  298. // bMustDelete为TRUE表示此CDib类分配的内存,负责删除
  299. // 否则的设置信息头分配状态为noAlloc
  300. if(bMustDelete == FALSE) {
  301. m_nBmihAlloc = noAlloc;
  302. }
  303. else {
  304. m_nBmihAlloc = ((hGlobal == NULL) ? crtAlloc : heapAlloc);
  305. }
  306. try {
  307. // 设置信息头指针
  308. m_lpBMIH = (LPBITMAPINFOHEADER) lpvMem;
  309. // 重新计算得到图象数据块的大小,并设置调色板的指针
  310. ComputeMetrics();
  311. // 计算调色板的尺寸
  312. ComputePaletteSize(m_lpBMIH->biBitCount);
  313. // 设置图象数据指针
  314. m_lpImage = (LPBYTE) m_lpvColorTable + sizeof(RGBQUAD) * m_nColorTableEntries;
  315. // 如果调色板存在的话,读取它,并创建一个Windows调色板,
  316. // 并将调色板的句柄存放在数据成员中
  317. MakePalette();
  318. }
  319. // 错误处理
  320. catch(CException* pe) {
  321. AfxMessageBox("AttachMemory error");
  322. pe->Delete();
  323. return FALSE;
  324. }
  325. // 返回
  326. return TRUE;
  327. }
  328. /*************************************************************************
  329.  *
  330.  * 函数名称:
  331.  *   UsePalette()
  332.  *
  333.  * 输入参数:
  334.  *   CDC* pDC - 要实现调色板的设备上下文指针
  335.  *   BOOL bBackground - 如果标记为FALSE(默认值),并且应用
  336.  * - 程序正在前台运行,则Windows将把该调
  337.  * - 色板作为前台调色板来实现(向系统调色
  338.  * - 板中复制尽可能多的颜色)。如果标记为
  339.  * - TURE,则Windows将把该调色板作为后台
  340.  * - 调色板来实现(尽可能相系统调色板映射
  341.  * - 逻辑调色板)
  342.  *
  343.  * 返回值:
  344.  *   UINT - 如果成功,则返回映射到系统调色板的逻
  345.  * - 辑调色板的表项数,否则返回GDI_ERROR 
  346.  *
  347.  * 说明:
  348.  *   该函数将CDib对象的逻辑调色板选入设备上下文,然后实现该调色板。Draw成员函
  349.  *   数在绘制DIB之前调用UsePalette。
  350.  *
  351.  ************************************************************************
  352.  */
  353. UINT CDib::UsePalette(CDC* pDC, BOOL bBackground /* = FALSE */)
  354. {
  355. // 判断是否存在调色板
  356. if(m_hPalette == NULL) return 0;
  357. // 得到设备上下文句柄
  358. HDC hdc = pDC->GetSafeHdc();
  359. // 选择调色板到设备上下文
  360. ::SelectPalette(hdc, m_hPalette, bBackground);
  361. // 实现该调色板
  362. return ::RealizePalette(hdc);
  363. }
  364. /*************************************************************************
  365.  *
  366.  * 函数名称:
  367.  *   Draw()
  368.  *
  369.  * 输入参数:
  370.  *   CDC* pDC - 指向将要接收DIB图象的设备上下文指针
  371.  *   CPoint origin - 显示DIB的逻辑坐标
  372.  *   CSize size - 显示矩形的宽度和高度
  373.  *
  374.  * 返回值:
  375.  *   BOOL - 如果成功,则为TRUE,
  376.  *
  377.  * 说明:
  378.  *   通过调用Win32 SDK的StretchDIBits函数将CDib对象输出到显示器(或者打印机)。
  379.  *   为了适合指定的矩形,位图可以进行必要的拉伸
  380.  *
  381.  ************************************************************************
  382.  */
  383. BOOL CDib::Draw(CDC* pDC, CPoint origin, CSize size)
  384. {
  385. // 如果信息头为空,表示尚未有数据,返回FALSE
  386. if(m_lpBMIH == NULL) return FALSE;
  387. // 如果调色板不为空,则将调色板选入设备上下文
  388. if(m_hPalette != NULL) {
  389. ::SelectPalette(pDC->GetSafeHdc(), m_hPalette, TRUE);
  390. }
  391. // 设置显示模式
  392. pDC->SetStretchBltMode(COLORONCOLOR);
  393. // 在设备的origin位置上画出大小为size的图象
  394. ::StretchDIBits(pDC->GetSafeHdc(), origin.x, origin.y,size.cx,size.cy,
  395. 0, 0, m_lpBMIH->biWidth, m_lpBMIH->biHeight,
  396. m_lpImage, (LPBITMAPINFO) m_lpBMIH, DIB_RGB_COLORS, SRCCOPY);
  397. // 返回
  398. return TRUE;
  399. }
  400. /*************************************************************************
  401.  *
  402.  * 函数名称:
  403.  *   CreateSection()
  404.  *
  405.  * 输入参数:
  406.  *   CDC* pDC - 设备上下文指针
  407.  *
  408.  * 返回值:
  409.  *   HBITMAP - 到GDI位图的句柄。如果不成功,则为NULL。
  410.  * - 该句柄也是作为公共数据成员存储的
  411.  *
  412.  * 说明:
  413.  *   通过调用Win32 SDK的CreateDIBSection函数创建一个DIB段。图象内存将不被初始化
  414.  *
  415.  ************************************************************************
  416.  */
  417. HBITMAP CDib::CreateSection(CDC* pDC /* = NULL */)
  418. {
  419. // 如果信息头为空,不作任何处理
  420. if(m_lpBMIH == NULL) return NULL;
  421. // 如果图象数据不存在,不作任何处理
  422. if(m_lpImage != NULL) return NULL; 
  423. // 创建一个DIB段
  424. m_hBitmap = ::CreateDIBSection(pDC->GetSafeHdc(), (LPBITMAPINFO) m_lpBMIH,
  425. DIB_RGB_COLORS, (LPVOID*) &m_lpImage, NULL, 0);
  426. ASSERT(m_lpImage != NULL);
  427. // 返回HBIMAP句柄
  428. return m_hBitmap;
  429. }
  430. /*************************************************************************
  431.  *
  432.  * 函数名称:
  433.  *   MakePalette()
  434.  *
  435.  * 输入参数:
  436.  *   无
  437.  *
  438.  * 返回值:
  439.  *   BOOL - 如果成功,则为TRUE
  440.  *
  441.  * 说明:
  442.  *   如果颜色表存在的话,该函数将读取它,并创建一个Windows调色板。
  443.  *   HPALETTE存储在一个数据成员中。
  444.  *
  445.  ************************************************************************
  446.  */
  447. BOOL CDib::MakePalette()
  448. {
  449. // 如果不存在调色板,则返回FALSE
  450. if(m_nColorTableEntries == 0) return FALSE;
  451. if(m_hPalette != NULL) ::DeleteObject(m_hPalette);
  452. TRACE("CDib::MakePalette -- m_nColorTableEntries = %dn", m_nColorTableEntries);
  453. // 给逻辑调色板分配内存
  454. LPLOGPALETTE pLogPal = (LPLOGPALETTE) new char[2 * sizeof(WORD) +
  455. m_nColorTableEntries * sizeof(PALETTEENTRY)];
  456. // 设置逻辑调色板的信息
  457. pLogPal->palVersion = 0x300;
  458. pLogPal->palNumEntries = m_nColorTableEntries;
  459. // 拷贝DIB中的颜色表到逻辑调色板
  460. LPRGBQUAD pDibQuad = (LPRGBQUAD) m_lpvColorTable;
  461. for(int i = 0; i < m_nColorTableEntries; i++) {
  462. pLogPal->palPalEntry[i].peRed = pDibQuad->rgbRed;
  463. pLogPal->palPalEntry[i].peGreen = pDibQuad->rgbGreen;
  464. pLogPal->palPalEntry[i].peBlue = pDibQuad->rgbBlue;
  465. pLogPal->palPalEntry[i].peFlags = 0;
  466. pDibQuad++;
  467. }
  468. // 创建逻辑调色板
  469. m_hPalette = ::CreatePalette(pLogPal);
  470. // 删除临时变量并返回TRUE
  471. delete pLogPal;
  472. return TRUE;
  473. }
  474. /*************************************************************************
  475.  *
  476.  * 函数名称:
  477.  *   SetSystemPalette()
  478.  *
  479.  * 输入参数:
  480.  *   CDC* pDC - 设备上下文指针
  481.  *
  482.  * 返回值:
  483.  *   BOOL - 如果成功,则为TRUE,
  484.  *
  485.  * 说明:
  486.  *   如果16bpp、24bpp或32bppDIB不具备调色板,则该函数可以为CDib对象创建一个逻辑调色板,
  487.  *   它与由CreatehalftonePalette函数返回的调色板相匹配。如果程序在256色调色板显示器上
  488.  *   运行,而你又没有调用SetSystemPalette,那么,你将不具有任何调色板,只有20中标准的
  489.  *   Windows颜色出现在DIB中
  490.  *
  491.  ************************************************************************
  492.  */
  493. BOOL CDib::SetSystemPalette(CDC* pDC)
  494. {
  495. // 如果DIB不具备调色板,则需要利用系统的调色板
  496. if(m_nColorTableEntries != 0) return FALSE;
  497. // 为设备上下文创建中间调色板,并将其与CPalette对象连接
  498. m_hPalette = ::CreateHalftonePalette(pDC->GetSafeHdc());
  499. // 返回
  500. return TRUE;
  501. }
  502. /*************************************************************************
  503.  *
  504.  * 函数名称:
  505.  *   CreateBitmap()
  506.  *
  507.  * 输入参数:
  508.  *   CDC* pDC - 设备上下文指针
  509.  *
  510.  * 返回值:
  511.  *   HBITMAP - 到GDI位图的句柄;如果不成功,则为NULL
  512.  * - 该句柄不是作为公共数据成员存储的
  513.  *
  514.  * 说明:
  515.  *   从已有的DIB中创建DDB位图。不要将这个函数与CreateSection
  516.  *   弄混了,后者的作用是生成DIB并保存句柄
  517.  *
  518.  ************************************************************************
  519.  */
  520. HBITMAP CDib::CreateBitmap(CDC* pDC)
  521. {
  522. // 如果不存在图象数据,则返回NULL
  523. if (m_dwSizeImage == 0) return NULL;
  524. // 用指定的DIB来创建DDB,并用DIB信息初始化位图的图象位
  525. HBITMAP hBitmap = ::CreateDIBitmap(pDC->GetSafeHdc(), m_lpBMIH,
  526. CBM_INIT, m_lpImage, (LPBITMAPINFO) m_lpBMIH, DIB_RGB_COLORS);
  527. ASSERT(hBitmap != NULL);
  528. // 返回DDB位图句柄
  529. return hBitmap;
  530. }
  531. /*************************************************************************
  532.  *
  533.  * 函数名称:
  534.  *   ConvertDDBToDIB()
  535.  *
  536.  * 输入参数:
  537.  *   HBITMAP hBitmap - 指向源数据的BITMAP句柄
  538.  *   CDib* pDibDst - 指向转换目标的CDib对象指针
  539.  *
  540.  * 返回值:
  541.  *   BOOL - 如果操作成功,则返回TRUE
  542.  *
  543.  * 说明:
  544.  *   该函数将源BITMAP类pDibSrc中的数据拷贝到pDibDst中,并对相应的数据成员赋值
  545.  *
  546.  *************************************************************************
  547.  */
  548. BOOL CDib::ConvertFromDDB(HBITMAP hBitmap, HPALETTE hPal)
  549. {
  550. // 声明一个BITMAP结构
  551. BITMAP bm;
  552. // 设备上下文
  553. HDC hDC;
  554. // 象素位数
  555. WORD biBitCount;
  556. // 调色板表项数
  557. int nColorTableEntries;
  558. // 如果hBitmap句柄无效,则返回
  559. if(!hBitmap){
  560. return FALSE;
  561. }
  562. // 释放已分配的内存
  563. Empty();
  564. // 填充图象数据到bm中,其中最后一个参数表示接收这个指定的对象的指针
  565. if(!GetObject(hBitmap,sizeof(BITMAP),(LPBYTE)&bm)){
  566. return FALSE;
  567. }
  568. // 计算象素位数
  569. biBitCount=bm.bmPlanes*bm.bmBitsPixel;
  570. if(biBitCount<=1)
  571. biBitCount=1;
  572. else if(biBitCount<=4)
  573. biBitCount=4;
  574. else if(biBitCount<=8)
  575. biBitCount=8;
  576. else 
  577. biBitCount=24;
  578. // 计算调色板的尺寸
  579. // 如果biClrUsed为零,则用到的颜色数为2的biBitCount次方
  580. switch(biBitCount) {
  581. case 1:
  582. nColorTableEntries = 2;
  583. break;
  584. case 4:
  585. nColorTableEntries = 16;
  586. break;
  587. case 8:
  588. nColorTableEntries = 256;
  589. break;
  590. case 16:
  591. case 24:
  592. case 32:
  593. nColorTableEntries = 0;
  594. break;
  595. default:
  596. ASSERT(FALSE);
  597. }
  598. ASSERT((nColorTableEntries >= 0) && (nColorTableEntries <= 256)); 
  599. m_nColorTableEntries = nColorTableEntries;
  600. // 分配DIB信息头和调色板的内存
  601. m_lpBMIH = (LPBITMAPINFOHEADER) new char
  602. [sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * nColorTableEntries];
  603. m_nBmihAlloc = m_nImageAlloc = crtAlloc;
  604. m_lpBMIH->biSize = sizeof(BITMAPINFOHEADER); 
  605. m_lpBMIH->biWidth = bm.bmWidth; 
  606. m_lpBMIH->biHeight = bm.bmHeight; 
  607. m_lpBMIH->biPlanes = 1; 
  608. m_lpBMIH->biBitCount = biBitCount; 
  609. m_lpBMIH->biCompression = BI_RGB; 
  610. m_lpBMIH->biSizeImage = 0; 
  611. m_lpBMIH->biXPelsPerMeter = 0; 
  612. m_lpBMIH->biYPelsPerMeter = 0; 
  613. m_lpBMIH->biClrUsed = nColorTableEntries;
  614. m_lpBMIH->biClrImportant = nColorTableEntries;
  615. // 获得设备上下文句柄
  616. hDC=GetDC(NULL);
  617.    
  618. // 如果没有指定调色板,则从系统中获得当前的系统调色板
  619. if(hPal==NULL){
  620. hPal = GetSystemPalette();
  621. }
  622. hPal = SelectPalette(hDC, hPal, FALSE); 
  623. RealizePalette(hDC); 
  624.  
  625. // 调用GetDIBits填充信息头,并获得图象数据的尺寸。注意这里图象数据指针为NULL
  626. GetDIBits( hDC, hBitmap, 0, (UINT)m_lpBMIH->biHeight, NULL, (LPBITMAPINFO)m_lpBMIH, DIB_RGB_COLORS);
  627. // 如果没有正确的获得图象数据尺寸,则重新计算
  628. if( m_lpBMIH->biSizeImage == 0 ){
  629. m_lpBMIH->biSizeImage=(((bm.bmWidth*biBitCount) + 31) / 32 * 4)*bm.bmHeight;
  630. }
  631. // 分配存放图象数据的内存
  632. m_lpImage = (LPBYTE) new char[m_lpBMIH->biSizeImage];
  633. // 调用GetDIBits加载图象数据,注意这里给出了图象数据指针
  634. // 如果加载图象数据不成功,则释放已经分配的内存,并返回FALSE
  635. if( GetDIBits( hDC, hBitmap, 0, (UINT)m_lpBMIH->biHeight, (LPBYTE)m_lpImage,
  636. (LPBITMAPINFO)m_lpBMIH, DIB_RGB_COLORS) == 0 ){
  637. //clean up and return NULL
  638. Empty();
  639. SelectPalette( hDC, hPal, TRUE );
  640. RealizePalette( hDC );
  641. ReleaseDC( NULL, hDC );
  642. return FALSE;
  643. }
  644. // 删除临时变量
  645. SelectPalette(hDC, hPal, TRUE); 
  646. RealizePalette(hDC); 
  647. ReleaseDC(NULL, hDC); 
  648. return TRUE;
  649. }
  650. /*************************************************************************
  651.  *
  652.  * 函数名称:
  653.  *   Compress()
  654.  *
  655.  * 输入参数:
  656.  *   CDC* pDC - 设备上下文指针
  657.  *   BOOL bCompress - TRUE对应于压缩的DIB,FALSE对应于不压缩的DIB
  658.  *
  659.  * 返回值:
  660.  *   BOOL - 如果成功,则返回TRUE
  661.  *
  662.  * 说明:
  663.  *   该函数将DIB重新生成为压缩或者不压缩的DIB。在内部,它转换已有的DIB为DDB位图
  664.  *   然后生成一个新的压缩或者不压缩的DIB。压缩仅为4bpp和8bpp的DIB所支持。不能
  665.  *   压缩DIB段
  666.  *
  667.  ************************************************************************
  668.  */
  669. BOOL CDib::Compress(CDC* pDC, BOOL bCompress /* = TRUE */)
  670. {
  671. // 判断是否为4bpp或者8bpp位图,否则,不进行压缩,返回FALSE
  672. if((m_lpBMIH->biBitCount != 4) && (m_lpBMIH->biBitCount != 8)) return FALSE;
  673. // 如果为DIB段,也不能支持压缩,返回FALSE
  674. if(m_hBitmap) return FALSE; 
  675. TRACE("Compress: original palette size = %dn", m_nColorTableEntries); 
  676. // 获得设备上下文句柄
  677. HDC hdc = pDC->GetSafeHdc();
  678. // 将此DIB的调色板选入设备上下文,并保存以前的调色板句柄
  679. HPALETTE hOldPalette = ::SelectPalette(hdc, m_hPalette, FALSE);
  680. HBITMAP hBitmap;  
  681. // 创建一个DDB位图,如果不成功,则返回FALSE
  682. if((hBitmap = CreateBitmap(pDC)) == NULL) return FALSE;
  683. // 计算信息头加上调色板的大小尺寸,并给它们分配内存
  684. int nSize = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * m_nColorTableEntries;
  685. LPBITMAPINFOHEADER lpBMIH = (LPBITMAPINFOHEADER) new char[nSize];
  686. // 将信息头和调色板拷贝到内存中
  687. memcpy(lpBMIH, m_lpBMIH, nSize);  // new header
  688. // 如果需要进行压缩,设置相应的信息,并创建压缩格式的DIB
  689. if(bCompress) {
  690. switch (lpBMIH->biBitCount) {
  691. case 4:
  692. lpBMIH->biCompression = BI_RLE4;
  693. break;
  694. case 8:
  695. lpBMIH->biCompression = BI_RLE8;
  696. break;
  697. default:
  698. ASSERT(FALSE);
  699. }
  700. // 设置位图数据指针为NULL,调用GetDIBits来得到压缩格式的DIB的尺寸
  701. // 如果不能创建DIB,则进行相应的错误处理。
  702. if(!::GetDIBits(pDC->GetSafeHdc(), hBitmap, 0, (UINT) lpBMIH->biHeight,
  703. NULL, (LPBITMAPINFO) lpBMIH, DIB_RGB_COLORS)) {
  704. AfxMessageBox("Unable to compress this DIB");
  705. // 删除临时变量,并释放已分配内存
  706.   ::DeleteObject(hBitmap);
  707. delete [] lpBMIH;
  708. // 重新将以前的调色板选入,并返回FALSE
  709. ::SelectPalette(hdc, hOldPalette, FALSE);
  710. return FALSE; 
  711. }
  712. // 如果位图数据为空,则进行相应的错误处理
  713. if (lpBMIH->biSizeImage == 0) {
  714. AfxMessageBox("Driver can't do compression");
  715. // 删除临时变量,并释放已分配内存
  716.   ::DeleteObject(hBitmap);
  717. delete [] lpBMIH;
  718. // 重新将以前的调色板选入,并返回FALSE
  719. ::SelectPalette(hdc, hOldPalette, FALSE);
  720. return FALSE; 
  721. }
  722. // 将位图数据尺寸赋值给类的成员变量
  723. else {
  724. m_dwSizeImage = lpBMIH->biSizeImage;
  725. }
  726. }
  727. // 如果是解压缩,进行相应的处理
  728. else {
  729. // 设置压缩格式为不压缩
  730. lpBMIH->biCompression = BI_RGB; 
  731. // 根据位图的宽度和高度计算位图数据内存的大小
  732. DWORD dwBytes = ((DWORD) lpBMIH->biWidth * lpBMIH->biBitCount) / 32;
  733. if(((DWORD) lpBMIH->biWidth * lpBMIH->biBitCount) % 32) {
  734. dwBytes++;
  735. }
  736. dwBytes *= 4;
  737. // 将得到位图数据的大小尺寸保存在类的成员变量中
  738. m_dwSizeImage = dwBytes * lpBMIH->biHeight; 
  739. // 将位图数据内存的大小赋值给临时的信息头中的相应的变量
  740. lpBMIH->biSizeImage = m_dwSizeImage;
  741. // 再次调用GetDIBits来生成DIB数据
  742. // 分配临时存放位图数据
  743. LPBYTE lpImage = (LPBYTE) new char[m_dwSizeImage];
  744. // 再次调用GetDIBits来生成DIB数据,注意此时位图数据指针不为空
  745. VERIFY(::GetDIBits(pDC->GetSafeHdc(), hBitmap, 0, (UINT) lpBMIH->biHeight,
  746.      lpImage, (LPBITMAPINFO) lpBMIH, DIB_RGB_COLORS));
  747. TRACE("dib successfully created - height = %dn", lpBMIH->biHeight);
  748. // 压缩转换完毕,进行相应的其他处理
  749. // 删除临时的DDB位图
  750. ::DeleteObject(hBitmap);
  751. // 释放原来的DIB分配的内存
  752. Empty();
  753. // 重新设置图象信息头和图象数据内存分配状态
  754. m_nBmihAlloc = m_nImageAlloc = crtAlloc;
  755. // 重新定位信息头和图象数据指针
  756. m_lpBMIH = lpBMIH;
  757. m_lpImage = lpImage;
  758. // 计算图象数据尺寸,并设置DIB中调色板的指针
  759. ComputeMetrics();
  760. // 计算DIB中调色板的尺寸
  761. ComputePaletteSize(m_lpBMIH->biBitCount);
  762. // 如果DIB中调色板存在的话,读取并创建一个Windows调色板
  763. MakePalette();
  764. // 恢复以前的调色板
  765. ::SelectPalette(hdc, hOldPalette, FALSE);
  766. TRACE("Compress: new palette size = %dn", m_nColorTableEntries); 
  767. // 返回
  768. return TRUE;
  769. }
  770. /*************************************************************************
  771.  *
  772.  * 函数名称:
  773.  *   Read()
  774.  *
  775.  * 输入参数:
  776.  *   CFile* pFile - 指向CFile对象的指针
  777.  *
  778.  * 返回值:
  779.  *   BOOL - 如果成功,则返回TRUE
  780.  *
  781.  * 说明:
  782.  *   该函数DIB从一个文件读入CDib对象。该文件必须成功打开。如果该文件是BMP文件
  783.  *   读取工作从文件头开始。如果该文件是一个文档,读取工作则从当前文件指针处开始 
  784.  *
  785.  ************************************************************************
  786.  */
  787. BOOL CDib::Read(CFile* pFile)
  788. {
  789. // 释放已经分配的内存
  790. Empty();
  791. // 临时存放信息的变量
  792. int nCount, nSize;
  793. BITMAPFILEHEADER bmfh;
  794. // 进行读操作
  795. try 
  796. {
  797. // 读取文件头
  798. nCount = pFile->Read((LPVOID) &bmfh, sizeof(BITMAPFILEHEADER));
  799. if(nCount != sizeof(BITMAPFILEHEADER)) {
  800. throw new CException;
  801. }
  802. // 如果文件类型部位"BM",则返回并进行相应错误处理
  803. if(bmfh.bfType != 0x4d42) {
  804. throw new CException;
  805. }
  806. // 计算信息头加上调色板的大小,并分配相应的内存
  807. nSize = bmfh.bfOffBits - sizeof(BITMAPFILEHEADER);
  808. m_lpBMIH = (LPBITMAPINFOHEADER) new char[nSize];
  809. m_nBmihAlloc = m_nImageAlloc = crtAlloc;
  810. // 读取信息头和调色板
  811. nCount = pFile->Read(m_lpBMIH, nSize); 
  812. // 计算图象数据大小并设置调色板指针
  813. ComputeMetrics();
  814. // 计算调色板的表项数
  815. ComputePaletteSize(m_lpBMIH->biBitCount);
  816. // 如果DIB中存在调色板,则创建一个Windows调色板
  817. MakePalette();
  818. // 分配图象数据内存,并从文件中读取图象数据
  819. m_lpImage = (LPBYTE) new char[m_dwSizeImage];
  820. nCount = pFile->Read(m_lpImage, m_dwSizeImage); 
  821. }
  822. // 错误处理
  823. catch(CException* pe) 
  824. {
  825. AfxMessageBox("Read error");
  826. pe->Delete();
  827. return FALSE;
  828. }
  829. // 返回
  830. return TRUE;
  831. }
  832. /*************************************************************************
  833.  *
  834.  * 函数名称:
  835.  *   ReadSection()
  836.  *
  837.  * 输入参数:
  838.  *   CFile* pFile - 指向CFile对象的指针;对应的磁盘
  839.  * - 文件中包含DIB
  840.  *   CDC* pDC - 设备上下文指针
  841.  *
  842.  * 返回值:
  843.  *   BOOL - 如果成功,则返回TRUE
  844.  *
  845.  * 说明:
  846.  *   该函数从BMP文件中读取信息头,调用CreateDIBSection来分配图象内存,然后将
  847.  *   图象从该文件读入刚才分配的内存。如果你想从磁盘读取一个DIB,然后通过调用
  848.  *   GDI函数编辑它的话,可以使用该函数。你可以用Write或CopyToMapFile将DIB写
  849.  *   回到磁盘
  850.  *
  851.  ************************************************************************
  852.  */
  853. BOOL CDib::ReadSection(CFile* pFile, CDC* pDC /* = NULL */)
  854. {
  855. // 释放已经分配的内存
  856. Empty();
  857. // 临时变量
  858. int nCount, nSize;
  859. BITMAPFILEHEADER bmfh;
  860. // 从文件中读取数据
  861. try {
  862. // 读取文件头
  863. nCount = pFile->Read((LPVOID) &bmfh, sizeof(BITMAPFILEHEADER));
  864. if(nCount != sizeof(BITMAPFILEHEADER)) {
  865. throw new CException;
  866. }
  867. // 如果文件类型部位"BM",则返回并进行相应错误处理
  868. if(bmfh.bfType != 0x4d42) {
  869. throw new CException;
  870. }
  871. // 计算信息头加上调色板的大小,并分配相应的内存
  872. nSize = bmfh.bfOffBits - sizeof(BITMAPFILEHEADER);
  873. m_lpBMIH = (LPBITMAPINFOHEADER) new char[nSize];
  874. m_nBmihAlloc = crtAlloc;
  875. m_nImageAlloc = noAlloc;
  876. // 读取信息头和调色板
  877. nCount = pFile->Read(m_lpBMIH, nSize); 
  878. // 如果图象为压缩格式,则不进行后续处理
  879. if(m_lpBMIH->biCompression != BI_RGB) {
  880. throw new CException;
  881. }
  882. // 计算图象数据大小并设置调色板指针
  883. ComputeMetrics();
  884. // 计算调色板的表项数
  885. ComputePaletteSize(m_lpBMIH->biBitCount);
  886. // 如果DIB中存在调色板,则创建一个Windows调色板
  887. MakePalette();
  888. // 将CDib对象的逻辑调色板选入设备上下文
  889. UsePalette(pDC);
  890. // 创建一个DIB段,并分配图象内存
  891. m_hBitmap = ::CreateDIBSection(pDC->GetSafeHdc(), (LPBITMAPINFO) m_lpBMIH,
  892. DIB_RGB_COLORS, (LPVOID*) &m_lpImage, NULL, 0);
  893. ASSERT(m_lpImage != NULL);
  894. // 从文件中读取图象数据
  895. nCount = pFile->Read(m_lpImage, m_dwSizeImage); 
  896. }
  897. // 错误处理
  898. catch(CException* pe) {
  899. AfxMessageBox("ReadSection error");
  900. pe->Delete();
  901. return FALSE;
  902. }
  903. return TRUE;
  904. }
  905. /*************************************************************************
  906.  *
  907.  * 函数名称:
  908.  *   Write()
  909.  *
  910.  * 输入参数:
  911.  *   CFile* pFile - 指向CFile对象的指针
  912.  *
  913.  * 返回值:
  914.  *   BOOL - 如果成功,则返回TRUE
  915.  *
  916.  * 说明:
  917.  *   该函数把DIB从CDib对象写进文件中。该文件必须成功打开或者创建
  918.  *
  919.  ************************************************************************
  920.  */
  921. BOOL CDib::Write(CFile* pFile)
  922. {
  923. BITMAPFILEHEADER bmfh;
  924. // 设置文件头中文件类型为"BM"
  925. bmfh.bfType = 0x4d42;  
  926. // 计算信息头和调色板的大小尺寸
  927. int nSizeHdr = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * m_nColorTableEntries;
  928. // 设置文件头信息
  929. bmfh.bfSize = sizeof(BITMAPFILEHEADER) + nSizeHdr + m_dwSizeImage;
  930. bmfh.bfReserved1 = bmfh.bfReserved2 = 0;
  931. bmfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) +
  932. sizeof(RGBQUAD) * m_nColorTableEntries;
  933. // 进行写操作
  934. try {
  935. pFile->Write((LPVOID) &bmfh, sizeof(BITMAPFILEHEADER));
  936. pFile->Write((LPVOID) m_lpBMIH,  nSizeHdr);
  937. pFile->Write((LPVOID) m_lpImage, m_dwSizeImage);
  938. }
  939. // 错误处理
  940. catch(CException* pe) {
  941. pe->Delete();
  942. AfxMessageBox("write error");
  943. return FALSE;
  944. }
  945. // 返回
  946. return TRUE;
  947. }
  948. /*************************************************************************
  949.  *
  950.  * 函数名称:
  951.  *   Serialize()
  952.  *
  953.  * 输入参数:
  954.  *   CArchive& ar - 指向应用程序归档对象
  955.  *
  956.  * 返回值:
  957.  *   无
  958.  *
  959.  * 说明:
  960.  *   该函数进行串行化过程,将CDib数据进行读入或者写出
  961.  *
  962.  ************************************************************************
  963.  */
  964. void CDib::Serialize(CArchive& ar)
  965. {
  966. DWORD dwPos;
  967. // 获得此归档文件的CFile对象指针
  968. dwPos = ar.GetFile()->GetPosition();
  969. TRACE("CDib::Serialize -- pos = %dn", dwPos);
  970. // 从归档文件缓冲区中冲掉未写入数据
  971. ar.Flush();
  972. // 重新获得此归档文件的CFile对象指针
  973. dwPos = ar.GetFile()->GetPosition();
  974. TRACE("CDib::Serialize -- pos = %dn", dwPos);
  975. // 确定归档文件是否被存储,是则进行存储
  976. if(ar.IsStoring()) {
  977. Write(ar.GetFile());
  978. }
  979. // 否则进行加载
  980. else {
  981. Read(ar.GetFile());
  982. }
  983. }
  984. /*************************************************************************
  985.  *
  986.  * 函数名称:
  987.  *   ComputePaletteSize()
  988.  *
  989.  * 输入参数:
  990.  *   int nBitCount - 指向CFile对象的指针
  991.  *
  992.  * 返回值:
  993.  *   无
  994.  *
  995.  * 说明:
  996.  *   该函数根据位图象素位数计算调色板的尺寸
  997.  *
  998.  ************************************************************************
  999.  */
  1000. void CDib::ComputePaletteSize(int nBitCount)
  1001. {
  1002. // 如果biClrUsed为零,则用到的颜色数为2的biBitCount次方
  1003. if((m_lpBMIH == NULL) || (m_lpBMIH->biClrUsed == 0)) {
  1004. switch(nBitCount) {
  1005. case 1:
  1006. m_nColorTableEntries = 2;
  1007. break;
  1008. case 4:
  1009. m_nColorTableEntries = 16;
  1010. break;
  1011. case 8:
  1012. m_nColorTableEntries = 256;
  1013. break;
  1014. case 16:
  1015. case 24:
  1016. case 32:
  1017. m_nColorTableEntries = 0;
  1018. break;
  1019. default:
  1020. ASSERT(FALSE);
  1021. }
  1022. }
  1023. // 否则调色板的表项数就是用到的颜色数目
  1024. else {
  1025. m_nColorTableEntries = m_lpBMIH->biClrUsed;
  1026. }
  1027. ASSERT((m_nColorTableEntries >= 0) && (m_nColorTableEntries <= 256)); 
  1028. }
  1029. /*************************************************************************
  1030.  *
  1031.  * 函数名称:
  1032.  *   ComputeMetrics()
  1033.  *
  1034.  * 输入参数:
  1035.  *   无
  1036.  *
  1037.  * 返回值:
  1038.  *   无
  1039.  *
  1040.  * 说明:
  1041.  *   该函数计算图象位图的尺寸,并对DIB中的调色板的指针进行赋值
  1042.  *
  1043.  ************************************************************************
  1044.  */
  1045. void CDib::ComputeMetrics()
  1046. {
  1047. // 如果结构的长度不对,则进行错误处理
  1048. if(m_lpBMIH->biSize != sizeof(BITMAPINFOHEADER)) {
  1049. TRACE("Not a valid Windows bitmap -- probably an OS/2 bitmapn");
  1050. throw new CException;
  1051. }
  1052. // 保存图象数据内存大小到CDib对象的数据成员中
  1053. m_dwSizeImage = m_lpBMIH->biSizeImage;
  1054. // 如果图象数据内存大小为0,则重新计算
  1055. if(m_dwSizeImage == 0) {
  1056. DWORD dwBytes = ((DWORD) m_lpBMIH->biWidth * m_lpBMIH->biBitCount) / 32;
  1057. if(((DWORD) m_lpBMIH->biWidth * m_lpBMIH->biBitCount) % 32) {
  1058. dwBytes++;
  1059. }
  1060. dwBytes *= 4;
  1061. m_dwSizeImage = dwBytes * m_lpBMIH->biHeight;
  1062. }
  1063. // 设置DIB中的调色板指针
  1064. m_lpvColorTable = (LPBYTE) m_lpBMIH + sizeof(BITMAPINFOHEADER);
  1065. }
  1066. /*************************************************************************
  1067.  *
  1068.  * 函数名称:
  1069.  *   Empty()
  1070.  *
  1071.  * 输入参数:
  1072.  *   无
  1073.  *
  1074.  * 返回值:
  1075.  *   无
  1076.  *
  1077.  * 说明:
  1078.  *   该函数清空DIB,释放已分配的内存,并且必要的时候关闭映射文件
  1079.  *
  1080.  ************************************************************************
  1081.  */
  1082. void CDib::Empty()
  1083. {
  1084. // 关闭内存映射文件的连接
  1085. DetachMapFile();
  1086. // 根据内存分配的状态,调用相应的函数释放信息头
  1087. if(m_nBmihAlloc == crtAlloc) {
  1088. delete [] m_lpBMIH;
  1089. }
  1090. else if(m_nBmihAlloc == heapAlloc) {
  1091. ::GlobalUnlock(m_hGlobal);
  1092. ::GlobalFree(m_hGlobal);
  1093. }
  1094. // 释放图象数据内存
  1095. if(m_nImageAlloc == crtAlloc) delete [] m_lpImage;
  1096. // 释放调色板句柄
  1097. if(m_hPalette != NULL) ::DeleteObject(m_hPalette);
  1098. // 如果创建了BITMAP,则进行释放
  1099. if(m_hBitmap != NULL) ::DeleteObject(m_hBitmap);
  1100. // 重新设置内存分配状态
  1101. m_nBmihAlloc = m_nImageAlloc = noAlloc;
  1102. // 释放内存后,还需要将指针设置为NULL并将相应的数据设置为0
  1103. m_hGlobal = NULL;
  1104. m_lpBMIH = NULL;
  1105. m_lpImage = NULL;
  1106. m_lpvColorTable = NULL;
  1107. m_nColorTableEntries = 0;
  1108. m_dwSizeImage = 0;
  1109. m_lpvFile = NULL;
  1110. m_hMap = NULL;
  1111. m_hFile = NULL;
  1112. m_hBitmap = NULL;
  1113. m_hPalette = NULL;
  1114. }
  1115. /*************************************************************************
  1116.  *
  1117.  * 函数名称:
  1118.  *   DetachMapFile()
  1119.  *
  1120.  * 输入参数:
  1121.  *   无
  1122.  *
  1123.  * 返回值:
  1124.  *   无
  1125.  *
  1126.  * 说明:
  1127.  *   函数可以释放现有的已分配的内存,并关闭以前关联的任何内存映射文件。
  1128.  *
  1129.  ************************************************************************
  1130.  */
  1131. void CDib::DetachMapFile()
  1132. {
  1133. // 如果没有进行内存映射,则不进行处理
  1134. if(m_hFile == NULL) return;
  1135. // 关闭内存映射
  1136. ::UnmapViewOfFile(m_lpvFile);
  1137. // 关闭内存映射对象和文件
  1138. ::CloseHandle(m_hMap);
  1139. ::CloseHandle(m_hFile);
  1140. m_hFile = NULL;
  1141. }
  1142. /*************************************************************************
  1143.  *
  1144.  * 函数名称:
  1145.  *   PaletteSize()
  1146.  *
  1147.  * 输入参数:
  1148.  *   无
  1149.  *
  1150.  * 返回值:
  1151.  *   DWORD - 返回调色板的尺寸
  1152.  *
  1153.  * 说明:
  1154.  *   该函数计算机调色板所需的尺寸
  1155.  *
  1156.  ************************************************************************
  1157.  */
  1158. WORD CDib::PaletteSize()
  1159. {
  1160. // 临时变量
  1161. WORD        NumColors;
  1162. LPBITMAPINFOHEADER lpbi=m_lpBMIH;
  1163. // 如果biClrUsed为零,且图象象素位数小于8,则计算调色板用到的表项数
  1164. NumColors =  ((lpbi)->biClrUsed == 0 && (lpbi)->biBitCount <= 8 
  1165.                                     ? (int)(1 << (int)(lpbi)->biBitCount)          
  1166.                                     : (int)(lpbi)->biClrUsed);
  1167. // 根据颜色表示的字节数计算调色板的尺寸
  1168. if (lpbi->biSize == sizeof(BITMAPCOREHEADER))
  1169. return NumColors * sizeof(RGBTRIPLE);
  1170. else 
  1171. return NumColors * sizeof(RGBQUAD);
  1172. }
  1173. /*************************************************************************
  1174.  *
  1175.  * 函数名称:
  1176.  *   IsEmpty()
  1177.  *
  1178.  * 输入参数:
  1179.  *   无
  1180.  *
  1181.  * 返回值:
  1182.  *   BOOL - 如果信息头和图象数据为空,则返回TRUE
  1183.  *
  1184.  * 说明:
  1185.  *   判断信息头和图象数据是否为空
  1186.  *
  1187.  ************************************************************************
  1188.  */
  1189. BOOL CDib::IsEmpty()
  1190. {
  1191. if( m_lpBMIH == NULL&&m_lpImage == NULL)
  1192. return TRUE;
  1193. else
  1194. return FALSE;
  1195. }
  1196. /*************************************************************************
  1197.  *
  1198.  * 函数名称:
  1199.  *   GetDibSaveDim()
  1200.  *
  1201.  * 输入参数:
  1202.  *   无
  1203.  *
  1204.  * 返回值:
  1205.  *   CSize - DIB实际存储的高度和宽度
  1206.  *
  1207.  * 说明:
  1208.  *   该函数函数用来得到dib的实际存储宽度(DWORD对齐)
  1209.  *
  1210.  ************************************************************************
  1211.  */
  1212. CSize CDib::GetDibSaveDim()
  1213. {
  1214. CSize sizeSaveDim;
  1215. sizeSaveDim.cx = ( m_lpBMIH->biWidth * m_lpBMIH->biBitCount + 31)/32 * 4;
  1216. sizeSaveDim.cy = m_lpBMIH->biHeight; 
  1217. return sizeSaveDim;
  1218. }
  1219. /*************************************************************************
  1220.  *
  1221.  * 函数名称:
  1222.  *   GetPixelOffset()
  1223.  *
  1224.  * 输入参数:
  1225.  *   int x - 象素在X轴的坐标
  1226.  *   int y - 象素在Y轴的坐标
  1227.  *
  1228.  * 返回值:
  1229.  *   int - 返回象素在图象数据块中的真实地址
  1230.  *
  1231.  * 说明:
  1232.  *   该函数得到坐标为(x,y)的象素点的真实地址。由于DIB结构中对图象数据排列的
  1233.  *   方式为从下到上,从左到右的,所以需要进行转换。
  1234.  *
  1235.  ************************************************************************
  1236.  */
  1237. LONG CDib::GetPixelOffset(int  x, int y)
  1238. {
  1239. CSize sizeSaveDim;
  1240. sizeSaveDim = GetDibSaveDim();
  1241. LONG lOffset = (LONG) (sizeSaveDim.cy - y - 1) * sizeSaveDim.cx +
  1242. x  / (8 / m_lpBMIH->biBitCount);
  1243. return lOffset;
  1244. }
  1245. /*************************************************************************
  1246.  *
  1247.  * 函数名称:
  1248.  *   GetPixel()
  1249.  *
  1250.  * 输入参数:
  1251.  *   int x - 象素在X轴的坐标
  1252.  *   int y - 象素在Y轴的坐标
  1253.  *
  1254.  * 返回值:
  1255.  *   RGBQUAD - 返回DIB在该点真实的颜色
  1256.  *
  1257.  * 说明:
  1258.  *   该函数得到DIB图象在该点真是的颜色。
  1259.  *
  1260.  ************************************************************************
  1261.  */
  1262. RGBQUAD CDib::GetPixel(int x, int y)
  1263. {
  1264. // 颜色结构
  1265. RGBQUAD cColor;
  1266. // 根据每象素比特数得到此点的象素值
  1267. switch (m_lpBMIH->biBitCount)
  1268. {
  1269. case 1 :
  1270. if (1<<(7-x%8) & *(LPBYTE)(m_lpImage+GetPixelOffset(x, y)))
  1271. {
  1272. cColor.rgbBlue  = 255;
  1273. cColor.rgbGreen = 255;
  1274. cColor.rgbRed   = 255;
  1275. cColor.rgbReserved =0;
  1276. }
  1277. else
  1278. {
  1279. cColor.rgbBlue  = 0;
  1280. cColor.rgbGreen = 0;
  1281. cColor.rgbRed   = 0;
  1282. cColor.rgbReserved =0;
  1283. }
  1284. break;
  1285. case 4 :
  1286. {
  1287. int nIndex = (*(LPBYTE)(m_lpImage+GetPixelOffset(x, y)) & 
  1288.    (x%2 ? 0x0f : 0xf0)) >> (x%2 ? 0 : 4);
  1289. LPRGBQUAD pDibQuad = (LPRGBQUAD) (m_lpvColorTable) + nIndex;
  1290. cColor.rgbBlue  = pDibQuad->rgbBlue;
  1291. cColor.rgbGreen = pDibQuad->rgbGreen;
  1292. cColor.rgbRed   = pDibQuad->rgbRed;
  1293. cColor.rgbReserved =0;
  1294. }
  1295. break;
  1296. case 8 :
  1297. {
  1298. int nIndex = *(BYTE*)(m_lpImage+GetPixelOffset(x, y));
  1299. LPRGBQUAD pDibQuad = (LPRGBQUAD) (m_lpvColorTable) + nIndex;
  1300. cColor.rgbBlue  = pDibQuad->rgbBlue;
  1301. cColor.rgbGreen = pDibQuad->rgbGreen;
  1302. cColor.rgbRed   = pDibQuad->rgbRed;
  1303. cColor.rgbReserved =0;
  1304. }
  1305. break;
  1306. default:
  1307. int nIndex = *(BYTE*)(m_lpImage+GetPixelOffset(x, y));
  1308. cColor.rgbRed   = m_lpImage[nIndex];
  1309. cColor.rgbGreen = m_lpImage[nIndex + 1];
  1310. cColor.rgbBlue  = m_lpImage[nIndex + 2];
  1311. cColor.rgbReserved =0;
  1312. break;
  1313. }
  1314. // 返回颜色结构
  1315. return cColor;
  1316. }