screencapture.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596
  1. #include "stdafx.h"
  2. #include "screencapture.h"
  3. #ifdef RVC_OS_WIN
  4. static HMONITOR GetPrimaryMonitorHandle()
  5. {
  6. const POINT ptZero = {0, 0};
  7. return MonitorFromPoint(ptZero, MONITOR_DEFAULTTOPRIMARY);
  8. }
  9. static HBITMAP CopyScreenToBitmap(LPRECT lpRect)
  10. {
  11. HDC hScrDC, hMemDC; // screen DC and memory DC
  12. // HBITMAP hBitmap; //,
  13. // HBITMAP hBitmap;
  14. // HBITMAP hOldBitmap; // handles to deice-dependent bitmaps
  15. int nX, nY, nX2, nY2; // coordinates of rectangle to grab
  16. int nWidth, nHeight; // DIB width and height
  17. int xScrn, yScrn; // screen resolution
  18. HGDIOBJ hOldBitmap , hBitmap;
  19. // check for an empty rectangle
  20. if (IsRectEmpty(lpRect))
  21. return NULL;
  22. // create a DC for the screen and create
  23. // a memory DC compatible to screen DC
  24. MONITORINFOEX mi;
  25. mi.cbSize = sizeof(mi);
  26. GetMonitorInfoA(GetPrimaryMonitorHandle(), &mi);
  27. //hScrDC = CreateDCA("DISPLAY", NULL, NULL, NULL);
  28. hScrDC = CreateDCA(mi.szDevice, NULL, NULL, NULL);
  29. hMemDC = CreateCompatibleDC(hScrDC); // get points of rectangle to grab
  30. nX = lpRect->left;
  31. nY = lpRect->top;
  32. nX2 = lpRect->right;
  33. nY2 = lpRect->bottom; // get screen resolution
  34. xScrn = GetDeviceCaps(hScrDC, HORZRES);
  35. yScrn = GetDeviceCaps(hScrDC, VERTRES);
  36. //make sure bitmap rectangle is visible
  37. if (nX < 0)
  38. nX = 0;
  39. if (nY < 0)
  40. nY = 0;
  41. if (nX2 > xScrn)
  42. nX2 = xScrn;
  43. if (nY2 > yScrn)
  44. nY2 = yScrn;
  45. nWidth = nX2 - nX;
  46. nHeight = nY2 - nY;
  47. // create a bitmap compatible with the screen DC
  48. hBitmap = CreateCompatibleBitmap(hScrDC, nWidth, nHeight);
  49. // select new bitmap into memory DC
  50. hOldBitmap = SelectObject (hMemDC, hBitmap);
  51. // bitblt screen DC to memory DC
  52. BitBlt(hMemDC, 0, 0, nWidth, nHeight, hScrDC, nX, nY, SRCCOPY);
  53. // select old bitmap back into memory DC and get handle to
  54. // bitmap of the screen
  55. hBitmap = SelectObject(hMemDC, hOldBitmap);
  56. // clean up
  57. DeleteDC(hScrDC);
  58. DeleteDC(hMemDC);
  59. // return handle to the bitmap
  60. return (HBITMAP)hBitmap;
  61. }
  62. static HPALETTE GetSystemPalette()
  63. {
  64. HDC hDC; // handle to a DC
  65. static HPALETTE hPal = NULL; // handle to a palette
  66. HANDLE hLogPal; // handle to a logical palette
  67. LPLOGPALETTE lpLogPal; // pointer to a logical palette
  68. int nColors; // number of colors
  69. // Find out how many palette entries we want.
  70. MONITORINFOEX mi;
  71. mi.cbSize = sizeof(mi);
  72. GetMonitorInfoA(GetPrimaryMonitorHandle(), &mi);
  73. hDC = CreateDCA(mi.szDevice, NULL, NULL, NULL);
  74. //hDC = CreateDC ( TEXT("DISPLAY"), NULL, NULL, NULL );
  75. if (!hDC)
  76. return NULL;
  77. nColors = 256; //PalEntriesOnDevice(hDC); // Number of palette entries
  78. // Allocate room for the palette and lock it.
  79. hLogPal = GlobalAlloc(GHND, sizeof(LOGPALETTE) + nColors *
  80. sizeof(PALETTEENTRY));
  81. // if we didn't get a logical palette, return NULL
  82. if (!hLogPal)
  83. return NULL;
  84. // get a pointer to the logical palette
  85. lpLogPal = (LPLOGPALETTE)GlobalLock(hLogPal);
  86. // set some important fields
  87. lpLogPal->palVersion = 0x300; //PALVERSION;
  88. lpLogPal->palNumEntries = nColors;
  89. // Copy the current system palette into our logical palette
  90. GetSystemPaletteEntries(hDC, 0, nColors,
  91. (LPPALETTEENTRY)(lpLogPal->palPalEntry));
  92. // Go ahead and create the palette. Once it's created,
  93. // we no longer need the LOGPALETTE, so free it.
  94. hPal = CreatePalette(lpLogPal);
  95. // clean up
  96. GlobalUnlock(hLogPal);
  97. GlobalFree(hLogPal);
  98. DeleteDC(hDC);
  99. return hPal;
  100. }
  101. static WORD DibNumColors (VOID FAR * pv)
  102. {
  103. int bits;
  104. LPBITMAPINFOHEADER lpbi;
  105. LPBITMAPCOREHEADER lpbc;
  106. lpbi = ((LPBITMAPINFOHEADER)pv);
  107. lpbc = ((LPBITMAPCOREHEADER)pv);
  108. /* With the BITMAPINFO format headers, the size of the palette
  109. * is in biClrUsed, whereas in the BITMAPCORE - style headers, it
  110. * is dependent on the bits per pixel ( = 2 raised to the power of
  111. * bits/pixel).
  112. */
  113. if (lpbi->biSize != sizeof(BITMAPCOREHEADER))
  114. {
  115. if (lpbi->biClrUsed != 0)
  116. return (WORD)lpbi->biClrUsed;
  117. bits = lpbi->biBitCount;
  118. }
  119. else
  120. bits = lpbc->bcBitCount;
  121. switch (bits)
  122. {
  123. case 1:
  124. return 2;
  125. case 4:
  126. return 16;
  127. case 8:
  128. return 256;
  129. default:
  130. // A 24 bitcount DIB has no color table
  131. return 0;
  132. }
  133. }
  134. static WORD PaletteSize (VOID FAR * pv)
  135. {
  136. LPBITMAPINFOHEADER lpbi;
  137. WORD NumColors;
  138. lpbi = (LPBITMAPINFOHEADER)pv;
  139. NumColors = DibNumColors(lpbi);
  140. if (lpbi->biSize == sizeof(BITMAPCOREHEADER))
  141. return NumColors * sizeof(RGBTRIPLE);
  142. else
  143. return NumColors * sizeof(RGBQUAD);
  144. }
  145. static HANDLE AllocRoomForDIB(BITMAPINFOHEADER bi, HBITMAP hBitmap)
  146. {
  147. DWORD dwLen;
  148. HANDLE hDIB;
  149. HDC hDC;
  150. LPBITMAPINFOHEADER lpbi;
  151. HANDLE hTemp;
  152. // Figure out the size needed to hold the BITMAPINFO structure
  153. // (which includes the BITMAPINFOHEADER and the color table).
  154. dwLen = bi.biSize + PaletteSize((LPSTR) &bi);
  155. hDIB = GlobalAlloc(GHND,dwLen);
  156. // Check that DIB handle is valid
  157. if (!hDIB)
  158. return NULL;
  159. // Set up the BITMAPINFOHEADER in the newly allocated global memory,
  160. // then call GetDIBits() with lpBits = NULL to have it fill in the
  161. // biSizeImage field for us.
  162. lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
  163. *lpbi = bi;
  164. MONITORINFOEX mi;
  165. mi.cbSize = sizeof(mi);
  166. GetMonitorInfoA(GetPrimaryMonitorHandle(), &mi);
  167. hDC = CreateDCA(mi.szDevice, NULL, NULL, NULL);
  168. GetDIBits(hDC, hBitmap, 0, (UINT) bi.biHeight, NULL, (LPBITMAPINFO)lpbi,
  169. DIB_RGB_COLORS);
  170. DeleteDC(hDC);
  171. // If the driver did not fill in the biSizeImage field,
  172. // fill it in -- NOTE: this is a bug in the driver!
  173. if (lpbi->biSizeImage == 0)
  174. lpbi->biSizeImage = (DWORD)(lpbi->biWidth * lpbi->biBitCount) * lpbi->biHeight / 8;
  175. // Get the size of the memory block we need
  176. dwLen = lpbi->biSize + PaletteSize((LPSTR) &bi) + lpbi->biSizeImage;
  177. // Unlock the memory block
  178. GlobalUnlock(hDIB);
  179. // ReAlloc the buffer big enough to hold all the bits
  180. if (hTemp = GlobalReAlloc(hDIB,dwLen,0))
  181. return hTemp;
  182. else
  183. {
  184. // Else free memory block and return failure
  185. GlobalFree(hDIB);
  186. return NULL;
  187. }
  188. }
  189. static HANDLE ChangeBitmapFormat(HBITMAP hBitmap, WORD wBitCount, DWORD dwCompression, HPALETTE hPal)
  190. {
  191. HDC hDC; // Screen DC
  192. HANDLE hNewDIB=NULL; // Handle to new DIB
  193. BITMAP Bitmap; // BITMAP data structure
  194. BITMAPINFOHEADER bi; // Bitmap info. header
  195. LPBITMAPINFOHEADER lpbi; // Pointer to bitmap header
  196. HPALETTE hOldPal=NULL; // Handle to palette
  197. WORD NewBPP; // New bits per pixel
  198. DWORD NewComp; // New compression format
  199. // Check for a valid bitmap handle
  200. if (!hBitmap)
  201. return NULL;
  202. // Validate wBitCount and dwCompression
  203. // They must match correctly (i.e., BI_RLE4 and 4 BPP or
  204. // BI_RLE8 and 8BPP, etc.) or we return failure
  205. if (wBitCount == 0)
  206. {
  207. NewComp = dwCompression;
  208. if (NewComp == BI_RLE4)
  209. NewBPP = 4;
  210. else if (NewComp == BI_RLE8)
  211. NewBPP = 8;
  212. else // Not enough info */
  213. return NULL;
  214. }
  215. else if (wBitCount == 1 && dwCompression == BI_RGB)
  216. {
  217. NewBPP = wBitCount;
  218. NewComp = BI_RGB;
  219. }
  220. else if (wBitCount == 4)
  221. {
  222. NewBPP = wBitCount;
  223. if (dwCompression == BI_RGB || dwCompression == BI_RLE4)
  224. NewComp = dwCompression;
  225. else
  226. return NULL;
  227. }
  228. else if (wBitCount == 8)
  229. {
  230. NewBPP = wBitCount;
  231. if (dwCompression == BI_RGB || dwCompression == BI_RLE8)
  232. NewComp = dwCompression;
  233. else
  234. return NULL;
  235. }
  236. else if (wBitCount == 24 && dwCompression == BI_RGB)
  237. {
  238. NewBPP = wBitCount;
  239. NewComp = BI_RGB;
  240. }
  241. else
  242. return NULL;
  243. // Get info about the bitmap
  244. GetObject(hBitmap, sizeof(BITMAP), (LPSTR)&Bitmap);
  245. // Fill in the BITMAPINFOHEADER appropriately
  246. bi.biSize = sizeof(BITMAPINFOHEADER);
  247. bi.biWidth = Bitmap.bmWidth;
  248. bi.biHeight = Bitmap.bmHeight;
  249. bi.biPlanes = 1;
  250. bi.biBitCount = NewBPP;
  251. bi.biCompression = NewComp;
  252. bi.biSizeImage = 0;
  253. bi.biXPelsPerMeter = 0;
  254. bi.biYPelsPerMeter = 0;
  255. bi.biClrUsed = 0;
  256. bi.biClrImportant = 0;
  257. // Go allocate room for the new DIB
  258. hNewDIB = AllocRoomForDIB(bi, hBitmap);
  259. if (!hNewDIB)
  260. return NULL;
  261. // Get a pointer to the new DIB
  262. lpbi = (LPBITMAPINFOHEADER)GlobalLock(hNewDIB);
  263. // If we have a palette, get a DC and select/realize it
  264. if (hPal)
  265. {
  266. MONITORINFOEX mi;
  267. mi.cbSize = sizeof(mi);
  268. GetMonitorInfoA(GetPrimaryMonitorHandle(), &mi);
  269. hDC = CreateDCA(mi.szDevice, NULL, NULL, NULL);
  270. hOldPal = SelectPalette(hDC, hPal, FALSE);
  271. RealizePalette(hDC);
  272. }
  273. // Call GetDIBits and get the new DIB bits
  274. if (!GetDIBits(hDC, hBitmap, 0, (UINT) lpbi->biHeight, (LPSTR)lpbi +
  275. (WORD)lpbi->biSize + PaletteSize((LPSTR)lpbi), (LPBITMAPINFO)lpbi,
  276. DIB_RGB_COLORS))
  277. {
  278. GlobalUnlock(hNewDIB);
  279. GlobalFree(hNewDIB);
  280. hNewDIB = NULL;
  281. }
  282. // Clean up and return
  283. if (hOldPal)
  284. {
  285. SelectPalette(hDC, hOldPal, TRUE);
  286. RealizePalette(hDC);
  287. DeleteDC(hDC);
  288. }
  289. // Unlock the new DIB's memory block
  290. if (hNewDIB)
  291. GlobalUnlock(hNewDIB);
  292. return hNewDIB;
  293. }
  294. static int SaveDib(HANDLE hDib, void *buf)
  295. {
  296. BITMAPFILEHEADER bmfHdr; // Header for Bitmap file
  297. LPBITMAPINFOHEADER lpBI; // Pointer to DIB info structure
  298. DWORD dwDIBSize;
  299. lpBI = (LPBITMAPINFOHEADER)GlobalLock(hDib);
  300. if (!lpBI)
  301. {
  302. return -1;
  303. }
  304. if (lpBI->biSize != sizeof(BITMAPINFOHEADER))
  305. {
  306. GlobalUnlock(hDib);
  307. return -1;
  308. }
  309. memcpy(buf, (LPSTR)lpBI + (WORD)lpBI->biSize + PaletteSize((LPSTR)lpBI), lpBI->biSizeImage);
  310. GlobalUnlock(hDib);
  311. return 0;
  312. }
  313. int screencapture_capture1(RECT *lprc, void *buf, int *size)
  314. {
  315. int width = lprc->right - lprc->left;
  316. int height = lprc->bottom - lprc->top;
  317. int linesize = (width * 3 + 3) & 0xfffffffc;
  318. if (buf == NULL) {
  319. *size = linesize * height;
  320. return 0;
  321. }
  322. HBITMAP hBitmap = CopyScreenToBitmap(lprc);
  323. HPALETTE hPal = GetSystemPalette();
  324. HANDLE hDIB = ChangeBitmapFormat(hBitmap, 24, BI_RGB, hPal);
  325. SaveDib(hDIB, buf);
  326. GlobalFree(hDIB);
  327. DeleteObject(hPal);
  328. DeleteObject(hBitmap);
  329. return 0;
  330. }
  331. int screencapture_capture(RECT *lprc, void *buf, int *size)
  332. {
  333. int width = lprc->right - lprc->left;
  334. int height = lprc->bottom - lprc->top;
  335. int linesize = (width * 3 + 3) & 0xfffffffc;
  336. if (buf == NULL) {
  337. *size = linesize * height;
  338. return 0;
  339. }
  340. assert(*size >= linesize * height);
  341. HDC dc = NULL;
  342. HDC memdc = NULL;
  343. HBITMAP hbm = NULL;
  344. int rc;
  345. BITMAPINFO bmpInfo;
  346. //HWND hWndDeskTop = GetDesktopWindow();
  347. void *data;
  348. MONITORINFOEX mi;
  349. mi.cbSize = sizeof(mi);
  350. GetMonitorInfoA(GetPrimaryMonitorHandle(), &mi);
  351. dc = CreateDCA(mi.szDevice, NULL, NULL, NULL);
  352. //dc = GetDC(hWndDeskTop);
  353. //dc = CreateDCA("DISPLAY", 0, 0, 0);
  354. if (!dc)
  355. return -1;
  356. memdc = CreateCompatibleDC(dc);
  357. if (memdc) {
  358. memset(&bmpInfo, 0, sizeof(bmpInfo));
  359. bmpInfo.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
  360. bmpInfo.bmiHeader.biPlanes = 1;
  361. bmpInfo.bmiHeader.biWidth = width;
  362. bmpInfo.bmiHeader.biHeight = height;
  363. bmpInfo.bmiHeader.biCompression = BI_RGB;
  364. bmpInfo.bmiHeader.biBitCount = 24;
  365. bmpInfo.bmiHeader.biSizeImage = width * height * 3;
  366. hbm = CreateDIBSection(dc, &bmpInfo, DIB_RGB_COLORS, &data, NULL, 0);
  367. //hbm = CreateCompatibleBitmap(memdc, width, height);
  368. }
  369. if (!memdc || !hbm) {
  370. rc = -1;
  371. goto on_error;
  372. }
  373. HGDIOBJ old = SelectObject(memdc, hbm);
  374. BOOL bret = BitBlt(memdc, 0, 0, width, height, dc, lprc ? lprc->left : 0, lprc ? lprc->top : 0, SRCCOPY);
  375. if (!bret) {
  376. rc = -1;
  377. goto on_error;
  378. }
  379. SelectObject(memdc, old);
  380. memcpy(buf, data, bmpInfo.bmiHeader.biSizeImage);
  381. *size = linesize * height;
  382. rc = 0;
  383. on_error:
  384. if (memdc)
  385. DeleteDC(memdc);
  386. if (hbm)
  387. DeleteObject(hbm);
  388. if (dc)
  389. DeleteDC(dc);//
  390. return rc;
  391. }
  392. #else
  393. #include <X11/Xutil.h>
  394. #include <X11/Xlib.h>
  395. int screencapture_capture(RECT* lprc, void* buf, int* size) {
  396. int width = lprc->right - lprc->left;
  397. int height = lprc->bottom - lprc->top;
  398. int linesize = (width * 3 + 3) & 0xfffffffc;
  399. if (buf == NULL) {
  400. *size = linesize * height;
  401. return 0;
  402. }
  403. Display* display = XOpenDisplay(NULL);
  404. Window root = DefaultRootWindow(display);
  405. XImage* image = XGetImage(display, root, lprc ? lprc->left : 0, lprc ? lprc->top : 0, width, height, AllPlanes, ZPixmap);
  406. unsigned long red_mask = image->red_mask;
  407. unsigned long green_mask = image->green_mask;
  408. unsigned long blue_mask = image->blue_mask;
  409. for (int x = 0; x < width; x++){
  410. for (int y = 0; y < height; y++)
  411. {
  412. unsigned long pixel = XGetPixel(image, x, y);
  413. unsigned char blue = pixel & blue_mask;
  414. unsigned char green = (pixel & green_mask) >> 8;
  415. unsigned char red = (pixel & red_mask) >> 16;
  416. ((unsigned char *)buf)[(x + width * y) * 3] = red;
  417. ((unsigned char*)buf)[(x + width * y) * 3 + 1] = green;
  418. ((unsigned char*)buf)[(x + width * y) * 3 + 2] = blue;
  419. }
  420. }
  421. *size = linesize * height;
  422. if (image != NULL) {
  423. XDestroyImage(image);
  424. image = NULL;
  425. }
  426. if (display != NULL) {
  427. XCloseDisplay(display);
  428. display = NULL;
  429. }
  430. return 0;
  431. }
  432. int getScreenSize(int* width, int* height) {
  433. Display* display = XOpenDisplay(NULL);
  434. int default_id = DefaultScreen(display);
  435. Screen* screen = ScreenOfDisplay(display, default_id);
  436. *width = screen->width;
  437. *height = screen->height;
  438. if (display != NULL) {
  439. XCloseDisplay(display);
  440. display = NULL;
  441. }
  442. return 0;
  443. }
  444. #endif
  445. int screencapture_clipoff(int width, int height, void* buf, int n_rc, RECT* rcs)
  446. {
  447. int i, k;
  448. char* p;
  449. for (i = 0; i < n_rc; ++i) {
  450. RECT* lprc = &rcs[i];
  451. for (k = lprc->top, p = (char*)buf + lprc->top * width * 3 + lprc->left * 3; k < lprc->bottom; ++k) {
  452. memset(p, 0, (lprc->right - lprc->left) * 3);
  453. p += width * 3;
  454. }
  455. }
  456. return 0;
  457. }