screenshare/venv/lib/python3.12/site-packages/pyscreenshot/plugins/gdk3pixbuf.py
2024-11-29 18:15:30 +00:00

77 lines
2.5 KiB
Python

# -*- coding: utf-8 -*-
"""Gdk3-based screenshotting.
Adapted from https://stackoverflow.com/a/37768950/81636, but uses
buffers directly instead of saving intermediate files (which is slow).
"""
from PIL import Image
from pyscreenshot.plugins.backend import CBackend
from pyscreenshot.util import platform_is_osx
class Gdk3BackendError(Exception):
pass
class Gdk3PixbufWrapper(CBackend):
name = "pygdk3"
def grab(self, bbox=None):
"""Grabs an image directly to a buffer.
:param bbox: Optional tuple or list containing (x1, y1, x2, y2) coordinates
of sub-region to capture.
:return: PIL RGB image
:raises: ValueError, if image data does not have 3 channels (RGB), each with 8
bits.
:rtype: Image
"""
if platform_is_osx():
raise Gdk3BackendError("osx not supported")
import gi # type: ignore
gi.require_version("Gdk", "3.0")
# gi.require_version('GdkPixbuf', '2.0')
from gi.repository import Gdk, GdkPixbuf # type: ignore
# read_pixel_bytes: New in version 2.32.
if GdkPixbuf.PIXBUF_MAJOR == 2:
if GdkPixbuf.PIXBUF_MINOR < 32:
raise ValueError(
"GdkPixbuf min supported version: 2.32 current:"
+ GdkPixbuf.PIXBUF_VERSION
)
w = Gdk.get_default_root_window()
if bbox is not None:
g = [bbox[0], bbox[1], bbox[2] - bbox[0], bbox[3] - bbox[1]]
else:
g = w.get_geometry()
pb = Gdk.pixbuf_get_from_window(w, *g)
if not pb:
raise Gdk3BackendError("empty buffer")
if pb.get_bits_per_sample() != 8:
raise Gdk3BackendError("Expected 8 bits per pixel.")
elif pb.get_n_channels() != 3:
raise Gdk3BackendError("Expected RGB image.")
# Read the entire buffer into a python bytes object.
# read_pixel_bytes: New in version 2.32.
pixel_bytes = pb.read_pixel_bytes().get_data() # type: bytes
width, height = g[2], g[3]
# Probably for SSE alignment reasons, the pixbuf has extra data in each line.
# The args after "raw" help handle this; see
# http://effbot.org/imagingbook/decoder.htm#the-raw-decoder
return Image.frombytes(
"RGB", (width, height), pixel_bytes, "raw", "RGB", pb.get_rowstride(), 1
)
def backend_version(self):
import gi
return ".".join(map(str, gi.version_info))