mirror of
				https://github.com/python-pillow/Pillow.git
				synced 2025-10-30 23:47:27 +03:00 
			
		
		
		
	xcb screengrab fixes
This commit is contained in:
		
							parent
							
								
									3c39e6fcf6
								
							
						
					
					
						commit
						f9c74825a6
					
				|  | @ -2,67 +2,68 @@ 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: | ||||||
|         def test_grab(self): |     @pytest.mark.skipif( | ||||||
|             for im in [ |         sys.platform not in ("win32", "darwin"), reason="requires Windows or macOS" | ||||||
|                 ImageGrab.grab(), |     ) | ||||||
|                 ImageGrab.grab(include_layered_windows=True), |     def test_grab(self): | ||||||
|                 ImageGrab.grab(all_screens=True), |         for im in [ | ||||||
|             ]: |             ImageGrab.grab(), | ||||||
|                 assert_image(im, im.mode, im.size) |             ImageGrab.grab(include_layered_windows=True), | ||||||
| 
 |             ImageGrab.grab(all_screens=True), | ||||||
|             im = ImageGrab.grab(bbox=(10, 20, 50, 80)) |         ]: | ||||||
|             assert_image(im, im.mode, (40, 60)) |  | ||||||
| 
 |  | ||||||
|         def test_grabclipboard(self): |  | ||||||
|             if sys.platform == "darwin": |  | ||||||
|                 subprocess.call(["screencapture", "-cx"]) |  | ||||||
|             else: |  | ||||||
|                 p = subprocess.Popen( |  | ||||||
|                     ["powershell", "-command", "-"], stdin=subprocess.PIPE |  | ||||||
|                 ) |  | ||||||
|                 p.stdin.write( |  | ||||||
|                     b"""[Reflection.Assembly]::LoadWithPartialName("System.Drawing") |  | ||||||
| [Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") |  | ||||||
| $bmp = New-Object Drawing.Bitmap 200, 200 |  | ||||||
| [Windows.Forms.Clipboard]::SetImage($bmp)""" |  | ||||||
|                 ) |  | ||||||
|                 p.communicate() |  | ||||||
| 
 |  | ||||||
|             im = ImageGrab.grabclipboard() |  | ||||||
|             assert_image(im, im.mode, im.size) |             assert_image(im, im.mode, im.size) | ||||||
| 
 | 
 | ||||||
|  |         im = ImageGrab.grab(bbox=(10, 20, 50, 80)) | ||||||
|  |         assert_image(im, im.mode, (40, 60)) | ||||||
| 
 | 
 | ||||||
| except ImportError: |     @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) | ||||||
| 
 | 
 | ||||||
|     class TestImageGrab: |             im2 = ImageGrab.grab(xdisplay="") | ||||||
|         @pytest.mark.skip(reason="ImageGrab ImportError") |             assert_image(im2, im2.mode, im2.size) | ||||||
|         def test_skip(self): |         except IOError as e: | ||||||
|             pass |             pytest.skip(str(e)) | ||||||
| 
 | 
 | ||||||
| 
 |     @pytest.mark.skipif(not Image.core.HAVE_XCB, reason="requires XCB") | ||||||
| class TestImageGrabImport: |     def test_grab_invalid_xdisplay(self): | ||||||
|     def test_import(self): |  | ||||||
|         # Arrange |  | ||||||
|         exception = None |         exception = None | ||||||
| 
 | 
 | ||||||
|         # Act |  | ||||||
|         try: |         try: | ||||||
|             from PIL import ImageGrab |             ImageGrab.grab(xdisplay="error.test:0.0") | ||||||
| 
 |  | ||||||
|             ImageGrab.__name__  # dummy to prevent Pyflakes warning |  | ||||||
|         except Exception as e: |         except Exception as e: | ||||||
|             exception = e |             exception = e | ||||||
| 
 | 
 | ||||||
|         # Assert |         assert isinstance(exception, IOError) | ||||||
|         if sys.platform in ["win32", "darwin"]: |         assert str(exception).startswith("X connection failed") | ||||||
|             assert exception is None | 
 | ||||||
|  |     @pytest.mark.skipif( | ||||||
|  |         sys.platform not in ("win32", "darwin"), reason="requires Windows or macOS" | ||||||
|  |     ) | ||||||
|  |     def test_grabclipboard(self): | ||||||
|  |         if sys.platform == "darwin": | ||||||
|  |             subprocess.call(["screencapture", "-cx"]) | ||||||
|  |         elif sys.platform == "win32": | ||||||
|  |             p = subprocess.Popen(["powershell", "-command", "-"], stdin=subprocess.PIPE) | ||||||
|  |             p.stdin.write( | ||||||
|  |                 b"""[Reflection.Assembly]::LoadWithPartialName("System.Drawing") | ||||||
|  | [Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") | ||||||
|  | $bmp = New-Object Drawing.Bitmap 200, 200 | ||||||
|  | [Windows.Forms.Clipboard]::SetImage($bmp)""" | ||||||
|  |             ) | ||||||
|  |             p.communicate() | ||||||
|         else: |         else: | ||||||
|             assert isinstance(exception, ImportError) |             pytest.skip("ImageGrab.grabclipboard() is macOS and Windows only") | ||||||
|             assert str(exception) == "ImageGrab is macOS and Windows only" |             return | ||||||
|  | 
 | ||||||
|  |         im = ImageGrab.grabclipboard() | ||||||
|  |         assert_image(im, im.mode, im.size) | ||||||
|  |  | ||||||
							
								
								
									
										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 */ | ||||||
| 
 | 
 | ||||||
|     buffer = PyBytes_FromStringAndSize((char*)xcb_get_image_data(reply), |     if (reply->depth == 24) { | ||||||
|                                        xcb_get_image_data_length(reply)); |         buffer = PyBytes_FromStringAndSize((char*)xcb_get_image_data(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