Leaked source code of windows server 2003
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.

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