DIBAPI.CPP
上传用户:sgmlaoniu
上传日期:2013-03-16
资源大小:403k
文件大小:29k
源码类别:

Windows编程

开发平台:

Visual C++

  1. // ************************************************************************
  2. //  文件名:dibapi.cpp
  3. //
  4. //  DIB(Independent Bitmap) API函数库:
  5. //
  6. //  PaintDIB()          - 绘制DIB对象
  7. //  CreateDIBPalette()  - 创建DIB对象调色板
  8. //  FindDIBBits()       - 返回DIB图像象素起始位置
  9. //  DIBWidth()          - 返回DIB宽度
  10. //  DIBHeight()         - 返回DIB高度
  11. //  PaletteSize()       - 返回DIB调色板大小
  12. //  DIBNumColors()      - 计算DIB调色板颜色数目
  13. //  CopyHandle()        - 拷贝内存块
  14. //
  15. //  SaveDIB()           - 将DIB保存到指定文件中
  16. //  ReadDIBFile()       - 重指定文件中读取DIB对象
  17. //
  18. //  DIBToPCX256() - 将指定的256色DIB对象保存为256色PCX文件
  19. //  ReadPCX256() - 读取256色PCX文件
  20. //
  21. // ************************************************************************
  22. #include "stdafx.h"
  23. #include "dibapi.h"
  24. #include <io.h>
  25. #include <errno.h>
  26. #include <math.h>
  27. #include <direct.h>
  28. /*
  29.  * Dib文件头标志(字符串"BM",写DIB时用到该常数)
  30.  */
  31. #define DIB_HEADER_MARKER   ((WORD) ('M' << 8) | 'B')
  32. /*************************************************************************
  33.  *
  34.  * 函数名称:
  35.  *   PaintDIB()
  36.  *
  37.  * 参数:
  38.  *   HDC hDC            - 输出设备DC
  39.  *   LPRECT lpDCRect    - 绘制矩形区域
  40.  *   HDIB hDIB          - 指向DIB对象的指针
  41.  *   LPRECT lpDIBRect   - 要输出的DIB区域
  42.  *   CPalette* pPal     - 指向DIB对象调色板的指针
  43.  *
  44.  * 返回值:
  45.  *   BOOL               - 绘制成功返回TRUE,否则返回FALSE。
  46.  *
  47.  * 说明:
  48.  * 该函数主要用来绘制DIB对象。其中调用了StretchDIBits()或者
  49.  * SetDIBitsToDevice()来绘制DIB对象。输出的设备由由参数hDC指
  50.  * 定;绘制的矩形区域由参数lpDCRect指定;输出DIB的区域由参数
  51.  * lpDIBRect指定。
  52.  *
  53.  ************************************************************************/
  54. BOOL WINAPI PaintDIB(HDC     hDC,
  55. LPRECT  lpDCRect,
  56. HDIB    hDIB,
  57. LPRECT  lpDIBRect,
  58. CPalette* pPal)
  59. {
  60. LPSTR    lpDIBHdr;            // BITMAPINFOHEADER指针
  61. LPSTR    lpDIBBits;           // DIB象素指针
  62. BOOL     bSuccess=FALSE;      // 成功标志
  63. HPALETTE hPal=NULL;           // DIB调色板
  64. HPALETTE hOldPal=NULL;        // 以前的调色板
  65. // 判断DIB对象是否为空
  66. if (hDIB == NULL)
  67. {
  68. // 返回
  69. return FALSE;
  70. }
  71. // 锁定DIB
  72. lpDIBHdr  = (LPSTR) ::GlobalLock((HGLOBAL) hDIB);
  73. // 找到DIB图像象素起始位置
  74. lpDIBBits = ::FindDIBBits(lpDIBHdr);
  75. // 获取DIB调色板,并选中它
  76. if (pPal != NULL)
  77. {
  78. hPal = (HPALETTE) pPal->m_hObject;
  79. // 选中调色板
  80. hOldPal = ::SelectPalette(hDC, hPal, TRUE);
  81. }
  82. // 设置显示模式
  83. ::SetStretchBltMode(hDC, COLORONCOLOR);
  84. // 判断是调用StretchDIBits()还是SetDIBitsToDevice()来绘制DIB对象
  85. if ((RECTWIDTH(lpDCRect)  == RECTWIDTH(lpDIBRect)) &&
  86.    (RECTHEIGHT(lpDCRect) == RECTHEIGHT(lpDIBRect)))
  87. {
  88. // 原始大小,不用拉伸。
  89. bSuccess = ::SetDIBitsToDevice(hDC,                    // hDC
  90.    lpDCRect->left,             // DestX
  91.    lpDCRect->top,              // DestY
  92.    RECTWIDTH(lpDCRect),        // nDestWidth
  93.    RECTHEIGHT(lpDCRect),       // nDestHeight
  94.    lpDIBRect->left,            // SrcX
  95.    (int)DIBHeight(lpDIBHdr) -
  96.   lpDIBRect->top -
  97.   RECTHEIGHT(lpDIBRect),   // SrcY
  98.    0,                          // nStartScan
  99.    (WORD)DIBHeight(lpDIBHdr),  // nNumScans
  100.    lpDIBBits,                  // lpBits
  101.    (LPBITMAPINFO)lpDIBHdr,     // lpBitsInfo
  102.    DIB_RGB_COLORS);            // wUsage
  103. }
  104.     else
  105. {
  106. // 非原始大小,拉伸。
  107. bSuccess = ::StretchDIBits(hDC,                          // hDC
  108.    lpDCRect->left,                 // DestX
  109.    lpDCRect->top,                  // DestY
  110.    RECTWIDTH(lpDCRect),            // nDestWidth
  111.    RECTHEIGHT(lpDCRect),           // nDestHeight
  112.    lpDIBRect->left,                // SrcX
  113.    lpDIBRect->top,                 // SrcY
  114.    RECTWIDTH(lpDIBRect),           // wSrcWidth
  115.    RECTHEIGHT(lpDIBRect),          // wSrcHeight
  116.    lpDIBBits,                      // lpBits
  117.    (LPBITMAPINFO)lpDIBHdr,         // lpBitsInfo
  118.    DIB_RGB_COLORS,                 // wUsage
  119.    SRCCOPY);                       // dwROP
  120. }
  121.     // 解除锁定
  122. ::GlobalUnlock((HGLOBAL) hDIB);
  123. // 恢复以前的调色板
  124. if (hOldPal != NULL)
  125. {
  126. ::SelectPalette(hDC, hOldPal, TRUE);
  127. }
  128. // 返回
  129. return bSuccess;
  130. }
  131. /*************************************************************************
  132.  *
  133.  * 函数名称:
  134.  *   CreateDIBPalette()
  135.  *
  136.  * 参数:
  137.  *   HDIB hDIB          - 指向DIB对象的指针
  138.  *   CPalette* pPal     - 指向DIB对象调色板的指针
  139.  *
  140.  * 返回值:
  141.  *   BOOL               - 创建成功返回TRUE,否则返回FALSE。
  142.  *
  143.  * 说明:
  144.  *   该函数按照DIB创建一个逻辑调色板,从DIB中读取颜色表并存到调色板中,
  145.  * 最后按照该逻辑调色板创建一个新的调色板,并返回该调色板的句柄。这样
  146.  * 可以用最好的颜色来显示DIB图像。
  147.  *
  148.  ************************************************************************/
  149. BOOL WINAPI CreateDIBPalette(HDIB hDIB, CPalette* pPal)
  150. {
  151. // 指向逻辑调色板的指针
  152. LPLOGPALETTE lpPal;
  153. // 逻辑调色板的句柄
  154. HANDLE hLogPal;
  155. // 调色板的句柄
  156. HPALETTE hPal = NULL;
  157. // 循环变量
  158. int i;
  159. // 颜色表中的颜色数目
  160. WORD wNumColors;
  161. // 指向DIB的指针
  162. LPSTR lpbi;
  163. // 指向BITMAPINFO结构的指针(Win3.0)
  164. LPBITMAPINFO lpbmi;
  165. // 指向BITMAPCOREINFO结构的指针
  166. LPBITMAPCOREINFO lpbmc;
  167. // 表明是否是Win3.0 DIB的标记
  168. BOOL bWinStyleDIB;
  169. // 创建结果
  170. BOOL bResult = FALSE;
  171. // 判断DIB是否为空
  172. if (hDIB == NULL)
  173. {
  174. // 返回FALSE
  175. return FALSE;
  176. }
  177. // 锁定DIB
  178. lpbi = (LPSTR) ::GlobalLock((HGLOBAL) hDIB);
  179. // 获取指向BITMAPINFO结构的指针(Win3.0)
  180. lpbmi = (LPBITMAPINFO)lpbi;
  181. // 获取指向BITMAPCOREINFO结构的指针
  182. lpbmc = (LPBITMAPCOREINFO)lpbi;
  183. // 获取DIB中颜色表中的颜色数目
  184. wNumColors = ::DIBNumColors(lpbi);
  185. if (wNumColors != 0)
  186. {
  187. // 分配为逻辑调色板内存
  188. hLogPal = ::GlobalAlloc(GHND, sizeof(LOGPALETTE)
  189. + sizeof(PALETTEENTRY)
  190. * wNumColors);
  191. // 如果内存不足,退出
  192. if (hLogPal == 0)
  193. {
  194. // 解除锁定
  195. ::GlobalUnlock((HGLOBAL) hDIB);
  196. // 返回FALSE
  197. return FALSE;
  198. }
  199. lpPal = (LPLOGPALETTE) ::GlobalLock((HGLOBAL) hLogPal);
  200. // 设置版本号
  201. lpPal->palVersion = PALVERSION;
  202. // 设置颜色数目
  203. lpPal->palNumEntries = (WORD)wNumColors;
  204. // 判断是否是WIN3.0的DIB
  205. bWinStyleDIB = IS_WIN30_DIB(lpbi);
  206. // 读取调色板
  207. for (i = 0; i < (int)wNumColors; i++)
  208. {
  209. if (bWinStyleDIB)
  210. {
  211. // 读取红色分量
  212. lpPal->palPalEntry[i].peRed = lpbmi->bmiColors[i].rgbRed;
  213. // 读取绿色分量
  214. lpPal->palPalEntry[i].peGreen = lpbmi->bmiColors[i].rgbGreen;
  215. // 读取蓝色分量
  216. lpPal->palPalEntry[i].peBlue = lpbmi->bmiColors[i].rgbBlue;
  217. // 保留位
  218. lpPal->palPalEntry[i].peFlags = 0;
  219. }
  220. else
  221. {
  222. // 读取红色分量
  223. lpPal->palPalEntry[i].peRed = lpbmc->bmciColors[i].rgbtRed;
  224. // 读取绿色分量
  225. lpPal->palPalEntry[i].peGreen = lpbmc->bmciColors[i].rgbtGreen;
  226. // 读取红色分量
  227. lpPal->palPalEntry[i].peBlue = lpbmc->bmciColors[i].rgbtBlue;
  228. // 保留位
  229. lpPal->palPalEntry[i].peFlags = 0;
  230. }
  231. }
  232. // 按照逻辑调色板创建调色板,并返回指针
  233. bResult = pPal->CreatePalette(lpPal);
  234. // 解除锁定
  235. ::GlobalUnlock((HGLOBAL) hLogPal);
  236. // 释放逻辑调色板
  237. ::GlobalFree((HGLOBAL) hLogPal);
  238. }
  239. // 解除锁定
  240. ::GlobalUnlock((HGLOBAL) hDIB);
  241. // 返回结果
  242. return bResult;
  243. }
  244. /*************************************************************************
  245.  *
  246.  * 函数名称:
  247.  *   FindDIBBits()
  248.  *
  249.  * 参数:
  250.  *   LPSTR lpbi         - 指向DIB对象的指针
  251.  *
  252.  * 返回值:
  253.  *   LPSTR              - 指向DIB图像象素起始位置
  254.  *
  255.  * 说明:
  256.  *   该函数计算DIB中图像象素的起始位置,并返回指向它的指针。
  257.  *
  258.  ************************************************************************/
  259. LPSTR WINAPI FindDIBBits(LPSTR lpbi)
  260. {
  261. return (lpbi + *(LPDWORD)lpbi + ::PaletteSize(lpbi));
  262. }
  263. /*************************************************************************
  264.  *
  265.  * 函数名称:
  266.  *   DIBWidth()
  267.  *
  268.  * 参数:
  269.  *   LPSTR lpbi         - 指向DIB对象的指针
  270.  *
  271.  * 返回值:
  272.  *   DWORD              - DIB中图像的宽度
  273.  *
  274.  * 说明:
  275.  *   该函数返回DIB中图像的宽度。对于Windows 3.0 DIB,返回BITMAPINFOHEADER
  276.  * 中的biWidth值;对于其它返回BITMAPCOREHEADER中的bcWidth值。
  277.  *
  278.  ************************************************************************/
  279. DWORD WINAPI DIBWidth(LPSTR lpDIB)
  280. {
  281. // 指向BITMAPINFO结构的指针(Win3.0)
  282. LPBITMAPINFOHEADER lpbmi;
  283. // 指向BITMAPCOREINFO结构的指针
  284. LPBITMAPCOREHEADER lpbmc;
  285. // 获取指针
  286. lpbmi = (LPBITMAPINFOHEADER)lpDIB;
  287. lpbmc = (LPBITMAPCOREHEADER)lpDIB;
  288. // 返回DIB中图像的宽度
  289. if (IS_WIN30_DIB(lpDIB))
  290. {
  291. // 对于Windows 3.0 DIB,返回lpbmi->biWidth
  292. return lpbmi->biWidth;
  293. }
  294. else
  295. {
  296. // 对于其它格式的DIB,返回lpbmc->bcWidth
  297. return (DWORD)lpbmc->bcWidth;
  298. }
  299. }
  300. /*************************************************************************
  301.  *
  302.  * 函数名称:
  303.  *   DIBHeight()
  304.  *
  305.  * 参数:
  306.  *   LPSTR lpDIB        - 指向DIB对象的指针
  307.  *
  308.  * 返回值:
  309.  *   DWORD              - DIB中图像的高度
  310.  *
  311.  * 说明:
  312.  *   该函数返回DIB中图像的高度。对于Windows 3.0 DIB,返回BITMAPINFOHEADER
  313.  * 中的biHeight值;对于其它返回BITMAPCOREHEADER中的bcHeight值。
  314.  *
  315.  ************************************************************************/
  316. DWORD WINAPI DIBHeight(LPSTR lpDIB)
  317. {
  318. // 指向BITMAPINFO结构的指针(Win3.0)
  319. LPBITMAPINFOHEADER lpbmi;
  320. // 指向BITMAPCOREINFO结构的指针
  321. LPBITMAPCOREHEADER lpbmc;
  322. // 获取指针
  323. lpbmi = (LPBITMAPINFOHEADER)lpDIB;
  324. lpbmc = (LPBITMAPCOREHEADER)lpDIB;
  325. // 返回DIB中图像的宽度
  326. if (IS_WIN30_DIB(lpDIB))
  327. {
  328. // 对于Windows 3.0 DIB,返回lpbmi->biHeight
  329. return lpbmi->biHeight;
  330. }
  331. else
  332. {
  333. // 对于其它格式的DIB,返回lpbmc->bcHeight
  334. return (DWORD)lpbmc->bcHeight;
  335. }
  336. }
  337. /*************************************************************************
  338.  *
  339.  * 函数名称:
  340.  *   PaletteSize()
  341.  *
  342.  * 参数:
  343.  *   LPSTR lpbi         - 指向DIB对象的指针
  344.  *
  345.  * 返回值:
  346.  *   WORD               - DIB中调色板的大小
  347.  *
  348.  * 说明:
  349.  *   该函数返回DIB中调色板的大小。对于Windows 3.0 DIB,返回颜色数目×
  350.  * RGBQUAD的大小;对于其它返回颜色数目×RGBTRIPLE的大小。
  351.  *
  352.  ************************************************************************/
  353. WORD WINAPI PaletteSize(LPSTR lpbi)
  354. {
  355. // 计算DIB中调色板的大小
  356. if (IS_WIN30_DIB (lpbi))
  357. {
  358. //返回颜色数目×RGBQUAD的大小
  359. return (WORD)(::DIBNumColors(lpbi) * sizeof(RGBQUAD));
  360. }
  361. else
  362. {
  363. //返回颜色数目×RGBTRIPLE的大小
  364. return (WORD)(::DIBNumColors(lpbi) * sizeof(RGBTRIPLE));
  365. }
  366. }
  367. /*************************************************************************
  368.  *
  369.  * 函数名称:
  370.  *   DIBNumColors()
  371.  *
  372.  * 参数:
  373.  *   LPSTR lpbi         - 指向DIB对象的指针
  374.  *
  375.  * 返回值:
  376.  *   WORD               - 返回调色板中颜色的种数
  377.  *
  378.  * 说明:
  379.  *   该函数返回DIB中调色板的颜色的种数。对于单色位图,返回2,
  380.  * 对于16色位图,返回16,对于256色位图,返回256;对于真彩色
  381.  * 位图(24位),没有调色板,返回0。
  382.  *
  383.  ************************************************************************/
  384. WORD WINAPI DIBNumColors(LPSTR lpbi)
  385. {
  386. WORD wBitCount;
  387. // 对于Windows的DIB, 实际颜色的数目可以比象素的位数要少。
  388. // 对于这种情况,则返回一个近似的数值。
  389. // 判断是否是WIN3.0 DIB
  390. if (IS_WIN30_DIB(lpbi))
  391. {
  392. DWORD dwClrUsed;
  393. // 读取dwClrUsed值
  394. dwClrUsed = ((LPBITMAPINFOHEADER)lpbi)->biClrUsed;
  395. if (dwClrUsed != 0)
  396. {
  397. // 如果dwClrUsed(实际用到的颜色数)不为0,直接返回该值
  398. return (WORD)dwClrUsed;
  399. }
  400. }
  401. // 读取象素的位数
  402. if (IS_WIN30_DIB(lpbi))
  403. {
  404. // 读取biBitCount值
  405. wBitCount = ((LPBITMAPINFOHEADER)lpbi)->biBitCount;
  406. }
  407. else
  408. {
  409. // 读取biBitCount值
  410. wBitCount = ((LPBITMAPCOREHEADER)lpbi)->bcBitCount;
  411. }
  412. // 按照象素的位数计算颜色数目
  413. switch (wBitCount)
  414. {
  415. case 1:
  416. return 2;
  417. case 4:
  418. return 16;
  419. case 8:
  420. return 256;
  421. default:
  422. return 0;
  423. }
  424. }
  425. /*************************************************************************
  426.  *
  427.  * 函数名称:
  428.  *   DIBBitCount()
  429.  *
  430.  * 参数:
  431.  *   LPSTR lpbi         - 指向DIB对象的指针
  432.  *
  433.  * 返回值:
  434.  *   WORD               - 返回调色板中颜色的种数
  435.  *
  436.  * 说明:
  437.  *   该函数返回DIBBitCount。
  438.  *
  439.  ************************************************************************/
  440. WORD WINAPI DIBBitCount(LPSTR lpbi)
  441. {
  442. WORD wBitCount;
  443. // 读取象素的位数
  444. if (IS_WIN30_DIB(lpbi))
  445. {
  446. // 读取biBitCount值
  447. wBitCount = ((LPBITMAPINFOHEADER)lpbi)->biBitCount;
  448. }
  449. else
  450. {
  451. // 读取biBitCount值
  452. wBitCount = ((LPBITMAPCOREHEADER)lpbi)->bcBitCount;
  453. }
  454. // 返回wBitCount
  455. return wBitCount;
  456. }
  457. /*************************************************************************
  458.  *
  459.  * 函数名称:
  460.  *   CopyHandle()
  461.  *
  462.  * 参数:
  463.  *   HGLOBAL h          - 要复制的内存区域
  464.  *
  465.  * 返回值:
  466.  *   HGLOBAL            - 复制后的新内存区域
  467.  *
  468.  * 说明:
  469.  *   该函数复制指定的内存区域。返回复制后的新内存区域,出错时返回0。
  470.  *
  471.  ************************************************************************/
  472. HGLOBAL WINAPI CopyHandle (HGLOBAL h)
  473. {
  474. if (h == NULL)
  475. return NULL;
  476. // 获取指定内存区域大小
  477. DWORD dwLen = ::GlobalSize((HGLOBAL) h);
  478. // 分配新内存空间
  479. HGLOBAL hCopy = ::GlobalAlloc(GHND, dwLen);
  480. // 判断分配是否成功
  481. if (hCopy != NULL)
  482. {
  483. // 锁定
  484. void* lpCopy = ::GlobalLock((HGLOBAL) hCopy);
  485. void* lp     = ::GlobalLock((HGLOBAL) h);
  486. // 复制
  487. memcpy(lpCopy, lp, dwLen);
  488. // 解除锁定
  489. ::GlobalUnlock(hCopy);
  490. ::GlobalUnlock(h);
  491. }
  492. return hCopy;
  493. }
  494. /*************************************************************************
  495.  *
  496.  * 函数名称:
  497.  *   SaveDIB()
  498.  *
  499.  * 参数:
  500.  *   HDIB hDib          - 要保存的DIB
  501.  *   CFile& file        - 保存文件CFile
  502.  *
  503.  * 返回值:
  504.  *   BOOL               - 成功返回TRUE,否则返回FALSE或者CFileException
  505.  *
  506.  * 说明:
  507.  *   该函数将指定的DIB对象保存到指定的CFile中。该CFile由调用程序打开和关闭。
  508.  *
  509.  *************************************************************************/
  510. BOOL WINAPI SaveDIB(HDIB hDib, CFile& file)
  511. {
  512. // Bitmap文件头
  513. BITMAPFILEHEADER bmfHdr;
  514. // 指向BITMAPINFOHEADER的指针
  515. LPBITMAPINFOHEADER lpBI;
  516. // DIB大小
  517. DWORD dwDIBSize;
  518. if (hDib == NULL)
  519. {
  520. // 如果DIB为空,返回FALSE
  521. return FALSE;
  522. }
  523. // 读取BITMAPINFO结构,并锁定
  524. lpBI = (LPBITMAPINFOHEADER) ::GlobalLock((HGLOBAL) hDib);
  525. if (lpBI == NULL)
  526. {
  527. // 为空,返回FALSE
  528. return FALSE;
  529. }
  530. // 判断是否是WIN3.0 DIB
  531. if (!IS_WIN30_DIB(lpBI))
  532. {
  533. // 不支持其它类型的DIB保存
  534. // 解除锁定
  535. ::GlobalUnlock((HGLOBAL) hDib);
  536. // 返回FALSE
  537. return FALSE;
  538. }
  539. // 填充文件头
  540. // 文件类型"BM"
  541. bmfHdr.bfType = DIB_HEADER_MARKER;
  542. // 计算DIB大小时,最简单的方法是调用GlobalSize()函数。但是全局内存大小并
  543. // 不是DIB真正的大小,它总是多几个字节。这样就需要计算一下DIB的真实大小。
  544. // 文件头大小+颜色表大小
  545. // (BITMAPINFOHEADER和BITMAPCOREHEADER结构的第一个DWORD都是该结构的大小)
  546. dwDIBSize = *(LPDWORD)lpBI + ::PaletteSize((LPSTR)lpBI);
  547. // 计算图像大小
  548. if ((lpBI->biCompression == BI_RLE8) || (lpBI->biCompression == BI_RLE4))
  549. {
  550. // 对于RLE位图,没法计算大小,只能信任biSizeImage内的值
  551. dwDIBSize += lpBI->biSizeImage;
  552. }
  553. else
  554. {
  555. // 象素的大小
  556. DWORD dwBmBitsSize;
  557. // 大小为Width * Height
  558. dwBmBitsSize = WIDTHBYTES((lpBI->biWidth)*((DWORD)lpBI->biBitCount)) * lpBI->biHeight;
  559. // 计算出DIB真正的大小
  560. dwDIBSize += dwBmBitsSize;
  561. // 更新biSizeImage(很多BMP文件头中biSizeImage的值是错误的)
  562. lpBI->biSizeImage = dwBmBitsSize;
  563. }
  564. // 计算文件大小:DIB大小+BITMAPFILEHEADER结构大小
  565. bmfHdr.bfSize = dwDIBSize + sizeof(BITMAPFILEHEADER);
  566. // 两个保留字
  567. bmfHdr.bfReserved1 = 0;
  568. bmfHdr.bfReserved2 = 0;
  569. // 计算偏移量bfOffBits,它的大小为Bitmap文件头大小+DIB头大小+颜色表大小
  570. bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + lpBI->biSize
  571.   + PaletteSize((LPSTR)lpBI);
  572. // 尝试写文件
  573. TRY
  574. {
  575. // 写文件头
  576. file.Write((LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER));
  577. // 写DIB头和象素
  578. file.WriteHuge(lpBI, dwDIBSize);
  579. }
  580. CATCH (CFileException, e)
  581. {
  582. // 解除锁定
  583. ::GlobalUnlock((HGLOBAL) hDib);
  584. // 抛出异常
  585. THROW_LAST();
  586. }
  587. END_CATCH
  588. // 解除锁定
  589. ::GlobalUnlock((HGLOBAL) hDib);
  590. // 返回TRUE
  591. return TRUE;
  592. }
  593. /*************************************************************************
  594.  *
  595.  * 函数名称:
  596.  *   ReadDIBFile()
  597.  *
  598.  * 参数:
  599.  *   CFile& file        - 要读取得文件文件CFile
  600.  *
  601.  * 返回值:
  602.  *   HDIB               - 成功返回DIB的句柄,否则返回NULL。
  603.  *
  604.  * 说明:
  605.  *   该函数将指定的文件中的DIB对象读到指定的内存区域中。除BITMAPFILEHEADER
  606.  * 外的内容都将被读入内存。
  607.  *
  608.  *************************************************************************/
  609. HDIB WINAPI ReadDIBFile(CFile& file)
  610. {
  611. BITMAPFILEHEADER bmfHeader;
  612. DWORD dwBitsSize;
  613. HDIB hDIB;
  614. LPSTR pDIB;
  615. // 获取DIB(文件)长度(字节)
  616. dwBitsSize = file.GetLength();
  617. // 尝试读取DIB文件头
  618. if (file.Read((LPSTR)&bmfHeader, sizeof(bmfHeader)) != sizeof(bmfHeader))
  619. {
  620. // 大小不对,返回NULL。
  621. return NULL;
  622. }
  623. // 判断是否是DIB对象,检查头两个字节是否是"BM"
  624. if (bmfHeader.bfType != DIB_HEADER_MARKER)
  625. {
  626. // 非DIB对象,返回NULL。
  627. return NULL;
  628. }
  629. // 为DIB分配内存
  630. hDIB = (HDIB) ::GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, dwBitsSize);
  631. if (hDIB == 0)
  632. {
  633. // 内存分配失败,返回NULL。
  634. return NULL;
  635. }
  636. // 锁定
  637. pDIB = (LPSTR) ::GlobalLock((HGLOBAL) hDIB);
  638. // 读象素
  639. if (file.ReadHuge(pDIB, dwBitsSize - sizeof(BITMAPFILEHEADER)) !=
  640. dwBitsSize - sizeof(BITMAPFILEHEADER) )
  641. {
  642. // 大小不对。
  643. // 解除锁定
  644. ::GlobalUnlock((HGLOBAL) hDIB);
  645. // 释放内存
  646. ::GlobalFree((HGLOBAL) hDIB);
  647. // 返回NULL。
  648. return NULL;
  649. }
  650. // 解除锁定
  651. ::GlobalUnlock((HGLOBAL) hDIB);
  652. // 返回DIB句柄
  653. return hDIB;
  654. }
  655. /*************************************************************************
  656.  *
  657.  * 函数名称:
  658.  *   DIBToPCX256()
  659.  *
  660.  * 参数:
  661.  *   LPSTR lpDIB        - 指向DIB对象的指针
  662.  *   CFile& file        - 要保存的文件
  663.  *
  664.  * 返回值:
  665.  *   BOOL               - 成功返回True,否则返回False。
  666.  *
  667.  * 说明:
  668.  *   该函数将指定的256色DIB对象保存为256色PCX文件。
  669.  *
  670.  *************************************************************************/
  671. BOOL WINAPI DIBToPCX256(LPSTR lpDIB, CFile& file)
  672. {
  673. // 循环变量
  674. LONG i;
  675. LONG j;
  676. // DIB高度
  677. WORD wHeight;
  678. // DIB宽度
  679. WORD wWidth;
  680. // 中间变量
  681. BYTE bChar1;
  682. BYTE bChar2;
  683. // 指向源图像象素的指针
  684. BYTE * lpSrc;
  685. // 指向编码后图像数据的指针
  686. BYTE * lpDst;
  687. // 图像每行的字节数
  688. LONG lLineBytes;
  689. // 重复像素计数
  690. int iCount;
  691. // 缓冲区已使用的字节数
  692. DWORD dwBuffUsed;
  693. // 指向DIB象素指针
  694. LPSTR   lpDIBBits;
  695. // 获取DIB高度
  696. wHeight = (WORD) DIBHeight(lpDIB);
  697. // 获取DIB宽度
  698. wWidth  = (WORD) DIBWidth(lpDIB);
  699. // 找到DIB图像象素起始位置
  700. lpDIBBits = FindDIBBits(lpDIB);
  701. // 计算图像每行的字节数
  702. lLineBytes = WIDTHBYTES(wWidth * 8);
  703. //*************************************************************************
  704. // PCX文件头
  705. PCXHEADER pcxHdr;
  706. // 给文件头赋值
  707. // PCX标识码
  708. pcxHdr.bManufacturer = 0x0A;
  709. // PCX版本号
  710. pcxHdr.bVersion = 5;
  711. // PCX编码方式(1表示RLE编码)
  712. pcxHdr.bEncoding = 1;
  713. // 像素位数(256色为8位)
  714. pcxHdr.bBpp = 8;
  715. // 图像相对于屏幕的左上角X坐标(以像素为单位)
  716. pcxHdr.wLeft = 0;
  717. // 图像相对于屏幕的左上角Y坐标(以像素为单位)
  718. pcxHdr.wTop = 0;
  719. // 图像相对于屏幕的右下角X坐标(以像素为单位)
  720. pcxHdr.wRight = wWidth - 1;
  721. // 图像相对于屏幕的右下角Y坐标(以像素为单位)
  722. pcxHdr.wBottom = wHeight - 1;
  723. // 图像的水平分辨率
  724. pcxHdr.wXResolution = wWidth;
  725. // 图像的垂直分辨率
  726. pcxHdr.wYResolution = wHeight;
  727. // 调色板数据(对于256色PCX无意义,直接赋值为0)
  728. for (i = 0; i < 48; i ++)
  729. {
  730. pcxHdr.bPalette[i] = 0;
  731. }
  732. // 保留域,设定为0。
  733. pcxHdr.bReserved = 0;
  734. // 图像色彩平面数目(对于256色PCX设定为1)。
  735. pcxHdr.bPlanes = 1;
  736. // 图像的宽度(字节为单位),必须为偶数。
  737. // if ((wWidth & 1) == 0)
  738. // {
  739. pcxHdr.wLineBytes = wWidth;
  740. // }
  741. // else
  742. // {
  743. // pcxHdr.wLineBytes = wWidth + 1;
  744. // }
  745. // 图像调色板的类型,1表示彩色或者单色图像,2表示图像是灰度图。
  746. pcxHdr.wPaletteType = 1;
  747. // 制作该图像的屏幕宽度(像素为单位)
  748. pcxHdr.wSrcWidth = 0;
  749. // 制作该图像的屏幕高度(像素为单位)
  750. pcxHdr.wSrcDepth = 0;
  751. // 保留域,取值设定为0。
  752. for (i = 0; i < 54; i ++)
  753. {
  754. pcxHdr.bFiller[i] = 0;
  755. }
  756. // 写入文件头
  757. file.Write((LPSTR)&pcxHdr, sizeof(PCXHEADER));
  758. //*******************************************************************************
  759. // 开始编码
  760. // 开辟一片缓冲区(2被原始图像大小)以保存编码结果
  761. lpDst = new BYTE[wHeight * wWidth * 2];
  762. // 指明当前已经用了多少缓冲区(字节数)
  763. dwBuffUsed = 0;
  764. // 每行
  765. for (i = 0; i < wHeight; i++)
  766. {
  767. // 指向DIB第i行,第0个象素的指针
  768. lpSrc = (BYTE *)lpDIBBits + lLineBytes * (wHeight - 1 - i);
  769. // 给bChar1赋值
  770. bChar1 = *lpSrc;
  771. // 设置iCount为1
  772. iCount = 1;
  773. // 剩余列
  774. for (j = 1; j < wWidth; j ++)
  775. {
  776. // 指向DIB第i行,第j个象素的指针
  777. lpSrc++;
  778. // 读取下一个像素
  779. bChar2 = *lpSrc;
  780. // 判断是否和bChar1相同并且iCount < 63
  781. if ((bChar1 == bChar2) && (iCount < 63))
  782. {
  783. // 相同,计数加1
  784. iCount ++;
  785. // 继续读下一个
  786. }
  787. else
  788. {
  789. // 不同,或者iCount = 63
  790. // 写入缓冲区
  791. if ((iCount > 1) || (bChar1 >= 0xC0))
  792. {
  793. // 保存码长信息
  794. lpDst[dwBuffUsed] = iCount | 0xC0;
  795. // 保存bChar1
  796. lpDst[dwBuffUsed + 1] = bChar1;
  797. // 更新dwBuffUsed
  798. dwBuffUsed += 2;
  799. }
  800. else
  801. {
  802. // 直接保存该值
  803. lpDst[dwBuffUsed] = bChar1;
  804. // 更新dwBuffUsed
  805. dwBuffUsed ++;
  806. }
  807. // 重新给bChar1赋值
  808. bChar1 = bChar2;
  809. // 设置iCount为1
  810. iCount = 1;
  811. }
  812. }
  813. // 保存每行最后一部分编码
  814. if ((iCount > 1) || (bChar1 >= 0xC0))
  815. {
  816. // 保存码长信息
  817. lpDst[dwBuffUsed] = iCount | 0xC0;
  818. // 保存bChar1
  819. lpDst[dwBuffUsed + 1] = bChar1;
  820. // 更新dwBuffUsed
  821. dwBuffUsed += 2;
  822. }
  823. else
  824. {
  825. // 直接保存该值
  826. lpDst[dwBuffUsed] = bChar1;
  827. // 更新dwBuffUsed
  828. dwBuffUsed ++;
  829. }
  830. }
  831. // 写入编码结果
  832. file.WriteHuge((LPSTR)lpDst, dwBuffUsed);
  833. // 释放内存
  834. delete lpDst;
  835. //**************************************************************************
  836. // 写入调色板信息
  837. // 指向BITMAPINFO结构的指针(Win3.0)
  838. LPBITMAPINFO lpbmi;
  839. // 指向BITMAPCOREINFO结构的指针
  840. LPBITMAPCOREINFO lpbmc;
  841. // 表明是否是Win3.0 DIB的标记
  842. BOOL bWinStyleDIB;
  843. // 开辟一片缓冲区以保存调色板
  844. lpDst = new BYTE[769];
  845. // 调色板起始字节
  846. * lpDst = 0x0C;
  847. // 获取指向BITMAPINFO结构的指针(Win3.0)
  848. lpbmi = (LPBITMAPINFO)lpDIB;
  849. // 获取指向BITMAPCOREINFO结构的指针
  850. lpbmc = (LPBITMAPCOREINFO)lpDIB;
  851. // 判断是否是WIN3.0的DIB
  852. bWinStyleDIB = IS_WIN30_DIB(lpDIB);
  853. // 读取当前DIB调色板
  854. for (i = 0; i < 256; i ++)
  855. {
  856. if (bWinStyleDIB)
  857. {
  858. // 读取DIB调色板红色分量
  859. lpDst[i * 3 + 1] = lpbmi->bmiColors[i].rgbRed;
  860. // 读取DIB调色板绿色分量
  861. lpDst[i * 3 + 2] = lpbmi->bmiColors[i].rgbGreen;
  862. // 读取DIB调色板蓝色分量
  863. lpDst[i * 3 + 3] = lpbmi->bmiColors[i].rgbBlue;
  864. }
  865. else
  866. {
  867. // 读取DIB调色板红色分量
  868. lpDst[i * 3 + 1] = lpbmc->bmciColors[i].rgbtRed;
  869. // 读取DIB调色板绿色分量
  870. lpDst[i * 3 + 2] = lpbmc->bmciColors[i].rgbtGreen;
  871. // 读取DIB调色板蓝色分量
  872. lpDst[i * 3 + 3] = lpbmc->bmciColors[i].rgbtBlue;
  873. }
  874. }
  875. // 写入调色板信息
  876. file.Write((LPSTR)lpDst, 769);
  877. // 返回
  878. return TRUE;
  879. }
  880. /*************************************************************************
  881.  *
  882.  * 函数名称:
  883.  *   ReadPCX256()
  884.  *
  885.  * 参数:
  886.  *   CFile& file        - 要读取的文件
  887.  *
  888.  * 返回值:
  889.  *   HDIB               - 成功返回DIB的句柄,否则返回NULL。
  890.  *
  891.  * 说明:
  892.  *   该函数将读取指定的256色PCX文件。将读取的结果保存在一个未压缩
  893.  * 编码的DIB对象中。
  894.  *
  895.  *************************************************************************/
  896. HDIB WINAPI ReadPCX256(CFile& file)
  897. {
  898. // PCX文件头
  899. PCXHEADER pcxHdr;
  900. // DIB大小(字节数)
  901. DWORD dwDIBSize;
  902. // DIB句柄
  903. HDIB hDIB;
  904. // DIB指针
  905. LPSTR pDIB;
  906. // 循环变量
  907. LONG i;
  908. LONG j;
  909. // 重复像素计数
  910. int iCount;
  911. // DIB高度
  912. WORD wHeight;
  913. // DIB宽度
  914. WORD wWidth;
  915. // 图像每行的字节数
  916. LONG lLineBytes;
  917. // 中间变量
  918. BYTE bChar;
  919. // 指向源图像象素的指针
  920. BYTE * lpSrc;
  921. // 指向编码后图像数据的指针
  922. BYTE * lpDst;
  923. // 临时指针
  924. BYTE * lpTemp;
  925. // 尝试读取PCX文件头
  926. if (file.Read((LPSTR)&pcxHdr, sizeof(PCXHEADER)) != sizeof(PCXHEADER))
  927. {
  928. // 大小不对,返回NULL。
  929. return NULL;
  930. }
  931. // 判断是否是256色PCX文件,检查第一个字节是否是0x0A,
  932. if ((pcxHdr.bManufacturer != 0x0A) || (pcxHdr.bBpp != 8) || (pcxHdr.bPlanes != 1))
  933. {
  934. // 非256色PCX文件,返回NULL。
  935. return NULL;
  936. }
  937. // 获取图像高度
  938. wHeight = pcxHdr.wBottom - pcxHdr.wTop + 1;
  939. // 获取图像宽度
  940. wWidth  = pcxHdr.wRight - pcxHdr.wLeft + 1;
  941. // 计算图像每行的字节数
  942. lLineBytes = WIDTHBYTES(wWidth * 8);
  943. // 计算DIB长度(字节)
  944. dwDIBSize = sizeof(BITMAPINFOHEADER) + 1024 + wHeight * lLineBytes;
  945. // 为DIB分配内存
  946. hDIB = (HDIB) ::GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, dwDIBSize);
  947. if (hDIB == 0)
  948. {
  949. // 内存分配失败,返回NULL。
  950. return NULL;
  951. }
  952. // 锁定
  953. pDIB = (LPSTR) ::GlobalLock((HGLOBAL) hDIB);
  954. // 指向BITMAPINFOHEADER的指针
  955. LPBITMAPINFOHEADER lpBI;
  956. // 赋值
  957. lpBI = (LPBITMAPINFOHEADER) pDIB;
  958. // 给lpBI成员赋值
  959. lpBI->biSize = 40;
  960. lpBI->biWidth = wWidth;
  961. lpBI->biHeight = wHeight;
  962. lpBI->biPlanes = 1;
  963. lpBI->biBitCount = 8;
  964. lpBI->biCompression = BI_RGB;
  965. lpBI->biSizeImage = wHeight * lLineBytes;
  966. lpBI->biXPelsPerMeter = pcxHdr.wXResolution;
  967. lpBI->biYPelsPerMeter = pcxHdr.wYResolution;
  968. lpBI->biClrUsed = 0;
  969. lpBI->biClrImportant = 0;
  970. // 分配内存以读取编码后的象素
  971. lpSrc = new BYTE[file.GetLength() - sizeof(PCXHEADER) - 769];
  972. lpTemp = lpSrc;
  973. // 读取编码后的象素
  974. if (file.ReadHuge(lpSrc, file.GetLength() - sizeof(PCXHEADER) - 769) !=
  975. file.GetLength() - sizeof(PCXHEADER) - 769 )
  976. {
  977. // 大小不对。
  978. // 解除锁定
  979. ::GlobalUnlock((HGLOBAL) hDIB);
  980. // 释放内存
  981. ::GlobalFree((HGLOBAL) hDIB);
  982. // 返回NULL。
  983. return NULL;
  984. }
  985. // 计算DIB中像素位置
  986. lpDst = (BYTE *) FindDIBBits(pDIB);
  987. // 一行一行解码
  988. for (j = 0; j <wHeight; j++)
  989. {
  990. i = 0;
  991. while (i < wWidth)
  992. {
  993. // 读取一个字节
  994. bChar = *lpTemp;
  995. lpTemp++;
  996. if ((bChar & 0xC0) == 0xC0)
  997. {
  998. // 行程
  999. iCount = bChar & 0x3F;
  1000. // 读取下一个字节
  1001. bChar = *lpTemp;
  1002. lpTemp++;
  1003. // bChar重复iCount次保存
  1004. memset(&lpDst[(wHeight - j - 1) * lLineBytes + i], bChar, iCount);
  1005. // 已经读取像素的个数加iCount
  1006. i += iCount;
  1007. }
  1008. else
  1009. {
  1010. // 保存当前字节
  1011. lpDst[(wHeight - j - 1) * lLineBytes + i] = bChar;
  1012. // 已经读取像素的个数加1
  1013. i += 1;
  1014. }
  1015. }
  1016. }
  1017. // 释放内存
  1018. delete lpSrc;
  1019. //*************************************************************
  1020. // 调色板
  1021. // 读调色板标志位
  1022. file.Read(&bChar, 1);
  1023. if (bChar != 0x0C)
  1024. {
  1025. // 出错
  1026. // 解除锁定
  1027. ::GlobalUnlock((HGLOBAL) hDIB);
  1028. // 释放内存
  1029. ::GlobalFree((HGLOBAL) hDIB);
  1030. // 返回NULL。
  1031. return NULL;
  1032. }
  1033. // 分配内存以读取编码后的象素
  1034. lpSrc = new BYTE[768];
  1035. // 计算DIB中调色板的位置
  1036. lpDst = (BYTE *) pDIB + sizeof(BITMAPINFOHEADER);
  1037. // 读取调色板
  1038. if (file.Read(lpSrc, 768) != 768)
  1039. {
  1040. // 大小不对。
  1041. // 解除锁定
  1042. ::GlobalUnlock((HGLOBAL) hDIB);
  1043. // 释放内存
  1044. ::GlobalFree((HGLOBAL) hDIB);
  1045. // 返回NULL。
  1046. return NULL;
  1047. }
  1048. // 给调色板赋值
  1049. for (i = 0; i < 256; i++)
  1050. {
  1051. lpDst[i * 4] = lpSrc[i * 3 + 2];
  1052. lpDst[i * 4 + 1] = lpSrc[i * 3 + 1];
  1053. lpDst[i * 4 + 2] = lpSrc[i * 3];
  1054. lpDst[i * 4 + 3] = 0;
  1055. }
  1056. // 释放内存
  1057. delete lpSrc;
  1058. // 解除锁定
  1059. ::GlobalUnlock((HGLOBAL) hDIB);
  1060. // 返回DIB句柄
  1061. return hDIB;
  1062. }
  1063. /**************************************************************************** 
  1064. *     FUNCTION: BytesPerLine 
  1065. *     PURPOSE:  Calculates the number of bytes in one scan line. 
  1066. *     PARAMS:   LPBYTE lpDIB - pointer to the BITMAPINFOHEADER 
  1067.                               that begins the CF_DIB block 
  1068. *     RETURNS:  DWORD - number of bytes in one scan line (DWORD aligned) 
  1069. ****************************************************************************/ 
  1070. DWORD BytesPerLine(LPBYTE lpDIB) 
  1071.     return WIDTHBYTES(((LPBITMAPINFOHEADER)lpDIB)->biWidth * ((LPBITMAPINFOHEADER)lpDIB)->biPlanes * ((LPBITMAPINFOHEADER)lpDIB)->biBitCount); 
  1072. DWORD BytesPerLine(HDIB hDIB) 
  1073. LPBYTE lpDIB = (LPBYTE)GlobalLock(hDIB);
  1074. DWORD dw = BytesPerLine(lpDIB);
  1075. GlobalUnlock(hDIB);
  1076. return dw;