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.

702 lines
20 KiB

  1. /****************************************************************************
  2. *
  3. * capdib.c
  4. *
  5. * DIB processing module.
  6. *
  7. * Microsoft Video for Windows Sample Capture Class
  8. *
  9. * Copyright (c) 1992, 1993 Microsoft Corporation. All Rights Reserved.
  10. *
  11. * You have a royalty-free right to use, modify, reproduce and
  12. * distribute the Sample Files (and/or any modified version) in
  13. * any way you find useful, provided that you agree that
  14. * Microsoft has no warranty obligations or liability for any
  15. * Sample Application Files which are modified.
  16. *
  17. ***************************************************************************/
  18. #include <windows.h>
  19. #include <windowsx.h>
  20. #include <mmsystem.h>
  21. #include <msvideo.h>
  22. #include <drawdib.h>
  23. #include "avicap.h"
  24. #include "avicapi.h"
  25. //
  26. // Initialize a DIB to the default format of 160x120x8, BI_RGB
  27. //
  28. void SetDefaultCaptureFormat (LPBITMAPINFOHEADER lpbih)
  29. {
  30. lpbih->biSize = sizeof (BITMAPINFOHEADER);
  31. lpbih->biWidth = 160;
  32. lpbih->biHeight = 120;
  33. lpbih->biBitCount = 8;
  34. lpbih->biPlanes = 1;
  35. lpbih->biCompression = BI_RGB;
  36. lpbih->biSizeImage = DIBWIDTHBYTES (*lpbih) * lpbih->biHeight;
  37. lpbih->biXPelsPerMeter = 0;
  38. lpbih->biYPelsPerMeter = 0;
  39. lpbih->biClrUsed = 256;
  40. lpbih->biClrImportant = 0;
  41. }
  42. //
  43. // Whenever we get a new format from the driver, OR
  44. // start using a new palette, we must reallocate
  45. // our global BITMAPINFOHEADER. This allows JPEG
  46. // quantization tables to be tacked onto the BITMAPINFO
  47. // or any other format specific stuff. The color table
  48. // is always offset biSize from the start of the BITMAPINFO.
  49. // Returns: 0 on success, or DV_ERR_... code
  50. //
  51. DWORD AllocNewGlobalBitmapInfo (LPCAPSTREAM lpcs, LPBITMAPINFOHEADER lpbi)
  52. {
  53. DWORD dwSize;
  54. dwSize = lpbi->biSize + 256 * sizeof (RGBQUAD);
  55. // The 256 entry above is HARDWIRED ON PURPOSE
  56. // If biClrUsed was used instead, we would have to realloc
  57. // whenever a palette is pasted (during DibNewPalette())!!!
  58. if (lpcs->lpBitsInfo)
  59. lpcs->lpBitsInfo = (LPBITMAPINFO) GlobalReAllocPtr (lpcs->lpBitsInfo,
  60. dwSize, GHND);
  61. else
  62. lpcs->lpBitsInfo = (LPBITMAPINFO) GlobalAllocPtr (GHND, dwSize);
  63. if (!lpcs->lpBitsInfo)
  64. return (DV_ERR_NOMEM);
  65. // Copy over the BITMAPINFOHEADER
  66. hmemcpy ((HPSTR)lpcs->lpBitsInfo, (HPSTR)lpbi, lpbi->biSize);
  67. return DV_ERR_OK;
  68. }
  69. //
  70. // Whenever we get a new format from the driver
  71. // allocate a new global bitspace. This bitspace is used
  72. // in preview mode and single frame capture.
  73. // Returns: 0 on success, or DV_ERR_... code
  74. //
  75. DWORD AllocNewBitSpace (LPCAPSTREAM lpcs, LPBITMAPINFOHEADER lpbih)
  76. {
  77. DWORD dwSize;
  78. dwSize = lpbih->biSizeImage;
  79. if (lpcs->lpBits)
  80. lpcs->lpBits = GlobalReAllocPtr (lpcs->lpBits, dwSize, GHND);
  81. else
  82. lpcs->lpBits = GlobalAllocPtr (GHND, dwSize);
  83. if (!lpcs->lpBits)
  84. return (DV_ERR_NOMEM);
  85. return DV_ERR_OK;
  86. }
  87. //
  88. // Dib Inititialization code
  89. // Returns: 0 on success, or DV_ERR_... code
  90. //
  91. DWORD DibInit (LPCAPSTREAM lpcs)
  92. {
  93. BITMAPINFOHEADER bmih;
  94. SetDefaultCaptureFormat (&bmih);
  95. return ((WORD) AllocNewGlobalBitmapInfo (lpcs, &bmih));
  96. }
  97. //
  98. // Fini code to free all bitmap resources
  99. //
  100. void DibFini (LPCAPSTREAM lpcs)
  101. {
  102. if (lpcs->lpBits) {
  103. GlobalFreePtr (lpcs->lpBits);
  104. lpcs->lpBits = NULL;
  105. }
  106. if (lpcs->lpBitsInfo) {
  107. GlobalFreePtr (lpcs->lpBitsInfo);
  108. lpcs->lpBitsInfo = NULL;
  109. }
  110. lpcs->dxBits = 0;
  111. lpcs->dyBits = 0;
  112. }
  113. //
  114. // Send a format to the driver.
  115. // Whenever we do a format change, send the driver the
  116. // Source and destination rects.
  117. // Returns: 0 on success, or DV_ERR_... code
  118. //
  119. DWORD SendDriverFormat (LPCAPSTREAM lpcs, LPBITMAPINFOHEADER lpbih, DWORD dwInfoHeaderSize)
  120. {
  121. RECT rc;
  122. DWORD dwError = DV_ERR_NOTSUPPORTED;
  123. rc.left = rc.top = 0;
  124. rc.right = (int) lpbih->biWidth;
  125. rc.bottom = (int) lpbih->biHeight;
  126. if (dwError = videoConfigure(lpcs->hVideoIn,
  127. DVM_FORMAT,
  128. VIDEO_CONFIGURE_SET, NULL,
  129. (LPBITMAPINFOHEADER)lpbih, dwInfoHeaderSize,
  130. NULL, NULL ) ) {
  131. return dwError;
  132. }
  133. else {
  134. // Set the ExternalIn Destination rectangle to the same size
  135. videoMessage (lpcs->hVideoCapture,
  136. DVM_DST_RECT,
  137. (DWORD) (LPVOID)&rc, VIDEO_CONFIGURE_SET);
  138. // Set the VideoIn Source Rectangle to the same size
  139. videoMessage (lpcs->hVideoIn,
  140. DVM_SRC_RECT,
  141. (DWORD) (LPVOID)&rc, VIDEO_CONFIGURE_SET);
  142. // Set the VideoIn Destination Rectangle to the same size
  143. videoMessage (lpcs->hVideoIn,
  144. DVM_DST_RECT,
  145. (DWORD) (LPVOID)&rc, VIDEO_CONFIGURE_SET);
  146. }
  147. return dwError;
  148. }
  149. //
  150. // Given a DIB, see if the driver likes it, then
  151. // allocate the global BITMAPINFOHEADER and bitspace.
  152. //
  153. //
  154. DWORD SetFormatFromDIB (LPCAPSTREAM lpcs, LPBITMAPINFOHEADER lpbih)
  155. {
  156. DWORD dwError;
  157. // Fill optional fields in the DIB header
  158. if (lpbih->biSizeImage == 0)
  159. lpbih->biSizeImage = DIBWIDTHBYTES (*lpbih) * lpbih->biHeight;
  160. // Is the format palatized or full-color
  161. if (lpbih->biBitCount <= 8 && lpbih->biClrUsed == 0)
  162. lpbih->biClrUsed = (1 << lpbih-> biBitCount); // paletized
  163. // See if the driver will support it
  164. if (dwError = SendDriverFormat (lpcs, lpbih, lpbih->biSize) )
  165. return dwError;
  166. // Realloc our global header
  167. if (dwError = AllocNewGlobalBitmapInfo (lpcs, lpbih))
  168. return dwError;
  169. // Realloc the bits
  170. if (dwError = AllocNewBitSpace (lpcs, lpbih))
  171. return dwError;
  172. lpcs->dxBits = (int)lpbih->biWidth;
  173. lpcs->dyBits = (int)lpbih->biHeight;
  174. lpcs->VidHdr.lpData = lpcs->lpBits;
  175. lpcs->VidHdr.dwBufferLength = lpbih->biSizeImage;
  176. lpcs->VidHdr.dwUser = 0;
  177. lpcs->VidHdr.dwFlags = 0;
  178. return (DV_ERR_OK);
  179. }
  180. //
  181. // Returns: a LPBITMAPINFO allocated from global memory
  182. // containing the current format, or NULL on error.
  183. // Note that this structure can be larger than
  184. // sizeof (BITMAPINFO), ie. JPEG !!!
  185. //
  186. LPBITMAPINFO DibGetCurrentFormat (LPCAPSTREAM lpcs)
  187. {
  188. DWORD dwError;
  189. DWORD dwSize = 0;
  190. LPBITMAPINFO lpBInfo = NULL;
  191. if (!lpcs->fHardwareConnected)
  192. return NULL;
  193. // How large is the BITMAPINFOHEADER?
  194. videoConfigure( lpcs->hVideoIn,
  195. DVM_FORMAT,
  196. VIDEO_CONFIGURE_GET | VIDEO_CONFIGURE_QUERYSIZE,
  197. &dwSize, NULL, NULL, NULL, NULL);
  198. if (!dwSize)
  199. dwSize = sizeof (BITMAPINFOHEADER);
  200. if (!(lpBInfo = (LPBITMAPINFO) GlobalAllocPtr (GMEM_MOVEABLE, dwSize)))
  201. return (NULL);
  202. if (dwError = videoConfigure( lpcs->hVideoIn,
  203. DVM_FORMAT,
  204. VIDEO_CONFIGURE_GET | VIDEO_CONFIGURE_CURRENT, NULL,
  205. (LPBITMAPINFOHEADER) lpBInfo, dwSize,
  206. NULL, NULL ) ) {
  207. // very bad. the driver can't tell us its format. we're hosed.
  208. GlobalFreePtr (lpBInfo);
  209. return NULL;
  210. }
  211. return (lpBInfo);
  212. }
  213. //
  214. // Main entry point when changing capture formats.
  215. // This is called when the user closes the drivers format dialog.
  216. // Returns: 0 on success, or DV_ERR_... code
  217. //
  218. DWORD DibGetNewFormatFromDriver (LPCAPSTREAM lpcs)
  219. {
  220. BOOL f;
  221. BITMAPINFOHEADER bih;
  222. DWORD dwError;
  223. LPBITMAPINFO lpBInfo;
  224. if (!lpcs->fHardwareConnected)
  225. return DV_ERR_OK; // Return OK if no hardware exists
  226. lpBInfo = DibGetCurrentFormat (lpcs);
  227. if (lpBInfo == NULL)
  228. return DV_ERR_NOTSUPPORTED;
  229. // Set our internal state
  230. if (dwError = SetFormatFromDIB (lpcs, (LPBITMAPINFOHEADER) lpBInfo)) {
  231. // couldn't change formats, time to punt!
  232. // Try to switch back to minimal format (120x160x8)
  233. errorDriverID (lpcs, dwError);
  234. SetDefaultCaptureFormat (&bih);
  235. dwError = SetFormatFromDIB (lpcs, &bih);
  236. }
  237. // Force a new frame to be taken, so the DIB contains good
  238. // data. Especially important to prevent codecs from exploding!
  239. if (!dwError)
  240. videoFrame (lpcs->hVideoIn, &lpcs->VidHdr);
  241. if (lpBInfo)
  242. GlobalFreePtr (lpBInfo);
  243. f = DrawDibBegin(lpcs->hdd,NULL,-1,-1,(LPBITMAPINFOHEADER)(lpcs->lpBitsInfo),-1,-1,0);
  244. if (!f)
  245. errorUpdateError (lpcs, IDS_CAP_AVI_DRAWDIB_ERROR);
  246. return (dwError);
  247. }
  248. //
  249. // Main entry point when changing capture formats via App message.
  250. // Returns: TRUE on success, or FALSE if format not supported
  251. //
  252. BOOL DibNewFormatFromApp (LPCAPSTREAM lpcs, LPBITMAPINFO lpbiNew, WORD dwSize)
  253. {
  254. BOOL f;
  255. DWORD dwError;
  256. LPBITMAPINFO lpBInfo;
  257. if (!lpcs->fHardwareConnected)
  258. return FALSE;
  259. lpBInfo = DibGetCurrentFormat (lpcs); // Allocs memory!!!
  260. if (lpBInfo == NULL)
  261. return FALSE;
  262. // Set our internal state
  263. if (dwError = SetFormatFromDIB (lpcs, (LPBITMAPINFOHEADER) lpbiNew)) {
  264. // Driver didn't accept the format,
  265. // switch back to the original
  266. errorDriverID (lpcs, dwError);
  267. SetFormatFromDIB (lpcs, (LPBITMAPINFOHEADER)lpBInfo);
  268. }
  269. // Force a new frame to be taken, so the DIB contains good
  270. // data. Especially important to prevent codecs from exploding!
  271. videoFrame (lpcs->hVideoIn, &lpcs->VidHdr);
  272. if (lpBInfo)
  273. GlobalFreePtr (lpBInfo);
  274. f = DrawDibBegin(lpcs->hdd,NULL,-1,-1,(LPBITMAPINFOHEADER)(lpcs->lpBitsInfo),-1,-1,0);
  275. if (!f)
  276. errorDriverID (lpcs, IDS_CAP_AVI_DRAWDIB_ERROR);
  277. return (dwError == DV_ERR_OK);
  278. }
  279. void xlatClut8 (BYTE _huge *pb, DWORD dwSize, BYTE _huge *xlat)
  280. {
  281. DWORD dw;
  282. for (dw = 0; dw < dwSize; dw++, ((BYTE huge *)pb)++)
  283. *pb = xlat[*pb];
  284. }
  285. //
  286. // DibNewPalette
  287. //
  288. // Performs three functions:
  289. // 1. Updates the biClrUsed field if biBitCount <= 8.
  290. // 2. Remaps BI_RGB images through a LUT when a new palette is assigned.
  291. // 3. Copies the palette entries into our global BITMAPINFO
  292. //
  293. // Returns: TRUE on success
  294. //
  295. DWORD DibNewPalette (LPCAPSTREAM lpcs, HPALETTE hPalNew)
  296. {
  297. LPBITMAPINFOHEADER lpbi;
  298. int n;
  299. int nColors;
  300. BYTE FAR * lpBits;
  301. RGBQUAD FAR * lpRgb;
  302. BYTE xlat[256];
  303. DWORD dwSize;
  304. PALETTEENTRY pe;
  305. if (!hPalNew || !lpcs->lpBits || !lpcs->lpBitsInfo)
  306. return FALSE;
  307. lpbi = &(lpcs->lpBitsInfo->bmiHeader);
  308. lpRgb = (RGBQUAD FAR *)((LPSTR)lpbi + (WORD)lpbi->biSize);
  309. lpBits = lpcs->lpBits;
  310. GetObject(hPalNew, sizeof(int), (LPSTR) &nColors);
  311. if (nColors > 256)
  312. nColors = 256;
  313. // Get the palette entries regardless of the compression
  314. // Supermac uses non BI_RGB with a palette!
  315. if (lpbi->biBitCount == 8) {
  316. for (n=0; n<nColors; n++) {
  317. GetPaletteEntries(hPalNew, n, 1, &pe);
  318. lpRgb[n].rgbRed = pe.peRed;
  319. lpRgb[n].rgbGreen = pe.peGreen;
  320. lpRgb[n].rgbBlue = pe.peBlue;
  321. }
  322. }
  323. if (lpbi->biBitCount == 8 && lpbi->biCompression == BI_RGB) {
  324. //
  325. // build a xlat table. from the old Palette to the new palette.
  326. //
  327. for (n=0; n<(int)lpbi->biClrUsed; n++) {
  328. xlat[n] = (BYTE)GetNearestPaletteIndex(hPalNew,
  329. RGB(lpRgb[n].rgbRed,lpRgb[n].rgbGreen,lpRgb[n].rgbBlue));
  330. }
  331. //
  332. // translate the DIB bits
  333. //
  334. if ((dwSize = lpbi->biSizeImage) == 0)
  335. dwSize = lpbi->biHeight * DIBWIDTHBYTES(*lpbi);
  336. switch ((WORD)lpbi->biCompression)
  337. {
  338. case BI_RGB:
  339. xlatClut8(lpBits, dwSize, xlat);
  340. }
  341. }
  342. // Fix for Supermac, force biClrUsed to the number of palette entries
  343. // even if non-BI_RGB formats.
  344. if (lpbi-> biBitCount <= 8)
  345. lpbi->biClrUsed = nColors;
  346. return TRUE;
  347. }
  348. /* DibPaint(LPCAPSTREAM lpcs, hdc)
  349. *
  350. * Paint the current DIB into the window;
  351. */
  352. void DibPaint(LPCAPSTREAM lpcs, HDC hdc)
  353. {
  354. RECT rc;
  355. BOOL fOK;
  356. fOK = (lpcs->lpBits != NULL);
  357. if (fOK) {
  358. if (lpcs-> fScale) {
  359. GetClientRect(lpcs->hwnd, &rc);
  360. fOK = DrawDibDraw(lpcs->hdd, hdc, 0, 0,
  361. rc.right - rc.left, rc.bottom - rc.top,
  362. (LPBITMAPINFOHEADER)lpcs->lpBitsInfo, lpcs->lpBits,
  363. 0, 0, -1, -1, DDF_BACKGROUNDPAL);
  364. }
  365. else
  366. fOK = DrawDibDraw(lpcs->hdd, hdc, 0, 0,
  367. lpcs->dxBits, lpcs->dyBits,
  368. (LPBITMAPINFOHEADER)lpcs->lpBitsInfo, lpcs->lpBits,
  369. 0, 0, -1, -1, DDF_BACKGROUNDPAL);
  370. }
  371. if (!fOK) {
  372. SelectObject(hdc, GetStockObject(BLACK_BRUSH));
  373. GetClientRect(lpcs->hwnd, &rc);
  374. PatBlt(hdc, 0, 0, rc.right, rc.bottom, PATCOPY);
  375. }
  376. }
  377. /*
  378. *
  379. * CreatePackedDib() - return the current DIB in packed (ie CF_DIB) format
  380. *
  381. */
  382. HANDLE CreatePackedDib (LPBITMAPINFO lpBitsInfo, LPSTR lpSrcBits, HPALETTE hPalette)
  383. {
  384. HANDLE hdib;
  385. LPBITMAPINFO lpbi;
  386. int i;
  387. DWORD dwSize;
  388. PALETTEENTRY pe;
  389. LPBYTE lpBits;
  390. RGBQUAD FAR * lpRgb;
  391. // If the data is compressed, let ICM do the work for us...
  392. if ( lpBitsInfo->bmiHeader.biCompression != BI_RGB &&
  393. lpBitsInfo->bmiHeader.biCompression != BI_RLE8 &&
  394. (lpBitsInfo->bmiHeader.biBitCount != 8 ||
  395. lpBitsInfo->bmiHeader.biBitCount != 24 )) {
  396. LPBITMAPINFO lpOutFormat = NULL;
  397. HANDLE hPackedDIBOut = NULL;
  398. if (!(lpOutFormat = (LPBITMAPINFO)GlobalAllocPtr(
  399. GMEM_MOVEABLE, sizeof (BITMAPINFOHEADER) +
  400. 256 * sizeof (RGBQUAD))))
  401. return NULL;
  402. hmemcpy ((HPSTR)lpOutFormat, (HPSTR)lpBitsInfo, sizeof (BITMAPINFOHEADER));
  403. // Try to get an RGB format
  404. lpOutFormat->bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
  405. lpOutFormat->bmiHeader.biCompression = BI_RGB;
  406. lpOutFormat->bmiHeader.biClrUsed = 0;
  407. lpOutFormat->bmiHeader.biClrImportant = 0;
  408. // Uh, oh, force to a 24-bit DIB if > 8 BPP
  409. if (lpBitsInfo->bmiHeader.biBitCount <= 8)
  410. lpOutFormat->bmiHeader.biBitCount = 8;
  411. else
  412. lpOutFormat->bmiHeader.biBitCount = 24;
  413. lpOutFormat->bmiHeader.biSizeImage =
  414. WIDTHBYTES (lpOutFormat->bmiHeader.biWidth *
  415. (lpOutFormat->bmiHeader.biBitCount == 8 ? 1 : 3)) *
  416. lpOutFormat->bmiHeader.biHeight;
  417. hPackedDIBOut = ICImageDecompress (
  418. NULL, /*hic*/
  419. 0, /*uiFlags*/
  420. lpBitsInfo, /*lpbiIn*/
  421. lpSrcBits, /*lpBits*/
  422. lpOutFormat); /*use default format chosen by compressor*/
  423. if (lpOutFormat)
  424. GlobalFreePtr (lpOutFormat);
  425. return (hPackedDIBOut);
  426. }
  427. dwSize = lpBitsInfo->bmiHeader.biSize +
  428. lpBitsInfo->bmiHeader.biClrUsed * sizeof(RGBQUAD) +
  429. lpBitsInfo->bmiHeader.biSizeImage;
  430. hdib = GlobalAlloc(GMEM_MOVEABLE, dwSize);
  431. if (!hdib)
  432. return NULL;
  433. lpbi = (LPVOID)GlobalLock(hdib);
  434. //
  435. // copy the header
  436. //
  437. hmemcpy ((HPSTR)lpbi, (HPSTR)lpBitsInfo, lpBitsInfo->bmiHeader.biSize);
  438. //
  439. // copy the color table
  440. //
  441. lpRgb = (RGBQUAD FAR *)((LPSTR)lpbi + (WORD)lpbi->bmiHeader.biSize);
  442. for (i=0; i < (int)lpBitsInfo->bmiHeader.biClrUsed; i++) {
  443. GetPaletteEntries(hPalette, i, 1, &pe);
  444. lpRgb[i].rgbRed = pe.peRed;
  445. lpRgb[i].rgbGreen = pe.peGreen;
  446. lpRgb[i].rgbBlue = pe.peBlue;
  447. lpRgb[i].rgbReserved = 0;
  448. }
  449. //
  450. // copy the bits.
  451. //
  452. lpBits = (LPBYTE)lpbi +
  453. lpbi->bmiHeader.biSize +
  454. lpbi->bmiHeader.biClrUsed * sizeof(RGBQUAD);
  455. hmemcpy ((LPSTR)lpBits, (LPSTR)lpSrcBits,
  456. lpbi->bmiHeader.biSizeImage);
  457. GlobalUnlock (hdib);
  458. return hdib;
  459. }
  460. /*---------------------------------------------------------------------+
  461. | dibIsWritable() - return TRUE if the dib format is writable, |
  462. | by out dibWrite() function, FALSE if not. |
  463. | |
  464. +---------------------------------------------------------------------*/
  465. BOOL FAR PASCAL dibIsWritable (LPBITMAPINFO lpBitsInfo)
  466. {
  467. if (!lpBitsInfo)
  468. return FALSE;
  469. // For now, just assume that all capture formats have an installed
  470. // codec which can convert to RGB. In the future, each time the
  471. // format is changed, test that the codec actually accepts the format.
  472. return TRUE;
  473. }
  474. /*---------------------------------------------------------------------+
  475. | dibWrite() - write out the DIB to a file. The global header is |
  476. | in <glpBitsInfo> and the actual dib bits are in |
  477. | <glpBits>. If it is palettized then the palette is in |
  478. | <ghPalCurrent>. |
  479. | |
  480. | We won't do error reporting in this function, let the caller take |
  481. | care of that along with Opening and Closing the HMMIO. |
  482. | |
  483. +---------------------------------------------------------------------*/
  484. BOOL FAR PASCAL dibWrite(LPCAPSTREAM lpcs, HMMIO hmmio)
  485. {
  486. BITMAPFILEHEADER bfh;
  487. DWORD dw;
  488. HANDLE hPackedDib = NULL;
  489. LPBITMAPINFO lpbi = NULL;
  490. BOOL fOK = FALSE;
  491. /* do some checking */
  492. WinAssert(hmmio != 0);
  493. if (!lpcs->lpBits || !lpcs->lpBitsInfo)
  494. return FALSE;
  495. // Create a packed DIB, converting from a compressed format,
  496. // if necessary.
  497. hPackedDib = CreatePackedDib (lpcs->lpBitsInfo,
  498. lpcs->lpBits,
  499. lpcs->hPalCurrent);
  500. lpbi = (LPBITMAPINFO) GlobalLock (hPackedDib);
  501. if (!lpbi)
  502. goto WriteError;
  503. /* initialize the bitmap file header */
  504. bfh.bfType = 'B' | 'M' << 8;
  505. bfh.bfSize = sizeof(bfh) + sizeof(BITMAPINFOHEADER) +
  506. lpbi->bmiHeader.biSizeImage +
  507. (lpbi->bmiHeader.biBitCount > 8 ? 0 : (lpbi->bmiHeader.biClrUsed * sizeof(RGBQUAD)));
  508. bfh.bfReserved1 = bfh.bfReserved2 = 0;
  509. bfh.bfOffBits = bfh.bfSize - lpbi->bmiHeader.biSizeImage ;
  510. // dw is the size of the BITMAPINFO + color table + image
  511. dw = bfh.bfSize - sizeof(bfh);
  512. /* write out the file header portion */
  513. if (mmioWrite(hmmio, (HPSTR)&bfh, (LONG)sizeof(BITMAPFILEHEADER)) !=
  514. sizeof(BITMAPFILEHEADER)){
  515. goto WriteError;
  516. }
  517. /* now write out the header and bits */
  518. if (mmioWrite(hmmio, (HPSTR)lpbi, (LONG) dw) == (LONG) dw) {
  519. fOK = TRUE;
  520. }
  521. WriteError:
  522. if (lpbi)
  523. GlobalUnlock (hPackedDib);
  524. if (hPackedDib)
  525. GlobalFree (hPackedDib);
  526. return fOK;
  527. }
  528. /*--------------------------------------------------------------+
  529. | fileSaveDIB - save the frame as a DIB |
  530. | Top level routine to save a single frame |
  531. +--------------------------------------------------------------*/
  532. BOOL FAR PASCAL fileSaveDIB(LPCAPSTREAM lpcs, LPSTR lpszFileName)
  533. {
  534. HMMIO hmmio;
  535. HCURSOR hOldCursor;
  536. BOOL fOK;
  537. hmmio = mmioOpen(lpszFileName, NULL, MMIO_WRITE);
  538. if( !hmmio ) {
  539. /* try and create */
  540. hmmio = mmioOpen(lpszFileName, NULL, MMIO_CREATE | MMIO_WRITE);
  541. if( !hmmio ) {
  542. /* find out if the file was read only or we are just */
  543. /* totally hosed up here. */
  544. hmmio = mmioOpen(lpszFileName, NULL, MMIO_READ);
  545. if (hmmio){
  546. /* file was read only, error on it */
  547. errorUpdateError (lpcs, IDS_CAP_READONLYFILE, (LPSTR)lpszFileName);
  548. mmioClose(hmmio, 0);
  549. return FALSE;
  550. } else {
  551. /* even weirder error has occured here, give CANTOPEN */
  552. errorUpdateError (lpcs, IDS_CAP_CANTOPEN, (LPSTR) lpszFileName);
  553. return FALSE;
  554. }
  555. }
  556. }
  557. hOldCursor = SetCursor( lpcs-> hWaitCursor );
  558. mmioSeek(hmmio, 0, SEEK_SET);
  559. fOK = dibWrite(lpcs, hmmio);
  560. mmioClose( hmmio, 0 );
  561. SetCursor( hOldCursor );
  562. if (!fOK)
  563. errorUpdateError (lpcs, IDS_CAP_ERRORDIBSAVE, (LPSTR) lpszFileName);
  564. return fOK;
  565. }