home *** CD-ROM | disk | FTP | other *** search
/ Freelog 54 / Freelog054.iso / Bas / Détente / WinPenguins / screen_capture.c < prev    next >
C/C++ Source or Header  |  2001-04-08  |  13KB  |  477 lines

  1. /**
  2.  * $Id: screen_capture.c,v 1.3 2001/04/08 15:53:07 mvines Exp $
  3.  *
  4.  *  Copyright (C) 2000  Tom Lee
  5.  *
  6.  *  This program is free software; you can redistribute it and/or modify
  7.  *  it under the terms of the GNU General Public License as published by
  8.  *  the Free Software Foundation; either version 2 of the License, or
  9.  *  (at your option) any later version.
  10.  *
  11.  *  This program is distributed in the hope that it will be useful,
  12.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  *  GNU General Public License for more details.
  15.  *
  16.  *  You should have received a copy of the GNU General Public License
  17.  *  along with this program; if not, write to the Free Software
  18.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  19.  *
  20.  *  As a special exception, Michael Vines gives permission to link this program
  21.  *  with the Microsoft Visual C++ Runtime/MFC Environment, and distribute the
  22.  *  resulting executable, without including the source code for the Microsoft 
  23.  *  Visual C++ Runtime/MFC Environment in the source distribution
  24.  */
  25. #include "screen_capture.h"
  26.  
  27. ////////////////////////////////////////////////////////////////
  28. //
  29. // + Method:      CreateDisplayDC
  30. //
  31. // + Description: Creates a DC associated with the Display
  32. //
  33. // + Params:      
  34. //                  -> LPRECTCAPINFO lpCapInfo: A reset 
  35. //                     capture info structure
  36. //
  37. // + Return Type: int
  38. //
  39. // + Returns:     
  40. //                  -> -1: Display DC has already been created in
  41. //                         this LPRECTCAPINFO
  42. //                  -> -2: Unable to create new Display DC
  43. //                  -> 0:  Display DC successfully created
  44. //
  45. // + Change Log:  
  46. //
  47. //                -> 3/28/01: Method created
  48. //
  49. ////////////////////////////////////////////////////////////////
  50.  
  51. int __cdecl CreateDisplayDC( LPRECTCAPINFO lpCapInfo )
  52. {
  53.     if( lpCapInfo->hDisplayDC != NULL )
  54.     {
  55.         return -1;
  56.     }
  57.  
  58.     lpCapInfo->hDisplayDC = CreateDC( "DISPLAY", NULL, NULL, NULL );
  59.  
  60.     if( lpCapInfo->hDisplayDC == NULL )
  61.     {
  62.         return -2;
  63.     }
  64.  
  65.     lpCapInfo->dwBPP = GetDeviceCaps( lpCapInfo->hDisplayDC, BITSPIXEL );
  66.  
  67.     if( lpCapInfo->dwBPP <= 8 )
  68.     {
  69.         lpCapInfo->dwNumColors = GetDeviceCaps( lpCapInfo->hDisplayDC, NUMCOLORS );
  70.     }
  71.     else
  72.     {
  73.         lpCapInfo->dwNumColors = 0;
  74.     }
  75.  
  76.     return 0;
  77. }
  78.  
  79. ////////////////////////////////////////////////////////////////
  80. //
  81. // + Method:      AdjustCaptureRect
  82. //
  83. // + Description: Adjusts the rectangle to capture
  84. //
  85. // + Params:      
  86. //                  -> LPRECTCAPINFO lpCapInfo: The LPRECTCAPINFO
  87. //                     whose coordinates are to be adjusted
  88. //                  -> int x, y, nWidth, nHeight: Position & size
  89. //                     of the capture rectangle
  90. //
  91. // + Return Type: void
  92. //
  93. // + Returns:     None
  94. //
  95. // + Change Log:  
  96. //
  97. //                -> 3/28/01: Method created
  98. //
  99. ////////////////////////////////////////////////////////////////
  100.  
  101. void __cdecl AdjustCaptureRect( LPRECTCAPINFO lpCapInfo, int x, int y, int nWidth, int nHeight )
  102. {
  103.     lpCapInfo->nCapX = x;
  104.     lpCapInfo->nCapY = y;
  105.     lpCapInfo->nCapWidth = nWidth;
  106.     lpCapInfo->nCapHeight = nHeight;
  107. }
  108.  
  109. ////////////////////////////////////////////////////////////////
  110. //
  111. // + Method:      CreateSuitableDIB
  112. //
  113. // + Description: Creates a DIB and a DC to be associated with it.
  114. //                  These are used together to save the copy of the
  115. //                  screen to memory.
  116. //
  117. // + Params:      
  118. //                  -> LPRECTCAPINFO lpCapInfo: Capture info that's
  119. //                     had CreateDisplayDC and AdjustCaptureRect
  120. //                     perform the necessary operations.
  121. //
  122. // + Return Type: int
  123. //
  124. // + Returns:     
  125. //                  -1: hImage or hImageDC has already been created
  126. //                  -2: Unable to create the DIB
  127. //                  -3: Unable to create the DIB's DC
  128. //                  0: Created both the new DIB and DC
  129. //
  130. // + Change Log:  
  131. //
  132. //                -> 3/28/01: Method created
  133. //
  134. ////////////////////////////////////////////////////////////////
  135.  
  136. int __cdecl CreateSuitableDIB( LPRECTCAPINFO lpCapInfo )
  137. {
  138.     BITMAPINFO bi;
  139.     BITMAPINFOHEADER *hdr;
  140.     
  141.     if( lpCapInfo->hImage != 0 || lpCapInfo->hImageDC != 0 )
  142.     {
  143.         return -1;
  144.     }
  145.  
  146.     hdr = &bi.bmiHeader;
  147.  
  148.     hdr->biSize                = sizeof( BITMAPINFOHEADER );
  149.     hdr->biBitCount            = (WORD)lpCapInfo->dwBPP;
  150.     hdr->biClrImportant        = lpCapInfo->dwNumColors;
  151.     hdr->biClrUsed            = lpCapInfo->dwNumColors;
  152.     hdr->biCompression        = BI_RGB;
  153.     hdr->biPlanes            = 1;
  154.     hdr->biWidth            = lpCapInfo->nCapWidth;
  155.     hdr->biHeight            = lpCapInfo->nCapHeight;
  156.     hdr->biXPelsPerMeter    = 0;
  157.     hdr->biYPelsPerMeter    = 0;
  158.     hdr->biSizeImage        = 0;
  159.  
  160.     lpCapInfo->hImage = CreateDIBSection( lpCapInfo->hDisplayDC, &bi, DIB_PAL_COLORS, &lpCapInfo->pBits, NULL, 0 );
  161.  
  162.     if( lpCapInfo->hImage == NULL )
  163.     {
  164.         return -2;
  165.     }
  166.  
  167.     lpCapInfo->hImageDC = CreateCompatibleDC( lpCapInfo->hDisplayDC );
  168.  
  169.     if( lpCapInfo->hImageDC == NULL )
  170.     {
  171.         DeleteObject( lpCapInfo->hImage );
  172.         return -3;
  173.     }
  174.     else
  175.     {
  176.         SelectObject( lpCapInfo->hImageDC, lpCapInfo->hImage );
  177.         return 0;
  178.     }
  179. }
  180.  
  181. ////////////////////////////////////////////////////////////////
  182. //
  183. // + Method:      PerformBitBlockTransfer
  184. //
  185. // + Description: A fancy way of saying BitBlt :)
  186. //
  187. // + Params:      
  188. //                  -> LPRECTCAPINFO lpCapInfo: A pointer to a 
  189. //                     RECTCAPINFO structure that's had the hDisplayDC,
  190. //                     hImage, hImageDC, x, y, nWidth, nHeight members set.
  191. //
  192. // + Return Type: int
  193. //
  194. // + Returns:     
  195. //                  -> -1: hImageDC or hDisplayDC is NULL
  196. //                  -> -2: BitBlt failed
  197. //                  -> 0: Copied the image to hImage
  198. //
  199. // + Change Log:  
  200. //
  201. //                -> 3/28/01: Method created
  202. //
  203. ////////////////////////////////////////////////////////////////
  204.  
  205. int __cdecl PerformBitBlockTransfer( LPRECTCAPINFO lpCapInfo )
  206. {
  207.     if( lpCapInfo->hImageDC == NULL || lpCapInfo->hDisplayDC == NULL )
  208.     {
  209.         return -1;
  210.     }
  211.  
  212.     if( !BitBlt( lpCapInfo->hImageDC, 0, 0, lpCapInfo->nCapWidth, lpCapInfo->nCapHeight, lpCapInfo->hDisplayDC, lpCapInfo->nCapX, lpCapInfo->nCapY, SRCCOPY ) )
  213.     {
  214.         return -2;
  215.     }
  216.     else
  217.     {
  218.         return 0;
  219.     }
  220. }
  221.  
  222. ////////////////////////////////////////////////////////////////
  223. //
  224. // + Method:      FullScreenCapture
  225. //
  226. // + Description: Captures the entire display and saves all
  227. //                  recorded info into lpCapInfo
  228. //
  229. // + Params:      
  230. //                  -> LPRECTCAPINFO lpCapInfo: receives info about
  231. //                     the capture.
  232. //
  233. // + Return Type: int
  234. //
  235. // + Returns:     
  236. //                  -> -1: Couldn't create display DC
  237. //                  -> -2: Couldn't create suitable DIB
  238. //                  -> -3: BitBlt failed
  239. //                  -> 0: Screen sucessfully captured
  240. //
  241. // + Change Log:  
  242. //
  243. //                -> 3/28/01: Method created
  244. //
  245. ////////////////////////////////////////////////////////////////
  246.  
  247. int __cdecl FullScreenCapture( LPRECTCAPINFO lpCapInfo )
  248. {
  249.     ResetCaptureInfo( lpCapInfo, FALSE );
  250.  
  251.     if( CreateDisplayDC( lpCapInfo ) != 0 )
  252.     {
  253.         return -1;
  254.     }
  255.  
  256.     AdjustCaptureRect( lpCapInfo, 0, 0, GetDeviceCaps( lpCapInfo->hDisplayDC, HORZRES ), GetDeviceCaps( lpCapInfo->hDisplayDC, VERTRES ) );
  257.  
  258.     if( CreateSuitableDIB( lpCapInfo ) != 0 )
  259.     {
  260.         ResetCaptureInfo( lpCapInfo, TRUE );
  261.         return -2;
  262.     }
  263.  
  264.     if( PerformBitBlockTransfer( lpCapInfo ) != 0 )
  265.     {
  266.         ResetCaptureInfo( lpCapInfo, TRUE );
  267.         return -3;
  268.     }
  269.  
  270.     return 0;
  271. }
  272.  
  273. ////////////////////////////////////////////////////////////////
  274. //
  275. // + Method:      CaptureScreenRect
  276. //
  277. // + Description: Captures a portion of the screen
  278. //
  279. // + Params:      
  280. //                  -> LPRECTCAPINFO lpCapInfo: Structure to receive
  281. //                     capture information
  282. //                  -> LPRECT lpBounds: Pointer to a rect containing
  283. //                     the coordinates to capture
  284. //
  285. // + Return Type: int
  286. //
  287. // + Returns:     As for FullScreenCapture
  288. //
  289. // + Change Log:  
  290. //
  291. //                -> 3/28/01: Method created
  292. //
  293. ////////////////////////////////////////////////////////////////
  294.  
  295. int __cdecl CaptureScreenRect( LPRECTCAPINFO lpCapInfo, LPRECT lpBounds )
  296. {
  297.     if( CreateDisplayDC( lpCapInfo ) != 0 )
  298.     {
  299.         return -1;
  300.     }
  301.  
  302.     AdjustCaptureRect( lpCapInfo, lpBounds->left, lpBounds->top, lpBounds->right - lpBounds->left, lpBounds->bottom - lpBounds->top );
  303.  
  304.     if( CreateSuitableDIB( lpCapInfo ) != 0 )
  305.     {
  306.         ResetCaptureInfo( lpCapInfo, TRUE );
  307.         return -2;
  308.     }
  309.  
  310.     if( PerformBitBlockTransfer( lpCapInfo ) != 0 )
  311.     {
  312.         ResetCaptureInfo( lpCapInfo, TRUE );
  313.         return -3;
  314.     }
  315.  
  316.     return 0;
  317. }
  318.  
  319. ////////////////////////////////////////////////////////////////
  320. //
  321. // + Method:      CaptureWindow
  322. //
  323. // + Description: Captures a still image of a window
  324. //
  325. // + Params:      
  326. //                  -> LPRECTCAPINFO lpCapInfo: structure to receive
  327. //                     info about the capture operation
  328. //                  -> HWND hWnd: Window to capture
  329. //
  330. // + Return Type: int
  331. //
  332. // + Returns:     As per CaptureScreenRect
  333. //
  334. // + Change Log:  
  335. //
  336. //                -> 3/28/01: Method created
  337. //
  338. ////////////////////////////////////////////////////////////////
  339.  
  340. int __cdecl CaptureWindow( LPRECTCAPINFO lpCapInfo, HWND hWnd )
  341. {
  342.     RECT rc;
  343.  
  344.     GetWindowRect( hWnd, &rc );
  345.  
  346.     return CaptureScreenRect( lpCapInfo, &rc );
  347. }
  348.  
  349. ////////////////////////////////////////////////////////////////
  350. //
  351. // + Method:      ResetCaptureInfo
  352. //
  353. // + Description: Zeroes RECTCAPINFO structure and, if wished,
  354. //                  frees memory associated with it.
  355. //
  356. // + Params:      
  357. //                  -> LPRECTCAPINFO lpCapInfo: structure to reset
  358. //                  -> BOOL bCheckMem: checks for allocated memory 
  359. //                     within the structure and frees it as necessary
  360. //
  361. // + Return Type: int
  362. //
  363. // + Returns:     0 - always
  364. //
  365. // + Change Log:  
  366. //
  367. //                -> 3/28/01: Method created
  368. //
  369. ////////////////////////////////////////////////////////////////
  370.  
  371. int __cdecl ResetCaptureInfo( LPRECTCAPINFO lpCapInfo, BOOL bCheckMem )
  372. {
  373.     if( bCheckMem )
  374.     {
  375.         if( lpCapInfo->hDisplayDC != NULL )
  376.         {
  377.             DeleteDC( lpCapInfo->hDisplayDC );
  378.         }
  379.  
  380.         if( lpCapInfo->hImageDC != NULL )
  381.         {
  382.             DeleteDC( lpCapInfo->hImageDC );
  383.         }
  384.  
  385.         if( lpCapInfo->hImage != NULL )
  386.         {
  387.             DeleteObject( lpCapInfo->hImage );
  388.         }
  389.     }
  390.  
  391.     memset( lpCapInfo, 0, sizeof( RECTCAPINFO ) );
  392.  
  393.     return 0;
  394. }
  395.  
  396. ////////////////////////////////////////////////////////////////
  397. //
  398. // + Method:      SaveCaptureToFile
  399. //
  400. // + Description: Saves a screen capture to disk
  401. //
  402. // + Params:      
  403. //                  -> LPRECTCAPINFO lpCapInfo: structure containing
  404. //                     information retrieved from a successful capture
  405. //                  -> const char *pszFileName: Name of the file to save
  406. //                     to. Be warned, this file will be OVERWRITTEN if
  407. //                     it already exists!
  408. //
  409. // + Return Type: int
  410. //
  411. // + Returns:     
  412. //                  -> -1: lpCapInfo doesn't contain enough info
  413. //                  -> -2: Couldn't open pszFileName for writing
  414. //                  -> 0: Saved capture to file!
  415. //
  416. // + Change Log:  
  417. //
  418. //                -> 3/28/01: Method created
  419. //
  420. ////////////////////////////////////////////////////////////////
  421.  
  422. int __cdecl SaveCaptureToFile( LPRECTCAPINFO lpCapInfo, const char *pszFileName )
  423. {
  424.     HANDLE hFile; DWORD dwWriteSize;
  425.     RGBQUAD clrs[ 256 ];
  426.     BITMAPFILEHEADER bfh;
  427.     BITMAPINFOHEADER bih;
  428.  
  429.     if( lpCapInfo->hDisplayDC == NULL || lpCapInfo->hImageDC == NULL || lpCapInfo->hImage == NULL || lpCapInfo->pBits == NULL )
  430.     {
  431.         return -1;
  432.     }
  433.  
  434.     hFile = CreateFile( pszFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
  435.  
  436.     if( hFile == INVALID_HANDLE_VALUE )
  437.     {
  438.         return -2;
  439.     }
  440.  
  441.     if( lpCapInfo->dwNumColors != 0 )
  442.     {
  443.         lpCapInfo->dwNumColors = GetDIBColorTable( lpCapInfo->hImageDC, 0, lpCapInfo->dwNumColors, clrs );
  444.     }
  445.  
  446.     bfh.bfType = 0x4D42;
  447.     bfh.bfSize = ((lpCapInfo->nCapWidth * lpCapInfo->nCapHeight * lpCapInfo->dwBPP)/8 ) + sizeof( BITMAPFILEHEADER ) + sizeof( BITMAPINFOHEADER ) + (lpCapInfo->dwNumColors * sizeof( RGBQUAD ) );
  448.     bfh.bfReserved1 = 0;
  449.     bfh.bfReserved2 = 0;
  450.     bfh.bfOffBits = sizeof( BITMAPFILEHEADER ) + sizeof( BITMAPINFOHEADER ) + ( lpCapInfo->dwNumColors * sizeof( RGBQUAD ) );
  451.  
  452.     bih.biSize = sizeof( BITMAPINFOHEADER );
  453.     bih.biWidth = lpCapInfo->nCapWidth;
  454.     bih.biHeight = lpCapInfo->nCapHeight;
  455.     bih.biPlanes = 1;
  456.     bih.biBitCount = (WORD)lpCapInfo->dwBPP;
  457.     bih.biCompression = BI_RGB;
  458.     bih.biClrUsed = lpCapInfo->dwNumColors;
  459.     bih.biClrImportant = 0;
  460.     bih.biXPelsPerMeter = 0;
  461.     bih.biYPelsPerMeter = 0;
  462.     bih.biSizeImage = 0;
  463.  
  464.     WriteFile( hFile, &bfh, sizeof( BITMAPFILEHEADER ), &dwWriteSize, NULL );
  465.     WriteFile( hFile, &bih, sizeof( BITMAPINFOHEADER ), &dwWriteSize, NULL );
  466.  
  467.     if( lpCapInfo->dwNumColors != 0 )
  468.     {
  469.         WriteFile( hFile, clrs, lpCapInfo->dwNumColors * sizeof( RGBQUAD ), &dwWriteSize, NULL );
  470.     }
  471.  
  472.     WriteFile( hFile, lpCapInfo->pBits, (lpCapInfo->nCapWidth * lpCapInfo->nCapHeight * lpCapInfo->dwBPP)/8, &dwWriteSize, NULL );
  473.     CloseHandle( hFile );
  474.  
  475.     return 0;
  476. }
  477.