cdib.cpp
上传用户:piaozanzhu
上传日期:2008-02-14
资源大小:212k
文件大小: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.     
  394. // 在设备的origin位置上画出大小为size的图象
  395. ::StretchDIBits(pDC->GetSafeHdc(), origin.x, origin.y,size.cx,size.cy,
  396. 0, 0, m_lpBMIH->biWidth, m_lpBMIH->biHeight,
  397. m_lpImage, (LPBITMAPINFO) m_lpBMIH, DIB_RGB_COLORS, SRCCOPY);
  398. // 返回
  399. return TRUE;
  400. }
  401. /*************************************************************************
  402.  *
  403.  * 函数名称:
  404.  *   CreateSection()
  405.  *
  406.  * 输入参数:
  407.  *   CDC* pDC - 设备上下文指针
  408.  *
  409.  * 返回值:
  410.  *   HBITMAP - 到GDI位图的句柄。如果不成功,则为NULL。
  411.  * - 该句柄也是作为公共数据成员存储的
  412.  *
  413.  * 说明:
  414.  *   通过调用Win32 SDK的CreateDIBSection函数创建一个DIB段。图象内存将不被初始化
  415.  *
  416.  ************************************************************************
  417.  */
  418. HBITMAP CDib::CreateSection(CDC* pDC /* = NULL */)
  419. {
  420. // 如果信息头为空,不作任何处理
  421. if(m_lpBMIH == NULL) return NULL;
  422. // 如果图象数据不存在,不作任何处理
  423. if(m_lpImage != NULL) return NULL; 
  424. // 创建一个DIB段
  425. m_hBitmap = ::CreateDIBSection(pDC->GetSafeHdc(), (LPBITMAPINFO) m_lpBMIH,
  426. DIB_RGB_COLORS, (LPVOID*) &m_lpImage, NULL, 0);
  427. ASSERT(m_lpImage != NULL);
  428. // 返回HBIMAP句柄
  429. return m_hBitmap;
  430. }
  431. /*************************************************************************
  432.  *
  433.  * 函数名称:
  434.  *   MakePalette()
  435.  *
  436.  * 输入参数:
  437.  *   无
  438.  *
  439.  * 返回值:
  440.  *   BOOL - 如果成功,则为TRUE
  441.  *
  442.  * 说明:
  443.  *   如果颜色表存在的话,该函数将读取它,并创建一个Windows调色板。
  444.  *   HPALETTE存储在一个数据成员中。
  445.  *
  446.  ************************************************************************
  447.  */
  448. BOOL CDib::MakePalette()
  449. {
  450. // 如果不存在调色板,则返回FALSE
  451. if(m_nColorTableEntries == 0) return FALSE;
  452. if(m_hPalette != NULL) ::DeleteObject(m_hPalette);
  453. TRACE("CDib::MakePalette -- m_nColorTableEntries = %dn", m_nColorTableEntries);
  454. // 给逻辑调色板分配内存
  455. LPLOGPALETTE pLogPal = (LPLOGPALETTE) new char[2 * sizeof(WORD) +
  456. m_nColorTableEntries * sizeof(PALETTEENTRY)];
  457. // 设置逻辑调色板的信息
  458. pLogPal->palVersion = 0x300;
  459. pLogPal->palNumEntries = m_nColorTableEntries;
  460. // 拷贝DIB中的颜色表到逻辑调色板
  461. LPRGBQUAD pDibQuad = (LPRGBQUAD) m_lpvColorTable;
  462. for(int i = 0; i < m_nColorTableEntries; i++) {
  463. pLogPal->palPalEntry[i].peRed = pDibQuad->rgbRed;
  464. pLogPal->palPalEntry[i].peGreen = pDibQuad->rgbGreen;
  465. pLogPal->palPalEntry[i].peBlue = pDibQuad->rgbBlue;
  466. pLogPal->palPalEntry[i].peFlags = 0;
  467. pDibQuad++;
  468. }
  469. // 创建逻辑调色板
  470. m_hPalette = ::CreatePalette(pLogPal);
  471. // 删除临时变量并返回TRUE
  472. delete pLogPal;
  473. return TRUE;
  474. }
  475. /*************************************************************************
  476.  *
  477.  * 函数名称:
  478.  *   SetSystemPalette()
  479.  *
  480.  * 输入参数:
  481.  *   CDC* pDC - 设备上下文指针
  482.  *
  483.  * 返回值:
  484.  *   BOOL - 如果成功,则为TRUE,
  485.  *
  486.  * 说明:
  487.  *   如果16bpp、24bpp或32bppDIB不具备调色板,则该函数可以为CDib对象创建一个逻辑调色板,
  488.  *   它与由CreatehalftonePalette函数返回的调色板相匹配。如果程序在256色调色板显示器上
  489.  *   运行,而你又没有调用SetSystemPalette,那么,你将不具有任何调色板,只有20中标准的
  490.  *   Windows颜色出现在DIB中
  491.  *
  492.  ************************************************************************
  493.  */
  494. BOOL CDib::SetSystemPalette(CDC* pDC)
  495. {
  496. // 如果DIB不具备调色板,则需要利用系统的调色板
  497. if(m_nColorTableEntries != 0) return FALSE;
  498. // 为设备上下文创建中间调色板,并将其与CPalette对象连接
  499. m_hPalette = ::CreateHalftonePalette(pDC->GetSafeHdc());
  500. // 返回
  501. return TRUE;
  502. }
  503. /*************************************************************************
  504.  *
  505.  * 函数名称:
  506.  *   CreateBitmap()
  507.  *
  508.  * 输入参数:
  509.  *   CDC* pDC - 设备上下文指针
  510.  *
  511.  * 返回值:
  512.  *   HBITMAP - 到GDI位图的句柄;如果不成功,则为NULL
  513.  * - 该句柄不是作为公共数据成员存储的
  514.  *
  515.  * 说明:
  516.  *   从已有的DIB中创建DDB位图。不要将这个函数与CreateSection
  517.  *   弄混了,后者的作用是生成DIB并保存句柄
  518.  *
  519.  ************************************************************************
  520.  */
  521. HBITMAP CDib::CreateBitmap(CDC* pDC)
  522. {
  523. // 如果不存在图象数据,则返回NULL
  524. if (m_dwSizeImage == 0) return NULL;
  525. // 用指定的DIB来创建DDB,并用DIB信息初始化位图的图象位
  526. HBITMAP hBitmap = ::CreateDIBitmap(pDC->GetSafeHdc(), m_lpBMIH,
  527. CBM_INIT, m_lpImage, (LPBITMAPINFO) m_lpBMIH, DIB_RGB_COLORS);
  528. ASSERT(hBitmap != NULL);
  529. // 返回DDB位图句柄
  530. return hBitmap;
  531. }
  532. /*************************************************************************
  533.  *
  534.  * 函数名称:
  535.  *   ConvertDDBToDIB()
  536.  *
  537.  * 输入参数:
  538.  *   HBITMAP hBitmap - 指向源数据的BITMAP句柄
  539.  *   CDib* pDibDst - 指向转换目标的CDib对象指针
  540.  *
  541.  * 返回值:
  542.  *   BOOL - 如果操作成功,则返回TRUE
  543.  *
  544.  * 说明:
  545.  *   该函数将源BITMAP类pDibSrc中的数据拷贝到pDibDst中,并对相应的数据成员赋值
  546.  *
  547.  *************************************************************************
  548.  */
  549. BOOL CDib::ConvertFromDDB(HBITMAP hBitmap, HPALETTE hPal)
  550. {
  551. // 声明一个BITMAP结构
  552. BITMAP bm;
  553. // 设备上下文
  554. HDC hDC;
  555. // 象素位数
  556. WORD biBitCount;
  557. // 调色板表项数
  558. int nColorTableEntries;
  559. // 如果hBitmap句柄无效,则返回
  560. if(!hBitmap){
  561. return FALSE;
  562. }
  563. // 释放已分配的内存
  564. Empty();
  565. // 填充图象数据到bm中,其中最后一个参数表示接收这个指定的对象的指针
  566. if(!GetObject(hBitmap,sizeof(BITMAP),(LPBYTE)&bm)){
  567. return FALSE;
  568. }
  569. // 计算象素位数
  570. biBitCount=bm.bmPlanes*bm.bmBitsPixel;
  571. if(biBitCount<=1)
  572. biBitCount=1;
  573. else if(biBitCount<=4)
  574. biBitCount=4;
  575. else if(biBitCount<=8)
  576. biBitCount=8;
  577. else 
  578. biBitCount=24;
  579. // 计算调色板的尺寸
  580. // 如果biClrUsed为零,则用到的颜色数为2的biBitCount次方
  581. switch(biBitCount) {
  582. case 1:
  583. nColorTableEntries = 2;
  584. break;
  585. case 4:
  586. nColorTableEntries = 16;
  587. break;
  588. case 8:
  589. nColorTableEntries = 256;
  590. break;
  591. case 16:
  592. case 24:
  593. case 32:
  594. nColorTableEntries = 0;
  595. break;
  596. default:
  597. ASSERT(FALSE);
  598. }
  599. ASSERT((nColorTableEntries >= 0) && (nColorTableEntries <= 256)); 
  600. m_nColorTableEntries = nColorTableEntries;
  601. // 分配DIB信息头和调色板的内存
  602. m_lpBMIH = (LPBITMAPINFOHEADER) new char
  603. [sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * nColorTableEntries];
  604. m_nBmihAlloc = m_nImageAlloc = crtAlloc;
  605. m_lpBMIH->biSize = sizeof(BITMAPINFOHEADER); 
  606. m_lpBMIH->biWidth = bm.bmWidth; 
  607. m_lpBMIH->biHeight = bm.bmHeight; 
  608. m_lpBMIH->biPlanes = 1; 
  609. m_lpBMIH->biBitCount = biBitCount; 
  610. m_lpBMIH->biCompression = BI_RGB; 
  611. m_lpBMIH->biSizeImage = 0; 
  612. m_lpBMIH->biXPelsPerMeter = 0; 
  613. m_lpBMIH->biYPelsPerMeter = 0; 
  614. m_lpBMIH->biClrUsed = nColorTableEntries;
  615. m_lpBMIH->biClrImportant = nColorTableEntries;
  616. // 获得设备上下文句柄
  617. hDC=GetDC(NULL);
  618.    
  619. // 如果没有指定调色板,则从系统中获得当前的系统调色板
  620. if(hPal==NULL){
  621. hPal = GetSystemPalette();
  622. }
  623. hPal = SelectPalette(hDC, hPal, FALSE); 
  624. RealizePalette(hDC); 
  625.  
  626. // 调用GetDIBits填充信息头,并获得图象数据的尺寸。注意这里图象数据指针为NULL
  627. GetDIBits( hDC, hBitmap, 0, (UINT)m_lpBMIH->biHeight, NULL, (LPBITMAPINFO)m_lpBMIH, DIB_RGB_COLORS);
  628. // 如果没有正确的获得图象数据尺寸,则重新计算
  629. if( m_lpBMIH->biSizeImage == 0 ){
  630. m_lpBMIH->biSizeImage=(((bm.bmWidth*biBitCount) + 31) / 32 * 4)*bm.bmHeight;
  631. }
  632. // 分配存放图象数据的内存
  633. m_lpImage = (LPBYTE) new char[m_lpBMIH->biSizeImage];
  634. // 调用GetDIBits加载图象数据,注意这里给出了图象数据指针
  635. // 如果加载图象数据不成功,则释放已经分配的内存,并返回FALSE
  636. if( GetDIBits( hDC, hBitmap, 0, (UINT)m_lpBMIH->biHeight, (LPBYTE)m_lpImage,
  637. (LPBITMAPINFO)m_lpBMIH, DIB_RGB_COLORS) == 0 ){
  638. //clean up and return NULL
  639. Empty();
  640. SelectPalette( hDC, hPal, TRUE );
  641. RealizePalette( hDC );
  642. ReleaseDC( NULL, hDC );
  643. return FALSE;
  644. }
  645. // 删除临时变量
  646. SelectPalette(hDC, hPal, TRUE); 
  647. RealizePalette(hDC); 
  648. ReleaseDC(NULL, hDC); 
  649. return TRUE;
  650. }
  651. /*************************************************************************
  652.  *
  653.  * 函数名称:
  654.  *   Compress()
  655.  *
  656.  * 输入参数:
  657.  *   CDC* pDC - 设备上下文指针
  658.  *   BOOL bCompress - TRUE对应于压缩的DIB,FALSE对应于不压缩的DIB
  659.  *
  660.  * 返回值:
  661.  *   BOOL - 如果成功,则返回TRUE
  662.  *
  663.  * 说明:
  664.  *   该函数将DIB重新生成为压缩或者不压缩的DIB。在内部,它转换已有的DIB为DDB位图
  665.  *   然后生成一个新的压缩或者不压缩的DIB。压缩仅为4bpp和8bpp的DIB所支持。不能
  666.  *   压缩DIB段
  667.  *
  668.  ************************************************************************
  669.  */
  670. BOOL CDib::Compress(CDC* pDC, BOOL bCompress /* = TRUE */)
  671. {
  672. // 判断是否为4bpp或者8bpp位图,否则,不进行压缩,返回FALSE
  673. if((m_lpBMIH->biBitCount != 4) && (m_lpBMIH->biBitCount != 8)) return FALSE;
  674. // 如果为DIB段,也不能支持压缩,返回FALSE
  675. if(m_hBitmap) return FALSE; 
  676. TRACE("Compress: original palette size = %dn", m_nColorTableEntries); 
  677. // 获得设备上下文句柄
  678. HDC hdc = pDC->GetSafeHdc();
  679. // 将此DIB的调色板选入设备上下文,并保存以前的调色板句柄
  680. HPALETTE hOldPalette = ::SelectPalette(hdc, m_hPalette, FALSE);
  681. HBITMAP hBitmap;  
  682. // 创建一个DDB位图,如果不成功,则返回FALSE
  683. if((hBitmap = CreateBitmap(pDC)) == NULL) return FALSE;
  684. // 计算信息头加上调色板的大小尺寸,并给它们分配内存
  685. int nSize = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * m_nColorTableEntries;
  686. LPBITMAPINFOHEADER lpBMIH = (LPBITMAPINFOHEADER) new char[nSize];
  687. // 将信息头和调色板拷贝到内存中
  688. memcpy(lpBMIH, m_lpBMIH, nSize);  // new header
  689. // 如果需要进行压缩,设置相应的信息,并创建压缩格式的DIB
  690. if(bCompress) {
  691. switch (lpBMIH->biBitCount) {
  692. case 4:
  693. lpBMIH->biCompression = BI_RLE4;
  694. break;
  695. case 8:
  696. lpBMIH->biCompression = BI_RLE8;
  697. break;
  698. default:
  699. ASSERT(FALSE);
  700. }
  701. // 设置位图数据指针为NULL,调用GetDIBits来得到压缩格式的DIB的尺寸
  702. // 如果不能创建DIB,则进行相应的错误处理。
  703. if(!::GetDIBits(pDC->GetSafeHdc(), hBitmap, 0, (UINT) lpBMIH->biHeight,
  704. NULL, (LPBITMAPINFO) lpBMIH, DIB_RGB_COLORS)) {
  705. AfxMessageBox("Unable to compress this DIB");
  706. // 删除临时变量,并释放已分配内存
  707.   ::DeleteObject(hBitmap);
  708. delete [] lpBMIH;
  709. // 重新将以前的调色板选入,并返回FALSE
  710. ::SelectPalette(hdc, hOldPalette, FALSE);
  711. return FALSE; 
  712. }
  713. // 如果位图数据为空,则进行相应的错误处理
  714. if (lpBMIH->biSizeImage == 0) {
  715. AfxMessageBox("Driver can't do compression");
  716. // 删除临时变量,并释放已分配内存
  717.   ::DeleteObject(hBitmap);
  718. delete [] lpBMIH;
  719. // 重新将以前的调色板选入,并返回FALSE
  720. ::SelectPalette(hdc, hOldPalette, FALSE);
  721. return FALSE; 
  722. }
  723. // 将位图数据尺寸赋值给类的成员变量
  724. else {
  725. m_dwSizeImage = lpBMIH->biSizeImage;
  726. }
  727. }
  728. // 如果是解压缩,进行相应的处理
  729. else {
  730. // 设置压缩格式为不压缩
  731. lpBMIH->biCompression = BI_RGB; 
  732. // 根据位图的宽度和高度计算位图数据内存的大小
  733. DWORD dwBytes = ((DWORD) lpBMIH->biWidth * lpBMIH->biBitCount) / 32;
  734. if(((DWORD) lpBMIH->biWidth * lpBMIH->biBitCount) % 32) {
  735. dwBytes++;
  736. }
  737. dwBytes *= 4;
  738. // 将得到位图数据的大小尺寸保存在类的成员变量中
  739. m_dwSizeImage = dwBytes * lpBMIH->biHeight; 
  740. // 将位图数据内存的大小赋值给临时的信息头中的相应的变量
  741. lpBMIH->biSizeImage = m_dwSizeImage;
  742. // 再次调用GetDIBits来生成DIB数据
  743. // 分配临时存放位图数据
  744. LPBYTE lpImage = (LPBYTE) new char[m_dwSizeImage];
  745. // 再次调用GetDIBits来生成DIB数据,注意此时位图数据指针不为空
  746. VERIFY(::GetDIBits(pDC->GetSafeHdc(), hBitmap, 0, (UINT) lpBMIH->biHeight,
  747.      lpImage, (LPBITMAPINFO) lpBMIH, DIB_RGB_COLORS));
  748. TRACE("dib successfully created - height = %dn", lpBMIH->biHeight);
  749. // 压缩转换完毕,进行相应的其他处理
  750. // 删除临时的DDB位图
  751. ::DeleteObject(hBitmap);
  752. // 释放原来的DIB分配的内存
  753. Empty();
  754. // 重新设置图象信息头和图象数据内存分配状态
  755. m_nBmihAlloc = m_nImageAlloc = crtAlloc;
  756. // 重新定位信息头和图象数据指针
  757. m_lpBMIH = lpBMIH;
  758. m_lpImage = lpImage;
  759. // 计算图象数据尺寸,并设置DIB中调色板的指针
  760. ComputeMetrics();
  761. // 计算DIB中调色板的尺寸
  762. ComputePaletteSize(m_lpBMIH->biBitCount);
  763. // 如果DIB中调色板存在的话,读取并创建一个Windows调色板
  764. MakePalette();
  765. // 恢复以前的调色板
  766. ::SelectPalette(hdc, hOldPalette, FALSE);
  767. TRACE("Compress: new palette size = %dn", m_nColorTableEntries); 
  768. // 返回
  769. return TRUE;
  770. }
  771. /*************************************************************************
  772.  *
  773.  * 函数名称:
  774.  *   Read()
  775.  *
  776.  * 输入参数:
  777.  *   CFile* pFile - 指向CFile对象的指针
  778.  *
  779.  * 返回值:
  780.  *   BOOL - 如果成功,则返回TRUE
  781.  *
  782.  * 说明:
  783.  *   该函数DIB从一个文件读入CDib对象。该文件必须成功打开。如果该文件是BMP文件
  784.  *   读取工作从文件头开始。如果该文件是一个文档,读取工作则从当前文件指针处开始 
  785.  *
  786.  ************************************************************************
  787.  */
  788. BOOL CDib::Read(CFile* pFile)
  789. {
  790. // 释放已经分配的内存
  791. Empty();
  792. // 临时存放信息的变量
  793. int nCount, nSize;
  794. BITMAPFILEHEADER bmfh;
  795. // 进行读操作
  796. try 
  797. {
  798. // 读取文件头
  799. nCount = pFile->Read((LPVOID) &bmfh, sizeof(BITMAPFILEHEADER));
  800. if(nCount != sizeof(BITMAPFILEHEADER)) {
  801. throw new CException;
  802. }
  803. // 如果文件类型部位"BM",则返回并进行相应错误处理
  804. if(bmfh.bfType != 0x4d42) {
  805. throw new CException;
  806. }
  807. // 计算信息头加上调色板的大小,并分配相应的内存
  808. nSize = bmfh.bfOffBits - sizeof(BITMAPFILEHEADER);
  809. m_lpBMIH = (LPBITMAPINFOHEADER) new char[nSize];
  810. m_nBmihAlloc = m_nImageAlloc = crtAlloc;
  811. // 读取信息头和调色板
  812. nCount = pFile->Read(m_lpBMIH, nSize); 
  813. // 计算图象数据大小并设置调色板指针
  814. ComputeMetrics();
  815. // 计算调色板的表项数
  816. ComputePaletteSize(m_lpBMIH->biBitCount);
  817. // 如果DIB中存在调色板,则创建一个Windows调色板
  818. MakePalette();
  819. // 分配图象数据内存,并从文件中读取图象数据
  820. m_lpImage = (LPBYTE) new char[m_dwSizeImage];
  821. nCount = pFile->Read(m_lpImage, m_dwSizeImage); 
  822. }
  823. // 错误处理
  824. catch(CException* pe) 
  825. {
  826. AfxMessageBox("Read error");
  827. pe->Delete();
  828. return FALSE;
  829. }
  830. // 返回
  831. return TRUE;
  832. }
  833. /*************************************************************************
  834.  *
  835.  * 函数名称:
  836.  *   ReadSection()
  837.  *
  838.  * 输入参数:
  839.  *   CFile* pFile - 指向CFile对象的指针;对应的磁盘
  840.  * - 文件中包含DIB
  841.  *   CDC* pDC - 设备上下文指针
  842.  *
  843.  * 返回值:
  844.  *   BOOL - 如果成功,则返回TRUE
  845.  *
  846.  * 说明:
  847.  *   该函数从BMP文件中读取信息头,调用CreateDIBSection来分配图象内存,然后将
  848.  *   图象从该文件读入刚才分配的内存。如果你想从磁盘读取一个DIB,然后通过调用
  849.  *   GDI函数编辑它的话,可以使用该函数。你可以用Write或CopyToMapFile将DIB写
  850.  *   回到磁盘
  851.  *
  852.  ************************************************************************
  853.  */
  854. BOOL CDib::ReadSection(CFile* pFile, CDC* pDC /* = NULL */)
  855. {
  856. // 释放已经分配的内存
  857. Empty();
  858. // 临时变量
  859. int nCount, nSize;
  860. BITMAPFILEHEADER bmfh;
  861. // 从文件中读取数据
  862. try {
  863. // 读取文件头
  864. nCount = pFile->Read((LPVOID) &bmfh, sizeof(BITMAPFILEHEADER));
  865. if(nCount != sizeof(BITMAPFILEHEADER)) {
  866. throw new CException;
  867. }
  868. // 如果文件类型部位"BM",则返回并进行相应错误处理
  869. if(bmfh.bfType != 0x4d42) {
  870. throw new CException;
  871. }
  872. // 计算信息头加上调色板的大小,并分配相应的内存
  873. nSize = bmfh.bfOffBits - sizeof(BITMAPFILEHEADER);
  874. m_lpBMIH = (LPBITMAPINFOHEADER) new char[nSize];
  875. m_nBmihAlloc = crtAlloc;
  876. m_nImageAlloc = noAlloc;
  877. // 读取信息头和调色板
  878. nCount = pFile->Read(m_lpBMIH, nSize); 
  879. // 如果图象为压缩格式,则不进行后续处理
  880. if(m_lpBMIH->biCompression != BI_RGB) {
  881. throw new CException;
  882. }
  883. // 计算图象数据大小并设置调色板指针
  884. ComputeMetrics();
  885. // 计算调色板的表项数
  886. ComputePaletteSize(m_lpBMIH->biBitCount);
  887. // 如果DIB中存在调色板,则创建一个Windows调色板
  888. MakePalette();
  889. // 将CDib对象的逻辑调色板选入设备上下文
  890. UsePalette(pDC);
  891. // 创建一个DIB段,并分配图象内存
  892. m_hBitmap = ::CreateDIBSection(pDC->GetSafeHdc(), (LPBITMAPINFO) m_lpBMIH,
  893. DIB_RGB_COLORS, (LPVOID*) &m_lpImage, NULL, 0);
  894. ASSERT(m_lpImage != NULL);
  895. // 从文件中读取图象数据
  896. nCount = pFile->Read(m_lpImage, m_dwSizeImage); 
  897. }
  898. // 错误处理
  899. catch(CException* pe) {
  900. AfxMessageBox("ReadSection error");
  901. pe->Delete();
  902. return FALSE;
  903. }
  904. return TRUE;
  905. }
  906. /*************************************************************************
  907.  *
  908.  * 函数名称:
  909.  *   Write()
  910.  *
  911.  * 输入参数:
  912.  *   CFile* pFile - 指向CFile对象的指针
  913.  *
  914.  * 返回值:
  915.  *   BOOL - 如果成功,则返回TRUE
  916.  *
  917.  * 说明:
  918.  *   该函数把DIB从CDib对象写进文件中。该文件必须成功打开或者创建
  919.  *
  920.  ************************************************************************
  921.  */
  922. BOOL CDib::Write(CFile* pFile)
  923. {
  924. BITMAPFILEHEADER bmfh;
  925. // 设置文件头中文件类型为"BM"
  926. bmfh.bfType = 0x4d42;  
  927. // 计算信息头和调色板的大小尺寸
  928. int nSizeHdr = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * m_nColorTableEntries;
  929. // 设置文件头信息
  930. bmfh.bfSize = sizeof(BITMAPFILEHEADER) + nSizeHdr + m_dwSizeImage;
  931. bmfh.bfReserved1 = bmfh.bfReserved2 = 0;
  932. bmfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) +
  933. sizeof(RGBQUAD) * m_nColorTableEntries;
  934. // 进行写操作
  935. try {
  936. pFile->Write((LPVOID) &bmfh, sizeof(BITMAPFILEHEADER));
  937. pFile->Write((LPVOID) m_lpBMIH,  nSizeHdr);
  938. pFile->Write((LPVOID) m_lpImage, m_dwSizeImage);
  939. }
  940. // 错误处理
  941. catch(CException* pe) {
  942. pe->Delete();
  943. AfxMessageBox("write error");
  944. return FALSE;
  945. }
  946. // 返回
  947. return TRUE;
  948. }
  949. /*************************************************************************
  950.  *
  951.  * 函数名称:
  952.  *   Serialize()
  953.  *
  954.  * 输入参数:
  955.  *   CArchive& ar - 指向应用程序归档对象
  956.  *
  957.  * 返回值:
  958.  *   无
  959.  *
  960.  * 说明:
  961.  *   该函数进行串行化过程,将CDib数据进行读入或者写出
  962.  *
  963.  ************************************************************************
  964.  */
  965. void CDib::Serialize(CArchive& ar)
  966. {
  967. DWORD dwPos;
  968. // 获得此归档文件的CFile对象指针
  969. dwPos = ar.GetFile()->GetPosition();
  970. TRACE("CDib::Serialize -- pos = %dn", dwPos);
  971. // 从归档文件缓冲区中冲掉未写入数据
  972. ar.Flush();
  973. // 重新获得此归档文件的CFile对象指针
  974. dwPos = ar.GetFile()->GetPosition();
  975. TRACE("CDib::Serialize -- pos = %dn", dwPos);
  976. // 确定归档文件是否被存储,是则进行存储
  977. if(ar.IsStoring()) {
  978. Write(ar.GetFile());
  979. }
  980. // 否则进行加载
  981. else {
  982. Read(ar.GetFile());
  983. }
  984. }
  985. /*************************************************************************
  986.  *
  987.  * 函数名称:
  988.  *   ComputePaletteSize()
  989.  *
  990.  * 输入参数:
  991.  *   int nBitCount - 指向CFile对象的指针
  992.  *
  993.  * 返回值:
  994.  *   无
  995.  *
  996.  * 说明:
  997.  *   该函数根据位图象素位数计算调色板的尺寸
  998.  *
  999.  ************************************************************************
  1000.  */
  1001. void CDib::ComputePaletteSize(int nBitCount)
  1002. {
  1003. // 如果biClrUsed为零,则用到的颜色数为2的biBitCount次方
  1004. if((m_lpBMIH == NULL) || (m_lpBMIH->biClrUsed == 0)) {
  1005. switch(nBitCount) {
  1006. case 1:
  1007. m_nColorTableEntries = 2;
  1008. break;
  1009. case 4:
  1010. m_nColorTableEntries = 16;
  1011. break;
  1012. case 8:
  1013. m_nColorTableEntries = 256;
  1014. break;
  1015. case 16:
  1016. case 24:
  1017. case 32:
  1018. m_nColorTableEntries = 0;
  1019. break;
  1020. default:
  1021. ASSERT(FALSE);
  1022. }
  1023. }
  1024. // 否则调色板的表项数就是用到的颜色数目
  1025. else {
  1026. m_nColorTableEntries = m_lpBMIH->biClrUsed;
  1027. }
  1028. ASSERT((m_nColorTableEntries >= 0) && (m_nColorTableEntries <= 256)); 
  1029. }
  1030. /*************************************************************************
  1031.  *
  1032.  * 函数名称:
  1033.  *   ComputeMetrics()
  1034.  *
  1035.  * 输入参数:
  1036.  *   无
  1037.  *
  1038.  * 返回值:
  1039.  *   无
  1040.  *
  1041.  * 说明:
  1042.  *   该函数计算图象位图的尺寸,并对DIB中的调色板的指针进行赋值
  1043.  *
  1044.  ************************************************************************
  1045.  */
  1046. void CDib::ComputeMetrics()
  1047. {
  1048. // 如果结构的长度不对,则进行错误处理
  1049. if(m_lpBMIH->biSize != sizeof(BITMAPINFOHEADER)) {
  1050. TRACE("Not a valid Windows bitmap -- probably an OS/2 bitmapn");
  1051. throw new CException;
  1052. }
  1053. // 保存图象数据内存大小到CDib对象的数据成员中
  1054. m_dwSizeImage = m_lpBMIH->biSizeImage;
  1055. // 如果图象数据内存大小为0,则重新计算
  1056. if(m_dwSizeImage == 0) {
  1057. DWORD dwBytes = ((DWORD) m_lpBMIH->biWidth * m_lpBMIH->biBitCount) / 32;
  1058. if(((DWORD) m_lpBMIH->biWidth * m_lpBMIH->biBitCount) % 32) {
  1059. dwBytes++;
  1060. }
  1061. dwBytes *= 4;
  1062. m_dwSizeImage = dwBytes * m_lpBMIH->biHeight;
  1063. }
  1064. // 设置DIB中的调色板指针
  1065. m_lpvColorTable = (LPBYTE) m_lpBMIH + sizeof(BITMAPINFOHEADER);
  1066. }
  1067. /*************************************************************************
  1068.  *
  1069.  * 函数名称:
  1070.  *   Empty()
  1071.  *
  1072.  * 输入参数:
  1073.  *   无
  1074.  *
  1075.  * 返回值:
  1076.  *   无
  1077.  *
  1078.  * 说明:
  1079.  *   该函数清空DIB,释放已分配的内存,并且必要的时候关闭映射文件
  1080.  *
  1081.  ************************************************************************
  1082.  */
  1083. void CDib::Empty()
  1084. {
  1085. // 关闭内存映射文件的连接
  1086. DetachMapFile();
  1087. // 根据内存分配的状态,调用相应的函数释放信息头
  1088. if(m_nBmihAlloc == crtAlloc) {
  1089. delete [] m_lpBMIH;
  1090. }
  1091. else if(m_nBmihAlloc == heapAlloc) {
  1092. ::GlobalUnlock(m_hGlobal);
  1093. ::GlobalFree(m_hGlobal);
  1094. }
  1095. // 释放图象数据内存
  1096. if(m_nImageAlloc == crtAlloc) delete [] m_lpImage;
  1097. // 释放调色板句柄
  1098. if(m_hPalette != NULL) ::DeleteObject(m_hPalette);
  1099. // 如果创建了BITMAP,则进行释放
  1100. if(m_hBitmap != NULL) ::DeleteObject(m_hBitmap);
  1101. // 重新设置内存分配状态
  1102. m_nBmihAlloc = m_nImageAlloc = noAlloc;
  1103. // 释放内存后,还需要将指针设置为NULL并将相应的数据设置为0
  1104. m_hGlobal = NULL;
  1105. m_lpBMIH = NULL;
  1106. m_lpImage = NULL;
  1107. m_lpvColorTable = NULL;
  1108. m_nColorTableEntries = 0;
  1109. m_dwSizeImage = 0;
  1110. m_lpvFile = NULL;
  1111. m_hMap = NULL;
  1112. m_hFile = NULL;
  1113. m_hBitmap = NULL;
  1114. m_hPalette = NULL;
  1115. }
  1116. /*************************************************************************
  1117.  *
  1118.  * 函数名称:
  1119.  *   DetachMapFile()
  1120.  *
  1121.  * 输入参数:
  1122.  *   无
  1123.  *
  1124.  * 返回值:
  1125.  *   无
  1126.  *
  1127.  * 说明:
  1128.  *   函数可以释放现有的已分配的内存,并关闭以前关联的任何内存映射文件。
  1129.  *
  1130.  ************************************************************************
  1131.  */
  1132. void CDib::DetachMapFile()
  1133. {
  1134. // 如果没有进行内存映射,则不进行处理
  1135. if(m_hFile == NULL) return;
  1136. // 关闭内存映射
  1137. ::UnmapViewOfFile(m_lpvFile);
  1138. // 关闭内存映射对象和文件
  1139. ::CloseHandle(m_hMap);
  1140. ::CloseHandle(m_hFile);
  1141. m_hFile = NULL;
  1142. }
  1143. /*************************************************************************
  1144.  *
  1145.  * 函数名称:
  1146.  *   PaletteSize()
  1147.  *
  1148.  * 输入参数:
  1149.  *   无
  1150.  *
  1151.  * 返回值:
  1152.  *   DWORD - 返回调色板的尺寸
  1153.  *
  1154.  * 说明:
  1155.  *   该函数计算机调色板所需的尺寸
  1156.  *
  1157.  ************************************************************************
  1158.  */
  1159. WORD CDib::PaletteSize()
  1160. {
  1161. // 临时变量
  1162. WORD        NumColors;
  1163. LPBITMAPINFOHEADER lpbi=m_lpBMIH;
  1164. // 如果biClrUsed为零,且图象象素位数小于等于8,则计算调色板用到的表项数
  1165. NumColors =  ((lpbi)->biClrUsed == 0 && (lpbi)->biBitCount <= 8 
  1166.                                     ? (int)(1 << (int)(lpbi)->biBitCount)          
  1167.                                     : (int)(lpbi)->biClrUsed);
  1168. // 根据颜色表示的字节数计算调色板的尺寸
  1169. if (lpbi->biSize == sizeof(BITMAPCOREHEADER))
  1170. return NumColors * sizeof(RGBTRIPLE);
  1171. else 
  1172. return NumColors * sizeof(RGBQUAD);
  1173. }
  1174. /*************************************************************************
  1175.  *
  1176.  * 函数名称:
  1177.  *   IsEmpty()
  1178.  *
  1179.  * 输入参数:
  1180.  *   无
  1181.  *
  1182.  * 返回值:
  1183.  *   BOOL - 如果信息头和图象数据为空,则返回TRUE
  1184.  *
  1185.  * 说明:
  1186.  *   判断信息头和图象数据是否为空
  1187.  *
  1188.  ************************************************************************
  1189.  */
  1190. BOOL CDib::IsEmpty()
  1191. {
  1192. if( m_lpBMIH == NULL&&m_lpImage == NULL)
  1193. return TRUE;
  1194. else
  1195. return FALSE;
  1196. }
  1197. /*************************************************************************
  1198.  *
  1199.  * 函数名称:
  1200.  *   GetDibSaveDim()
  1201.  *
  1202.  * 输入参数:
  1203.  *   无
  1204.  *
  1205.  * 返回值:
  1206.  *   CSize - DIB实际存储的高度和宽度
  1207.  *
  1208.  * 说明:
  1209.  *   该函数函数用来得到dib的实际存储宽度(DWORD对齐)
  1210.  *
  1211.  ************************************************************************
  1212.  */
  1213. CSize CDib::GetDibSaveDim()
  1214. {
  1215. CSize sizeSaveDim;
  1216. sizeSaveDim.cx = ( m_lpBMIH->biWidth * m_lpBMIH->biBitCount + 31)/32 * 4;
  1217. sizeSaveDim.cy = m_lpBMIH->biHeight; 
  1218. return sizeSaveDim;
  1219. }
  1220. /*************************************************************************
  1221.  *
  1222.  * 函数名称:
  1223.  *   GetPixelOffset()
  1224.  *
  1225.  * 输入参数:
  1226.  *   int x - 象素在X轴的坐标
  1227.  *   int y - 象素在Y轴的坐标
  1228.  *
  1229.  * 返回值:
  1230.  *   int - 返回象素在图象数据块中的真实地址
  1231.  *
  1232.  * 说明:
  1233.  *   该函数得到坐标为(x,y)的象素点的真实地址。由于DIB结构中对图象数据排列的
  1234.  *   方式为从下到上,从左到右的,所以需要进行转换。
  1235.  *
  1236.  ************************************************************************
  1237.  */
  1238. LONG CDib::GetPixelOffset(int  x, int y)
  1239. {
  1240. CSize sizeSaveDim;
  1241. sizeSaveDim = GetDibSaveDim();
  1242. LONG lOffset = (LONG) (sizeSaveDim.cy - y - 1) * sizeSaveDim.cx +
  1243. x  / (8 / m_lpBMIH->biBitCount);
  1244. return lOffset;
  1245. }
  1246. /*************************************************************************
  1247.  *
  1248.  * 函数名称:
  1249.  *   GetPixel()
  1250.  *
  1251.  * 输入参数:
  1252.  *   int x - 象素在X轴的坐标
  1253.  *   int y - 象素在Y轴的坐标
  1254.  *
  1255.  * 返回值:
  1256.  *   RGBQUAD - 返回DIB在该点真实的颜色
  1257.  *
  1258.  * 说明:
  1259.  *   该函数得到DIB图象在该点真是的颜色。
  1260.  *
  1261.  ************************************************************************
  1262.  */
  1263. RGBQUAD CDib::GetPixel(int x, int y)
  1264. {
  1265. // 颜色结构
  1266. RGBQUAD cColor;
  1267. // 根据每象素比特数得到此点的象素值
  1268. switch (m_lpBMIH->biBitCount)
  1269. {
  1270. case 1 :
  1271. if (1<<(7-x%8) & *(LPBYTE)(m_lpImage+GetPixelOffset(x, y)))
  1272. {
  1273. cColor.rgbBlue  = 255;
  1274. cColor.rgbGreen = 255;
  1275. cColor.rgbRed   = 255;
  1276. cColor.rgbReserved =0;
  1277. }
  1278. else
  1279. {
  1280. cColor.rgbBlue  = 0;
  1281. cColor.rgbGreen = 0;
  1282. cColor.rgbRed   = 0;
  1283. cColor.rgbReserved =0;
  1284. }
  1285. break;
  1286. case 4 :
  1287. {
  1288. int nIndex = (*(LPBYTE)(m_lpImage+GetPixelOffset(x, y)) & 
  1289.    (x%2 ? 0x0f : 0xf0)) >> (x%2 ? 0 : 4);
  1290. LPRGBQUAD pDibQuad = (LPRGBQUAD) (m_lpvColorTable) + nIndex;
  1291. cColor.rgbBlue  = pDibQuad->rgbBlue;
  1292. cColor.rgbGreen = pDibQuad->rgbGreen;
  1293. cColor.rgbRed   = pDibQuad->rgbRed;
  1294. cColor.rgbReserved =0;
  1295. }
  1296. break;
  1297. case 8 :
  1298. {
  1299. int nIndex = *(BYTE*)(m_lpImage+GetPixelOffset(x, y));
  1300. LPRGBQUAD pDibQuad = (LPRGBQUAD) (m_lpvColorTable) + nIndex;
  1301. cColor.rgbBlue  = pDibQuad->rgbBlue;
  1302. cColor.rgbGreen = pDibQuad->rgbGreen;
  1303. cColor.rgbRed   = pDibQuad->rgbRed;
  1304. cColor.rgbReserved =0;
  1305. }
  1306. break;
  1307. default:
  1308. int nIndex = *(BYTE*)(m_lpImage+GetPixelOffset(x, y));
  1309. cColor.rgbRed   = m_lpImage[nIndex];
  1310. cColor.rgbGreen = m_lpImage[nIndex + 1];
  1311. cColor.rgbBlue  = m_lpImage[nIndex + 2];
  1312. cColor.rgbReserved =0;
  1313. break;
  1314. }
  1315. // 返回颜色结构
  1316. return cColor;
  1317. }