Skip to content

Question: trying to grab a screenshot using ScreenCaptureKit #590

Description

@Saba-Sabato

Hello,
This is the first time I've used PyObjC. I'm trying to grab a screenshot in Python, using ScreenCaptureKit, adapting the code from this Apple Videos guide. (go to code tab, bottom two code blocks)
I've encountered several problems along the way, and I'm here to ask if I've just gone about this completely the wrong way. I went through the PyObjC documentation and the relevant Apple documentation pages: ScreenCaptureKit, captureImageWithFilter, SCContentFilter, SCShareableContent.
Here is the code I have so far:

from time import sleep
import objc
from ScreenCaptureKit import (
    SCContentFilter,
    SCScreenshotManager,
    SCStreamConfiguration,
    SCShareableContent,
)
import Quartz.CoreGraphics as CG


def capture_screenshot():
    SCShareableContent.getShareableContentWithCompletionHandler_(
        shareable_content_callback
    )
    sleep(1)  # Without this, the handlers are never executed

def shareable_content_callback(shareable_content, error=None):
    display = shareable_content.displays()[0]
    content_filter = SCContentFilter.alloc().initWithDisplay_excludingWindows_(
        display, []
    )
    configuration = SCStreamConfiguration.alloc().init()

    SCScreenshotManager.captureImageWithFilter_configuration_completionHandler_(
        content_filter, configuration, cg_image_handler
    )

    content_filter.dealloc()
    configuration.dealloc()

def cg_image_handler(cg_image_ref, error=None):
    # Process my CGImage e.g. write it out to file
    pass

def main():
    with objc.autorelease_pool():
        capture_screenshot()

if __name__ == "__main__":
    main()

I can't figure out how to write normal, synchronous code to get the screenshot. The function captureImageWithFilter has a required parameter SCContentFilter, which is initialized with a SCDisplay. To get that I need to call getShareableContentWithCompletionHandler which takes as a parameter a completion handler. That handler will receive the resulting SCDisplay. Only then can I create the parameters required to call captureImageWithFilter which in turn receives yet another handler, and only that final handler will have the CGImage. This feels like callback hell, and I'm sure it's not the way it's supposed to be called. What is the correct way to do this?

Thank you very very much,
Saba

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions