如何在OSX中访问NSWindow的像素缓冲区?

6
我正在寻找一种类似于CamTwist“桌面+”功能的方式来获取窗口内容。这可以捕获任何窗口,即使它在后台也可以。
苹果的OpenGLScreenCapture示例展示了如何从主屏幕捕获,但无法从隐藏的表面捕获。
你有没有想到CamTwist是如何访问NSWindow的像素缓冲区的呢?
2个回答

6
据我所知,官方API可以在CoreGraphics的CGWindow.h中找到:
/* Create an image containing a composite of the specified set of windows
   contained within a rectangular area. The set of windows is specified
   using options from `CGWindowListOption', along with an optional
   additional window ID.

   The windows list options are:

   --- kCGWindowListOptionAll, kCGWindowListOptionOnScreenOnly: Use all
   on-screen windows in this user session to construct the image. The
   parameter `windowID' should be `kCGNullWindowID'.

   --- kCGWindowListOptionOnScreenAboveWindow: Use all on-screen windows in
   this user session above the window specified by `windowID', ordered from
   front to back, to construct the image. To include the window specified by
   `windowID', add the flag `kCGWindowListOptionIncludingWindow'.

   --- kCGWindowListOptionOnScreenBelowWindow: Use all on-screen windows in
   this user session below the window specified by `windowID', ordered from
   front to back, to construct the image. To include the window specified by
   `windowID', add the flag `kCGWindowListOptionIncludingWindow'.

   --- kCGWindowListOptionIncludingWindow: Use only the window specified by
   `windowID' to construct the image.

   The parameter `screenBounds' specifies the rectangle in screen space
   (origin at the upper-left; y-value increasing downward). Setting
   `screenBounds' to `CGRectInfinite' will include all the windows on the
   entire desktop. Setting `screenBounds' to `CGRectNull' will use the
   bounding box of the specified windows as the screen space rectangle.

中断

   /* The parameter `imageOptions' allows you to specify whether the window
   frame ornamentation, such as a shadow or similar effect, should be
   included or excluded in the bounds calculation when `CGRectNull' is
   specified for the window bounds.

   If no windows meet the specified criteria, or the windows can't be read,
   then a transparent black image will be returned.

   Any on-screen window with sharing type `kCGWindowSharingNone' will not
   be included in the image.

   This function returns NULL if the caller is not running within a Quartz
   GUI session or the window server is disabled. */

CG_EXTERN CGImageRef CGWindowListCreateImage(CGRect screenBounds,
  CGWindowListOption listOption, CGWindowID windowID,
  CGWindowImageOption imageOption)
  CG_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_NA);

/* Create an image containing a composite of the specified set of windows
   contained within a rectangular area à la `CGWindowListCreateImage'. The
   set of windows is specified by `windowArray', an array of window IDs. */

CG_EXTERN CGImageRef CGWindowListCreateImageFromArray(CGRect screenBounds,
  CFArrayRef windowArray, CGWindowImageOption imageOption)
  CG_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_NA);

抱歉,无法在苹果官网上找到文档链接。然而,他们似乎在Son of Grab中提供了示例代码。


太棒了!Grab的儿子示例恰好符合我想要的。你配得上你的昵称 :-) - Frans

4
据我所知,您不能使用官方API来做到这一点。当然这是可能的,否则苹果怎么实现Exposé呢?在这里,您可以找到一个头文件,人们通过逆向工程苹果的代码创建了它;使用它需要自担风险(由于是私有API,任何一个调用都可能随时更改,而且不会有任何通知),如果您使用它,不要指望苹果会让您进入App Store :-) 正如您看到的,您可以使用此API获取所有应用程序的所有窗口列表(包括隐藏的窗口),甚至可以操纵它们;尽管您真正被允许做什么可能取决于您的应用程序权限。这里有代码展示了您如何使用此私有API来捕获任何您喜欢的窗口内容。请注意,该代码根据操作系统版本的不同而运行方式不同,有一种方法是在10.5之前的系统上执行,而另一种方法是在10.5之后的系统上执行,所以如果您针对旧系统,请确保同时实现这两种方法。顺便提一下,用于真正获取图像的最终API调用不是私有的,它们可以在官方SDK头文件中找到,只有获取对于您当前进程不属于的窗口引用的方法是私有的。 更新:从10.5开始,苹果已经公开了从窗口服务器复制WindowIDs的重要功能;因此,它不再是私有API。但是,在10.5之前就已经可能检索这些WindowIDs了,但当时该标头不是公开的,而且仍然没有将逆向工程标头中发现的所有函数公开。

这个答案中的链接已经失效,而且答案本身对于这个问题没有任何有用的贡献。 - mah
如果链接失效,只需在Internet Archive上挖掘它们(我已相应更换链接)。整个内容都是遗留的。问题和答案来自2011年,也就是10年前,而反向工程代码则来自2007年,与当前macOS系统的工作方式不兼容。 - Mecki

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接