mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-05-29 02:03:25 +03:00
xcb screengrab fixes
This commit is contained in:
parent
3c39e6fcf6
commit
f9c74825a6
|
@ -2,13 +2,15 @@ import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
from PIL import Image, ImageGrab
|
||||||
|
|
||||||
from .helper import assert_image
|
from .helper import assert_image
|
||||||
|
|
||||||
try:
|
|
||||||
from PIL import ImageGrab
|
|
||||||
|
|
||||||
class TestImageGrab:
|
class TestImageGrab:
|
||||||
|
@pytest.mark.skipif(
|
||||||
|
sys.platform not in ("win32", "darwin"), reason="requires Windows or macOS"
|
||||||
|
)
|
||||||
def test_grab(self):
|
def test_grab(self):
|
||||||
for im in [
|
for im in [
|
||||||
ImageGrab.grab(),
|
ImageGrab.grab(),
|
||||||
|
@ -20,13 +22,38 @@ try:
|
||||||
im = ImageGrab.grab(bbox=(10, 20, 50, 80))
|
im = ImageGrab.grab(bbox=(10, 20, 50, 80))
|
||||||
assert_image(im, im.mode, (40, 60))
|
assert_image(im, im.mode, (40, 60))
|
||||||
|
|
||||||
|
@pytest.mark.skipif(not Image.core.HAVE_XCB, reason="requires XCB")
|
||||||
|
def test_grab_x11(self):
|
||||||
|
try:
|
||||||
|
if sys.platform not in ("win32", "darwin"):
|
||||||
|
im = ImageGrab.grab()
|
||||||
|
assert_image(im, im.mode, im.size)
|
||||||
|
|
||||||
|
im2 = ImageGrab.grab(xdisplay="")
|
||||||
|
assert_image(im2, im2.mode, im2.size)
|
||||||
|
except IOError as e:
|
||||||
|
pytest.skip(str(e))
|
||||||
|
|
||||||
|
@pytest.mark.skipif(not Image.core.HAVE_XCB, reason="requires XCB")
|
||||||
|
def test_grab_invalid_xdisplay(self):
|
||||||
|
exception = None
|
||||||
|
|
||||||
|
try:
|
||||||
|
ImageGrab.grab(xdisplay="error.test:0.0")
|
||||||
|
except Exception as e:
|
||||||
|
exception = e
|
||||||
|
|
||||||
|
assert isinstance(exception, IOError)
|
||||||
|
assert str(exception).startswith("X connection failed")
|
||||||
|
|
||||||
|
@pytest.mark.skipif(
|
||||||
|
sys.platform not in ("win32", "darwin"), reason="requires Windows or macOS"
|
||||||
|
)
|
||||||
def test_grabclipboard(self):
|
def test_grabclipboard(self):
|
||||||
if sys.platform == "darwin":
|
if sys.platform == "darwin":
|
||||||
subprocess.call(["screencapture", "-cx"])
|
subprocess.call(["screencapture", "-cx"])
|
||||||
else:
|
elif sys.platform == "win32":
|
||||||
p = subprocess.Popen(
|
p = subprocess.Popen(["powershell", "-command", "-"], stdin=subprocess.PIPE)
|
||||||
["powershell", "-command", "-"], stdin=subprocess.PIPE
|
|
||||||
)
|
|
||||||
p.stdin.write(
|
p.stdin.write(
|
||||||
b"""[Reflection.Assembly]::LoadWithPartialName("System.Drawing")
|
b"""[Reflection.Assembly]::LoadWithPartialName("System.Drawing")
|
||||||
[Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
|
[Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
|
||||||
|
@ -34,35 +61,9 @@ $bmp = New-Object Drawing.Bitmap 200, 200
|
||||||
[Windows.Forms.Clipboard]::SetImage($bmp)"""
|
[Windows.Forms.Clipboard]::SetImage($bmp)"""
|
||||||
)
|
)
|
||||||
p.communicate()
|
p.communicate()
|
||||||
|
else:
|
||||||
|
pytest.skip("ImageGrab.grabclipboard() is macOS and Windows only")
|
||||||
|
return
|
||||||
|
|
||||||
im = ImageGrab.grabclipboard()
|
im = ImageGrab.grabclipboard()
|
||||||
assert_image(im, im.mode, im.size)
|
assert_image(im, im.mode, im.size)
|
||||||
|
|
||||||
|
|
||||||
except ImportError:
|
|
||||||
|
|
||||||
class TestImageGrab:
|
|
||||||
@pytest.mark.skip(reason="ImageGrab ImportError")
|
|
||||||
def test_skip(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class TestImageGrabImport:
|
|
||||||
def test_import(self):
|
|
||||||
# Arrange
|
|
||||||
exception = None
|
|
||||||
|
|
||||||
# Act
|
|
||||||
try:
|
|
||||||
from PIL import ImageGrab
|
|
||||||
|
|
||||||
ImageGrab.__name__ # dummy to prevent Pyflakes warning
|
|
||||||
except Exception as e:
|
|
||||||
exception = e
|
|
||||||
|
|
||||||
# Assert
|
|
||||||
if sys.platform in ["win32", "darwin"]:
|
|
||||||
assert exception is None
|
|
||||||
else:
|
|
||||||
assert isinstance(exception, ImportError)
|
|
||||||
assert str(exception) == "ImageGrab is macOS and Windows only"
|
|
||||||
|
|
1
setup.py
1
setup.py
|
@ -823,6 +823,7 @@ class pil_build_ext(build_ext):
|
||||||
(feature.lcms, "LITTLECMS2"),
|
(feature.lcms, "LITTLECMS2"),
|
||||||
(feature.webp, "WEBP"),
|
(feature.webp, "WEBP"),
|
||||||
(feature.webpmux, "WEBPMUX"),
|
(feature.webpmux, "WEBPMUX"),
|
||||||
|
(feature.xcb, "XCB (X protocol)"),
|
||||||
]
|
]
|
||||||
|
|
||||||
all = 1
|
all = 1
|
||||||
|
|
|
@ -22,12 +22,12 @@ import tempfile
|
||||||
|
|
||||||
from . import Image
|
from . import Image
|
||||||
|
|
||||||
if sys.platform == "win32":
|
if sys.platform == "darwin":
|
||||||
pass
|
|
||||||
elif sys.platform == "darwin":
|
|
||||||
import os
|
import os
|
||||||
import tempfile
|
import tempfile
|
||||||
import subprocess
|
import subprocess
|
||||||
|
elif sys.platform == "win32":
|
||||||
|
pass
|
||||||
elif not Image.core.HAVE_XCB:
|
elif not Image.core.HAVE_XCB:
|
||||||
raise ImportError("ImageGrab requires Windows, macOS, or the XCB library")
|
raise ImportError("ImageGrab requires Windows, macOS, or the XCB library")
|
||||||
|
|
||||||
|
@ -65,17 +65,9 @@ def grab(bbox=None, include_layered_windows=False, all_screens=False, xdisplay=N
|
||||||
return im
|
return im
|
||||||
# use xdisplay=None for default display on non-win32/macOS systems
|
# use xdisplay=None for default display on non-win32/macOS systems
|
||||||
if not Image.core.HAVE_XCB:
|
if not Image.core.HAVE_XCB:
|
||||||
raise OSError("XCB support not included")
|
raise AttributeError("XCB support not present")
|
||||||
size, data = Image.core.grabscreen_x11(xdisplay)
|
size, data = Image.core.grabscreen_x11(xdisplay)
|
||||||
im = Image.frombytes(
|
im = Image.frombytes("RGB", size, data, "raw", "BGRX", size[0] * 4, 1)
|
||||||
"RGB",
|
|
||||||
size,
|
|
||||||
data,
|
|
||||||
"raw",
|
|
||||||
"BGRX",
|
|
||||||
size[0] * 4,
|
|
||||||
1,
|
|
||||||
)
|
|
||||||
if bbox:
|
if bbox:
|
||||||
im = im.crop(bbox)
|
im = im.crop(bbox)
|
||||||
return im
|
return im
|
||||||
|
|
|
@ -845,8 +845,8 @@ PyImaging_GrabScreenX11(PyObject* self, PyObject* args)
|
||||||
|
|
||||||
connection = xcb_connect(display_name, &screen_number);
|
connection = xcb_connect(display_name, &screen_number);
|
||||||
if (xcb_connection_has_error(connection)) {
|
if (xcb_connection_has_error(connection)) {
|
||||||
|
PyErr_Format(PyExc_IOError, "X connection failed: error %i", xcb_connection_has_error(connection));
|
||||||
xcb_disconnect(connection);
|
xcb_disconnect(connection);
|
||||||
PyErr_SetString(PyExc_IOError, "X connection failed");
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -857,7 +857,8 @@ PyImaging_GrabScreenX11(PyObject* self, PyObject* args)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (screen == NULL) {
|
if (screen == NULL || screen->root == 0) {
|
||||||
|
// this case is usually caught with "X connection failed: error 6" above
|
||||||
xcb_disconnect(connection);
|
xcb_disconnect(connection);
|
||||||
PyErr_SetString(PyExc_IOError, "X screen not found");
|
PyErr_SetString(PyExc_IOError, "X screen not found");
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -873,16 +874,21 @@ PyImaging_GrabScreenX11(PyObject* self, PyObject* args)
|
||||||
0, 0, width, height, 0x00ffffff),
|
0, 0, width, height, 0x00ffffff),
|
||||||
&error);
|
&error);
|
||||||
if (reply == NULL) {
|
if (reply == NULL) {
|
||||||
|
PyErr_Format(PyExc_IOError, "X get_image failed: error %i (%i, %i, %i)",
|
||||||
|
error->error_code, error->major_code, error->minor_code, error->resource_id);
|
||||||
free(error);
|
free(error);
|
||||||
xcb_disconnect(connection);
|
xcb_disconnect(connection);
|
||||||
PyErr_SetString(PyExc_IOError, "X get_image failed");
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* store data in Python buffer */
|
/* store data in Python buffer */
|
||||||
|
|
||||||
|
if (reply->depth == 24) {
|
||||||
buffer = PyBytes_FromStringAndSize((char*)xcb_get_image_data(reply),
|
buffer = PyBytes_FromStringAndSize((char*)xcb_get_image_data(reply),
|
||||||
xcb_get_image_data_length(reply));
|
xcb_get_image_data_length(reply));
|
||||||
|
} else {
|
||||||
|
PyErr_Format(PyExc_IOError, "usupported bit depth: %i", reply->depth);
|
||||||
|
}
|
||||||
|
|
||||||
free(reply);
|
free(reply);
|
||||||
xcb_disconnect(connection);
|
xcb_disconnect(connection);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user