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.

1675 lines
44 KiB

  1. #include "stdafx.h"
  2. #include "global.h"
  3. #include "pbrush.h"
  4. #include "pbrusdoc.h"
  5. #include "pbrusfrm.h"
  6. #include "pbrusvw.h"
  7. #include "minifwnd.h"
  8. #include "bmobject.h"
  9. #include "imgsuprt.h"
  10. #include "imgwnd.h"
  11. #include "imgbrush.h"
  12. #include "imgwell.h"
  13. #include "imgtools.h"
  14. #include "toolbox.h"
  15. #include "imgfile.h"
  16. #include "colorsrc.h"
  17. #include "undo.h"
  18. #include "props.h"
  19. #include "ferr.h"
  20. #include "cmpmsg.h"
  21. #include "loadimag.h"
  22. #ifdef _DEBUG
  23. #undef THIS_FILE
  24. static CHAR BASED_CODE THIS_FILE[] = __FILE__;
  25. #endif
  26. IMPLEMENT_DYNCREATE( CBitmapObj, CObject )
  27. #include "memtrace.h"
  28. /***************************************************************************/
  29. // Map from the value in CBitmapObj::m_nColors to bits per pixel
  30. int mpncolorsbits [] =
  31. {
  32. 1, 4, 8, 24
  33. };
  34. /***************************************************************************/
  35. CBitmapObj::CBitmapObj() : CObject(), m_dependants()
  36. {
  37. m_bDirty = FALSE;
  38. m_bTempName = FALSE;
  39. m_hThing = NULL;
  40. m_lMemSize = 0L;
  41. m_pImg = NULL;
  42. m_nWidth = 0;
  43. m_nHeight = 0;
  44. m_nColors = 0;
  45. m_nSaveColors = -1;
  46. #ifdef ICO_SUPPORT
  47. m_bSaveIcon = FALSE;
  48. #endif
  49. #ifdef PCX_SUPPORT
  50. m_bPCX = FALSE;
  51. #endif
  52. m_bCompressed = FALSE;
  53. m_nShrink = 0;
  54. m_dwOffBits = 0;
  55. }
  56. /***************************************************************************/
  57. CBitmapObj::~CBitmapObj()
  58. {
  59. ASSERT_VALID(this);
  60. InformDependants( SN_DESTROY );
  61. if (m_hThing != NULL)
  62. {
  63. Free();
  64. }
  65. if (m_pImg)
  66. FreeImg(m_pImg);
  67. }
  68. /***************************************************************************/
  69. void CBitmapObj::AddDependant( CBitmapObj* newDependant )
  70. {
  71. POSITION pos = m_dependants.Find( newDependant );
  72. if (pos == NULL)
  73. m_dependants.AddTail( newDependant );
  74. }
  75. /***************************************************************************/
  76. void CBitmapObj::RemoveDependant( CBitmapObj* oldDependant )
  77. {
  78. POSITION pos = m_dependants.Find(oldDependant);
  79. if (pos != NULL)
  80. m_dependants.RemoveAt(pos);
  81. }
  82. /***************************************************************************/
  83. void CBitmapObj::InformDependants( UINT idChange )
  84. {
  85. POSITION pos = m_dependants.GetHeadPosition();
  86. while (pos != NULL)
  87. {
  88. CBitmapObj* pSlob = (CBitmapObj*)m_dependants.GetNext(pos);
  89. pSlob->OnInform(this, idChange);
  90. }
  91. }
  92. /***************************************************************************/
  93. void CBitmapObj::OnInform( CBitmapObj* pChangedSlob, UINT idChange )
  94. {
  95. if (idChange == SN_DESTROY)
  96. {
  97. POSITION pos = m_dependants.Find(pChangedSlob);
  98. if (pos != NULL)
  99. m_dependants.RemoveAt(pos);
  100. }
  101. }
  102. /***************************************************************************/
  103. void CBitmapObj::SetDirty(BOOL bDirty)
  104. {
  105. m_bDirty = bDirty;
  106. }
  107. /*****************************************************************************/
  108. void CBitmapObj::Zap()
  109. {
  110. m_bDirty = FALSE;
  111. }
  112. /*****************************************************************************/
  113. BOOL CBitmapObj::Alloc() // m_hThing of size m_lMemSize
  114. {
  115. if (m_lMemSize == 0L)
  116. return FALSE;
  117. m_hThing = GlobalAlloc(GPTR, m_lMemSize);
  118. if (m_hThing == NULL)
  119. {
  120. theApp.SetMemoryEmergency( TRUE );
  121. return FALSE;
  122. }
  123. return TRUE;
  124. }
  125. /*****************************************************************************/
  126. void CBitmapObj::Free() // m_hThing and set m_lMemSize to zero
  127. {
  128. if (m_hThing == NULL)
  129. {
  130. TRACE(TEXT("Warning: called Free on a CBitmapObj with no thing!\n"));
  131. return;
  132. }
  133. GlobalFree(m_hThing);
  134. m_hThing = NULL;
  135. m_lMemSize = 0;
  136. }
  137. /***************************************************************************/
  138. CString CBitmapObj::GetDefExtension(int iStringId)
  139. {
  140. CString cStringExtension;
  141. if (iStringId != 0)
  142. {
  143. TRY
  144. {
  145. cStringExtension.LoadString( iStringId );
  146. }
  147. CATCH(CMemoryException,e)
  148. {
  149. cStringExtension.Empty();
  150. }
  151. END_CATCH
  152. }
  153. else
  154. {
  155. cStringExtension.Empty();
  156. }
  157. return cStringExtension;
  158. }
  159. void PBGetDefDims(int &pnWidth, int &pnHeight)
  160. {
  161. // Setup default parameters...
  162. // Don't use the whole screen, those bitmaps get HUGE
  163. //
  164. pnWidth = GetSystemMetrics( SM_CXSCREEN )/2;
  165. pnHeight = GetSystemMetrics( SM_CYSCREEN )/2;
  166. // Check if this is a low memory machine and use a small default bitmap
  167. // size
  168. if (GetSystemMetrics(SM_SLOWMACHINE) & 0x0002)
  169. {
  170. pnWidth = 640/2;
  171. pnHeight = 480/2;
  172. }
  173. }
  174. /*****************************************************************************/
  175. BOOL CBitmapObj::MakeEmpty()
  176. {
  177. PBGetDefDims(m_nWidth, m_nHeight);
  178. if (theApp.m_sizeBitmap.cx
  179. && theApp.m_sizeBitmap.cy)
  180. {
  181. m_nWidth = theApp.m_sizeBitmap.cx;
  182. m_nHeight = theApp.m_sizeBitmap.cy;
  183. }
  184. if (theApp.m_bEmbedded)
  185. {
  186. // make a nice size for embedded objects, lets try for 5 centimeters
  187. m_nWidth = theApp.ScreenDeviceInfo.ixPelsPerDM / 2;
  188. m_nHeight = theApp.ScreenDeviceInfo.iyPelsPerDM / 2;
  189. }
  190. //
  191. // default to 256 colors if not monochrome
  192. //
  193. m_nColors = theApp.m_bMonoDevice? 0 : 2;
  194. m_bDirty = TRUE;
  195. return TRUE;
  196. }
  197. /*****************************************************************************/
  198. // Create and setup an IMG for this resource
  199. BOOL CBitmapObj::CreateImg()
  200. {
  201. ASSERT(! m_pImg);
  202. LONG cXPelsPerMeter = 0;
  203. LONG cYPelsPerMeter = 0;
  204. LPSTR lpbi = (LPSTR) GlobalLock(m_hThing); // NOTE: this is NULL for new resources!
  205. if (lpbi)
  206. {
  207. if (IS_WIN30_DIB( lpbi ))
  208. {
  209. PBITMAPINFOHEADER pbmih = (PBITMAPINFOHEADER) lpbi;
  210. m_bCompressed = pbmih->biCompression != BI_RGB;
  211. cXPelsPerMeter = pbmih->biXPelsPerMeter;
  212. cYPelsPerMeter = pbmih->biYPelsPerMeter;
  213. }
  214. m_nWidth = (int)DIBWidth ( lpbi );
  215. m_nHeight = (int)DIBHeight( lpbi );
  216. m_nColors = DIBNumColors( lpbi, FALSE );
  217. if (m_nColors <= 0 || m_nColors > 256)
  218. m_nColors = 3;
  219. else
  220. if (m_nColors <= 2)
  221. m_nColors = 0;
  222. else
  223. if (m_nColors <= 16)
  224. m_nColors = 1;
  225. else
  226. if (m_nColors <= 256)
  227. m_nColors = 2;
  228. }
  229. UINT nColors = (m_nColors? 0: 1);
  230. m_pImg = ::CreateImg( lpbi ? 0 : m_nWidth, lpbi ? 0 : m_nHeight,
  231. nColors, nColors, cXPelsPerMeter, cYPelsPerMeter, theApp.m_bPaletted );
  232. if (! m_pImg)
  233. {
  234. TRACE(TEXT("CreateImg failed\n"));
  235. theApp.SetMemoryEmergency();
  236. GlobalUnlock(m_hThing);
  237. return FALSE;
  238. }
  239. if (g_pColors)
  240. {
  241. g_pColors->ResetColors ((m_nColors==1)?16:256);
  242. }
  243. m_pImg->cxWidth = m_nWidth;
  244. m_pImg->cyHeight = m_nHeight;
  245. if (! lpbi)
  246. {
  247. nColors = m_pImg->cPlanes * m_pImg->cBitCount;
  248. //FEATURE - Shouldn't this be " == 0 || == 1" ??
  249. //Half a page up negative values == TRUE color!
  250. //This shell game with the values isn't very good...
  251. if (nColors <= 1)
  252. m_nColors = 0;
  253. else
  254. if (nColors <= 4)
  255. m_nColors = 1;
  256. else
  257. if (nColors <= 8)
  258. m_nColors = 2;
  259. else // 24-bit image
  260. m_nColors = 3;
  261. }
  262. m_pImg->m_pBitmapObj = this;
  263. m_pImg->bDirty = m_bDirty;
  264. if (lpbi)
  265. {
  266. // Load the bitmap/icon/cursor...
  267. HBITMAP hbm = DIBToDS( lpbi, m_dwOffBits, m_pImg->hDC );
  268. if (! hbm)
  269. {
  270. theApp.SetMemoryEmergency();
  271. GlobalUnlock(m_hThing);
  272. return FALSE;
  273. }
  274. m_pImg->hBitmap = hbm;
  275. m_pImg->hBitmapOld = (HBITMAP)::SelectObject( m_pImg->hDC, hbm );
  276. }
  277. if ( theApp.m_bPaletted)
  278. // If LoadImage was used && paletted
  279. {
  280. // Create the Palette from the dib section instead.
  281. m_pImg->m_pPalette = PaletteFromDS(m_pImg->hDC);
  282. }
  283. theApp.m_pPalette = NULL;
  284. if (m_pImg->m_pPalette && theApp.m_bPaletted)
  285. {
  286. m_pImg->m_hPalOld = SelectPalette( m_pImg->hDC,
  287. (HPALETTE)m_pImg->m_pPalette->m_hObject,
  288. FALSE );
  289. RealizePalette( m_pImg->hDC );
  290. theApp.m_pPalette = m_pImg->m_pPalette;
  291. }
  292. else
  293. if (m_pImg->m_pPalette)
  294. {
  295. delete m_pImg->m_pPalette;
  296. m_pImg->m_pPalette = NULL;
  297. m_pImg->m_hPalOld = NULL;
  298. }
  299. if (g_pColors)
  300. g_pColors->SetMono( ! m_nColors );
  301. GlobalUnlock(m_hThing);
  302. return TRUE;
  303. }
  304. /*****************************************************************************/
  305. BOOL CBitmapObj::Export(const TCHAR* szFileName)
  306. {
  307. // If the file already exists and we aren't dirty, then don't bother
  308. // saving, just return...
  309. CFileStatus fStat;
  310. CString strFullName;
  311. MkFullPath( strFullName, (const TCHAR*)szFileName );
  312. if (CFile::GetStatus( strFullName, fStat ) && ! m_bDirty)
  313. return TRUE;
  314. CFile file;
  315. CFileException e;
  316. CFileSaver saver( szFileName );
  317. if (! saver.CanSave())
  318. return FALSE;
  319. theApp.SetFileError( IDS_ERROR_EXPORT, CFileException::none, szFileName );
  320. if (! OpenSubFile( file, saver, CFile::modeWrite
  321. | CFile::modeCreate
  322. | CFile::typeBinary, &e ))
  323. {
  324. theApp.SetFileError( IDS_ERROR_EXPORT, e.m_cause );
  325. return FALSE;
  326. }
  327. BOOL bWritten = FALSE;
  328. TRY
  329. {
  330. #ifdef PCX_SUPPORT
  331. if (m_bPCX)
  332. bWritten = WritePCX( &file );
  333. else
  334. #endif
  335. bWritten = WriteResource( &file );
  336. file.Close();
  337. }
  338. CATCH( CFileException, ex )
  339. {
  340. file.Abort();
  341. theApp.SetFileError( IDS_ERROR_EXPORT, ex->m_cause );
  342. return FALSE;
  343. }
  344. END_CATCH
  345. if (bWritten)
  346. bWritten = saver.Finish();
  347. else
  348. saver.Finish();
  349. return bWritten;
  350. }
  351. typedef union _BITMAPHEADER
  352. {
  353. BITMAPINFOHEADER bmi;
  354. BITMAPCOREHEADER bmc;
  355. } BITMAPHEADER, *LPBITMAPHEADER;
  356. inline WORD PaletteSize(LPBITMAPHEADER lpHdr) {return(PaletteSize((LPSTR)lpHdr));}
  357. inline WORD DIBNumColors(LPBITMAPHEADER lpHdr) {return(DIBNumColors((LPSTR)lpHdr));}
  358. inline DWORD DIBWidth(LPBITMAPHEADER lpHdr) {return(DIBWidth((LPSTR)lpHdr));}
  359. inline DWORD DIBHeight(LPBITMAPHEADER lpHdr) {return(DIBHeight((LPSTR)lpHdr));}
  360. /*****************************************************************************/
  361. BOOL CBitmapObj::WriteResource( CFile* pfile, PBResType rtType )
  362. {
  363. BOOL bPBrushOLEHeader = (rtType == rtPBrushOLEObj);
  364. BOOL bFileHeader = (rtType == rtFile)|| (rtType == rtPaintOLEObj) || bPBrushOLEHeader;
  365. if (m_pImg == NULL)
  366. {
  367. // The image has not been loaded, so we'll just copy the
  368. // original out to the file...
  369. ASSERT( m_hThing );
  370. if (! m_hThing)
  371. return FALSE;
  372. }
  373. else
  374. {
  375. // The image has been loaded and may have been edited, so
  376. // we'll convert it back to a dib to save...
  377. if (! m_hThing)
  378. SaveResource( FALSE );
  379. if (! m_hThing)
  380. return FALSE;
  381. }
  382. LPBITMAPHEADER lpDib = (LPBITMAPHEADER)GlobalLock(m_hThing);
  383. DWORD dwLength = m_lMemSize;
  384. DWORD dwWriteLength = dwLength;
  385. DWORD dwHeadLength = 0;
  386. struct _BMINFO
  387. {
  388. BITMAPINFOHEADER hdr;
  389. RGBQUAD rgb[256];
  390. } bmInfo;
  391. LPBITMAPHEADER lpOldHdr = lpDib;
  392. LPBITMAPHEADER lpNewHdr = lpOldHdr;
  393. DWORD dwOldHdrLen = lpOldHdr->bmi.biSize + PaletteSize(lpOldHdr);
  394. DWORD dwNewHdrLen = dwOldHdrLen;
  395. if (bPBrushOLEHeader)
  396. {
  397. if (!IS_WIN30_DIB(lpDib))
  398. {
  399. LPBITMAPCOREINFO lpCoreInfo = (LPBITMAPCOREINFO)(&lpOldHdr->bmc);
  400. memset(&bmInfo.hdr, 0, sizeof(bmInfo.hdr));
  401. bmInfo.hdr.biSize = sizeof(bmInfo.hdr);
  402. bmInfo.hdr.biWidth = lpCoreInfo->bmciHeader.bcWidth;
  403. bmInfo.hdr.biHeight = lpCoreInfo->bmciHeader.bcHeight;
  404. bmInfo.hdr.biPlanes = lpCoreInfo->bmciHeader.bcPlanes;
  405. bmInfo.hdr.biBitCount = lpCoreInfo->bmciHeader.bcBitCount;
  406. bmInfo.hdr.biCompression = BI_RGB;
  407. for (int i=DIBNumColors(lpOldHdr)-1; i>=0; --i)
  408. {
  409. bmInfo.rgb[i].rgbBlue = lpCoreInfo->bmciColors[i].rgbtBlue;
  410. bmInfo.rgb[i].rgbGreen = lpCoreInfo->bmciColors[i].rgbtGreen;
  411. bmInfo.rgb[i].rgbRed = lpCoreInfo->bmciColors[i].rgbtRed;
  412. bmInfo.rgb[i].rgbReserved = 0;
  413. }
  414. lpNewHdr = (LPBITMAPHEADER)(&bmInfo);
  415. dwNewHdrLen = lpNewHdr->bmi.biSize + PaletteSize(lpNewHdr);
  416. }
  417. dwWriteLength += dwNewHdrLen - dwOldHdrLen;
  418. dwLength += dwNewHdrLen - dwOldHdrLen;
  419. if (bFileHeader)
  420. {
  421. #ifdef ICO_SUPPORT
  422. if (IsSaveIcon())
  423. {
  424. dwHeadLength = sizeof(ICONFILEHEADER);
  425. dwWriteLength += dwHeadLength;
  426. }
  427. else
  428. #endif
  429. {
  430. dwHeadLength = sizeof(BITMAPFILEHEADER);
  431. dwWriteLength += dwHeadLength;
  432. // PBrush rounded up to 32 bytes (I don't know why)
  433. dwWriteLength = (dwWriteLength+31) & ~31;
  434. }
  435. }
  436. pfile->Write( &dwWriteLength, sizeof( dwWriteLength ));
  437. }
  438. if (bFileHeader)
  439. {
  440. // Icon support is not in application anymore, right?
  441. #ifdef ICO_SUPPORT
  442. if (IsSaveIcon())
  443. {
  444. ICONFILEHEADER hdr;
  445. hdr.icoReserved = 0;
  446. hdr.icoResourceType = 1;
  447. hdr.icoResourceCount = 1;
  448. pfile->Write( &hdr, sizeof( ICONFILEHEADER ) );
  449. pfile->Seek( sizeof( ICONDIRENTRY ), CFile::current );
  450. }
  451. else
  452. #endif
  453. {
  454. BITMAPFILEHEADER hdr;
  455. hdr.bfType = ((WORD)('M' << 8) | 'B');
  456. hdr.bfSize = dwLength + sizeof( BITMAPFILEHEADER );
  457. hdr.bfReserved1 = 0;
  458. hdr.bfReserved2 = 0;
  459. hdr.bfOffBits = (DWORD)sizeof(hdr)
  460. + lpNewHdr->bmi.biSize
  461. + PaletteSize(lpNewHdr);
  462. pfile->Write( &hdr, sizeof( hdr ));
  463. }
  464. }
  465. pfile->Write(lpNewHdr, dwNewHdrLen);
  466. BYTE* hp = ((BYTE*)lpDib) + dwOldHdrLen;
  467. // We subtract the new header length because we have already translated
  468. // dwLength to the new size
  469. DWORD dwWrite = dwLength - dwNewHdrLen;
  470. DWORD dwIconPos = pfile->GetPosition();;
  471. while (dwWrite > 0)
  472. {
  473. UINT cbWrite = (UINT)min( dwWrite, 16384 );
  474. pfile->Write( (LPVOID)hp, cbWrite );
  475. hp += cbWrite;
  476. dwWrite -= cbWrite;
  477. }
  478. dwWriteLength -= dwHeadLength;
  479. if (dwWriteLength > dwLength)
  480. {
  481. // We rounded up to 32 bytes above, so this should always be < 32
  482. ASSERT(dwWriteLength-dwLength < 32);
  483. DWORD dwZeros[] =
  484. {
  485. 0, 0, 0, 0, 0, 0, 0, 0,
  486. } ;
  487. pfile->Write( dwZeros, dwWriteLength-dwLength );
  488. }
  489. ASSERT( dwWrite == 0 );
  490. // Icon support is not in application anymore, right?
  491. #ifdef ICO_SUPPORT
  492. if (IsSaveIcon())
  493. {
  494. DWORD nextPos = pfile->GetPosition();
  495. pfile->Seek( (bFileHeader? sizeof( ICONFILEHEADER ): 0), CFile::begin );
  496. ICONDIRENTRY dir;
  497. dir.nWidth = (BYTE)DIBWidth ( lpDib );
  498. dir.nHeight = (BYTE)DIBHeight ( lpDib ) / 2;
  499. dir.nColorCount = (BYTE)DIBNumColors( lpDib );
  500. dir.bReserved = 0;
  501. dir.wReserved1 = 0;
  502. dir.wReserved2 = 0;
  503. dir.icoDIBSize = dwLength;
  504. dir.icoDIBOffset = dwIconPos;
  505. pfile->Write( &dir, sizeof( ICONDIRENTRY ) );
  506. pfile->Seek( nextPos, CFile::begin );
  507. }
  508. else
  509. #endif
  510. m_bDirty = FALSE;
  511. pfile->Flush();
  512. GlobalUnlock(m_hThing);
  513. return TRUE;
  514. }
  515. /*****************************************************************************/
  516. BOOL CBitmapObj::Import( LPCTSTR szFileName )
  517. {
  518. CFile file;
  519. CFileException e;
  520. theApp.SetFileError( IDS_ERROR_READLOAD, CFileException::none, szFileName );
  521. if (! file.Open( szFileName, CFile::modeRead | CFile::typeBinary, &e ))
  522. {
  523. theApp.SetFileError( IDS_ERROR_READLOAD, e.m_cause );
  524. return FALSE;
  525. }
  526. BOOL bGoodFile = TRUE;
  527. TRY
  528. {
  529. bGoodFile = ReadResource( &file );
  530. file.Close();
  531. }
  532. CATCH(CFileException, ex)
  533. {
  534. file.Abort();
  535. bGoodFile = FALSE;
  536. }
  537. END_CATCH
  538. if (!bGoodFile)
  539. {
  540. HGLOBAL hDib;
  541. if (hDib = LoadDIBFromFile(szFileName, &theApp.m_guidFltTypeUsed))
  542. {
  543. bGoodFile = ReadResource(hDib);
  544. if (bGoodFile)
  545. {
  546. theApp.SetFileError(0, CFileException::none);
  547. }
  548. else
  549. {
  550. theApp.SetFileError( IDS_ERROR_READLOAD, ferrNotValidBmp);
  551. }
  552. }
  553. }
  554. return bGoodFile;
  555. }
  556. /*****************************************************************************/
  557. BOOL CBitmapObj::ReadResource( CFile* pfile, PBResType rtType )
  558. {
  559. BOOL bPBrushOLEHeader = (rtType == rtPBrushOLEObj);
  560. BOOL bFileHeader = (rtType == rtFile)
  561. || (rtType == rtPaintOLEObj)|| bPBrushOLEHeader;
  562. DWORD dwLength = pfile->GetLength();
  563. // special case zero length files.
  564. if (! dwLength)
  565. {
  566. if (m_hThing)
  567. Free();
  568. m_bDirty = TRUE;
  569. return TRUE;
  570. }
  571. if (bPBrushOLEHeader)
  572. {
  573. DWORD dwReadLen;
  574. if (pfile->Read( &dwReadLen, sizeof( dwReadLen )) != sizeof( dwReadLen )
  575. || dwReadLen > dwLength)
  576. {
  577. theApp.SetFileError( IDS_ERROR_READLOAD, ferrNotValidBmp );
  578. return FALSE;
  579. }
  580. dwLength -= sizeof(dwReadLen);
  581. }
  582. m_dwOffBits = 0;
  583. if (bFileHeader)
  584. {
  585. BITMAPFILEHEADER hdr;
  586. if (pfile->Read( &hdr, sizeof( hdr )) != sizeof( hdr ))
  587. {
  588. theApp.SetFileError( IDS_ERROR_READLOAD, ferrNotValidBmp );
  589. return FALSE;
  590. }
  591. if (hdr.bfType != ((WORD)('M' << 8) | 'B'))
  592. {
  593. theApp.SetFileError( IDS_ERROR_READLOAD, ferrNotValidBmp );
  594. return FALSE;
  595. }
  596. dwLength -= sizeof( hdr );
  597. // Store the offset from the beginning of the BITMAPINFO
  598. if (hdr.bfOffBits)
  599. {
  600. m_dwOffBits = hdr.bfOffBits - sizeof(hdr);
  601. }
  602. else
  603. {
  604. m_dwOffBits = 0;
  605. }
  606. }
  607. if (m_hThing != NULL)
  608. Free();
  609. m_lMemSize = dwLength;
  610. if (! Alloc())
  611. return FALSE;
  612. ASSERT( m_hThing );
  613. PVOID lpvThing = GlobalLock(m_hThing);
  614. BYTE* hp = (BYTE*)lpvThing;
  615. while (dwLength > 0)
  616. {
  617. UINT cbRead = (UINT)min( dwLength, 16384 );
  618. if (pfile->Read( (void FAR*)hp, cbRead ) != cbRead)
  619. {
  620. theApp.SetFileError( IDS_ERROR_READLOAD, ferrReadFailed );
  621. GlobalUnlock(m_hThing);
  622. return FALSE;
  623. }
  624. dwLength -= cbRead;
  625. hp += cbRead;
  626. }
  627. ASSERT( dwLength == 0 );
  628. //
  629. // Calculate the bits offset because the BITMAPFILEHEADER had 0
  630. //
  631. if (!m_dwOffBits)
  632. {
  633. m_dwOffBits = (DWORD)(FindDIBBits ((LPSTR)lpvThing, 0) -
  634. (LPSTR)lpvThing);
  635. }
  636. GlobalUnlock(m_hThing);
  637. return TRUE;
  638. }
  639. /*****************************************************************************/
  640. BOOL CBitmapObj::ReadResource( HGLOBAL hDib )
  641. {
  642. LPBITMAPINFOHEADER lpbi = (LPBITMAPINFOHEADER) GlobalLock(hDib);
  643. DWORD dwSizeImage;
  644. if (lpbi == NULL || lpbi->biSize != sizeof(BITMAPINFOHEADER))
  645. {
  646. theApp.SetFileError( IDS_ERROR_READLOAD, ferrNotValidBmp );
  647. return FALSE;
  648. }
  649. m_dwOffBits = lpbi->biSize + lpbi->biClrUsed * sizeof(RGBQUAD);
  650. if (lpbi->biClrUsed == 0 && lpbi->biBitCount <= 8)
  651. m_dwOffBits += (1 << lpbi->biBitCount) * sizeof(RGBQUAD);
  652. if (lpbi->biSizeImage)
  653. {
  654. lpbi->biSizeImage = abs(lpbi->biSizeImage);
  655. dwSizeImage = lpbi->biSizeImage;
  656. }
  657. else
  658. {
  659. dwSizeImage = abs(lpbi->biHeight) * ((lpbi->biWidth*lpbi->biBitCount+31)&~31)/8;
  660. }
  661. if (m_hThing != NULL)
  662. Free();
  663. m_lMemSize = m_dwOffBits + dwSizeImage;
  664. m_hThing = hDib;
  665. GlobalUnlock(hDib);
  666. return TRUE;
  667. }
  668. /*****************************************************************************/
  669. void CBitmapObj::ReLoadImage( CPBDoc* pbDoc )
  670. {
  671. FreeImg( m_pImg );
  672. CleanupImgUndo();
  673. CleanupImgRubber();
  674. m_pImg = NULL;
  675. if (CreateImg())
  676. {
  677. POSITION pos = pbDoc->GetFirstViewPosition();
  678. CPBView* pView = (CPBView*)pbDoc->GetNextView( pos );
  679. if (pView)
  680. {
  681. pView->m_pImgWnd->SetImg( m_pImg );
  682. pbDoc->UpdateAllViews( pView );
  683. InvalImgRect( m_pImg, NULL );
  684. }
  685. }
  686. }
  687. /*****************************************************************************/
  688. void SwapBitmaps(HDC hDC1, int x1, int y1, int wid, int hgt,
  689. HDC hDC2, int x2, int y2, CPalette* pPalette)
  690. {
  691. #if 0
  692. // We would like to just XOR 3 times to swap, but sometimes the middle of the
  693. // palette is empty, so we cannot
  694. BitBlt(m_pImg->hDC, rect.left , rect.top,
  695. rect.Width(), rect.Height(), hDC, 0, 0, DSx);
  696. BitBlt(hDC, 0, 0, rect.Width(), rect.Height(), m_pImg->hDC,
  697. rect.left, rect.top, DSx);
  698. BitBlt(m_pImg->hDC, rect.left, rect.top, rect.Width(), rect.Height(),
  699. hDC, 0, 0, DSx);
  700. #else
  701. CDC dcTemp;
  702. CDC dc1, dc2;
  703. dc1.Attach(hDC1);
  704. dc2.Attach(hDC2);
  705. BOOL bSuccess = dcTemp.CreateCompatibleDC(&dc1);
  706. // Don't create a bitmap that is too large, or we will spend all our time
  707. // swapping
  708. int hgtTemp = 0x10000/wid;
  709. hgtTemp = min(hgt, max(1, hgtTemp));
  710. CBitmap bmTemp;
  711. bSuccess = bSuccess && bmTemp.CreateCompatibleBitmap(&dc1, wid, hgtTemp);
  712. bSuccess = bSuccess && dcTemp.SelectObject(&bmTemp)!=NULL;
  713. if (!bSuccess)
  714. {
  715. // Make sure the DC's do not get deleted
  716. dc1.Detach();
  717. dc2.Detach();
  718. return;
  719. }
  720. if (pPalette)
  721. {
  722. dcTemp.SelectPalette(pPalette, TRUE);
  723. dcTemp.RealizePalette();
  724. }
  725. int yTemp;
  726. for (yTemp=0; yTemp<hgt; yTemp+=hgtTemp)
  727. {
  728. hgtTemp = min(hgtTemp, hgt-yTemp);
  729. dcTemp.BitBlt(0, 0, wid, hgtTemp, &dc1, x1, y1+yTemp, SRCCOPY);
  730. dc1.BitBlt(x1, y1+yTemp, wid, hgtTemp, &dc2 , x2, y2+yTemp, SRCCOPY);
  731. dc2.BitBlt(x2, y2+yTemp, wid, hgtTemp, &dcTemp, 0 , 0, SRCCOPY);
  732. }
  733. // Make sure the DC's do not get deleted
  734. dc1.Detach();
  735. dc2.Detach();
  736. // Note that I explicitly delete the DC first, so I do not have to worry
  737. // about selecting old objects back in
  738. dcTemp.DeleteDC();
  739. #endif
  740. }
  741. void CBitmapObj::UndoAction( CBmObjSequence* pSeq, UINT nActionID )
  742. {
  743. switch (nActionID)
  744. {
  745. default:
  746. break;
  747. case A_ImageChange:
  748. if (((CImgTool::GetCurrentID() == IDMB_PICKTOOL)
  749. || (CImgTool::GetCurrentID() == IDMB_PICKRGNTOOL))
  750. && theImgBrush.m_pImg != NULL)
  751. {
  752. HideBrush();
  753. InvalImgRect( theImgBrush.m_pImg, NULL ); // hide tracker
  754. theImgBrush.m_pImg = NULL;
  755. }
  756. int cb;
  757. CRect rect;
  758. HBITMAP hImgBitmap;
  759. pSeq->RetrieveInt( cb );
  760. ASSERT(cb == sizeof( CRect ) + sizeof( hImgBitmap ));
  761. pSeq->RetrieveRect( rect );
  762. int nCursor = pSeq->m_nCursor;
  763. pSeq->Retrieve( (BYTE*)&hImgBitmap, sizeof( hImgBitmap ) );
  764. // Wipe out the old handles since we're reusing them in the
  765. // new record and we don't what them deleted when this record
  766. // is removed!
  767. memset(&pSeq->ElementAt(nCursor), 0, sizeof( hImgBitmap ));
  768. // Perform undo using these parameters...
  769. SetupRubber(m_pImg);
  770. SetUndo(m_pImg); // For redo...
  771. HideBrush();
  772. ASSERT(m_pImg != NULL);
  773. HDC hDC = CreateCompatibleDC(m_pImg->hDC);
  774. if (hDC == NULL)
  775. {
  776. theApp.SetGdiEmergency();
  777. return;
  778. }
  779. HPALETTE hOldPalette = NULL;
  780. HBITMAP hOldBitmap = (HBITMAP)SelectObject(hDC, hImgBitmap);
  781. ASSERT(hOldBitmap != NULL);
  782. if (m_pImg->m_pPalette)
  783. {
  784. hOldPalette = SelectPalette( hDC, (HPALETTE)m_pImg->m_pPalette->m_hObject,
  785. FALSE ); // Background ??
  786. RealizePalette( hDC );
  787. }
  788. // Three blits here swap the image and the undo bits, that
  789. // way the undo bits are set up for a redo!
  790. ASSERT(m_pImg->hDC != NULL);
  791. SwapBitmaps(m_pImg->hDC, rect.left, rect.top,
  792. rect.Width(), rect.Height(), hDC, 0, 0, m_pImg->m_pPalette);
  793. if (hOldPalette)
  794. SelectPalette( hDC, hOldPalette, FALSE ); // Background ??
  795. SelectObject(hDC, hOldBitmap);
  796. DeleteDC(hDC);
  797. InvalImgRect (m_pImg, &rect);
  798. CommitImgRect(m_pImg, &rect);
  799. // Record the redo information...
  800. theUndo.Insert((BYTE*)&hImgBitmap, sizeof (hImgBitmap));
  801. theUndo.InsertRect(rect);
  802. theUndo.InsertInt(sizeof (CRect) + sizeof (hImgBitmap));
  803. theUndo.InsertInt(A_ImageChange);
  804. theUndo.InsertPtr(m_pImg->m_pBitmapObj);
  805. theUndo.InsertByte(CUndoBmObj::opAction);
  806. break;
  807. }
  808. }
  809. /*****************************************************************************/
  810. void CBitmapObj::DeleteUndoAction(CBmObjSequence* pSeq, UINT nActionID)
  811. {
  812. switch (nActionID)
  813. {
  814. default:
  815. break;
  816. case A_ImageChange:
  817. CRect rect;
  818. HBITMAP hImgBitmap;
  819. pSeq->RetrieveRect(rect);
  820. pSeq->Retrieve((BYTE*)&hImgBitmap, sizeof (hImgBitmap));
  821. if (hImgBitmap != NULL)
  822. DeleteObject(hImgBitmap);
  823. break;
  824. }
  825. }
  826. /*****************************************************************************/
  827. BOOL CBitmapObj::FinishUndo(const CRect* pRect)
  828. {
  829. ASSERT( g_hUndoImgBitmap );
  830. CRect rect;
  831. if (pRect == NULL)
  832. rect.SetRect(0, 0, m_pImg->cxWidth, m_pImg->cyHeight);
  833. else
  834. rect = *pRect;
  835. HDC hDC1 = NULL;
  836. HDC hDC2 = NULL;
  837. HPALETTE hOldPalette = NULL;
  838. HPALETTE hOldPalette2 = NULL;
  839. HBITMAP hImgBitmap = NULL;
  840. HBITMAP hOldBitmap1;
  841. HBITMAP hOldBitmap2;
  842. if (rect.left >= rect.right || rect.top >= rect.bottom)
  843. {
  844. // Not an error, just nothing to do...
  845. return TRUE;
  846. }
  847. hImgBitmap = CreateCompatibleBitmap( m_pImg->hDC, rect.Width(), rect.Height() );
  848. if (hImgBitmap == NULL)
  849. goto LError;
  850. if ((hDC1 = CreateCompatibleDC(m_pImg->hDC)) == NULL)
  851. goto LError;
  852. if ((hDC2 = CreateCompatibleDC(m_pImg->hDC)) == NULL)
  853. goto LError;
  854. if (m_pImg->m_pPalette)
  855. {
  856. hOldPalette = SelectPalette(hDC1, (HPALETTE)m_pImg->m_pPalette->m_hObject, FALSE );
  857. RealizePalette( hDC1 );
  858. hOldPalette2 = SelectPalette(hDC2, (HPALETTE)m_pImg->m_pPalette->m_hObject, FALSE );
  859. RealizePalette( hDC2 );
  860. }
  861. VERIFY((hOldBitmap1 = (HBITMAP)SelectObject(hDC1, hImgBitmap)) != NULL);
  862. VERIFY((hOldBitmap2 = (HBITMAP)SelectObject(hDC2, g_hUndoImgBitmap)) != NULL);
  863. BitBlt(hDC1, 0, 0, rect.Width(), rect.Height(),
  864. hDC2, rect.left , rect.top, SRCCOPY);
  865. SelectObject(hDC1, hOldBitmap1);
  866. SelectObject(hDC2, hOldBitmap2);
  867. if (hOldPalette != NULL)
  868. {
  869. ::SelectPalette(hDC1, hOldPalette, FALSE ); // Background ??
  870. }
  871. if (hOldPalette2 != NULL)
  872. {
  873. ::SelectPalette(hDC2, hOldPalette2, FALSE ); // Background ??
  874. }
  875. DeleteDC(hDC1);
  876. DeleteDC(hDC2);
  877. theUndo.BeginUndo( IDS_UNDO_PAINTING );
  878. theUndo.Insert((BYTE*)&hImgBitmap , sizeof (hImgBitmap));
  879. theUndo.InsertRect(rect);
  880. theUndo.InsertInt(sizeof (CRect) + sizeof (hImgBitmap));
  881. theUndo.InsertInt(A_ImageChange);
  882. theUndo.InsertPtr(this);
  883. theUndo.InsertByte(CUndoBmObj::opAction);
  884. theUndo.EndUndo();
  885. // NOTE: At this point, we could free the undo bitmaps, but instead
  886. // they are left around for next time...
  887. return TRUE;
  888. LError:
  889. if (hImgBitmap != NULL)
  890. DeleteObject(hImgBitmap);
  891. if (hDC1 != NULL)
  892. DeleteDC(hDC1);
  893. if (hDC2 != NULL)
  894. DeleteDC(hDC2);
  895. // REVIEW: Since we couldn't allocate something here, there will
  896. // be no way to undo the last operation... What should we do?
  897. // Chances are, the system is so low on memory, a message box
  898. // giving an option might even fail.
  899. //
  900. // For now, let's just beep to try to tell the user that whatever
  901. // just happend can't be undone. Also, free the image sized bitmaps
  902. // so the system has a little free memory.
  903. CleanupImgUndo();
  904. MessageBeep(0);
  905. #ifdef _DEBUG
  906. TRACE(TEXT("Not enough memory to undo image change!\n"));
  907. #endif
  908. return FALSE;
  909. }
  910. /*****************************************************************************/
  911. BOOL CBitmapObj::SetIntProp(UINT nPropID, int val)
  912. {
  913. CWaitCursor waitCursor; // these all take awhile!
  914. switch (nPropID)
  915. {
  916. case P_Width:
  917. return SetSizeProp( P_Size, CSize( val, m_nHeight ) );
  918. break;
  919. case P_Height:
  920. return SetSizeProp( P_Size, CSize( m_nWidth, val ) );
  921. break;
  922. case P_Colors:
  923. if (CImgTool::GetCurrentID() == IDMB_PICKTOOL
  924. || CImgTool::GetCurrentID() == IDMB_PICKRGNTOOL)
  925. {
  926. CommitSelection( TRUE );
  927. theImgBrush.m_pImg = NULL;
  928. }
  929. SetUndo( m_pImg );
  930. FinishUndo( NULL );
  931. // Perform the color-count conversion with DIBs
  932. DWORD dwSize;
  933. ::SelectObject( m_pImg->hDC, m_pImg->hBitmapOld );
  934. LPSTR lpDib = (LPSTR) DibFromBitmap(
  935. m_pImg->hBitmap, BI_RGB, m_pImg->cPlanes * m_pImg->cBitCount,
  936. m_pImg->m_pPalette, NULL, dwSize,
  937. m_pImg->cXPelsPerMeter, m_pImg->cYPelsPerMeter );
  938. ::SelectObject( m_pImg->hDC, m_pImg->hBitmap );
  939. if (lpDib == NULL)
  940. {
  941. theApp.SetGdiEmergency();
  942. return FALSE;
  943. }
  944. // Make a new palette appropriate for this colors setting
  945. CPalette* pNewPalette = NULL;
  946. int iPlanes = (val? 1: ::GetDeviceCaps( m_pImg->hDC, PLANES ));
  947. int iBitCnt = (val? 1: ::GetDeviceCaps( m_pImg->hDC, BITSPIXEL ));
  948. int iColors = iPlanes * iBitCnt;
  949. val = 3;
  950. if (theApp.m_bPaletted)
  951. switch (iColors)
  952. {
  953. case 1:
  954. pNewPalette = GetStd2Palette();
  955. break;
  956. case 4:
  957. pNewPalette = GetStd16Palette();
  958. break;
  959. case 8:
  960. pNewPalette = GetStd256Palette();
  961. break;
  962. }
  963. switch (iColors)
  964. {
  965. case 8:
  966. val = 2;
  967. break;
  968. case 4:
  969. val = 1;
  970. break;
  971. case 1:
  972. val = 0;
  973. break;
  974. }
  975. HBITMAP hTmpBitmap = CreateBitmap( 1, 1, iPlanes, iBitCnt, NULL );
  976. HBITMAP hNewBitmap = CreateBitmap( m_pImg->cxWidth,
  977. m_pImg->cyHeight,
  978. iPlanes, iBitCnt, NULL );
  979. if (! hTmpBitmap || ! hNewBitmap)
  980. {
  981. FreeDib( lpDib );
  982. if (hTmpBitmap)
  983. ::DeleteObject( hTmpBitmap );
  984. if (hNewBitmap)
  985. ::DeleteObject( hNewBitmap );
  986. if (pNewPalette)
  987. delete pNewPalette;
  988. theApp.SetGdiEmergency();
  989. return FALSE;
  990. }
  991. HPALETTE hPalOld = NULL;
  992. ::SelectObject( m_pImg->hDC, hTmpBitmap );
  993. if (pNewPalette)
  994. {
  995. hPalOld = ::SelectPalette( m_pImg->hDC, (HPALETTE)pNewPalette->m_hObject, FALSE );
  996. ::RealizePalette( m_pImg->hDC );
  997. }
  998. int iLinesDone = SetDIBits( m_pImg->hDC, hNewBitmap, 0,
  999. m_pImg->cyHeight,
  1000. FindDIBBits( lpDib ),
  1001. (LPBITMAPINFO)lpDib, DIB_RGB_COLORS );
  1002. FreeDib( lpDib );
  1003. if (iLinesDone != m_pImg->cyHeight)
  1004. {
  1005. ::SelectObject( m_pImg->hDC, m_pImg->hBitmap );
  1006. if (hPalOld)
  1007. {
  1008. ::SelectPalette( m_pImg->hDC, hPalOld, FALSE );
  1009. ::RealizePalette( m_pImg->hDC );
  1010. delete pNewPalette;
  1011. }
  1012. ::DeleteObject( hTmpBitmap );
  1013. ::DeleteObject( hNewBitmap );
  1014. theApp.SetGdiEmergency();
  1015. return FALSE;
  1016. }
  1017. m_pImg->cPlanes = iPlanes;
  1018. m_pImg->cBitCount = iBitCnt;
  1019. m_nColors = val;
  1020. ::SelectObject( m_pImg->hDC, hNewBitmap );
  1021. ::DeleteObject( m_pImg->hBitmap );
  1022. m_pImg->hBitmap = hNewBitmap;
  1023. if (m_pImg->m_pPalette)
  1024. {
  1025. if (! pNewPalette)
  1026. {
  1027. ::SelectPalette( m_pImg->hDC, m_pImg->m_hPalOld, FALSE );
  1028. m_pImg->m_hPalOld = NULL;
  1029. }
  1030. delete m_pImg->m_pPalette;
  1031. }
  1032. m_pImg->m_pPalette = pNewPalette;
  1033. theApp.m_pPalette = pNewPalette;
  1034. ::DeleteObject( hTmpBitmap );
  1035. DirtyImg( m_pImg );
  1036. InvalImgRect( m_pImg, NULL );
  1037. // The rubber-banding bitmap is now invalid...
  1038. if (m_pImg == pRubberImg)
  1039. {
  1040. TRACE(TEXT("Clearing rubber\n"));
  1041. pRubberImg = NULL;
  1042. SetupRubber( m_pImg );
  1043. }
  1044. if (g_pColors)
  1045. g_pColors->SetMono( ! m_nColors );
  1046. InformDependants( P_Image );
  1047. break;
  1048. }
  1049. m_bDirty = TRUE;
  1050. return TRUE;
  1051. }
  1052. /*****************************************************************************/
  1053. GPT CBitmapObj::GetIntProp(UINT nPropID, int& val)
  1054. {
  1055. switch (nPropID)
  1056. {
  1057. case P_Colors:
  1058. val = m_nColors;
  1059. return valid;
  1060. break;
  1061. case P_Image:
  1062. val = NULL;
  1063. return valid; // Must return now since this is a fake prop...
  1064. }
  1065. return invalid;
  1066. }
  1067. /*****************************************************************************/
  1068. BOOL CBitmapObj::SetSizeProp(UINT nPropID, const CSize& val)
  1069. {
  1070. ASSERT(m_pImg != NULL);
  1071. if ((CImgTool::GetCurrentID() == IDMB_PICKTOOL)
  1072. || (CImgTool::GetCurrentID() == IDMB_PICKRGNTOOL))
  1073. {
  1074. CommitSelection(TRUE);
  1075. theImgBrush.m_pImg = NULL;
  1076. }
  1077. switch (nPropID)
  1078. {
  1079. default:
  1080. ASSERT(FALSE);
  1081. case P_Size:
  1082. if (val.cx == m_pImg->cxWidth && val.cy == m_pImg->cyHeight)
  1083. return TRUE;
  1084. if (val.cx < 1 || val.cy < 1)
  1085. {
  1086. CmpMessageBox(IDS_ERROR_BITMAPSIZE, AFX_IDS_APP_TITLE,
  1087. MB_OK | MB_ICONEXCLAMATION);
  1088. return FALSE;
  1089. }
  1090. CWaitCursor waitCursor;
  1091. BOOL bStretch = FALSE;
  1092. CSize curSize;
  1093. GetImgSize(m_pImg, curSize);
  1094. bStretch = m_nShrink;
  1095. SetUndo(m_pImg);
  1096. CRect undoRect(0, 0, m_pImg->cxWidth, m_pImg->cyHeight);
  1097. if (! SetImgSize(m_pImg, (CSize)val, bStretch))
  1098. {
  1099. theApp.SetMemoryEmergency();
  1100. return FALSE;
  1101. }
  1102. FinishUndo(&undoRect);
  1103. DirtyImg(m_pImg);
  1104. pRubberImg = NULL;
  1105. SetupRubber(m_pImg);
  1106. if (theUndo.IsRecording())
  1107. {
  1108. theUndo.OnSetIntProp(this, P_Width, m_nWidth);
  1109. theUndo.OnSetIntProp(this, P_Height, m_nHeight);
  1110. }
  1111. int nOldWidth = m_nWidth;
  1112. int nOldHeight = m_nHeight;
  1113. m_nWidth = val.cx;
  1114. m_nHeight = val.cy;
  1115. if (m_nWidth != nOldWidth)
  1116. InformDependants(P_Width);
  1117. if (m_nHeight != nOldHeight)
  1118. InformDependants(P_Height);
  1119. InformDependants(P_Image);
  1120. break;
  1121. }
  1122. return TRUE;
  1123. }
  1124. /*****************************************************************************/
  1125. BOOL CBitmapObj::SaveResource( BOOL bClear )
  1126. {
  1127. if (m_pImg == NULL)
  1128. return TRUE;
  1129. if (bClear)
  1130. {
  1131. if (m_hThing && ! m_pImg->bDirty && ! m_bDirty)
  1132. return TRUE; // nothing to save
  1133. m_bDirty |= m_pImg->bDirty;
  1134. if (m_pImg == theImgBrush.m_pImg)
  1135. theImgBrush.m_pImg = NULL;
  1136. if (m_pImg == pRubberImg)
  1137. pRubberImg = NULL;
  1138. HideBrush();
  1139. }
  1140. DWORD dwStyle = BI_RGB;
  1141. int iColors = m_nColors;
  1142. if (m_nSaveColors >= 0)
  1143. {
  1144. iColors = m_nSaveColors;
  1145. m_nSaveColors = -1;
  1146. }
  1147. if (m_bCompressed)
  1148. {
  1149. switch (iColors)
  1150. {
  1151. case 1:
  1152. dwStyle = BI_RLE4;
  1153. break;
  1154. case 2:
  1155. dwStyle = BI_RLE8;
  1156. break;
  1157. }
  1158. }
  1159. switch (iColors)
  1160. {
  1161. case 0:
  1162. iColors = 1;
  1163. break;
  1164. case 1:
  1165. iColors = 4;
  1166. break;
  1167. case 2:
  1168. iColors = 8;
  1169. break;
  1170. case 3:
  1171. iColors = 24;
  1172. break;
  1173. default:
  1174. iColors = 0;
  1175. break;
  1176. }
  1177. HBITMAP hBitmap = m_pImg->hBitmap;
  1178. HBITMAP hMaskBitmap = NULL;
  1179. BOOL bNewBitmap = FALSE;
  1180. HGLOBAL lpDIB;
  1181. DWORD dwSize;
  1182. // Icon support is not in application anymore, right?
  1183. #ifdef ICO_SUPPORT
  1184. if (IsSaveIcon())
  1185. {
  1186. // build a mask based on the current background color
  1187. // and make sure the bitmap is the icon size
  1188. bNewBitmap = SetupForIcon( hBitmap, hMaskBitmap );
  1189. if (iColors > 4 || iColors < 1)
  1190. iColors = 4;
  1191. }
  1192. #endif
  1193. ::SelectObject( m_pImg->hDC, m_pImg->hBitmapOld );
  1194. lpDIB = DibFromBitmap(
  1195. hBitmap, dwStyle, (WORD)iColors,
  1196. theApp.m_pPalette, hMaskBitmap, dwSize,
  1197. m_pImg->cXPelsPerMeter, m_pImg->cYPelsPerMeter );
  1198. ::SelectObject( m_pImg->hDC, m_pImg->hBitmap );
  1199. if (bNewBitmap)
  1200. {
  1201. ::DeleteObject( hBitmap );
  1202. ::DeleteObject( hMaskBitmap );
  1203. }
  1204. if (lpDIB == NULL)
  1205. {
  1206. theApp.SetMemoryEmergency();
  1207. return FALSE;
  1208. }
  1209. if (m_hThing != NULL)
  1210. Free();
  1211. // We packed the DIB, so the offset will always be right after the palette,
  1212. // which is implied by this being 0
  1213. m_dwOffBits = 0;
  1214. m_hThing = lpDIB;
  1215. m_lMemSize = dwSize;
  1216. if (bClear)
  1217. m_pImg->bDirty = FALSE;
  1218. return TRUE;
  1219. }
  1220. /*****************************************************************************/
  1221. // Icon support is not in application anymore, right?
  1222. BOOL CBitmapObj::SetupForIcon( HBITMAP& hBitmap, HBITMAP& hMaskBitmap )
  1223. {
  1224. CDC dcIcon;
  1225. CDC dcMask;
  1226. CBitmap bmIcon;
  1227. CBitmap bmMask;
  1228. CDC* pdcBitmap = CDC::FromHandle( m_pImg->hDC );
  1229. CSize sizeIcon( ::GetSystemMetrics( SM_CXICON ),
  1230. ::GetSystemMetrics( SM_CYICON ) );
  1231. BOOL bNewBitmap = FALSE;
  1232. if (dcIcon.CreateCompatibleDC( pdcBitmap )
  1233. && dcMask.CreateCompatibleDC( pdcBitmap )
  1234. && bmIcon.CreateCompatibleBitmap( pdcBitmap, sizeIcon.cx, sizeIcon.cy )
  1235. && bmMask.CreateBitmap( sizeIcon.cx, sizeIcon.cy, 1, 1, NULL ))
  1236. {
  1237. CPalette* ppalOld = NULL;
  1238. CBitmap* pbmOldIcon = dcIcon.SelectObject( &bmIcon );
  1239. CBitmap* pbmOldMask = dcMask.SelectObject( &bmMask );
  1240. if (theApp.m_pPalette)
  1241. {
  1242. ppalOld = dcIcon.SelectPalette( theApp.m_pPalette, FALSE );
  1243. dcIcon.RealizePalette();
  1244. }
  1245. dcIcon.PatBlt( 0, 0, sizeIcon.cx, sizeIcon.cy, WHITENESS );
  1246. CBrush brBackGround( crRight );
  1247. if (brBackGround.GetSafeHandle() != NULL)
  1248. {
  1249. CRect rect( 0, 0, sizeIcon.cx, sizeIcon.cy );
  1250. dcIcon.FillRect( &rect, &brBackGround );
  1251. brBackGround.DeleteObject();
  1252. }
  1253. int iWidth = min( sizeIcon.cx, m_pImg->cxWidth );
  1254. int iHeight = min( sizeIcon.cy, m_pImg->cyHeight );
  1255. dcIcon.BitBlt( 0, 0, iWidth, iHeight, pdcBitmap, 0, 0, SRCCOPY );
  1256. COLORREF oldBkColor = dcIcon.SetBkColor( crRight );
  1257. dcMask.BitBlt( 0, 0, sizeIcon.cx, sizeIcon.cy, &dcIcon, 0, 0, SRCCOPY );
  1258. COLORREF cRefFGColorOld = dcMask.SetTextColor( RGB( 0, 0, 0 ) );
  1259. COLORREF cRefBKColorOld = dcMask.SetBkColor ( RGB( 255, 255, 255 ) );
  1260. dcIcon.BitBlt( 0, 0, sizeIcon.cx, sizeIcon.cy, &dcMask, 0, 0, DSna );
  1261. dcMask.SetTextColor( cRefFGColorOld );
  1262. dcMask.SetBkColor ( cRefBKColorOld );
  1263. dcIcon.SetBkColor ( oldBkColor );
  1264. if (ppalOld != NULL)
  1265. dcIcon.SelectPalette( ppalOld, FALSE );
  1266. if (pbmOldIcon != NULL)
  1267. dcIcon.SelectObject( pbmOldIcon );
  1268. if (pbmOldMask != NULL)
  1269. dcMask.SelectObject( pbmOldMask );
  1270. hBitmap = (HBITMAP)bmIcon.Detach();
  1271. hMaskBitmap = (HBITMAP)bmMask.Detach();
  1272. bNewBitmap = TRUE;
  1273. }
  1274. if (dcIcon.GetSafeHdc() != NULL)
  1275. dcIcon.DeleteDC();
  1276. if (dcMask.GetSafeHdc() != NULL)
  1277. dcMask.DeleteDC();
  1278. if (bmIcon.GetSafeHandle() != NULL)
  1279. bmIcon.DeleteObject();
  1280. if (bmMask.GetSafeHandle() != NULL)
  1281. bmMask.DeleteObject();
  1282. return bNewBitmap;
  1283. }
  1284. /*****************************************************************************/