screengrab_c.h 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. #include "../base/bitmap_free_c.h"
  2. #include <stdlib.h> /* malloc() */
  3. #if defined(IS_MACOSX)
  4. #include <OpenGL/OpenGL.h>
  5. #include <OpenGL/gl.h>
  6. #include <ApplicationServices/ApplicationServices.h>
  7. #include <ScreenCaptureKit/ScreenCaptureKit.h>
  8. #elif defined(USE_X11)
  9. #include <X11/Xlib.h>
  10. #include <X11/Xutil.h>
  11. #include "../base/xdisplay_c.h"
  12. #elif defined(IS_WINDOWS)
  13. #include <string.h>
  14. #endif
  15. #include "screen_c.h"
  16. #if defined(IS_MACOSX) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > MAC_OS_VERSION_14_4
  17. static CGImageRef capture15(CGDirectDisplayID id, CGRect diIntersectDisplayLocal, CGColorSpaceRef colorSpace) {
  18. dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
  19. __block CGImageRef image1 = nil;
  20. [SCShareableContent getShareableContentWithCompletionHandler:^(SCShareableContent* content, NSError* error) {
  21. @autoreleasepool {
  22. if (error) {
  23. dispatch_semaphore_signal(semaphore);
  24. return;
  25. }
  26. SCDisplay* target = nil;
  27. for (SCDisplay *display in content.displays) {
  28. if (display.displayID == id) {
  29. target = display;
  30. break;
  31. }
  32. }
  33. if (!target) {
  34. dispatch_semaphore_signal(semaphore);
  35. return;
  36. }
  37. SCContentFilter* filter = [[SCContentFilter alloc] initWithDisplay:target excludingWindows:@[]];
  38. SCStreamConfiguration* config = [[SCStreamConfiguration alloc] init];
  39. config.queueDepth = 5;
  40. config.sourceRect = diIntersectDisplayLocal;
  41. config.width = diIntersectDisplayLocal.size.width * sys_scale(id);
  42. config.height = diIntersectDisplayLocal.size.height * sys_scale(id);
  43. config.scalesToFit = false;
  44. config.captureResolution = 1;
  45. [SCScreenshotManager captureImageWithFilter:filter
  46. configuration:config
  47. completionHandler:^(CGImageRef img, NSError* error) {
  48. if (!error) {
  49. image1 = CGImageCreateCopyWithColorSpace(img, colorSpace);
  50. }
  51. dispatch_semaphore_signal(semaphore);
  52. }];
  53. }
  54. }];
  55. dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
  56. dispatch_release(semaphore);
  57. return image1;
  58. }
  59. #endif
  60. MMBitmapRef copyMMBitmapFromDisplayInRect(MMRectInt32 rect, int32_t display_id, int8_t isPid) {
  61. #if defined(IS_MACOSX)
  62. MMBitmapRef bitmap = NULL;
  63. uint8_t *buffer = NULL;
  64. size_t bufferSize = 0;
  65. CGDirectDisplayID displayID = (CGDirectDisplayID) display_id;
  66. if (displayID == -1 || displayID == 0) {
  67. displayID = CGMainDisplayID();
  68. }
  69. MMPointInt32 o = rect.origin; MMSizeInt32 s = rect.size;
  70. #if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > MAC_OS_VERSION_14_4
  71. CGColorSpaceRef color = CGColorSpaceCreateWithName(kCGColorSpaceSRGB);
  72. CGImageRef image = capture15(displayID, CGRectMake(o.x, o.y, s.w, s.h), color);
  73. CGColorSpaceRelease(color);
  74. #else
  75. // This API is deprecated in macos 15, use ScreenCaptureKit's captureScreenshot
  76. CGImageRef image = CGDisplayCreateImageForRect(displayID, CGRectMake(o.x, o.y, s.w, s.h));
  77. #endif
  78. if (!image) { return NULL; }
  79. CFDataRef imageData = CGDataProviderCopyData(CGImageGetDataProvider(image));
  80. if (!imageData) { return NULL; }
  81. bufferSize = CFDataGetLength(imageData);
  82. buffer = malloc(bufferSize);
  83. CFDataGetBytes(imageData, CFRangeMake(0, bufferSize), buffer);
  84. bitmap = createMMBitmap_c(buffer,
  85. CGImageGetWidth(image), CGImageGetHeight(image), CGImageGetBytesPerRow(image),
  86. CGImageGetBitsPerPixel(image), CGImageGetBitsPerPixel(image) / 8);
  87. CFRelease(imageData);
  88. CGImageRelease(image);
  89. return bitmap;
  90. #elif defined(USE_X11)
  91. MMBitmapRef bitmap;
  92. Display *display;
  93. if (display_id == -1) {
  94. display = XOpenDisplay(NULL);
  95. } else {
  96. display = XGetMainDisplay();
  97. }
  98. MMPointInt32 o = rect.origin; MMSizeInt32 s = rect.size;
  99. XImage *image = XGetImage(display, XDefaultRootWindow(display),
  100. (int)o.x, (int)o.y, (unsigned int)s.w, (unsigned int)s.h,
  101. AllPlanes, ZPixmap);
  102. XCloseDisplay(display);
  103. if (image == NULL) { return NULL; }
  104. bitmap = createMMBitmap_c((uint8_t *)image->data,
  105. s.w, s.h, (size_t)image->bytes_per_line,
  106. (uint8_t)image->bits_per_pixel, (uint8_t)image->bits_per_pixel / 8);
  107. image->data = NULL; /* Steal ownership of bitmap data so we don't have to copy it. */
  108. XDestroyImage(image);
  109. return bitmap;
  110. #elif defined(IS_WINDOWS)
  111. MMBitmapRef bitmap;
  112. void *data;
  113. HDC screen = NULL, screenMem = NULL;
  114. HBITMAP dib;
  115. BITMAPINFO bi;
  116. int32_t x = rect.origin.x, y = rect.origin.y;
  117. int32_t w = rect.size.w, h = rect.size.h;
  118. /* Initialize bitmap info. */
  119. bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
  120. bi.bmiHeader.biWidth = (long) w;
  121. bi.bmiHeader.biHeight = -(long) h; /* Non-cartesian, please */
  122. bi.bmiHeader.biPlanes = 1;
  123. bi.bmiHeader.biBitCount = 32;
  124. bi.bmiHeader.biCompression = BI_RGB;
  125. bi.bmiHeader.biSizeImage = (DWORD)(4 * w * h);
  126. bi.bmiHeader.biXPelsPerMeter = 0;
  127. bi.bmiHeader.biYPelsPerMeter = 0;
  128. bi.bmiHeader.biClrUsed = 0;
  129. bi.bmiHeader.biClrImportant = 0;
  130. HWND hwnd;
  131. if (display_id == -1 || isPid == 0) {
  132. // screen = GetDC(NULL); /* Get entire screen */
  133. hwnd = GetDesktopWindow();
  134. } else {
  135. hwnd = (HWND) (uintptr) display_id;
  136. }
  137. screen = GetDC(hwnd);
  138. if (screen == NULL) { return NULL; }
  139. // Todo: Use DXGI
  140. screenMem = CreateCompatibleDC(screen);
  141. /* Get screen data in display device context. */
  142. dib = CreateDIBSection(screen, &bi, DIB_RGB_COLORS, &data, NULL, 0);
  143. /* Copy the data into a bitmap struct. */
  144. BOOL b = (screenMem == NULL) ||
  145. SelectObject(screenMem, dib) == NULL ||
  146. !BitBlt(screenMem, (int)0, (int)0, (int)w, (int)h, screen, x, y, SRCCOPY);
  147. if (b) {
  148. /* Error copying data. */
  149. ReleaseDC(hwnd, screen);
  150. DeleteObject(dib);
  151. if (screenMem != NULL) { DeleteDC(screenMem); }
  152. return NULL;
  153. }
  154. bitmap = createMMBitmap_c(NULL, w, h, 4 * w, (uint8_t)bi.bmiHeader.biBitCount, 4);
  155. /* Copy the data to our pixel buffer. */
  156. if (bitmap != NULL) {
  157. bitmap->imageBuffer = malloc(bitmap->bytewidth * bitmap->height);
  158. memcpy(bitmap->imageBuffer, data, bitmap->bytewidth * bitmap->height);
  159. }
  160. ReleaseDC(hwnd, screen);
  161. DeleteObject(dib);
  162. DeleteDC(screenMem);
  163. return bitmap;
  164. #endif
  165. }