Dib.cpp
上传用户:aqingfeng
上传日期:2014-03-25
资源大小:1839k
文件大小:24k
源码类别:

波变换

开发平台:

Visual C++

  1. // Dib.cpp: implementation of the CDib class.
  2. //
  3. //////////////////////////////////////////////////////////////////////
  4. #include "stdafx.h"
  5. #include "小波变换.h"
  6. #include "Dib.h"
  7. #include "math.h"
  8. #include "GlobalApi.h"
  9. #ifdef _DEBUG
  10. #undef THIS_FILE
  11. static char THIS_FILE[]=__FILE__;
  12. #define new DEBUG_NEW
  13. #endif
  14. //////////////////////////////////////////////////////////////////////
  15. // Construction/Destruction
  16. //////////////////////////////////////////////////////////////////////
  17. // 声明串行化过程
  18. IMPLEMENT_SERIAL(CDib, CObject, 0);
  19. /*************************************************************************
  20.  *
  21.  * 函数名称:
  22.  *   CDib()
  23.  *
  24.  * 输入参数:
  25.  * 无
  26.  *
  27.  * 返回值:
  28.  *   无
  29.  *
  30.  * 说明:
  31.  *   构造函数
  32.  *
  33.  ************************************************************************
  34.  */
  35. CDib::CDib()
  36. {
  37. m_hFile      = NULL;
  38. m_hBitmap    = NULL;
  39. m_hPalette   = NULL;
  40. m_nBmihAlloc = m_nImageAlloc = noAlloc;
  41. Empty();
  42. }
  43. /*************************************************************************
  44.  *
  45.  * 函数名称:
  46.  *   CDib()
  47.  *
  48.  * 输入参数:
  49.  * CSize size - 位图尺寸
  50.  * int nBitCount - 象素位数
  51.  *
  52.  * 返回值:
  53.  *   无
  54.  *
  55.  * 说明:
  56.  *   构造函数
  57.  *   根据给定的位图尺寸和象素位数构造CDib对象,并对信息头和调色板分配内存
  58.  *   但并没有给位图数据分配内存
  59.  *
  60.  ************************************************************************
  61.  */
  62. CDib::CDib(CSize size, int nBitCount)
  63. {
  64. m_hFile      = NULL;
  65. m_hBitmap    = NULL;
  66. m_hPalette   = NULL;
  67. m_nBmihAlloc = m_nImageAlloc = noAlloc;
  68. Empty();
  69. // 根据象素位数计算调色板尺寸
  70. ComputePaletteSize(nBitCount);
  71. // 分配DIB信息头和调色板的内存
  72. m_lpBMIH = (LPBITMAPINFOHEADER) new 
  73. char[sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * m_nColorTableEntries];
  74. // 设置信息头内存分配状态
  75. m_nBmihAlloc = crtAlloc;
  76. // 设置信息头中的信息
  77. m_lpBMIH->biSize = sizeof(BITMAPINFOHEADER);
  78. m_lpBMIH->biWidth = size.cx;
  79. m_lpBMIH->biHeight = size.cy;
  80. m_lpBMIH->biPlanes = 1;
  81. m_lpBMIH->biBitCount = nBitCount;
  82. m_lpBMIH->biCompression = BI_RGB;
  83. m_lpBMIH->biSizeImage = 0;
  84. m_lpBMIH->biXPelsPerMeter = 0;
  85. m_lpBMIH->biYPelsPerMeter = 0;
  86. m_lpBMIH->biClrUsed = m_nColorTableEntries;
  87. m_lpBMIH->biClrImportant= m_nColorTableEntries;
  88. // 计算图象数据内存的大小,并设置此DIB的调色板的指针
  89. ComputeMetrics();
  90. // 将此DIB的调色板初始化为0
  91. memset(m_lpvColorTable, 0, sizeof(RGBQUAD) * m_nColorTableEntries);
  92. // 暂时不分配图象数据内存
  93. m_lpImage = NULL; 
  94. }
  95. /*************************************************************************
  96.  *
  97.  * 函数名称:
  98.  *   ~CDib()
  99.  *
  100.  * 输入参数:
  101.  * 无
  102.  *
  103.  * 返回值:
  104.  *   无
  105.  *
  106.  * 说明:
  107.  *   析构函数,并释放所有分配的DIB内存
  108.  *
  109.  ************************************************************************
  110.  */
  111. CDib::~CDib()
  112. {
  113. Empty();
  114. }
  115. /*************************************************************************
  116.  *
  117.  * 函数名称:
  118.  *   GetDimensions()
  119.  *
  120.  * 输入参数:
  121.  *   无
  122.  *
  123.  * 返回值:
  124.  *   CSize - DIB的宽度和高度
  125.  *
  126.  * 说明:
  127.  *   返回以象素表示的DIB的宽度和高度
  128.  *
  129.  ************************************************************************
  130.  */
  131. CSize CDib::GetDimensions()
  132. {
  133. if(m_lpBMIH == NULL) return CSize(0, 0);
  134. return CSize((int) m_lpBMIH->biWidth, (int) m_lpBMIH->biHeight);
  135. }
  136. /*************************************************************************
  137.  *
  138.  * 函数名称:
  139.  *   UsePalette()
  140.  *
  141.  * 输入参数:
  142.  *   CDC* pDC - 要实现调色板的设备上下文指针
  143.  *   BOOL bBackground - 如果标记为FALSE(默认值),并且应用
  144.  * - 程序正在前台运行,则Windows将把该调
  145.  * - 色板作为前台调色板来实现(向系统调色
  146.  * - 板中复制尽可能多的颜色)。如果标记为
  147.  * - TURE,则Windows将把该调色板作为后台
  148.  * - 调色板来实现(尽可能相系统调色板映射
  149.  * - 逻辑调色板)
  150.  *
  151.  * 返回值:
  152.  *   UINT - 如果成功,则返回映射到系统调色板的逻
  153.  * - 辑调色板的表项数,否则返回GDI_ERROR 
  154.  *
  155.  * 说明:
  156.  *   该函数将CDib对象的逻辑调色板选入设备上下文,然后实现该调色板。Draw成员函
  157.  *   数在绘制DIB之前调用UsePalette。
  158.  *
  159.  ************************************************************************
  160.  */
  161. UINT CDib::UsePalette(CDC* pDC, BOOL bBackground /* = FALSE */)
  162. {
  163. // 判断是否存在调色板
  164. if(m_hPalette == NULL) return 0;
  165. // 得到设备上下文句柄
  166. HDC hdc = pDC->GetSafeHdc();
  167. // 选择调色板到设备上下文
  168. ::SelectPalette(hdc, m_hPalette, bBackground);
  169. // 实现该调色板
  170. return ::RealizePalette(hdc);
  171. }
  172. /*************************************************************************
  173.  *
  174.  * 函数名称:
  175.  *   Draw()
  176.  *
  177.  * 输入参数:
  178.  *   CDC* pDC - 指向将要接收DIB图象的设备上下文指针
  179.  *   CPoint origin - 显示DIB的逻辑坐标
  180.  *   CSize size - 显示矩形的宽度和高度
  181.  *
  182.  * 返回值:
  183.  *   BOOL - 如果成功,则为TRUE,
  184.  *
  185.  * 说明:
  186.  *   通过调用Win32 SDK的StretchDIBits函数将CDib对象输出到显示器(或者打印机)。
  187.  *   为了适合指定的矩形,位图可以进行必要的拉伸
  188.  *
  189.  ************************************************************************
  190.  */
  191. BOOL CDib::Draw(CDC* pDC, CPoint origin, CSize size)
  192. {
  193. // 如果信息头为空,表示尚未有数据,返回FALSE
  194. if(m_lpBMIH == NULL) return FALSE;
  195. // 如果调色板不为空,则将调色板选入设备上下文
  196. if(m_hPalette != NULL) {
  197. ::SelectPalette(pDC->GetSafeHdc(), m_hPalette, TRUE);
  198. }
  199. // 设置显示模式
  200. pDC->SetStretchBltMode(COLORONCOLOR);
  201. // 在设备的origin位置上画出大小为size的图象
  202. ::StretchDIBits(pDC->GetSafeHdc(), origin.x, origin.y,size.cx,size.cy,
  203. 0, 0, m_lpBMIH->biWidth, m_lpBMIH->biHeight,
  204. m_lpImage, (LPBITMAPINFO) m_lpBMIH, DIB_RGB_COLORS, SRCCOPY);
  205. // 返回
  206. return TRUE;
  207. }
  208. /*************************************************************************
  209.  *
  210.  * 函数名称:
  211.  *   MakePalette()
  212.  *
  213.  * 输入参数:
  214.  *   无
  215.  *
  216.  * 返回值:
  217.  *   BOOL - 如果成功,则为TRUE
  218.  *
  219.  * 说明:
  220.  *   如果颜色表存在的话,该函数将读取它,并创建一个Windows调色板。
  221.  *   HPALETTE存储在一个数据成员中。
  222.  *
  223.  ************************************************************************
  224.  */
  225. BOOL CDib::MakePalette()
  226. {
  227. // 如果不存在调色板,则返回FALSE
  228. if(m_nColorTableEntries == 0) return FALSE;
  229. if(m_hPalette != NULL) ::DeleteObject(m_hPalette);
  230. TRACE("CDib::MakePalette -- m_nColorTableEntries = %dn", m_nColorTableEntries);
  231. // 给逻辑调色板分配内存
  232. LPLOGPALETTE pLogPal = (LPLOGPALETTE) new char[2 * sizeof(WORD) +
  233. m_nColorTableEntries * sizeof(PALETTEENTRY)];
  234. // 设置逻辑调色板的信息
  235. pLogPal->palVersion = 0x300;
  236. pLogPal->palNumEntries = m_nColorTableEntries;
  237. // 拷贝DIB中的颜色表到逻辑调色板
  238. LPRGBQUAD pDibQuad = (LPRGBQUAD) m_lpvColorTable;
  239. for(int i = 0; i < m_nColorTableEntries; i++) {
  240. pLogPal->palPalEntry[i].peRed = pDibQuad->rgbRed;
  241. pLogPal->palPalEntry[i].peGreen = pDibQuad->rgbGreen;
  242. pLogPal->palPalEntry[i].peBlue = pDibQuad->rgbBlue;
  243. pLogPal->palPalEntry[i].peFlags = 0;
  244. pDibQuad++;
  245. }
  246. // 创建逻辑调色板
  247. m_hPalette = ::CreatePalette(pLogPal);
  248. // 删除临时变量并返回TRUE
  249. delete pLogPal;
  250. return TRUE;
  251. }
  252. /*************************************************************************
  253.  *
  254.  * 函数名称:
  255.  *   SetSystemPalette()
  256.  *
  257.  * 输入参数:
  258.  *   CDC* pDC - 设备上下文指针
  259.  *
  260.  * 返回值:
  261.  *   BOOL - 如果成功,则为TRUE,
  262.  *
  263.  * 说明:
  264.  *   如果16bpp、24bpp或32bppDIB不具备调色板,则该函数可以为CDib对象创建一个逻辑调色板,
  265.  *   它与由CreatehalftonePalette函数返回的调色板相匹配。如果程序在256色调色板显示器上
  266.  *   运行,而你又没有调用SetSystemPalette,那么,你将不具有任何调色板,只有20中标准的
  267.  *   Windows颜色出现在DIB中
  268.  *
  269.  ************************************************************************
  270.  */
  271. BOOL CDib::SetSystemPalette(CDC* pDC)
  272. {
  273. // 如果DIB不具备调色板,则需要利用系统的调色板
  274. if(m_nColorTableEntries != 0) return FALSE;
  275. // 为设备上下文创建中间调色板,并将其与CPalette对象连接
  276. m_hPalette = ::CreateHalftonePalette(pDC->GetSafeHdc());
  277. // 返回
  278. return TRUE;
  279. }
  280. /*************************************************************************
  281.  *
  282.  * 函数名称:
  283.  *   CreateBitmap()
  284.  *
  285.  * 输入参数:
  286.  *   CDC* pDC - 设备上下文指针
  287.  *
  288.  * 返回值:
  289.  *   HBITMAP - 到GDI位图的句柄;如果不成功,则为NULL
  290.  * - 该句柄不是作为公共数据成员存储的
  291.  *
  292.  * 说明:
  293.  *   从已有的DIB中创建DDB位图。不要将这个函数与CreateSection
  294.  *   弄混了,后者的作用是生成DIB并保存句柄
  295.  *
  296.  ************************************************************************
  297.  */
  298. HBITMAP CDib::CreateBitmap(CDC* pDC)
  299. {
  300. // 如果不存在图象数据,则返回NULL
  301. if (m_dwSizeImage == 0) return NULL;
  302. // 用指定的DIB来创建DDB,并用DIB信息初始化位图的图象位
  303. HBITMAP hBitmap = ::CreateDIBitmap(pDC->GetSafeHdc(), m_lpBMIH,
  304. CBM_INIT, m_lpImage, (LPBITMAPINFO) m_lpBMIH, DIB_RGB_COLORS);
  305. ASSERT(hBitmap != NULL);
  306. // 返回DDB位图句柄
  307. return hBitmap;
  308. }
  309. /*************************************************************************
  310.  *
  311.  * 函数名称:
  312.  *   ConvertDDBToDIB()
  313.  *
  314.  * 输入参数:
  315.  *   HBITMAP hBitmap - 指向源数据的BITMAP句柄
  316.  *   CDib* pDibDst - 指向转换目标的CDib对象指针
  317.  *
  318.  * 返回值:
  319.  *   BOOL - 如果操作成功,则返回TRUE
  320.  *
  321.  * 说明:
  322.  *   该函数将源BITMAP类pDibSrc中的数据拷贝到pDibDst中,并对相应的数据成员赋值
  323.  *
  324.  *************************************************************************
  325.  */
  326. BOOL CDib::ConvertFromDDB(HBITMAP hBitmap, HPALETTE hPal)
  327. {
  328. // 声明一个BITMAP结构
  329. BITMAP bm;
  330. // 设备上下文
  331. HDC hDC;
  332. // 象素位数
  333. WORD biBitCount;
  334. // 调色板表项数
  335. int nColorTableEntries;
  336. // 如果hBitmap句柄无效,则返回
  337. if(!hBitmap){
  338. return FALSE;
  339. }
  340. // 释放已分配的内存
  341. Empty();
  342. // 填充图象数据到bm中,其中最后一个参数表示接收这个指定的对象的指针
  343. if(!GetObject(hBitmap,sizeof(BITMAP),(LPBYTE)&bm)){
  344. return FALSE;
  345. }
  346. // 计算象素位数
  347. biBitCount=bm.bmPlanes*bm.bmBitsPixel;
  348. if(biBitCount<=1)
  349. biBitCount=1;
  350. else if(biBitCount<=4)
  351. biBitCount=4;
  352. else if(biBitCount<=8)
  353. biBitCount=8;
  354. else 
  355. biBitCount=24;
  356. // 计算调色板的尺寸
  357. // 如果biClrUsed为零,则用到的颜色数为2的biBitCount次方
  358. switch(biBitCount) {
  359. case 1:
  360. nColorTableEntries = 2;
  361. break;
  362. case 4:
  363. nColorTableEntries = 16;
  364. break;
  365. case 8:
  366. nColorTableEntries = 256;
  367. break;
  368. case 16:
  369. case 24:
  370. case 32:
  371. nColorTableEntries = 0;
  372. break;
  373. default:
  374. ASSERT(FALSE);
  375. }
  376. ASSERT((nColorTableEntries >= 0) && (nColorTableEntries <= 256)); 
  377. m_nColorTableEntries = nColorTableEntries;
  378. // 分配DIB信息头和调色板的内存
  379. m_lpBMIH = (LPBITMAPINFOHEADER) new char
  380. [sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * nColorTableEntries];
  381. m_nBmihAlloc = m_nImageAlloc = crtAlloc;
  382. m_lpBMIH->biSize = sizeof(BITMAPINFOHEADER); 
  383. m_lpBMIH->biWidth = bm.bmWidth; 
  384. m_lpBMIH->biHeight = bm.bmHeight; 
  385. m_lpBMIH->biPlanes = 1; 
  386. m_lpBMIH->biBitCount = biBitCount; 
  387. m_lpBMIH->biCompression = BI_RGB; 
  388. m_lpBMIH->biSizeImage = 0; 
  389. m_lpBMIH->biXPelsPerMeter = 0; 
  390. m_lpBMIH->biYPelsPerMeter = 0; 
  391. m_lpBMIH->biClrUsed = nColorTableEntries;
  392. m_lpBMIH->biClrImportant = nColorTableEntries;
  393. // 获得设备上下文句柄
  394. hDC=GetDC(NULL);
  395.    
  396. // 如果没有指定调色板,则从系统中获得当前的系统调色板
  397. if(hPal==NULL){
  398. hPal = GetSystemPalette();
  399. }
  400. hPal = SelectPalette(hDC, hPal, FALSE); 
  401. RealizePalette(hDC); 
  402.  
  403. // 调用GetDIBits填充信息头,并获得图象数据的尺寸。注意这里图象数据指针为NULL
  404. GetDIBits( hDC, hBitmap, 0, (UINT)m_lpBMIH->biHeight, NULL, (LPBITMAPINFO)m_lpBMIH, DIB_RGB_COLORS);
  405. // 如果没有正确的获得图象数据尺寸,则重新计算
  406. if( m_lpBMIH->biSizeImage == 0 ){
  407. m_lpBMIH->biSizeImage=(((bm.bmWidth*biBitCount) + 31) / 32 * 4)*bm.bmHeight;
  408. }
  409. // 分配存放图象数据的内存
  410. m_lpImage = (LPBYTE) new char[m_lpBMIH->biSizeImage];
  411. // 调用GetDIBits加载图象数据,注意这里给出了图象数据指针
  412. // 如果加载图象数据不成功,则释放已经分配的内存,并返回FALSE
  413. if( GetDIBits( hDC, hBitmap, 0, (UINT)m_lpBMIH->biHeight, (LPBYTE)m_lpImage,
  414. (LPBITMAPINFO)m_lpBMIH, DIB_RGB_COLORS) == 0 ){
  415. //clean up and return NULL
  416. Empty();
  417. SelectPalette( hDC, hPal, TRUE );
  418. RealizePalette( hDC );
  419. ReleaseDC( NULL, hDC );
  420. return FALSE;
  421. }
  422. // 删除临时变量
  423. SelectPalette(hDC, hPal, TRUE); 
  424. RealizePalette(hDC); 
  425. ReleaseDC(NULL, hDC); 
  426. return TRUE;
  427. }
  428. /*************************************************************************
  429.  *
  430.  * 函数名称:
  431.  *   Read()
  432.  *
  433.  * 输入参数:
  434.  *   CFile* pFile - 指向CFile对象的指针
  435.  *
  436.  * 返回值:
  437.  *   BOOL - 如果成功,则返回TRUE
  438.  *
  439.  * 说明:
  440.  *   该函数DIB从一个文件读入CDib对象。该文件必须成功打开。如果该文件是BMP文件
  441.  *   读取工作从文件头开始。如果该文件是一个文档,读取工作则从当前文件指针处开始 
  442.  *
  443.  ************************************************************************
  444.  */
  445. BOOL CDib::Read(CFile* pFile)
  446. {
  447. // 释放已经分配的内存
  448. Empty();
  449. // 临时存放信息的变量
  450. int nCount, nSize;
  451. BITMAPFILEHEADER bmfh;
  452. // 进行读操作
  453. try 
  454. {
  455. // 读取文件头
  456. nCount = pFile->Read((LPVOID) &bmfh, sizeof(BITMAPFILEHEADER));
  457. if(nCount != sizeof(BITMAPFILEHEADER)) {
  458. throw new CException;
  459. }
  460. // 如果文件类型部位"BM",则返回并进行相应错误处理
  461. if(bmfh.bfType != 0x4d42) {
  462. throw new CException;
  463. }
  464. // 计算信息头加上调色板的大小,并分配相应的内存
  465. nSize = bmfh.bfOffBits - sizeof(BITMAPFILEHEADER);
  466. m_lpBMIH = (LPBITMAPINFOHEADER) new char[nSize];
  467. m_nBmihAlloc = m_nImageAlloc = crtAlloc;
  468. // 读取信息头和调色板
  469. nCount = pFile->Read(m_lpBMIH, nSize); 
  470. // 计算图象数据大小并设置调色板指针
  471. ComputeMetrics();
  472. // 计算调色板的表项数
  473. ComputePaletteSize(m_lpBMIH->biBitCount);
  474. // 如果DIB中存在调色板,则创建一个Windows调色板
  475. MakePalette();
  476. // 分配图象数据内存,并从文件中读取图象数据
  477. m_lpImage = (LPBYTE) new char[m_dwSizeImage];
  478. nCount = pFile->Read(m_lpImage, m_dwSizeImage); 
  479. }
  480. // 错误处理
  481. catch(CException* pe) 
  482. {
  483. AfxMessageBox("Read error");
  484. pe->Delete();
  485. return FALSE;
  486. }
  487. // 返回
  488. return TRUE;
  489. }
  490. /*************************************************************************
  491.  *
  492.  * 函数名称:
  493.  *   Write()
  494.  *
  495.  * 输入参数:
  496.  *   CFile* pFile - 指向CFile对象的指针
  497.  *
  498.  * 返回值:
  499.  *   BOOL - 如果成功,则返回TRUE
  500.  *
  501.  * 说明:
  502.  *   该函数把DIB从CDib对象写进文件中。该文件必须成功打开或者创建
  503.  *
  504.  ************************************************************************
  505.  */
  506. BOOL CDib::Write(CFile* pFile)
  507. {
  508. BITMAPFILEHEADER bmfh;
  509. // 设置文件头中文件类型为"BM"
  510. bmfh.bfType = 0x4d42;  
  511. // 计算信息头和调色板的大小尺寸
  512. int nSizeHdr = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * m_nColorTableEntries;
  513. // 设置文件头信息
  514. bmfh.bfSize = sizeof(BITMAPFILEHEADER) + nSizeHdr + m_dwSizeImage;
  515. bmfh.bfReserved1 = bmfh.bfReserved2 = 0;
  516. bmfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) +
  517. sizeof(RGBQUAD) * m_nColorTableEntries;
  518. // 进行写操作
  519. try {
  520. pFile->Write((LPVOID) &bmfh, sizeof(BITMAPFILEHEADER));
  521. pFile->Write((LPVOID) m_lpBMIH,  nSizeHdr);
  522. pFile->Write((LPVOID) m_lpImage, m_dwSizeImage);
  523. }
  524. // 错误处理
  525. catch(CException* pe) {
  526. pe->Delete();
  527. AfxMessageBox("write error");
  528. return FALSE;
  529. }
  530. // 返回
  531. return TRUE;
  532. }
  533. /*************************************************************************
  534.  *
  535.  * 函数名称:
  536.  *   Serialize()
  537.  *
  538.  * 输入参数:
  539.  *   CArchive& ar - 指向应用程序归档对象
  540.  *
  541.  * 返回值:
  542.  *   无
  543.  *
  544.  * 说明:
  545.  *   该函数进行串行化过程,将CDib数据进行读入或者写出
  546.  *
  547.  ************************************************************************
  548.  */
  549. void CDib::Serialize(CArchive& ar)
  550. {
  551. DWORD dwPos;
  552. // 获得此归档文件的CFile对象指针
  553. dwPos = ar.GetFile()->GetPosition();
  554. TRACE("CDib::Serialize -- pos = %dn", dwPos);
  555. // 从归档文件缓冲区中冲掉未写入数据
  556. ar.Flush();
  557. // 重新获得此归档文件的CFile对象指针
  558. dwPos = ar.GetFile()->GetPosition();
  559. TRACE("CDib::Serialize -- pos = %dn", dwPos);
  560. // 确定归档文件是否被存储,是则进行存储
  561. if(ar.IsStoring()) {
  562. Write(ar.GetFile());
  563. }
  564. // 否则进行加载
  565. else {
  566. Read(ar.GetFile());
  567. }
  568. }
  569. /*************************************************************************
  570.  *
  571.  * 函数名称:
  572.  *   ComputePaletteSize()
  573.  *
  574.  * 输入参数:
  575.  *   int nBitCount - 指向CFile对象的指针
  576.  *
  577.  * 返回值:
  578.  *   无
  579.  *
  580.  * 说明:
  581.  *   该函数根据位图象素位数计算调色板的尺寸
  582.  *
  583.  ************************************************************************
  584.  */
  585. void CDib::ComputePaletteSize(int nBitCount)
  586. {
  587. // 如果biClrUsed为零,则用到的颜色数为2的biBitCount次方
  588. if((m_lpBMIH == NULL) || (m_lpBMIH->biClrUsed == 0)) {
  589. switch(nBitCount) {
  590. case 1:
  591. m_nColorTableEntries = 2;
  592. break;
  593. case 4:
  594. m_nColorTableEntries = 16;
  595. break;
  596. case 8:
  597. m_nColorTableEntries = 256;
  598. break;
  599. case 16:
  600. case 24:
  601. case 32:
  602. m_nColorTableEntries = 0;
  603. break;
  604. default:
  605. ASSERT(FALSE);
  606. }
  607. }
  608. // 否则调色板的表项数就是用到的颜色数目
  609. else {
  610. m_nColorTableEntries = m_lpBMIH->biClrUsed;
  611. }
  612. ASSERT((m_nColorTableEntries >= 0) && (m_nColorTableEntries <= 256)); 
  613. }
  614. /*************************************************************************
  615.  *
  616.  * 函数名称:
  617.  *   ComputeMetrics()
  618.  *
  619.  * 输入参数:
  620.  *   无
  621.  *
  622.  * 返回值:
  623.  *   无
  624.  *
  625.  * 说明:
  626.  *   该函数计算图象位图的尺寸,并对DIB中的调色板的指针进行赋值
  627.  *
  628.  ************************************************************************
  629.  */
  630. void CDib::ComputeMetrics()
  631. {
  632. // 如果结构的长度不对,则进行错误处理
  633. if(m_lpBMIH->biSize != sizeof(BITMAPINFOHEADER)) {
  634. TRACE("Not a valid Windows bitmap -- probably an OS/2 bitmapn");
  635. throw new CException;
  636. }
  637. // 保存图象数据内存大小到CDib对象的数据成员中
  638. m_dwSizeImage = m_lpBMIH->biSizeImage;
  639. // 如果图象数据内存大小为0,则重新计算
  640. if(m_dwSizeImage == 0) {
  641. DWORD dwBytes = ((DWORD) m_lpBMIH->biWidth * m_lpBMIH->biBitCount) / 32;
  642. if(((DWORD) m_lpBMIH->biWidth * m_lpBMIH->biBitCount) % 32) {
  643. dwBytes++;
  644. }
  645. dwBytes *= 4;
  646. m_dwSizeImage = dwBytes * m_lpBMIH->biHeight;
  647. }
  648. // 设置DIB中的调色板指针
  649. m_lpvColorTable = (LPBYTE) m_lpBMIH + sizeof(BITMAPINFOHEADER);
  650. }
  651. /*************************************************************************
  652.  *
  653.  * 函数名称:
  654.  *   Empty()
  655.  *
  656.  * 输入参数:
  657.  *   无
  658.  *
  659.  * 返回值:
  660.  *   无
  661.  *
  662.  * 说明:
  663.  *   该函数清空DIB,释放已分配的内存,并且必要的时候关闭映射文件
  664.  *
  665.  ************************************************************************
  666.  */
  667. void CDib::Empty()
  668. {
  669. // 关闭内存映射文件的连接
  670. DetachMapFile();
  671. // 根据内存分配的状态,调用相应的函数释放信息头
  672. if(m_nBmihAlloc == crtAlloc) {
  673. delete [] m_lpBMIH;
  674. }
  675. else if(m_nBmihAlloc == heapAlloc) {
  676. ::GlobalUnlock(m_hGlobal);
  677. ::GlobalFree(m_hGlobal);
  678. }
  679. // 释放图象数据内存
  680. if(m_nImageAlloc == crtAlloc) delete [] m_lpImage;
  681. // 释放调色板句柄
  682. if(m_hPalette != NULL) ::DeleteObject(m_hPalette);
  683. // 如果创建了BITMAP,则进行释放
  684. if(m_hBitmap != NULL) ::DeleteObject(m_hBitmap);
  685. // 重新设置内存分配状态
  686. m_nBmihAlloc = m_nImageAlloc = noAlloc;
  687. // 释放内存后,还需要将指针设置为NULL并将相应的数据设置为0
  688. m_hGlobal = NULL;
  689. m_lpBMIH = NULL;
  690. m_lpImage = NULL;
  691. m_lpvColorTable = NULL;
  692. m_nColorTableEntries = 0;
  693. m_dwSizeImage = 0;
  694. m_lpvFile = NULL;
  695. m_hMap = NULL;
  696. m_hFile = NULL;
  697. m_hBitmap = NULL;
  698. m_hPalette = NULL;
  699. }
  700. /*************************************************************************
  701.  *
  702.  * 函数名称:
  703.  *   DetachMapFile()
  704.  *
  705.  * 输入参数:
  706.  *   无
  707.  *
  708.  * 返回值:
  709.  *   无
  710.  *
  711.  * 说明:
  712.  *   函数可以释放现有的已分配的内存,并关闭以前关联的任何内存映射文件。
  713.  *
  714.  ************************************************************************
  715.  */
  716. void CDib::DetachMapFile()
  717. {
  718. // 如果没有进行内存映射,则不进行处理
  719. if(m_hFile == NULL) return;
  720. // 关闭内存映射
  721. ::UnmapViewOfFile(m_lpvFile);
  722. // 关闭内存映射对象和文件
  723. ::CloseHandle(m_hMap);
  724. ::CloseHandle(m_hFile);
  725. m_hFile = NULL;
  726. }
  727. /*************************************************************************
  728.  *
  729.  * 函数名称:
  730.  *   PaletteSize()
  731.  *
  732.  * 输入参数:
  733.  *   无
  734.  *
  735.  * 返回值:
  736.  *   DWORD - 返回调色板的尺寸
  737.  *
  738.  * 说明:
  739.  *   该函数计算机调色板所需的尺寸
  740.  *
  741.  ************************************************************************
  742.  */
  743. WORD CDib::PaletteSize()
  744. {
  745. // 临时变量
  746. WORD        NumColors;
  747. LPBITMAPINFOHEADER lpbi=m_lpBMIH;
  748. // 如果biClrUsed为零,且图象象素位数小于8,则计算调色板用到的表项数
  749. NumColors =  ((lpbi)->biClrUsed == 0 && (lpbi)->biBitCount <= 8 
  750.                                     ? (int)(1 << (int)(lpbi)->biBitCount)          
  751.                                     : (int)(lpbi)->biClrUsed);
  752. // 根据颜色表示的字节数计算调色板的尺寸
  753. if (lpbi->biSize == sizeof(BITMAPCOREHEADER))
  754. return NumColors * sizeof(RGBTRIPLE);
  755. else 
  756. return NumColors * sizeof(RGBQUAD);
  757. }
  758. /*************************************************************************
  759.  *
  760.  * 函数名称:
  761.  *   IsEmpty()
  762.  *
  763.  * 输入参数:
  764.  *   无
  765.  *
  766.  * 返回值:
  767.  *   BOOL - 如果信息头和图象数据为空,则返回TRUE
  768.  *
  769.  * 说明:
  770.  *   判断信息头和图象数据是否为空
  771.  *
  772.  ************************************************************************
  773.  */
  774. BOOL CDib::IsEmpty()
  775. {
  776. if( m_lpBMIH == NULL&&m_lpImage == NULL)
  777. return TRUE;
  778. else
  779. return FALSE;
  780. }
  781. /*************************************************************************
  782.  *
  783.  * 函数名称:
  784.  *   GetDibSaveDim()
  785.  *
  786.  * 输入参数:
  787.  *   无
  788.  *
  789.  * 返回值:
  790.  *   CSize - DIB实际存储的高度和宽度
  791.  *
  792.  * 说明:
  793.  *   该函数函数用来得到dib的实际存储宽度(DWORD对齐)
  794.  *
  795.  ************************************************************************
  796.  */
  797. CSize CDib::GetDibSaveDim()
  798. {
  799. CSize sizeSaveDim;
  800. sizeSaveDim.cx = ( m_lpBMIH->biWidth * m_lpBMIH->biBitCount + 31)/32 * 4;
  801. sizeSaveDim.cy = m_lpBMIH->biHeight; 
  802. return sizeSaveDim;
  803. }
  804. /*************************************************************************
  805.  *
  806.  * 函数名称:
  807.  *   GetPixelOffset()
  808.  *
  809.  * 输入参数:
  810.  *   int x - 象素在X轴的坐标
  811.  *   int y - 象素在Y轴的坐标
  812.  *
  813.  * 返回值:
  814.  *   int - 返回象素在图象数据块中的真实地址
  815.  *
  816.  * 说明:
  817.  *   该函数得到坐标为(x,y)的象素点的真实地址。由于DIB结构中对图象数据排列的
  818.  *   方式为从下到上,从左到右的,所以需要进行转换。
  819.  *
  820.  ************************************************************************
  821.  */
  822. LONG CDib::GetPixelOffset(int  x, int y)
  823. {
  824. CSize sizeSaveDim;
  825. sizeSaveDim = GetDibSaveDim();
  826. LONG lOffset = (LONG) (sizeSaveDim.cy - y - 1) * sizeSaveDim.cx +
  827. x  / (8 / m_lpBMIH->biBitCount);
  828. return lOffset;
  829. }
  830. /*************************************************************************
  831.  *
  832.  * 函数名称:
  833.  *   GetPixel()
  834.  *
  835.  * 输入参数:
  836.  *   int x - 象素在X轴的坐标
  837.  *   int y - 象素在Y轴的坐标
  838.  *
  839.  * 返回值:
  840.  *   RGBQUAD - 返回DIB在该点真实的颜色
  841.  *
  842.  * 说明:
  843.  *   该函数得到DIB图象在该点真是的颜色。
  844.  *
  845.  ************************************************************************
  846.  */
  847. RGBQUAD CDib::GetPixel(int x, int y)
  848. {
  849. // 颜色结构
  850. RGBQUAD cColor;
  851. // 根据每象素比特数得到此点的象素值
  852. switch (m_lpBMIH->biBitCount)
  853. {
  854. case 1 :
  855. if (1<<(7-x%8) & *(LPBYTE)(m_lpImage+GetPixelOffset(x, y)))
  856. {
  857. cColor.rgbBlue  = 255;
  858. cColor.rgbGreen = 255;
  859. cColor.rgbRed   = 255;
  860. cColor.rgbReserved =0;
  861. }
  862. else
  863. {
  864. cColor.rgbBlue  = 0;
  865. cColor.rgbGreen = 0;
  866. cColor.rgbRed   = 0;
  867. cColor.rgbReserved =0;
  868. }
  869. break;
  870. case 4 :
  871. {
  872. int nIndex = (*(LPBYTE)(m_lpImage+GetPixelOffset(x, y)) & 
  873.    (x%2 ? 0x0f : 0xf0)) >> (x%2 ? 0 : 4);
  874. LPRGBQUAD pDibQuad = (LPRGBQUAD) (m_lpvColorTable) + nIndex;
  875. cColor.rgbBlue  = pDibQuad->rgbBlue;
  876. cColor.rgbGreen = pDibQuad->rgbGreen;
  877. cColor.rgbRed   = pDibQuad->rgbRed;
  878. cColor.rgbReserved =0;
  879. }
  880. break;
  881. case 8 :
  882. {
  883. int nIndex = *(BYTE*)(m_lpImage+GetPixelOffset(x, y));
  884. LPRGBQUAD pDibQuad = (LPRGBQUAD) (m_lpvColorTable) + nIndex;
  885. cColor.rgbBlue  = pDibQuad->rgbBlue;
  886. cColor.rgbGreen = pDibQuad->rgbGreen;
  887. cColor.rgbRed   = pDibQuad->rgbRed;
  888. cColor.rgbReserved =0;
  889. }
  890. break;
  891. default:
  892. int nIndex = *(BYTE*)(m_lpImage+GetPixelOffset(x, y));
  893. cColor.rgbRed   = m_lpImage[nIndex];
  894. cColor.rgbGreen = m_lpImage[nIndex + 1];
  895. cColor.rgbBlue  = m_lpImage[nIndex + 2];
  896. cColor.rgbReserved =0;
  897. break;
  898. }
  899. // 返回颜色结构
  900. return cColor;
  901. }