OS X 和 ctypes:如何从 CGDataProviderCopyData() 检索原始像素?

OS X and ctypes: how to retrieve raw pixels from CGDataProviderCopyData()?

我正在尝试使用 ctypes 模块来捕获屏幕。不幸的是,我无法从 CGDataProviderCopyData 检索原始像素。我需要访问原始数据:

#!/usr/bin/env python
# coding: utf-8

from sys import maxsize
from ctypes import POINTER, Structure, c_double, byref, c_void_p, c_int32, c_uint32, c_float, cdll
from ctypes.util import find_library


CGFloat = c_double if maxsize > 2 ** 32 else c_float


class CGPoint(Structure):
    _fields_ = [('x', CGFloat), ('y', CGFloat)]


class CGSize(Structure):
    _fields_ = [('width', CGFloat), ('height', CGFloat)]


class CGRect(Structure):
    _fields_ = [('origin', CGPoint), ('size', CGSize)]


# Library
cgs = cdll.LoadLibrary(find_library('CoreGraphics'))

# Argtypes
cgs.CGGetActiveDisplayList.argtypes = [c_uint32, POINTER(c_uint32), POINTER(c_uint32)]
cgs.CGDisplayBounds.argtypes = [c_uint32]
cgs.CGRectStandardize.argtypes = [CGRect]
cgs.CGDisplayRotation.argtypes = [c_uint32]
cgs.CGWindowListCreateImage.argtypes = [CGRect, c_uint32, c_uint32, c_uint32]
cgs.CGImageGetWidth.argtypes = [c_void_p]
cgs.CGImageGetHeight.argtypes = [c_void_p]
cgs.CGImageGetDataProvider.argtypes = [c_void_p]
cgs.CGDataProviderCopyData.argtypes = [c_void_p]
cgs.CGDataProviderRelease.argtypes = [c_void_p]

# Restypes
cgs.CGGetActiveDisplayList.restype = c_int32
cgs.CGDisplayBounds.restype = CGRect
cgs.CGRectStandardize.restype = CGRect
cgs.CGDisplayRotation.restype = c_float
cgs.CGWindowListCreateImage.restype = c_void_p
cgs.CGImageGetWidth.restype = c_uint32
cgs.CGImageGetHeight.restype = c_uint32
cgs.CGImageGetDataProvider.restype = c_void_p
cgs.CGDataProviderCopyData.restype = c_void_p
cgs.CGDataProviderRelease.restype = c_void_p

# Monitors
max_displays = 32
display_count = c_uint32(0)
active_displays = (c_uint32 * max_displays)()
cgs.CGGetActiveDisplayList(max_displays, active_displays, byref(display_count))
for idx in range(display_count.value):
    display = active_displays[idx]
    rect = cgs.CGDisplayBounds(display)
    rect = cgs.CGRectStandardize(rect)

    image_ref = cgs.CGWindowListCreateImage(rect, 1, 0, 0)
    width = int(cgs.CGImageGetWidth(image_ref))
    height = int(cgs.CGImageGetHeight(image_ref))
    prov = cgs.CGImageGetDataProvider(image_ref)
    data = cgs.CGDataProviderCopyData(prov)

    # How to get raw pixels from data`?

MacOS X 版本 10.11.3.

Python 版本 2.7.10 和 2.6.9。

我没有使用 CoreGraphics API 的经验,但查看文档看起来 CGDataProviderCopyData return 是一个 CFDataRef 对象。 CFDataRef 的文档有一个关于 "Examining a CFData Object" 的部分,它描述了一个 CFDataGetLength 函数和一个 CFDataGetBytePtr 函数,其中 return 数据的长度和一个 UInt8*.

https://developer.apple.com/library/ios/documentation/GraphicsImaging/Reference/CGDataProvider/#//apple_ref/c/func/CGDataProviderCopyData

https://developer.apple.com/library/ios/documentation/CoreFoundation/Reference/CFDataRef/index.html

感谢 Snorfalorpagus,我终于成功了:

#...
data = cgs.CGDataProviderCopyData(prov)
data_ref = cgs.CFDataGetBytePtr(data)
buf_len = cgs.CFDataGetLength()
image_data = cast(data_ref, POINTER(c_ubyte * buf_len))
cgs.CGDataProviderRelease(prov)

# Raw pixels are in image_data.contents