【问题标题】:Programmatically grab screenshots in OSX以编程方式在 OSX 中抓取屏幕截图
【发布时间】:2012-02-28 13:37:30
【问题描述】:

我打算将一些用于 linux 的屏幕截图抓取代码 (C++) 移植到 osx。当前的解决方案在 xvfb 中运行图形应用程序,然后使用 xlib 从显示器中抓取屏幕截图。 (如果我们在没有 xvfb 的情况下运行,这也将支持)。

所以据我了解,osx 正在从 X11 移动 away,所以我的问题是除了 xlib 之外还可以使用什么来实现它?我找到了Quartz Display Services。这是现在使用的意义吗?这适用于 xvfb 吗?

【问题讨论】:

    标签: c++ macos screenshot quartz-graphics xvfb


    【解决方案1】:

    是的,您可以通过将应用程序服务框架链接到您的 C++ 工具来调用像 CGDisplayCreateImage(为您链接的文档)这样的函数。

    【讨论】:

    • 它可以截图xvfb吗?xvfb在未来的版本中还会存在吗?
    • 我不确定 100%,但该特定功能的描述说“返回包含指定显示内容的图像。”所以我读到的是屏幕上的任何内容,无论是 xvfb、Safari 还是 Photoshop 或其他任何东西,它最终都会出现在捕获的图像缓冲区中。
    • 我可以补充一点,截屏 Xvfb 不起作用。所以也许还有另一个可以在mac上使用的帧缓冲区。但是暂时我可以在没有人的情况下管理。
    • 我正在使用 CGDisplayCreateImage(CGMainDisplayID()) 来捕获屏幕。当我们快速用户切换到另一个用户时,它仍然从第一个用户捕获屏幕。第二个用户的 CGMainDisplayID() 返回 1104977152。知道为什么会这样吗?
    • 这听起来像是一个单独的新问题@SeemaKadavan
    【解决方案2】:

    我已经写了一个捕获pc显示屏幕并转换为opencv Mat的示例。

    #include <iostream>
    #include <opencv2/opencv.hpp>
    #include <unistd.h>
    #include <stdio.h>
    #include <ApplicationServices/ApplicationServices.h>
    
    using namespace std;
    using namespace cv;
    
    int main (int argc, char * const argv[])
    {
        size_t width = CGDisplayPixelsWide(CGMainDisplayID());
        size_t height = CGDisplayPixelsHigh(CGMainDisplayID());
    
        Mat im(cv::Size(width,height), CV_8UC4);
        Mat bgrim(cv::Size(width,height), CV_8UC3);
        Mat resizedim(cv::Size(width,height), CV_8UC3);
    
        CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
        CGContextRef contextRef = CGBitmapContextCreate(
                                                        im.data, im.cols, im.rows,
                                                        8, im.step[0],
                                                        colorSpace,    kCGImageAlphaPremultipliedLast|kCGBitmapByteOrderDefault);
    
        while (true)
        {
            CGImageRef imageRef = CGDisplayCreateImage(CGMainDisplayID());
            CGContextDrawImage(contextRef,
                               CGRectMake(0, 0, width, height),
                               imageRef);
            cvtColor(im, bgrim, CV_RGBA2BGR);
            resize(bgrim, resizedim,cv::Size(),0.5,0.5);
            imshow("test", resizedim);
            cvWaitKey(10);
            CGImageRelease(imageRef);
        }
    
    //    CGContextRelease(contextRef);
    //    CGColorSpaceRelease(colorSpace);
    
        return 0;
    }
    

    然后,结果就在这里。

    我原以为我当前的显示会被捕获,但实际上只捕获了背面壁纸。 CGMainDisplayID() 指的是这个问题的提示。

    无论如何,我希望这可能会接近您的目标。

    【讨论】:

      【解决方案3】:
      void captureScreen(){
          CGImageRef image_ref = CGDisplayCreateImage(CGMainDisplayID()); 
          CGDataProviderRef provider = CGImageGetDataProvider(image_ref);
          CFDataRef dataref = CGDataProviderCopyData(provider);
          size_t width, height;    width = CGImageGetWidth(image_ref);
          height = CGImageGetHeight(image_ref); 
          size_t bpp = CGImageGetBitsPerPixel(image_ref) / 8;
          uint8 *pixels = malloc(width * height * bpp);
          memcpy(pixels, CFDataGetBytePtr(dataref), width * height * bpp);
          CFRelease(dataref); 
         CGImageRelease(image_ref); 
         FILE *stream = fopen("/Users/username/Desktop/screencap.raw", "w+");
         fwrite(pixels, bpp, width * height, stream);
         fclose(stream); 
         free(pixels);
      }
      

      或在 C# 中:

      // https://stackoverflow.com/questions/1537587/capture-screen-image-in-c-on-osx
      // https://github.com/Acollie/C-Screenshot-OSX/blob/master/C%2B%2B-screenshot/C%2B%2B-screenshot/main.cpp
      // https://github.com/ScreenshotMonitor/ScreenshotCapture/blob/master/src/Pranas.ScreenshotCapture/ScreenshotCapture.cs
      // https://screenshotmonitor.com/blog/capturing-screenshots-in-net-and-mono/
      namespace rtaStreamingServer
      {
      
          // https://github.com/xamarin/xamarin-macios
      
      
          // https://qiita.com/shimshimkaz/items/18bcf4767143ea5897c7
          public static class OSxScreenshot
          {
      
              private const string LIBCOREGRAPHICS = "/System/Library/Frameworks/CoreGraphics.framework/CoreGraphics";
      
              [System.Runtime.InteropServices.DllImport(LIBCOREGRAPHICS)]
              private static extern System.IntPtr CGDisplayCreateImage(System.UInt32 displayId);
      
              [System.Runtime.InteropServices.DllImport(LIBCOREGRAPHICS)]
              private static extern void CFRelease(System.IntPtr handle);
      
      
              public static void TestCapture()
              {
                  Foundation.NSNumber mainScreen = (Foundation.NSNumber)AppKit.NSScreen.MainScreen.DeviceDescription["NSScreenNumber"];
      
                  using (CoreGraphics.CGImage cgImage = CreateImage(mainScreen.UInt32Value))
                  {
                      // https://stackoverflow.com/questions/17334786/get-pixel-from-the-screen-screenshot-in-max-osx/17343305#17343305
      
                      // Get byte-array from CGImage
                      // https://gist.github.com/zhangao0086/5fafb1e1c0b5d629eb76
      
                      AppKit.NSBitmapImageRep bitmapRep = new AppKit.NSBitmapImageRep(cgImage);
      
                      // var imageData = bitmapRep.representationUsingType(NSBitmapImageFileType.NSPNGFileType, properties: [:])
                      Foundation.NSData imageData = bitmapRep.RepresentationUsingTypeProperties(AppKit.NSBitmapImageFileType.Png);
      
                      long len = imageData.Length;
                      byte[] bytes = new byte[len];
                      System.Runtime.InteropServices.GCHandle pinnedArray = System.Runtime.InteropServices.GCHandle.Alloc(bytes, System.Runtime.InteropServices.GCHandleType.Pinned);
                      System.IntPtr pointer = pinnedArray.AddrOfPinnedObject();
                      // Do your stuff...
                      imageData.GetBytes(pointer, new System.IntPtr(len));
                      pinnedArray.Free();
      
                      using (AppKit.NSImage nsImage = new AppKit.NSImage(cgImage, new System.Drawing.SizeF(cgImage.Width, cgImage.Height)))
                      {
                          // ImageView.Image = nsImage;
                          // And now ? How to get the image bytes ? 
      
                          // https://theconfuzedsourcecode.wordpress.com/2016/02/24/convert-android-bitmap-image-and-ios-uiimage-to-byte-array-in-xamarin/
                          // https://stackoverflow.com/questions/5645157/nsimage-from-byte-array
                          // https://stackoverflow.com/questions/53060723/nsimage-source-from-byte-array-cocoa-app-xamarin-c-sharp
                          // https://gist.github.com/zhangao0086/5fafb1e1c0b5d629eb76
                          // https://www.quora.com/What-is-a-way-to-convert-UIImage-to-a-byte-array-in-Swift?share=1
                          // https://stackoverflow.com/questions/17112314/converting-uiimage-to-byte-array
      
                      } // End Using nsImage 
      
                  } // End Using cgImage 
      
              } // End Sub TestCapture 
      
      
              public static CoreGraphics.CGImage CreateImage(System.UInt32 displayId)
              {
                  System.IntPtr handle = System.IntPtr.Zero;
      
                  try
                  {
                      handle = CGDisplayCreateImage(displayId);
                      return new CoreGraphics.CGImage(handle);
                  }
                  finally
                  {
                      if (handle != System.IntPtr.Zero)
                      {
                          CFRelease(handle);
                      }
                  }
              } // End Sub CreateImage 
      
      
          } // End Class OSxScreenshot 
      
      
      } // End Namespace rtaStreamingServer 
      

      【讨论】:

        猜你喜欢
        • 2011-09-19
        • 2020-05-26
        • 1970-01-01
        • 1970-01-01
        • 2023-03-19
        • 2016-03-18
        • 1970-01-01
        • 2023-03-25
        • 1970-01-01
        相关资源
        最近更新 更多