Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

851 lines
23 KiB

  1. /*************************************************
  2. * dib.cpp *
  3. * *
  4. * Copyright (C) 1995-1999 Microsoft Inc. *
  5. * *
  6. *************************************************/
  7. // dib.cpp : implementation file
  8. //
  9. //
  10. #include "stdafx.h"
  11. #include "dib.h"
  12. #include "malloc.h"
  13. #ifdef _DEBUG
  14. #undef THIS_FILE
  15. static char BASED_CODE THIS_FILE[] = __FILE__;
  16. #endif
  17. #define WIDTHBYTES(i) ((i+31)/32*4)
  18. /////////////////////////////////////////////////////////////////////////////
  19. // CDIB
  20. IMPLEMENT_SERIAL(CDIB, CObject, 0 /* schema number*/ )
  21. // Create a small DIB here so m_pBMI and m_pBits are always valid
  22. CDIB::CDIB()
  23. {
  24. m_pBMI = NULL;
  25. m_pBits = NULL;
  26. m_bMyBits = TRUE;
  27. Create(16, 16);
  28. }
  29. CDIB::~CDIB()
  30. {
  31. // free the memory
  32. if (m_pBMI != NULL) free(m_pBMI);
  33. if (m_bMyBits && (m_pBits != NULL))
  34. free(m_pBits);
  35. }
  36. /////////////////////////////////////////////////////////////////////////////
  37. // CDIB serialization
  38. // We dont' support this yet
  39. void CDIB::Serialize(CArchive& ar)
  40. {
  41. ar.Flush();
  42. CFile *fp = ar.GetFile();
  43. if (ar.IsStoring()) {
  44. Save(fp);
  45. } else {
  46. Load(fp);
  47. }
  48. }
  49. /////////////////////////////////////////////////////////////////////////////
  50. // Private functions
  51. static BOOL IsWinDIB(BITMAPINFOHEADER *pBIH)
  52. {
  53. ASSERT(pBIH);
  54. if (((BITMAPCOREHEADER *)pBIH)->bcSize == sizeof(BITMAPCOREHEADER)) {
  55. return FALSE;
  56. }
  57. return TRUE;
  58. }
  59. static int NumDIBColorEntries(BITMAPINFO *pBmpInfo)
  60. {
  61. BITMAPINFOHEADER *pBIH;
  62. BITMAPCOREHEADER *pBCH;
  63. int iColors, iBitCount;
  64. ASSERT(pBmpInfo);
  65. pBIH = &(pBmpInfo->bmiHeader);
  66. pBCH = (BITMAPCOREHEADER *) pBIH;
  67. // start off by assuming the color table size from
  68. // the bit per pixel field
  69. if (IsWinDIB(pBIH)) {
  70. iBitCount = pBIH->biBitCount;
  71. } else {
  72. iBitCount = pBCH->bcBitCount;
  73. }
  74. switch (iBitCount) {
  75. case 1:
  76. iColors = 2;
  77. break;
  78. case 4:
  79. iColors = 16;
  80. break;
  81. case 8:
  82. iColors = 256;
  83. break;
  84. default:
  85. iColors = 0;
  86. break;
  87. }
  88. // If this is a Windows DIB, then the color table length
  89. // is determined by the biClrUsed field if it is non-zero
  90. if (IsWinDIB(pBIH) && (pBIH->biClrUsed != 0)) {
  91. iColors = pBIH->biClrUsed;
  92. }
  93. return iColors;
  94. }
  95. /////////////////////////////////////////////////////////////////////////////
  96. // CDIB commands
  97. // Create a new empty 8bpp DIB with a 256 entry color table
  98. BOOL CDIB::Create(int iWidth, int iHeight)
  99. {
  100. // delete any existing stuff
  101. if (m_pBMI != NULL) free(m_pBMI);
  102. if (m_bMyBits && (m_pBits != NULL)) free(m_pBits);
  103. // allocate memory for the header
  104. m_pBMI = (BITMAPINFO *) malloc(sizeof(BITMAPINFOHEADER)
  105. + 256 * sizeof(RGBQUAD));
  106. if (!m_pBMI) {
  107. TRACE("Out of memory for DIB header");
  108. return FALSE;
  109. }
  110. // allocate memory for the bits (DWORD aligned)
  111. int iBitsSize = ((iWidth + 3) & ~3) * iHeight;
  112. m_pBits = (BYTE *)malloc(iBitsSize);
  113. if (!m_pBits) {
  114. TRACE("Out of memory for DIB bits");
  115. free(m_pBMI);
  116. m_pBMI = NULL;
  117. return FALSE;
  118. }
  119. m_bMyBits = TRUE;
  120. // fill in the header info
  121. BITMAPINFOHEADER *pBI = (BITMAPINFOHEADER *) m_pBMI;
  122. pBI->biSize = sizeof(BITMAPINFOHEADER);
  123. pBI->biWidth = iWidth;
  124. pBI->biHeight = iHeight;
  125. pBI->biPlanes = 1;
  126. pBI->biBitCount = 8;
  127. pBI->biCompression = BI_RGB;
  128. pBI->biSizeImage = 0;
  129. pBI->biXPelsPerMeter = 0;
  130. pBI->biYPelsPerMeter = 0;
  131. pBI->biClrUsed = 0;
  132. pBI->biClrImportant = 0;
  133. // create an arb color table (gray scale)
  134. RGBQUAD *prgb = GetClrTabAddress();
  135. for (int i = 0; i < 256; i++) {
  136. prgb->rgbBlue = prgb->rgbGreen = prgb->rgbRed = (BYTE) i;
  137. prgb->rgbReserved = 0;
  138. prgb++;
  139. }
  140. // set all the bits to a known state (black)
  141. memset(m_pBits, 0, iBitsSize);
  142. return TRUE;
  143. }
  144. // Create a CDIB structure from existing header and bits. The DIB
  145. // won't delete the bits and makes a copy of the header.
  146. BOOL CDIB::Create(BITMAPINFO *pBMI, BYTE *pBits)
  147. {
  148. int iNumColorEntries;
  149. ASSERT(pBMI);
  150. ASSERT(pBits);
  151. if (m_pBMI != NULL) free(m_pBMI);
  152. m_pBMI = (BITMAPINFO *) malloc(sizeof(BITMAPINFOHEADER)
  153. + 256 * sizeof(RGBQUAD));
  154. ASSERT(m_pBMI);
  155. iNumColorEntries = NumDIBColorEntries(pBMI);
  156. if ( iNumColorEntries > 256 )
  157. iNumColorEntries = 256;
  158. memcpy(m_pBMI, pBMI, sizeof(BITMAPINFOHEADER)+
  159. iNumColorEntries * sizeof(RGBQUAD));
  160. if (m_bMyBits && (m_pBits != NULL)) free(m_pBits);
  161. m_pBits = pBits;
  162. m_bMyBits = FALSE; // we can't delete the bits
  163. return TRUE;
  164. }
  165. // Load a DIB from an open file.
  166. BOOL CDIB::Load(CFile *fp)
  167. {
  168. BOOL bIsPM = FALSE;
  169. BITMAPINFO *pBmpInfo = NULL;
  170. BYTE *pBits = NULL;
  171. // get the current file position
  172. DWORD dwFileStart = fp->GetPosition();
  173. // read the file header to get the file size and to
  174. // find where the bits start in the file
  175. BITMAPFILEHEADER BmpFileHdr;
  176. int iBytes;
  177. iBytes = fp->Read(&BmpFileHdr, sizeof(BmpFileHdr));
  178. if (iBytes != sizeof(BmpFileHdr)) {
  179. TRACE("Failed to read file header");
  180. goto $abort;
  181. }
  182. // check we have the magic 'BM' at the start
  183. if (BmpFileHdr.bfType != 0x4D42) {
  184. TRACE("Not a bitmap file");
  185. goto $abort;
  186. }
  187. // make a wild guess that the file is in Windows DIB
  188. // format and read the BITMAPINFOHEADER. If it turns
  189. // out to be a PM DIB file we'll convert it later.
  190. BITMAPINFOHEADER BmpInfoHdr;
  191. iBytes = fp->Read(&BmpInfoHdr, sizeof(BmpInfoHdr));
  192. if (iBytes != sizeof(BmpInfoHdr)) {
  193. TRACE("Failed to read BITMAPINFOHEADER");
  194. goto $abort;
  195. }
  196. // check we got a real Windows DIB file
  197. if (BmpInfoHdr.biSize != sizeof(BITMAPINFOHEADER)) {
  198. if (BmpInfoHdr.biSize != sizeof(BITMAPCOREHEADER)) {
  199. TRACE(" File is not Windows or PM DIB format");
  200. goto $abort;
  201. }
  202. // set a flag to convert PM file to Win format later
  203. bIsPM = TRUE;
  204. // back up the file pointer and read the BITMAPCOREHEADER
  205. // and create the BITMAPINFOHEADER from it
  206. fp->Seek(dwFileStart + sizeof(BITMAPFILEHEADER), CFile::begin);
  207. BITMAPCOREHEADER BmpCoreHdr;
  208. iBytes = fp->Read(&BmpCoreHdr, sizeof(BmpCoreHdr));
  209. if (iBytes != sizeof(BmpCoreHdr)) {
  210. TRACE("Failed to read BITMAPCOREHEADER");
  211. goto $abort;
  212. }
  213. BmpInfoHdr.biSize = sizeof(BITMAPINFOHEADER);
  214. BmpInfoHdr.biWidth = (int) BmpCoreHdr.bcWidth;
  215. BmpInfoHdr.biHeight = (int) BmpCoreHdr.bcHeight;
  216. BmpInfoHdr.biPlanes = BmpCoreHdr.bcPlanes;
  217. BmpInfoHdr.biBitCount = BmpCoreHdr.bcBitCount;
  218. BmpInfoHdr.biCompression = BI_RGB;
  219. BmpInfoHdr.biSizeImage = 0;
  220. BmpInfoHdr.biXPelsPerMeter = 0;
  221. BmpInfoHdr.biYPelsPerMeter = 0;
  222. BmpInfoHdr.biClrUsed = 0;
  223. BmpInfoHdr.biClrImportant = 0;
  224. }
  225. // Work out how much memory we need for the BITMAPINFO
  226. // structure, color table and then for the bits.
  227. // Allocate the memory blocks, copy the BmpInfoHdr we have so far
  228. // and then read in the color table from the file.
  229. int iColors;
  230. int iColorTableSize;
  231. iColors = NumDIBColorEntries((LPBITMAPINFO) &BmpInfoHdr);
  232. iColorTableSize = iColors * sizeof(RGBQUAD);
  233. int iBitsSize;
  234. int iBISize;
  235. // always allocate enough room for 256 entries
  236. iBISize = sizeof(BITMAPINFOHEADER)
  237. + 256 * sizeof(RGBQUAD);
  238. iBitsSize = BmpFileHdr.bfSize -
  239. BmpFileHdr.bfOffBits;
  240. // allocate the memory for the header
  241. pBmpInfo = (LPBITMAPINFO) malloc(iBISize);
  242. if (!pBmpInfo) {
  243. TRACE("Out of memory for DIB header");
  244. goto $abort;
  245. }
  246. // copy the header we already have
  247. memcpy(pBmpInfo, &BmpInfoHdr, sizeof(BITMAPINFOHEADER));
  248. // now read the color table in from the file
  249. if (bIsPM == FALSE) {
  250. // read the color table from the file
  251. iBytes = fp->Read(((LPBYTE) pBmpInfo) + sizeof(BITMAPINFOHEADER),
  252. iColorTableSize);
  253. if (iBytes != iColorTableSize) {
  254. TRACE("Failed to read color table");
  255. goto $abort;
  256. }
  257. } else {
  258. // read each PM color table entry in turn and convert it
  259. // to Win DIB format as we go
  260. LPRGBQUAD lpRGB;
  261. lpRGB = (LPRGBQUAD) ((LPBYTE) pBmpInfo + sizeof(BITMAPINFOHEADER));
  262. int i;
  263. RGBTRIPLE rgbt;
  264. for (i=0; i<iColors; i++) {
  265. iBytes = fp->Read(&rgbt, sizeof(RGBTRIPLE));
  266. if (iBytes != sizeof(RGBTRIPLE)) {
  267. TRACE("Failed to read RGBTRIPLE");
  268. goto $abort;
  269. }
  270. lpRGB->rgbBlue = rgbt.rgbtBlue;
  271. lpRGB->rgbGreen = rgbt.rgbtGreen;
  272. lpRGB->rgbRed = rgbt.rgbtRed;
  273. lpRGB->rgbReserved = 0;
  274. lpRGB++;
  275. }
  276. }
  277. // allocate the memory for the bits
  278. // and read the bits from the file
  279. pBits = (BYTE *) malloc(iBitsSize);
  280. if (!pBits) {
  281. TRACE("Out of memory for DIB bits");
  282. goto $abort;
  283. }
  284. // seek to the bits in the file
  285. fp->Seek(dwFileStart + BmpFileHdr.bfOffBits, CFile::begin);
  286. // read the bits
  287. iBytes = fp->Read(pBits, iBitsSize);
  288. if (iBytes != iBitsSize) {
  289. TRACE("Failed to read bits");
  290. goto $abort;
  291. }
  292. // Everything went OK
  293. if (m_pBMI != NULL) free(m_pBMI);
  294. m_pBMI = pBmpInfo;
  295. if (m_bMyBits && (m_pBits != NULL)) free (m_pBits);
  296. m_pBits = pBits;
  297. m_bMyBits = TRUE;
  298. return TRUE;
  299. $abort: // something went wrong
  300. if (pBmpInfo) free(pBmpInfo);
  301. if (pBits) free (pBits);
  302. return FALSE;
  303. }
  304. // Load a DIB from a disk file. If no file name is given, show
  305. // an open file dialog to get one.
  306. BOOL CDIB::Load(LPSTR pszFileName)
  307. {
  308. CString strFile;
  309. if ((pszFileName == NULL)
  310. || (strlen(pszFileName) == 0)) {
  311. // Show an open file dialog to get the name
  312. CFileDialog dlg (TRUE, // open
  313. NULL, // no default extension
  314. NULL, // no initial file name
  315. OFN_FILEMUSTEXIST
  316. | OFN_HIDEREADONLY,
  317. "Image files (*.DIB, *.BMP)|*.DIB;*.BMP|All files (*.*)|*.*||");
  318. if (dlg.DoModal() == IDOK) {
  319. strFile = dlg.GetPathName();
  320. } else {
  321. return FALSE;
  322. }
  323. } else {
  324. // copy the supplied file path
  325. strFile = pszFileName;
  326. }
  327. // Try to open the file for read access
  328. CFile file;
  329. if (! file.Open(strFile,
  330. CFile::modeRead | CFile::shareDenyWrite)) {
  331. AfxMessageBox("Failed to open file");
  332. return FALSE;
  333. }
  334. BOOL bResult = Load(&file);
  335. file.Close();
  336. if (!bResult) AfxMessageBox("Failed to load file");
  337. return bResult;
  338. }
  339. // Draw the DIB to a given DC
  340. void CDIB::Draw(CDC *pDC, int x, int y)
  341. {
  342. ::StretchDIBits(pDC->GetSafeHdc(),
  343. x, // dest x
  344. y, // dest y
  345. DibWidth(), // dest width
  346. DibHeight(), // dest height
  347. 0, // src x
  348. 0, // src y
  349. DibWidth(), // src width
  350. DibHeight(), // src height
  351. GetBitsAddress(), // bits
  352. GetBitmapInfoAddress(), // BITMAPINFO
  353. DIB_RGB_COLORS, // options
  354. SRCCOPY); // rop
  355. }
  356. // get the number of color table entries
  357. int CDIB::GetNumClrEntries()
  358. {
  359. return NumDIBColorEntries(m_pBMI);
  360. }
  361. int Power(int s)
  362. {
  363. return s * s;
  364. }
  365. BYTE GetNearest(PALETTEENTRY* pe,int nSize,int R,int G,int B)
  366. {
  367. int nMin = 99999999;
  368. BYTE nIndex = 0;
  369. for (int i=0; i<nSize; i++)
  370. {
  371. int s = Power(R - pe[i].peRed) +
  372. Power(G - pe[i].peGreen) +
  373. Power(B - pe[i].peBlue);
  374. if (s < nMin)
  375. {
  376. nMin = s;
  377. nIndex = (BYTE)i;
  378. }
  379. }
  380. return nIndex;
  381. }
  382. void CDIB::Inverse()
  383. {
  384. HWND hwndActive = ::GetActiveWindow();
  385. HDC hdcScreen = ::GetDC(hwndActive);
  386. ASSERT(hdcScreen);
  387. if (!(GetDeviceCaps(hdcScreen, RASTERCAPS) & RC_PALETTE))
  388. return;
  389. int iSysColors = GetDeviceCaps(hdcScreen, NUMCOLORS);
  390. int nColorMode;
  391. if (iSysColors == 16)
  392. nColorMode = 16;
  393. else
  394. nColorMode = 256;
  395. BYTE *pBits = (BYTE *)GetBitsAddress();
  396. int iSize = StorageWidth() * DibHeight();
  397. while (iSize--)
  398. {
  399. *pBits = (nColorMode - *pBits + 10) % nColorMode;
  400. pBits++;
  401. }
  402. }
  403. // NOTE: This assumes all CDIB objects have 256 color table entries
  404. BOOL CDIB::MapColorsToPalette(CPalette *pPal)
  405. {
  406. if (!pPal) {
  407. TRACE("No palette to map to");
  408. return FALSE;
  409. }
  410. ASSERT(m_pBMI->bmiHeader.biBitCount == 8);
  411. ASSERT(m_pBMI);
  412. ASSERT(m_pBits);
  413. LPRGBQUAD pctThis = GetClrTabAddress();
  414. ASSERT(pctThis);
  415. // build an index translation table to map this DIBs colors
  416. // to those of the reference DIB
  417. BYTE imap[256];
  418. int iChanged = 0; // for debugging only
  419. int i;
  420. for (i = 0; i < 256; i++) {
  421. imap[i] = (BYTE) pPal->GetNearestPaletteIndex(
  422. RGB(pctThis->rgbRed,
  423. pctThis->rgbGreen,
  424. pctThis->rgbBlue));
  425. pctThis++;
  426. if (imap[i] != i) iChanged++; // for debugging
  427. }
  428. // now map the DIB bits
  429. BYTE *pBits = (BYTE *)GetBitsAddress();
  430. int iSize = StorageWidth() * DibHeight();
  431. while (iSize--) {
  432. *pBits = imap[*pBits];
  433. pBits++;
  434. }
  435. // Now reset the DIB color table so that its RGB values match
  436. // those in the palette
  437. PALETTEENTRY pe[256];
  438. pPal->GetPaletteEntries(0, 256, pe);
  439. pctThis = GetClrTabAddress();
  440. for (i = 0; i < 256; i++) {
  441. pctThis->rgbRed = pe[i].peRed;
  442. pctThis->rgbGreen = pe[i].peGreen;
  443. pctThis->rgbBlue = pe[i].peBlue;
  444. pctThis++;
  445. }
  446. return TRUE;
  447. }
  448. // Get a pointer to a pixel
  449. // NOTE: DIB scan lines are DWORD aligned. The scan line
  450. // storage width may be wider than the scan line image width
  451. // so calc the storage width by rounding the image width
  452. // to the next highest dword value
  453. void *CDIB::GetPixelAddress(int x, int y)
  454. {
  455. int iWidth;
  456. // This version only deals with 8 bpp DIBs
  457. ASSERT(m_pBMI->bmiHeader.biBitCount == 8);
  458. // make sure it's in range and if not return zero
  459. if ((x >= DibWidth())
  460. || (y >= DibHeight())) {
  461. TRACE("Attempt to get out of range pixel addr");
  462. return NULL;
  463. }
  464. // Calculate the scan line storage width
  465. iWidth = StorageWidth();
  466. return m_pBits + (DibHeight()-y-1) * iWidth + x;
  467. }
  468. // get the bounding rectangle
  469. void CDIB::GetRect(CRect* pRect)
  470. {
  471. pRect->top = 0;
  472. pRect->left = 0;
  473. pRect->bottom = DibHeight();
  474. pRect->right = DibWidth();
  475. }
  476. // Copy a rectangle of the DIB to another DIB
  477. // Note we only support 8bpp DIBs here
  478. void CDIB::CopyBits(CDIB* pdibDest,
  479. int xd, int yd,
  480. int w, int h,
  481. int xs, int ys,
  482. COLORREF clrTrans)
  483. {
  484. ASSERT(m_pBMI->bmiHeader.biBitCount == 8);
  485. ASSERT(pdibDest);
  486. // test for strange cases
  487. if (w == 0 || h == 0) return;
  488. // get pointers to the start points in the source
  489. // and destination DIBs. Note that this will be the bottom left
  490. // corner of the DIB as the scan lines are reversed in memory
  491. BYTE* pSrc = (BYTE*)GetPixelAddress(xs, ys + h - 1);
  492. ASSERT(pSrc);
  493. if ( pSrc == NULL )
  494. return;
  495. BYTE* pDest = (BYTE*)pdibDest->GetPixelAddress(xd, yd + h - 1);
  496. ASSERT(pDest);
  497. if ( pDest == NULL )
  498. return;
  499. // get the scan line widths of each DIB
  500. int iScanS = StorageWidth();
  501. int iScanD = pdibDest->StorageWidth();
  502. if (clrTrans == 0xFFFFFFFF) {
  503. // copy the lines
  504. while (h--) {
  505. memcpy(pDest, pSrc, w);
  506. pSrc += iScanS;
  507. pDest += iScanD;
  508. }
  509. } else {
  510. // copy lines with transparency
  511. // We only accept a PALETTEINDEX description
  512. // for the color definition
  513. ASSERT((clrTrans & 0xFF000000) == 0x01000000);
  514. BYTE bTransClr = LOBYTE(LOWORD(clrTrans));
  515. int iSinc = iScanS - w; // source inc value
  516. int iDinc = iScanD - w; // dest inc value
  517. int iCount;
  518. BYTE pixel;
  519. while (h--) {
  520. iCount = w; // no of pixels to scan
  521. while (iCount--) {
  522. pixel = *pSrc++;
  523. // only copy pixel if not transparent
  524. if (pixel != bTransClr) {
  525. *pDest++ = pixel;
  526. } else {
  527. pDest++;
  528. }
  529. }
  530. // move on to the next line
  531. pSrc += iSinc;
  532. pDest += iDinc;
  533. }
  534. }
  535. }
  536. // Save a DIB to a disk file
  537. // This is somewhat simplistic because we only deal with 256 color DIBs
  538. // and we always write a 256 color table
  539. BOOL CDIB::Save(CFile *fp)
  540. {
  541. BITMAPFILEHEADER bfh;
  542. // construct the file header
  543. bfh.bfType = 0x4D42; // 'BM'
  544. bfh.bfSize =
  545. sizeof(BITMAPFILEHEADER) +
  546. sizeof(BITMAPINFOHEADER) +
  547. 256 * sizeof(RGBQUAD) +
  548. StorageWidth() * DibHeight();
  549. bfh.bfReserved1 = 0;
  550. bfh.bfReserved2 = 0;
  551. bfh.bfOffBits =
  552. sizeof(BITMAPFILEHEADER) +
  553. sizeof(BITMAPINFOHEADER) +
  554. 256 * sizeof(RGBQUAD);
  555. // write the file header
  556. int iSize = sizeof(bfh);
  557. TRY {
  558. fp->Write(&bfh, iSize);
  559. } CATCH(CFileException, e) {
  560. TRACE("Failed to write file header");
  561. return FALSE;
  562. } END_CATCH
  563. // write the BITMAPINFO
  564. // Note: we assume there are always 256 colors in the
  565. // color table
  566. ASSERT(m_pBMI);
  567. iSize =
  568. sizeof(BITMAPINFOHEADER) +
  569. 256 * sizeof(RGBQUAD);
  570. TRY {
  571. fp->Write(m_pBMI, iSize);
  572. } CATCH(CFileException, e) {
  573. TRACE("Failed to write BITMAPINFO");
  574. return FALSE;
  575. } END_CATCH
  576. // write the bits
  577. iSize = StorageWidth() * DibHeight();
  578. TRY {
  579. fp->Write(m_pBits, iSize);
  580. } CATCH(CFileException, e) {
  581. TRACE("Failed to write bits");
  582. return FALSE;
  583. } END_CATCH
  584. return TRUE;
  585. }
  586. // Save a DIB to a disk file. If no file name is given, show
  587. // a save file dialog to get one.
  588. BOOL CDIB::Save(LPSTR pszFileName)
  589. {
  590. CString strFile;
  591. if ((pszFileName == NULL)
  592. || (strlen(pszFileName) == 0)) {
  593. // Show a save file dialog to get the name
  594. CFileDialog dlg (FALSE, // save
  595. NULL, // no default extension
  596. NULL, // no initial file name
  597. OFN_OVERWRITEPROMPT
  598. | OFN_HIDEREADONLY,
  599. "Image files (*.DIB, *.BMP)|*.DIB;*.BMP|All files (*.*)|*.*||");
  600. if (dlg.DoModal() == IDOK) {
  601. strFile = dlg.GetPathName();
  602. } else {
  603. return FALSE;
  604. }
  605. } else {
  606. // copy the supplied file path
  607. strFile = pszFileName;
  608. }
  609. // Try to open the file for write access
  610. CFile file;
  611. if (! file.Open(strFile,
  612. CFile::modeReadWrite
  613. | CFile::modeCreate
  614. | CFile::shareExclusive)) {
  615. AfxMessageBox("Failed to open file");
  616. return FALSE;
  617. }
  618. BOOL bResult = Save(&file);
  619. file.Close();
  620. if (!bResult) AfxMessageBox("Failed to save file");
  621. return bResult;
  622. }
  623. WORD DibNumColors (VOID FAR * pv)
  624. {
  625. INT bits;
  626. LPBITMAPINFOHEADER lpbi;
  627. LPBITMAPCOREHEADER lpbc;
  628. lpbi = ((LPBITMAPINFOHEADER)pv);
  629. lpbc = ((LPBITMAPCOREHEADER)pv);
  630. /* With the BITMAPINFO format headers, the size of the palette
  631. * is in biClrUsed, whereas in the BITMAPCORE - style headers, it
  632. * is dependent on the bits per pixel ( = 2 raised to the power of
  633. * bits/pixel).
  634. */
  635. if (lpbi->biSize != sizeof(BITMAPCOREHEADER)){
  636. if (lpbi->biClrUsed != 0)
  637. return (WORD)lpbi->biClrUsed;
  638. bits = lpbi->biBitCount;
  639. }
  640. else
  641. bits = lpbc->bcBitCount;
  642. switch (bits){
  643. case 1:
  644. return 2;
  645. case 4:
  646. return 16;
  647. case 8:
  648. return 256;
  649. default:
  650. /* A 24 bitcount DIB has no color table */
  651. return 0;
  652. }
  653. }
  654. WORD PaletteSize (VOID FAR * pv)
  655. {
  656. LPBITMAPINFOHEADER lpbi;
  657. WORD NumColors;
  658. lpbi = (LPBITMAPINFOHEADER)pv;
  659. NumColors = DibNumColors(lpbi);
  660. if (lpbi->biSize == sizeof(BITMAPCOREHEADER))
  661. return (WORD)(NumColors * sizeof(RGBTRIPLE));
  662. else
  663. return (WORD)(NumColors * sizeof(RGBQUAD));
  664. }
  665. BOOL CDIB::Load(CBitmap* pBmp)
  666. {
  667. CPalette* pPal;
  668. BITMAP bm;
  669. BITMAPINFOHEADER bi;
  670. WORD biBits;
  671. DWORD biStyle;
  672. DWORD dwLen;
  673. CDC dcMem;
  674. BYTE *lpbi;
  675. BYTE *lpBits;
  676. if (! pBmp)
  677. return FALSE;
  678. pPal = CPalette::FromHandle((HPALETTE ) GetStockObject(DEFAULT_PALETTE));
  679. pBmp->GetObject(sizeof(BITMAP),&bm);
  680. biBits = 8;
  681. biStyle = BI_RGB;
  682. bi.biSize = sizeof(BITMAPINFOHEADER);
  683. bi.biWidth = bm.bmWidth;
  684. bi.biHeight = bm.bmHeight;
  685. bi.biPlanes = 1;
  686. bi.biBitCount = biBits;
  687. bi.biCompression = biStyle;
  688. bi.biSizeImage = 0;
  689. bi.biXPelsPerMeter = 0;
  690. bi.biYPelsPerMeter = 0;
  691. bi.biClrUsed = 0;
  692. bi.biClrImportant = 0;
  693. dwLen = bi.biSize + PaletteSize (&bi);
  694. dcMem.CreateCompatibleDC(NULL);
  695. pPal = dcMem.SelectPalette(pPal,FALSE);
  696. dcMem.RealizePalette();
  697. lpbi = (BYTE *) malloc(dwLen);
  698. memcpy(lpbi,&bi,sizeof(BITMAPINFOHEADER));
  699. GetDIBits(dcMem.GetSafeHdc(),
  700. (HBITMAP) pBmp->GetSafeHandle(),
  701. 0L,
  702. (DWORD) bi.biHeight,
  703. (LPBYTE) NULL,
  704. (LPBITMAPINFO)lpbi,
  705. (DWORD) DIB_RGB_COLORS);
  706. memcpy(&bi,lpbi,sizeof(BITMAPINFOHEADER));
  707. if (bi.biSizeImage == 0)
  708. {
  709. bi.biSizeImage = WIDTHBYTES((DWORD)bm.bmWidth * biBits) * bm.bmHeight;
  710. if (biStyle != BI_RGB)
  711. bi.biSizeImage = (bi.biSizeImage * 3) / 2;
  712. }
  713. lpBits = (BYTE *) malloc(bi.biSizeImage);
  714. GetDIBits(dcMem.GetSafeHdc(),
  715. (HBITMAP) pBmp->GetSafeHandle(),
  716. 0L,
  717. (DWORD) bi.biHeight,
  718. lpBits,
  719. (LPBITMAPINFO)lpbi,
  720. (DWORD) DIB_RGB_COLORS);
  721. dcMem.DeleteDC();
  722. // because default constructor has created 16x16 bitmap by default
  723. // so we need to release first, otherwise it will cause memory leack !
  724. if (m_pBMI)
  725. delete m_pBMI;
  726. if (m_pBits)
  727. delete m_pBits;
  728. m_pBMI = (LPBITMAPINFO) lpbi;
  729. m_pBits = lpBits;
  730. m_bMyBits = TRUE;
  731. return TRUE;
  732. }