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.

1239 lines
31 KiB

  1. #include <windows.h>
  2. #include "bmplib.h"
  3. /*
  4. * This came from: \\index1\src\nt\private\samples\wincap32\dibutil.c
  5. */
  6. #define IS_WIN30_DIB(lpbi) ((*(LPDWORD)(lpbi)) == sizeof(BITMAPINFOHEADER))
  7. #define WIDTHBYTES(bits) (((bits) + 31) / 32 * 4)
  8. #define DIB_HEADER_MARKER ((WORD) ('M' << 8) | 'B')
  9. WORD DIBNumColors(LPSTR lpDIB)
  10. {
  11. WORD wBitCount; // DIB bit count
  12. // If this is a Windows-style DIB, the number of colors in the
  13. // color table can be less than the number of bits per pixel
  14. // allows for (i.e. lpbi->biClrUsed can be set to some value).
  15. // If this is the case, return the appropriate value.
  16. if (IS_WIN30_DIB(lpDIB))
  17. {
  18. DWORD dwClrUsed;
  19. dwClrUsed = ((LPBITMAPINFOHEADER)lpDIB)->biClrUsed;
  20. if (dwClrUsed)
  21. return (WORD)dwClrUsed;
  22. }
  23. // Calculate the number of colors in the color table based on
  24. // the number of bits per pixel for the DIB.
  25. if (IS_WIN30_DIB(lpDIB))
  26. wBitCount = ((LPBITMAPINFOHEADER)lpDIB)->biBitCount;
  27. else
  28. wBitCount = ((LPBITMAPCOREHEADER)lpDIB)->bcBitCount;
  29. // return number of colors based on bits per pixel
  30. switch (wBitCount)
  31. {
  32. case 1:
  33. return 2;
  34. case 4:
  35. return 16;
  36. case 8:
  37. return 256;
  38. default:
  39. return 0;
  40. }
  41. }
  42. WORD PaletteSize(LPSTR lpDIB)
  43. {
  44. // calculate the size required by the palette
  45. if (IS_WIN30_DIB (lpDIB))
  46. return (DIBNumColors(lpDIB) * sizeof(RGBQUAD));
  47. else
  48. return (DIBNumColors(lpDIB) * sizeof(RGBTRIPLE));
  49. }
  50. LPSTR FindDIBBits(LPSTR lpDIB)
  51. {
  52. return (lpDIB + *(LPDWORD)lpDIB + PaletteSize(lpDIB));
  53. }
  54. /*************************************************************************
  55. *
  56. * DIBToBitmap()
  57. *
  58. * Parameters:
  59. *
  60. * HDIB hDIB - specifies the DIB to convert
  61. *
  62. * HPALETTE hPal - specifies the palette to use with the bitmap
  63. *
  64. * Return Value:
  65. *
  66. * HBITMAP - identifies the device-dependent bitmap
  67. *
  68. * Description:
  69. *
  70. * This function creates a bitmap from a DIB using the specified palette.
  71. * If no palette is specified, default is used.
  72. *
  73. * NOTE:
  74. *
  75. * The bitmap returned from this funciton is always a bitmap compatible
  76. * with the screen (e.g. same bits/pixel and color planes) rather than
  77. * a bitmap with the same attributes as the DIB. This behavior is by
  78. * design, and occurs because this function calls CreateDIBitmap to
  79. * do its work, and CreateDIBitmap always creates a bitmap compatible
  80. * with the hDC parameter passed in (because it in turn calls
  81. * CreateCompatibleBitmap).
  82. *
  83. * So for instance, if your DIB is a monochrome DIB and you call this
  84. * function, you will not get back a monochrome HBITMAP -- you will
  85. * get an HBITMAP compatible with the screen DC, but with only 2
  86. * colors used in the bitmap.
  87. *
  88. * If your application requires a monochrome HBITMAP returned for a
  89. * monochrome DIB, use the function SetDIBits().
  90. *
  91. * Also, the DIBpassed in to the function is not destroyed on exit. This
  92. * must be done later, once it is no longer needed.
  93. *
  94. ************************************************************************/
  95. HBITMAP
  96. BMPAPI
  97. DIBToBitmap(
  98. LPVOID pDIB,
  99. HPALETTE hPal
  100. )
  101. {
  102. LPSTR lpDIBHdr, lpDIBBits; // pointer to DIB header, pointer to DIB bits
  103. HBITMAP hBitmap; // handle to device-dependent bitmap
  104. HDC hDC; // handle to DC
  105. HPALETTE hOldPal = NULL; // handle to a palette
  106. // if invalid handle, return NULL
  107. if (!pDIB)
  108. return NULL;
  109. // lock memory block and get a pointer to it
  110. lpDIBHdr = pDIB;
  111. // get a pointer to the DIB bits
  112. lpDIBBits = FindDIBBits(lpDIBHdr);
  113. // get a DC
  114. hDC = GetDC(NULL);
  115. if (!hDC)
  116. {
  117. return NULL;
  118. }
  119. // select and realize palette
  120. if (hPal)
  121. hOldPal = SelectPalette(hDC, hPal, FALSE);
  122. RealizePalette(hDC);
  123. // create bitmap from DIB info. and bits
  124. hBitmap = CreateDIBitmap(hDC, (LPBITMAPINFOHEADER)lpDIBHdr, CBM_INIT,
  125. lpDIBBits, (LPBITMAPINFO)lpDIBHdr, DIB_RGB_COLORS);
  126. // restore previous palette
  127. if (hOldPal)
  128. SelectPalette(hDC, hOldPal, FALSE);
  129. // clean up
  130. ReleaseDC(NULL, hDC);
  131. // return handle to the bitmap
  132. return hBitmap;
  133. }
  134. /*************************************************************************
  135. *
  136. * BitmapToDIB()
  137. *
  138. * Parameters:
  139. *
  140. * HBITMAP hBitmap - specifies the bitmap to convert
  141. *
  142. * HPALETTE hPal - specifies the palette to use with the bitmap
  143. *
  144. * Return Value:
  145. *
  146. * HANDLE - identifies the device-dependent bitmap
  147. *
  148. * Description:
  149. *
  150. * This function creates a DIB from a bitmap using the specified palette.
  151. *
  152. ************************************************************************/
  153. HANDLE
  154. BMPAPI
  155. BitmapToDIB(
  156. HBITMAP hBitmap,
  157. HPALETTE hPal
  158. )
  159. {
  160. BITMAP bm; // bitmap structure
  161. BITMAPINFOHEADER bi; // bitmap header
  162. LPBITMAPINFOHEADER lpbi; // pointer to BITMAPINFOHEADER
  163. DWORD dwLen; // size of memory block
  164. HANDLE hDIB, h; // handle to DIB, temp handle
  165. HDC hDC; // handle to DC
  166. WORD biBits; // bits per pixel
  167. // check if bitmap handle is valid
  168. if (!hBitmap)
  169. return NULL;
  170. // fill in BITMAP structure, return NULL if it didn't work
  171. if (!GetObject(hBitmap, sizeof(bm), (LPSTR)&bm))
  172. return NULL;
  173. // if no palette is specified, use default palette
  174. if (hPal == NULL)
  175. hPal = GetStockObject(DEFAULT_PALETTE);
  176. // calculate bits per pixel
  177. biBits = bm.bmPlanes * bm.bmBitsPixel;
  178. // make sure bits per pixel is valid
  179. if (biBits <= 1)
  180. biBits = 1;
  181. else if (biBits <= 4)
  182. biBits = 4;
  183. else if (biBits <= 8)
  184. biBits = 8;
  185. else // if greater than 8-bit, force to 24-bit
  186. biBits = 24;
  187. // initialize BITMAPINFOHEADER
  188. bi.biSize = sizeof(BITMAPINFOHEADER);
  189. bi.biWidth = bm.bmWidth;
  190. bi.biHeight = bm.bmHeight;
  191. bi.biPlanes = 1;
  192. bi.biBitCount = biBits;
  193. bi.biCompression = BI_RGB;
  194. bi.biSizeImage = 0;
  195. bi.biXPelsPerMeter = 0;
  196. bi.biYPelsPerMeter = 0;
  197. bi.biClrUsed = 0;
  198. bi.biClrImportant = 0;
  199. // calculate size of memory block required to store BITMAPINFO
  200. dwLen = bi.biSize + PaletteSize((LPSTR)&bi);
  201. // get a DC
  202. hDC = GetDC(NULL);
  203. if (!hDC)
  204. {
  205. return NULL;
  206. }
  207. // select and realize our palette
  208. hPal = SelectPalette(hDC, hPal, FALSE);
  209. RealizePalette(hDC);
  210. // alloc memory block to store our bitmap
  211. hDIB = GlobalAlloc(GHND, dwLen);
  212. // if we couldn't get memory block
  213. if (!hDIB)
  214. {
  215. // clean up and return NULL
  216. SelectPalette(hDC, hPal, TRUE);
  217. RealizePalette(hDC);
  218. ReleaseDC(NULL, hDC);
  219. return NULL;
  220. }
  221. // lock memory and get pointer to it
  222. lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
  223. /// use our bitmap info. to fill BITMAPINFOHEADER
  224. *lpbi = bi;
  225. // call GetDIBits with a NULL lpBits param, so it will calculate the
  226. // biSizeImage field for us
  227. GetDIBits(hDC, hBitmap, 0, (UINT)bi.biHeight, NULL, (LPBITMAPINFO)lpbi,
  228. DIB_RGB_COLORS);
  229. // get the info. returned by GetDIBits and unlock memory block
  230. bi = *lpbi;
  231. GlobalUnlock(hDIB);
  232. // if the driver did not fill in the biSizeImage field, make one up
  233. if (bi.biSizeImage == 0)
  234. bi.biSizeImage = WIDTHBYTES((DWORD)bm.bmWidth * biBits) * bm.bmHeight;
  235. // realloc the buffer big enough to hold all the bits
  236. dwLen = bi.biSize + PaletteSize((LPSTR)&bi) + bi.biSizeImage;
  237. if (h = GlobalReAlloc(hDIB, dwLen, 0))
  238. hDIB = h;
  239. else
  240. {
  241. // clean up and return NULL
  242. GlobalFree(hDIB);
  243. hDIB = NULL;
  244. SelectPalette(hDC, hPal, TRUE);
  245. RealizePalette(hDC);
  246. ReleaseDC(NULL, hDC);
  247. return NULL;
  248. }
  249. // lock memory block and get pointer to it */
  250. lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
  251. // call GetDIBits with a NON-NULL lpBits param, and actualy get the
  252. // bits this time
  253. if (GetDIBits(hDC, hBitmap, 0, (UINT)bi.biHeight, (LPSTR)lpbi +
  254. (WORD)lpbi->biSize + PaletteSize((LPSTR)lpbi), (LPBITMAPINFO)lpbi,
  255. DIB_RGB_COLORS) == 0)
  256. {
  257. // clean up and return NULL
  258. GlobalUnlock(hDIB);
  259. hDIB = NULL;
  260. SelectPalette(hDC, hPal, TRUE);
  261. RealizePalette(hDC);
  262. ReleaseDC(NULL, hDC);
  263. return NULL;
  264. }
  265. bi = *lpbi;
  266. // clean up
  267. GlobalUnlock(hDIB);
  268. SelectPalette(hDC, hPal, TRUE);
  269. RealizePalette(hDC);
  270. ReleaseDC(NULL, hDC);
  271. // return handle to the DIB
  272. return hDIB;
  273. }
  274. /*************************************************************************
  275. *
  276. * SaveDIB()
  277. *
  278. * Saves the specified DIB into the specified file name on disk. No
  279. * error checking is done, so if the file already exists, it will be
  280. * written over.
  281. *
  282. * Parameters:
  283. *
  284. * HDIB hDib - Handle to the dib to save
  285. *
  286. * LPSTR lpFileName - pointer to full pathname to save DIB under
  287. *
  288. * Return value: 0 if successful, or one of:
  289. * ERR_INVALIDHANDLE
  290. * ERR_OPEN
  291. * ERR_LOCK
  292. *
  293. *************************************************************************/
  294. BOOL
  295. BMPAPI
  296. SaveDIB(
  297. LPVOID pDib,
  298. LPCSTR lpFileName
  299. )
  300. {
  301. BITMAPFILEHEADER bmfHdr; // Header for Bitmap file
  302. LPBITMAPINFOHEADER lpBI; // Pointer to DIB info structure
  303. HANDLE fh; // file handle for opened file
  304. DWORD dwDIBSize;
  305. DWORD dwWritten;
  306. if (!pDib)
  307. return FALSE;
  308. fh = CreateFile(lpFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
  309. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
  310. if (fh == INVALID_HANDLE_VALUE)
  311. return FALSE;
  312. // Get a pointer to the DIB memory, the first of which contains
  313. // a BITMAPINFO structure
  314. lpBI = (LPBITMAPINFOHEADER)pDib;
  315. if (!lpBI)
  316. {
  317. CloseHandle(fh);
  318. return FALSE;
  319. }
  320. // Check to see if we're dealing with an OS/2 DIB. If so, don't
  321. // save it because our functions aren't written to deal with these
  322. // DIBs.
  323. if (lpBI->biSize != sizeof(BITMAPINFOHEADER))
  324. {
  325. CloseHandle(fh);
  326. return FALSE;
  327. }
  328. // Fill in the fields of the file header
  329. // Fill in file type (first 2 bytes must be "BM" for a bitmap)
  330. bmfHdr.bfType = DIB_HEADER_MARKER; // "BM"
  331. // Calculating the size of the DIB is a bit tricky (if we want to
  332. // do it right). The easiest way to do this is to call GlobalSize()
  333. // on our global handle, but since the size of our global memory may have
  334. // been padded a few bytes, we may end up writing out a few too
  335. // many bytes to the file (which may cause problems with some apps,
  336. // like HC 3.0).
  337. //
  338. // So, instead let's calculate the size manually.
  339. //
  340. // To do this, find size of header plus size of color table. Since the
  341. // first DWORD in both BITMAPINFOHEADER and BITMAPCOREHEADER conains
  342. // the size of the structure, let's use this.
  343. // Partial Calculation
  344. dwDIBSize = *(LPDWORD)lpBI + PaletteSize((LPSTR)lpBI);
  345. // Now calculate the size of the image
  346. // It's an RLE bitmap, we can't calculate size, so trust the biSizeImage
  347. // field
  348. if ((lpBI->biCompression == BI_RLE8) || (lpBI->biCompression == BI_RLE4))
  349. dwDIBSize += lpBI->biSizeImage;
  350. else
  351. {
  352. DWORD dwBmBitsSize; // Size of Bitmap Bits only
  353. // It's not RLE, so size is Width (DWORD aligned) * Height
  354. dwBmBitsSize = WIDTHBYTES((lpBI->biWidth)*((DWORD)lpBI->biBitCount)) *
  355. lpBI->biHeight;
  356. dwDIBSize += dwBmBitsSize;
  357. // Now, since we have calculated the correct size, why don't we
  358. // fill in the biSizeImage field (this will fix any .BMP files which
  359. // have this field incorrect).
  360. lpBI->biSizeImage = dwBmBitsSize;
  361. }
  362. // Calculate the file size by adding the DIB size to sizeof(BITMAPFILEHEADER)
  363. bmfHdr.bfSize = dwDIBSize + sizeof(BITMAPFILEHEADER);
  364. bmfHdr.bfReserved1 = 0;
  365. bmfHdr.bfReserved2 = 0;
  366. // Now, calculate the offset the actual bitmap bits will be in
  367. // the file -- It's the Bitmap file header plus the DIB header,
  368. // plus the size of the color table.
  369. bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + lpBI->biSize +
  370. PaletteSize((LPSTR)lpBI);
  371. // Write the file header
  372. WriteFile(fh, (LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER), &dwWritten, NULL);
  373. // Write the DIB header and the bits -- use local version of
  374. // MyWrite, so we can write more than 32767 bytes of data
  375. WriteFile(fh, (LPSTR)lpBI, dwDIBSize, &dwWritten, NULL);
  376. CloseHandle(fh);
  377. if (dwWritten == 0)
  378. return FALSE; // oops, something happened in the write
  379. else
  380. return TRUE; // Success code
  381. }
  382. /*************************************************************************
  383. *
  384. * Function: ReadDIBFile (int)
  385. *
  386. * Purpose: Reads in the specified DIB file into a global chunk of
  387. * memory.
  388. *
  389. * Returns: A handle to a dib (hDIB) if successful.
  390. * NULL if an error occurs.
  391. *
  392. * Comments: BITMAPFILEHEADER is stripped off of the DIB. Everything
  393. * from the end of the BITMAPFILEHEADER structure on is
  394. * returned in the global memory handle.
  395. *
  396. *
  397. * NOTE: The DIB API were not written to handle OS/2 DIBs, so this
  398. * function will reject any file that is not a Windows DIB.
  399. *
  400. *************************************************************************/
  401. HANDLE
  402. BMPAPI
  403. ReadDIBFile(
  404. HANDLE hFile
  405. )
  406. {
  407. BITMAPFILEHEADER bmfHeader;
  408. DWORD dwBitsSize;
  409. UINT nNumColors; // Number of colors in table
  410. HANDLE hDIB;
  411. HANDLE hDIBtmp; // Used for GlobalRealloc() //MPB
  412. LPBITMAPINFOHEADER lpbi;
  413. DWORD offBits;
  414. DWORD dwRead;
  415. // get length of DIB in bytes for use when reading
  416. dwBitsSize = GetFileSize(hFile, NULL);
  417. // Allocate memory for header & color table. We'll enlarge this
  418. // memory as needed.
  419. hDIB = GlobalAlloc(GMEM_MOVEABLE, (DWORD)(sizeof(BITMAPINFOHEADER) +
  420. 256 * sizeof(RGBQUAD)));
  421. if (!hDIB)
  422. return NULL;
  423. lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
  424. if (!lpbi)
  425. {
  426. GlobalFree(hDIB);
  427. return NULL;
  428. }
  429. // read the BITMAPFILEHEADER from our file
  430. if (!ReadFile(hFile, (LPSTR)&bmfHeader, sizeof (BITMAPFILEHEADER),
  431. &dwRead, NULL))
  432. goto ErrExit;
  433. if (sizeof (BITMAPFILEHEADER) != dwRead)
  434. goto ErrExit;
  435. if (bmfHeader.bfType != 0x4d42) // 'BM'
  436. goto ErrExit;
  437. // read the BITMAPINFOHEADER
  438. if (!ReadFile(hFile, (LPSTR)lpbi, sizeof(BITMAPINFOHEADER), &dwRead,
  439. NULL))
  440. goto ErrExit;
  441. if (sizeof(BITMAPINFOHEADER) != dwRead)
  442. goto ErrExit;
  443. // Check to see that it's a Windows DIB -- an OS/2 DIB would cause
  444. // strange problems with the rest of the DIB API since the fields
  445. // in the header are different and the color table entries are
  446. // smaller.
  447. //
  448. // If it's not a Windows DIB (e.g. if biSize is wrong), return NULL.
  449. if (lpbi->biSize == sizeof(BITMAPCOREHEADER))
  450. goto ErrExit;
  451. // Now determine the size of the color table and read it. Since the
  452. // bitmap bits are offset in the file by bfOffBits, we need to do some
  453. // special processing here to make sure the bits directly follow
  454. // the color table (because that's the format we are susposed to pass
  455. // back)
  456. if (!(nNumColors = (UINT)lpbi->biClrUsed))
  457. {
  458. // no color table for 24-bit, default size otherwise
  459. if (lpbi->biBitCount != 24)
  460. nNumColors = 1 << lpbi->biBitCount; // standard size table
  461. }
  462. // fill in some default values if they are zero
  463. if (lpbi->biClrUsed == 0)
  464. lpbi->biClrUsed = nNumColors;
  465. if (lpbi->biSizeImage == 0)
  466. {
  467. lpbi->biSizeImage = ((((lpbi->biWidth * (DWORD)lpbi->biBitCount) +
  468. 31) & ~31) >> 3) * lpbi->biHeight;
  469. }
  470. // get a proper-sized buffer for header, color table and bits
  471. GlobalUnlock(hDIB);
  472. hDIBtmp = GlobalReAlloc(hDIB, lpbi->biSize + nNumColors *
  473. sizeof(RGBQUAD) + lpbi->biSizeImage, 0);
  474. if (!hDIBtmp) // can't resize buffer for loading
  475. goto ErrExitNoUnlock; //MPB
  476. else
  477. hDIB = hDIBtmp;
  478. lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
  479. // read the color table
  480. ReadFile (hFile, (LPSTR)(lpbi) + lpbi->biSize,
  481. nNumColors * sizeof(RGBQUAD), &dwRead, NULL);
  482. // offset to the bits from start of DIB header
  483. offBits = lpbi->biSize + nNumColors * sizeof(RGBQUAD);
  484. // If the bfOffBits field is non-zero, then the bits might *not* be
  485. // directly following the color table in the file. Use the value in
  486. // bfOffBits to seek the bits.
  487. if (bmfHeader.bfOffBits != 0L)
  488. SetFilePointer(hFile, bmfHeader.bfOffBits, NULL, FILE_BEGIN);
  489. if (ReadFile(hFile, (LPSTR)lpbi + offBits, lpbi->biSizeImage, &dwRead,
  490. NULL))
  491. goto OKExit;
  492. ErrExit:
  493. GlobalUnlock(hDIB);
  494. ErrExitNoUnlock:
  495. GlobalFree(hDIB);
  496. return NULL;
  497. OKExit:
  498. GlobalUnlock(hDIB);
  499. return hDIB;
  500. }
  501. //====================================
  502. BOOL
  503. BMPAPI
  504. SaveBitmapInFile(
  505. HBITMAP hBitmap,
  506. LPCSTR szFileName
  507. )
  508. {
  509. BOOL rv = FALSE;
  510. HANDLE hDIB = NULL;
  511. LPVOID pDIB = NULL;
  512. if (!hBitmap)
  513. goto exitpt;
  514. hDIB = BitmapToDIB(hBitmap, NULL);
  515. if (!hDIB)
  516. {
  517. // TRC(ERR, "Can't get DIB bits\n");
  518. goto exitpt;
  519. }
  520. pDIB = GlobalLock(hDIB);
  521. if (!pDIB)
  522. goto exitpt;
  523. if (!SaveDIB(pDIB, szFileName))
  524. goto exitpt;
  525. rv = TRUE;
  526. exitpt:
  527. if (pDIB)
  528. GlobalUnlock(hDIB);
  529. if (hDIB)
  530. GlobalFree(hDIB);
  531. return rv;
  532. }
  533. HANDLE
  534. ReadDIBFromFile(LPCSTR szFileName)
  535. {
  536. HANDLE hFile;
  537. HANDLE hDIB = NULL;
  538. hFile = CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL,
  539. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
  540. NULL);
  541. if (hFile != INVALID_HANDLE_VALUE)
  542. {
  543. hDIB = ReadDIBFile(hFile);
  544. CloseHandle(hFile);
  545. }
  546. return hDIB;
  547. }
  548. /*
  549. * size and color depth are already checked
  550. * the number of colors is 16 or 256
  551. */
  552. BOOL
  553. _CompareBits16to256(
  554. LPBITMAPINFO pbmi1, // 16 color bitmap
  555. LPBITMAPINFO pbmi2, // 256 color bitmap
  556. HDC hdcOutput
  557. )
  558. {
  559. BOOL rv = TRUE;
  560. INT nX, nY;
  561. INT nWidth, nHeight;
  562. INT nLineSize1, nLineSize2;
  563. RGBQUAD *pColorTable1;
  564. RGBQUAD *pColorTable2;
  565. LPSTR pBits1, pBits2;
  566. HBRUSH hRedBrush = NULL;
  567. if (!pbmi1 || !pbmi2)
  568. {
  569. // TRC(ERR, "NULL pointers passed\n");
  570. rv = FALSE;
  571. goto exitpt;
  572. }
  573. nLineSize1 = WIDTHBYTES(pbmi1->bmiHeader.biWidth*4);
  574. nLineSize2 = WIDTHBYTES(pbmi1->bmiHeader.biWidth*8);
  575. pColorTable1 = (RGBQUAD *)(((LPSTR)pbmi1) + pbmi1->bmiHeader.biSize);
  576. pColorTable2 = (RGBQUAD *)(((LPSTR)pbmi2) + pbmi2->bmiHeader.biSize);
  577. pBits1 = FindDIBBits((LPSTR)pbmi1);
  578. pBits2 = FindDIBBits((LPSTR)pbmi2);
  579. nWidth = pbmi1->bmiHeader.biWidth;
  580. nHeight = pbmi1->bmiHeader.biHeight;
  581. hRedBrush = CreateHatchBrush(HS_FDIAGONAL, RGB(255, 0, 0));
  582. SetBkMode(hdcOutput, TRANSPARENT);
  583. SetBrushOrgEx(hdcOutput, 0, 0, NULL);
  584. SetROP2(hdcOutput, R2_COPYPEN);
  585. for (nY = 0; nY < pbmi1->bmiHeader.biHeight; nY++)
  586. {
  587. for (nX = 0; nX < pbmi1->bmiHeader.biWidth; nX += 2)
  588. {
  589. PBYTE pPix1 = pBits1 + nLineSize1 * nY + nX / 2;
  590. PBYTE pPix2 = pBits2 + nLineSize2 * nY + nX;
  591. BYTE Pix1 = (*pPix1) >> 4;
  592. BYTE Pix2 = (*pPix2);
  593. RGBQUAD *pQuad1 = pColorTable1 + (Pix1);
  594. RGBQUAD *pQuad2 = pColorTable2 + (Pix2);
  595. BOOL cmp =
  596. pQuad1->rgbBlue == pQuad2->rgbBlue &&
  597. pQuad1->rgbGreen == pQuad2->rgbGreen &&
  598. pQuad1->rgbRed == pQuad2->rgbRed;
  599. if (cmp)
  600. {
  601. Pix1 = (*pPix1) & 0xf;
  602. Pix2 = (*(pPix2 + 1));
  603. pQuad1 = pColorTable1 + (Pix1);
  604. pQuad2 = pColorTable2 + (Pix2);
  605. cmp =
  606. pQuad1->rgbBlue == pQuad2->rgbBlue &&
  607. pQuad1->rgbGreen == pQuad2->rgbGreen &&
  608. pQuad1->rgbRed == pQuad2->rgbRed;
  609. }
  610. if (!cmp)
  611. {
  612. HRGN hrgn;
  613. hrgn = CreateRectRgn(nX - 3, nHeight - nY - 3,
  614. nX + 4, nHeight - nY + 4);
  615. if ( NULL != hrgn )
  616. {
  617. FillRgn(hdcOutput, hrgn, hRedBrush);
  618. DeleteObject(hrgn);
  619. }
  620. }
  621. rv = rv && cmp;
  622. }
  623. }
  624. exitpt:
  625. if (hRedBrush)
  626. DeleteObject(hRedBrush);
  627. return rv;
  628. }
  629. BOOL
  630. _CompareBits16(
  631. LPBITMAPINFO pbmi1,
  632. LPBITMAPINFO pbmi2,
  633. HDC hdcOutput
  634. )
  635. {
  636. BOOL rv = TRUE;
  637. INT nX, nY;
  638. INT nWidth, nHeight;
  639. INT nLineSize;
  640. RGBQUAD *pColorTable1;
  641. RGBQUAD *pColorTable2;
  642. LPSTR pBits1, pBits2;
  643. HBRUSH hRedBrush = NULL;
  644. if (!pbmi1 || !pbmi2)
  645. {
  646. // TRC(ERR, "NULL pointers passed\n");
  647. rv = FALSE;
  648. goto exitpt;
  649. }
  650. nLineSize = WIDTHBYTES(pbmi1->bmiHeader.biWidth*4);
  651. pColorTable1 = (RGBQUAD *)(((LPSTR)pbmi1) + pbmi1->bmiHeader.biSize);
  652. pColorTable2 = (RGBQUAD *)(((LPSTR)pbmi2) + pbmi2->bmiHeader.biSize);
  653. pBits1 = FindDIBBits((LPSTR)pbmi1);
  654. pBits2 = FindDIBBits((LPSTR)pbmi2);
  655. nWidth = pbmi1->bmiHeader.biWidth;
  656. nHeight = pbmi1->bmiHeader.biHeight;
  657. hRedBrush = CreateHatchBrush(HS_FDIAGONAL, RGB(255, 0, 0));
  658. SetBkMode(hdcOutput, TRANSPARENT);
  659. SetBrushOrgEx(hdcOutput, 0, 0, NULL);
  660. SetROP2(hdcOutput, R2_COPYPEN);
  661. for (nY = 0; nY < pbmi1->bmiHeader.biHeight; nY++)
  662. {
  663. for (nX = 0; nX < pbmi1->bmiHeader.biWidth; nX += 2)
  664. {
  665. PBYTE pPix1 = pBits1 + nLineSize * nY + nX / 2;
  666. PBYTE pPix2 = pBits2 + nLineSize * nY + nX / 2;
  667. BYTE Pix1 = (*pPix1) & 0xf;
  668. BYTE Pix2 = (*pPix2) & 0xf;
  669. RGBQUAD *pQuad1 = pColorTable1 + (Pix1);
  670. RGBQUAD *pQuad2 = pColorTable2 + (Pix2);
  671. BOOL cmp =
  672. pQuad1->rgbBlue == pQuad2->rgbBlue &&
  673. pQuad1->rgbGreen == pQuad2->rgbGreen &&
  674. pQuad1->rgbRed == pQuad2->rgbRed;
  675. if (cmp)
  676. {
  677. Pix1 = (*pPix1) >> 4;
  678. Pix2 = (*pPix2) >> 4;
  679. pQuad1 = pColorTable1 + (Pix1);
  680. pQuad2 = pColorTable2 + (Pix2);
  681. cmp =
  682. pQuad1->rgbBlue == pQuad2->rgbBlue &&
  683. pQuad1->rgbGreen == pQuad2->rgbGreen &&
  684. pQuad1->rgbRed == pQuad2->rgbRed;
  685. }
  686. if (!cmp)
  687. {
  688. HRGN hrgn;
  689. hrgn = CreateRectRgn(nX - 3, nHeight - nY - 3,
  690. nX + 4, nHeight - nY + 4);
  691. if ( NULL != hrgn )
  692. {
  693. FillRgn(hdcOutput, hrgn, hRedBrush);
  694. DeleteObject(hrgn);
  695. }
  696. }
  697. rv = rv && cmp;
  698. }
  699. }
  700. exitpt:
  701. if (hRedBrush)
  702. DeleteObject(hRedBrush);
  703. return rv;
  704. }
  705. BOOL
  706. _CompareBits256(
  707. LPBITMAPINFO pbmi1,
  708. LPBITMAPINFO pbmi2,
  709. HDC hdcOutput
  710. )
  711. {
  712. BOOL rv = TRUE;
  713. INT nX, nY;
  714. INT nWidth, nHeight;
  715. INT nLineSize;
  716. RGBQUAD *pColorTable1;
  717. RGBQUAD *pColorTable2;
  718. LPSTR pBits1, pBits2;
  719. HBRUSH hRedBrush = NULL;
  720. if (!pbmi1 || !pbmi2)
  721. {
  722. // TRC(ERR, "NULL pointers passed\n");
  723. rv = FALSE;
  724. goto exitpt;
  725. }
  726. nLineSize = WIDTHBYTES(pbmi1->bmiHeader.biWidth*8);
  727. pColorTable1 = (RGBQUAD *)(((LPSTR)pbmi1) + pbmi1->bmiHeader.biSize);
  728. pColorTable2 = (RGBQUAD *)(((LPSTR)pbmi2) + pbmi2->bmiHeader.biSize);
  729. pBits1 = FindDIBBits((LPSTR)pbmi1);
  730. pBits2 = FindDIBBits((LPSTR)pbmi2);
  731. nWidth = pbmi1->bmiHeader.biWidth;
  732. nHeight = pbmi1->bmiHeader.biHeight;
  733. hRedBrush = CreateHatchBrush(HS_FDIAGONAL, RGB(255, 0, 0));
  734. SetBkMode(hdcOutput, TRANSPARENT);
  735. SetBrushOrgEx(hdcOutput, 0, 0, NULL);
  736. SetROP2(hdcOutput, R2_COPYPEN);
  737. for (nY = 0; nY < pbmi1->bmiHeader.biHeight; nY++)
  738. {
  739. for (nX = 0; nX < pbmi1->bmiHeader.biWidth; nX++)
  740. {
  741. PBYTE pPix1 = pBits1 + nLineSize * nY + nX;
  742. PBYTE pPix2 = pBits2 + nLineSize * nY + nX;
  743. RGBQUAD *pQuad1 = pColorTable1 + (*pPix1);
  744. RGBQUAD *pQuad2 = pColorTable2 + (*pPix2);
  745. BOOL cmp =
  746. pQuad1->rgbBlue == pQuad2->rgbBlue &&
  747. pQuad1->rgbGreen == pQuad2->rgbGreen &&
  748. pQuad1->rgbRed == pQuad2->rgbRed;
  749. if (!cmp)
  750. {
  751. HRGN hrgn;
  752. hrgn = CreateRectRgn(nX - 3, nHeight - nY - 3,
  753. nX + 4, nHeight - nY + 4);
  754. if ( NULL != hrgn )
  755. {
  756. FillRgn(hdcOutput, hrgn, hRedBrush);
  757. DeleteObject(hrgn);
  758. }
  759. }
  760. rv = rv && cmp;
  761. }
  762. }
  763. exitpt:
  764. if (hRedBrush)
  765. DeleteObject(hRedBrush);
  766. return rv;
  767. }
  768. //
  769. // Supports only 4 and 8 color bit DIBs
  770. //
  771. BOOL
  772. BMPAPI
  773. CompareTwoDIBs(
  774. LPVOID pDIB1,
  775. LPVOID pDIB2,
  776. HBITMAP *phbmpOutput
  777. )
  778. {
  779. BOOL rv = FALSE;
  780. LPBITMAPINFO pbmi1 = NULL;
  781. LPBITMAPINFO pbmi2 = NULL;
  782. HBITMAP hbmpOutput = NULL;
  783. HDC hdcScreen;
  784. HDC hdcMem = NULL;
  785. HBITMAP hbmpOld = NULL;
  786. if (!phbmpOutput)
  787. goto exitpt;
  788. // use the second bitmap for the base of the result
  789. hbmpOutput = DIBToBitmap(pDIB2, NULL);
  790. if (!hbmpOutput)
  791. {
  792. // TRC(ERR, "Can't create output bitmap\n");
  793. goto exitpt;
  794. }
  795. pbmi1 = pDIB1;
  796. pbmi2 = pDIB2;
  797. if (!pbmi1 || !pbmi2)
  798. {
  799. // TRC(ERR, "Can't lock DIBs\n");
  800. goto exitpt;
  801. }
  802. hdcScreen = GetDC(NULL);
  803. if (hdcScreen)
  804. {
  805. hdcMem = CreateCompatibleDC(hdcScreen);
  806. ReleaseDC(NULL, hdcScreen);
  807. }
  808. if (!hdcMem)
  809. {
  810. // TRC(ERR, "Can't get a DC\n");
  811. goto exitpt;
  812. }
  813. hbmpOld = SelectObject(hdcMem, hbmpOutput);
  814. // check the size and color depth of the two bitmaps
  815. if (pbmi1->bmiHeader.biWidth != pbmi2->bmiHeader.biWidth ||
  816. pbmi1->bmiHeader.biHeight != pbmi2->bmiHeader.biHeight)
  817. {
  818. // TRC(INF, "The two bitmaps have different size\n");
  819. goto exitpt;
  820. }
  821. // check that we are going to be able to compare the two dibs
  822. if (
  823. (pbmi1->bmiHeader.biBitCount != 4 &&
  824. pbmi1->bmiHeader.biBitCount != 8) ||
  825. (pbmi2->bmiHeader.biBitCount != 4 &&
  826. pbmi2->bmiHeader.biBitCount != 8)
  827. )
  828. {
  829. // TRC(FATAL, "Unsupported format\n");
  830. goto exitpt;
  831. }
  832. if (pbmi1->bmiHeader.biBitCount == pbmi2->bmiHeader.biBitCount)
  833. {
  834. // compare the DIB bits
  835. if (pbmi1->bmiHeader.biBitCount == 4)
  836. rv = _CompareBits16(pbmi1, pbmi2, hdcMem);
  837. else
  838. rv = _CompareBits256(pbmi1, pbmi2, hdcMem);
  839. } else if (pbmi1->bmiHeader.biBitCount != pbmi2->bmiHeader.biBitCount)
  840. {
  841. if (pbmi1->bmiHeader.biBitCount == 4)
  842. rv = _CompareBits16to256(pbmi1, pbmi2, hdcMem);
  843. else
  844. rv = _CompareBits16to256(pbmi2, pbmi1, hdcMem);
  845. }
  846. // if different, save the result bitmap
  847. if (!rv)
  848. {
  849. SelectObject(hdcMem, hbmpOld);
  850. hbmpOld = NULL;
  851. }
  852. exitpt:
  853. if (hdcMem)
  854. {
  855. if (hbmpOld)
  856. SelectObject(hdcMem, hbmpOld);
  857. ReleaseDC(NULL, hdcMem);
  858. }
  859. if (rv && hbmpOutput)
  860. {
  861. // bitmaps are equal, delete the resulting bitmap
  862. DeleteObject(hbmpOutput);
  863. hbmpOutput = NULL;
  864. }
  865. if (phbmpOutput)
  866. *phbmpOutput = hbmpOutput;
  867. return rv;
  868. }
  869. BOOL
  870. BMPAPI
  871. CompareTwoBitmapFiles(
  872. LPCSTR szFile1,
  873. LPCSTR szFile2,
  874. LPCSTR szResultFileName
  875. )
  876. {
  877. BOOL rv = FALSE;
  878. HANDLE hDIB1 = NULL;
  879. HANDLE hDIB2 = NULL;
  880. HBITMAP hbmpOutput = NULL;
  881. LPVOID pDIB1 = NULL;
  882. LPVOID pDIB2 = NULL;
  883. hDIB1 = ReadDIBFromFile(szFile1);
  884. if (!hDIB1)
  885. {
  886. // TRC(ERR, "Can't read DIB file %s\n", szFile1);
  887. goto exitpt;
  888. }
  889. hDIB2 = ReadDIBFromFile(szFile2);
  890. if (!hDIB2)
  891. {
  892. // TRC(ERR, "Can't read DIB file %s\n", szFile2);
  893. goto exitpt;
  894. }
  895. pDIB1 = GlobalLock(hDIB1);
  896. if (!pDIB1)
  897. goto exitpt;
  898. pDIB2 = GlobalLock(hDIB2);
  899. if (!pDIB2)
  900. goto exitpt;
  901. rv = CompareTwoDIBs(pDIB1, pDIB2, &hbmpOutput);
  902. if (!rv && hbmpOutput)
  903. {
  904. SaveBitmapInFile(hbmpOutput, szResultFileName);
  905. }
  906. exitpt:
  907. if (hbmpOutput)
  908. DeleteObject(hbmpOutput);
  909. if (pDIB1)
  910. GlobalUnlock(hDIB1);
  911. if (pDIB2)
  912. GlobalUnlock(hDIB2);
  913. if (hDIB1)
  914. GlobalFree(hDIB1);
  915. if (hDIB2)
  916. GlobalFree(hDIB2);
  917. return rv;
  918. }
  919. BOOL
  920. GetScreenDIB(
  921. INT left,
  922. INT top,
  923. INT right,
  924. INT bottom,
  925. HANDLE *phDIB
  926. )
  927. {
  928. HDC hScreenDC = NULL;
  929. HDC hMemDC = NULL;
  930. BOOL rv = FALSE;
  931. HANDLE hDIB = NULL;
  932. HBITMAP hDstBitmap = NULL;
  933. HBITMAP hOldDstBmp = NULL;
  934. if (!phDIB)
  935. goto exitpt;
  936. hScreenDC = GetDC(NULL);
  937. if (!hScreenDC)
  938. goto exitpt;
  939. hMemDC = CreateCompatibleDC(hScreenDC);
  940. if (!hMemDC)
  941. goto exitpt;
  942. // Adjust the order of the rectangle
  943. if (left > right)
  944. {
  945. INT c = left;
  946. left = right;
  947. right = c;
  948. }
  949. if (top > bottom)
  950. {
  951. INT c = top;
  952. top = bottom;
  953. bottom = top;
  954. }
  955. hDstBitmap = CreateCompatibleBitmap(
  956. hScreenDC,
  957. right - left,
  958. bottom - top);
  959. if (!hDstBitmap)
  960. goto exitpt;
  961. hOldDstBmp = SelectObject(hMemDC, hDstBitmap);
  962. if (!BitBlt( hMemDC,
  963. 0, 0, // dest x,y
  964. right - left, // dest width
  965. bottom - top, // dest height
  966. hScreenDC,
  967. left, top, // source coordinates
  968. SRCCOPY))
  969. goto exitpt;
  970. hDIB = BitmapToDIB(hDstBitmap, NULL);
  971. if (hDIB)
  972. rv = TRUE;
  973. exitpt:
  974. if (hOldDstBmp)
  975. SelectObject(hMemDC, hOldDstBmp);
  976. if (hDstBitmap)
  977. DeleteObject(hDstBitmap);
  978. if (hScreenDC)
  979. ReleaseDC(NULL, hScreenDC);
  980. if (hMemDC)
  981. DeleteDC(hMemDC);
  982. if (phDIB)
  983. (*phDIB) = hDIB;
  984. return rv;
  985. }