Pillow/src/display.c

983 lines
24 KiB
C
Raw Normal View History

2010-07-31 06:52:47 +04:00
/*
* The Python Imaging Library.
*
* display support (and other windows-related stuff)
*
* History:
* 1996-05-13 fl Windows DIB support
* 1996-05-21 fl Added palette stuff
* 1996-05-28 fl Added display_mode stuff
* 1997-09-21 fl Added draw primitive
* 2001-09-17 fl Added ImagingGrabScreen (from _grabscreen.c)
* 2002-05-12 fl Added ImagingListWindows
* 2002-11-19 fl Added clipboard support
* 2002-11-25 fl Added GetDC/ReleaseDC helpers
* 2003-05-21 fl Added create window support (including window callback)
* 2003-09-05 fl Added fromstring/tostring methods
* 2009-03-14 fl Added WMF support (from pilwmf)
*
* Copyright (c) 1997-2003 by Secret Labs AB.
* Copyright (c) 1996-1997 by Fredrik Lundh.
*
* See the README file for information on usage and redistribution.
*/
2020-10-14 22:52:16 +03:00
#define PY_SSIZE_T_CLEAN
2010-07-31 06:52:47 +04:00
#include "Python.h"
#include "libImaging/Imaging.h"
2010-07-31 06:52:47 +04:00
/* -------------------------------------------------------------------- */
2020-05-01 15:08:57 +03:00
/* Windows DIB support */
2010-07-31 06:52:47 +04:00
#ifdef _WIN32
2010-07-31 06:52:47 +04:00
2020-09-22 06:33:05 +03:00
#include "libImaging/ImDib.h"
2010-07-31 06:52:47 +04:00
#if SIZEOF_VOID_P == 8
#define F_HANDLE "K"
#else
#define F_HANDLE "k"
#endif
2010-07-31 06:52:47 +04:00
typedef struct {
2021-01-03 06:17:51 +03:00
PyObject_HEAD ImagingDIB dib;
2010-07-31 06:52:47 +04:00
} ImagingDisplayObject;
static PyTypeObject ImagingDisplayType;
2010-07-31 06:52:47 +04:00
2021-01-03 06:17:51 +03:00
static ImagingDisplayObject *
_new(const char *mode, int xsize, int ysize) {
2010-07-31 06:52:47 +04:00
ImagingDisplayObject *display;
2020-05-10 12:56:36 +03:00
if (PyType_Ready(&ImagingDisplayType) < 0) {
return NULL;
2020-05-10 12:56:36 +03:00
}
2010-07-31 06:52:47 +04:00
display = PyObject_New(ImagingDisplayObject, &ImagingDisplayType);
2020-05-10 12:56:36 +03:00
if (display == NULL) {
2020-05-01 15:08:57 +03:00
return NULL;
2020-05-10 12:56:36 +03:00
}
2010-07-31 06:52:47 +04:00
display->dib = ImagingNewDIB(mode, xsize, ysize);
if (!display->dib) {
2020-05-01 15:08:57 +03:00
Py_DECREF(display);
return NULL;
2010-07-31 06:52:47 +04:00
}
return display;
}
static void
2021-01-03 06:17:51 +03:00
_delete(ImagingDisplayObject *display) {
2020-05-10 12:56:36 +03:00
if (display->dib) {
2020-05-01 15:08:57 +03:00
ImagingDeleteDIB(display->dib);
2020-05-10 12:56:36 +03:00
}
2010-07-31 06:52:47 +04:00
PyObject_Del(display);
}
2021-01-03 06:17:51 +03:00
static PyObject *
_expose(ImagingDisplayObject *display, PyObject *args) {
HDC hdc;
2020-05-10 12:56:36 +03:00
if (!PyArg_ParseTuple(args, F_HANDLE, &hdc)) {
2020-05-01 15:08:57 +03:00
return NULL;
2020-05-10 12:56:36 +03:00
}
2010-07-31 06:52:47 +04:00
ImagingExposeDIB(display->dib, hdc);
Py_INCREF(Py_None);
return Py_None;
}
2021-01-03 06:17:51 +03:00
static PyObject *
_draw(ImagingDisplayObject *display, PyObject *args) {
HDC hdc;
2010-07-31 06:52:47 +04:00
int dst[4];
int src[4];
2021-01-03 06:17:51 +03:00
if (!PyArg_ParseTuple(
args,
F_HANDLE "(iiii)(iiii)",
&hdc,
dst + 0,
dst + 1,
dst + 2,
dst + 3,
src + 0,
src + 1,
src + 2,
src + 3)) {
2020-05-01 15:08:57 +03:00
return NULL;
2020-05-10 12:56:36 +03:00
}
2010-07-31 06:52:47 +04:00
ImagingDrawDIB(display->dib, hdc, dst, src);
Py_INCREF(Py_None);
return Py_None;
}
2021-01-03 06:17:51 +03:00
extern Imaging
PyImaging_AsImaging(PyObject *op);
2010-07-31 06:52:47 +04:00
2021-01-03 06:17:51 +03:00
static PyObject *
_paste(ImagingDisplayObject *display, PyObject *args) {
2010-07-31 06:52:47 +04:00
Imaging im;
2021-01-03 06:17:51 +03:00
PyObject *op;
2010-07-31 06:52:47 +04:00
int xy[4];
xy[0] = xy[1] = xy[2] = xy[3] = 0;
2021-01-03 06:17:51 +03:00
if (!PyArg_ParseTuple(args, "O|(iiii)", &op, xy + 0, xy + 1, xy + 2, xy + 3)) {
2020-05-01 15:08:57 +03:00
return NULL;
2020-05-10 12:56:36 +03:00
}
2010-07-31 06:52:47 +04:00
im = PyImaging_AsImaging(op);
2020-05-10 12:56:36 +03:00
if (!im) {
2020-05-01 15:08:57 +03:00
return NULL;
2020-05-10 12:56:36 +03:00
}
2010-07-31 06:52:47 +04:00
2020-05-10 12:56:36 +03:00
if (xy[2] <= xy[0]) {
2020-05-01 15:08:57 +03:00
xy[2] = xy[0] + im->xsize;
2020-05-10 12:56:36 +03:00
}
if (xy[3] <= xy[1]) {
2020-05-01 15:08:57 +03:00
xy[3] = xy[1] + im->ysize;
2020-05-10 12:56:36 +03:00
}
2010-07-31 06:52:47 +04:00
ImagingPasteDIB(display->dib, im, xy);
Py_INCREF(Py_None);
return Py_None;
}
2021-01-03 06:17:51 +03:00
static PyObject *
_query_palette(ImagingDisplayObject *display, PyObject *args) {
HDC hdc;
2010-07-31 06:52:47 +04:00
int status;
2020-05-10 12:56:36 +03:00
if (!PyArg_ParseTuple(args, F_HANDLE, &hdc)) {
2020-05-01 15:08:57 +03:00
return NULL;
2020-05-10 12:56:36 +03:00
}
2010-07-31 06:52:47 +04:00
status = ImagingQueryPaletteDIB(display->dib, hdc);
return Py_BuildValue("i", status);
}
2021-01-03 06:17:51 +03:00
static PyObject *
_getdc(ImagingDisplayObject *display, PyObject *args) {
HWND window;
2010-07-31 06:52:47 +04:00
HDC dc;
2020-05-10 12:56:36 +03:00
if (!PyArg_ParseTuple(args, F_HANDLE, &window)) {
2020-05-01 15:08:57 +03:00
return NULL;
2020-05-10 12:56:36 +03:00
}
2010-07-31 06:52:47 +04:00
dc = GetDC(window);
2010-07-31 06:52:47 +04:00
if (!dc) {
PyErr_SetString(PyExc_OSError, "cannot create dc");
2010-07-31 06:52:47 +04:00
return NULL;
}
return Py_BuildValue(F_HANDLE, dc);
2010-07-31 06:52:47 +04:00
}
2021-01-03 06:17:51 +03:00
static PyObject *
_releasedc(ImagingDisplayObject *display, PyObject *args) {
HWND window;
HDC dc;
2010-07-31 06:52:47 +04:00
2020-05-10 12:56:36 +03:00
if (!PyArg_ParseTuple(args, F_HANDLE F_HANDLE, &window, &dc)) {
2020-05-01 15:08:57 +03:00
return NULL;
2020-05-10 12:56:36 +03:00
}
2010-07-31 06:52:47 +04:00
ReleaseDC(window, dc);
2010-07-31 06:52:47 +04:00
Py_INCREF(Py_None);
return Py_None;
}
2021-01-03 06:17:51 +03:00
static PyObject *
_frombytes(ImagingDisplayObject *display, PyObject *args) {
char *ptr;
2020-10-14 22:52:16 +03:00
Py_ssize_t bytes;
2020-05-10 12:56:36 +03:00
if (!PyArg_ParseTuple(args, "y#:frombytes", &ptr, &bytes)) {
return NULL;
2020-05-10 12:56:36 +03:00
}
2010-07-31 06:52:47 +04:00
if (display->dib->ysize * display->dib->linesize != bytes) {
PyErr_SetString(PyExc_ValueError, "wrong size");
return NULL;
}
memcpy(display->dib->bits, ptr, bytes);
Py_INCREF(Py_None);
return Py_None;
}
2021-01-03 06:17:51 +03:00
static PyObject *
_tobytes(ImagingDisplayObject *display, PyObject *args) {
2020-05-10 12:56:36 +03:00
if (!PyArg_ParseTuple(args, ":tobytes")) {
return NULL;
2020-05-10 12:56:36 +03:00
}
2010-07-31 06:52:47 +04:00
return PyBytes_FromStringAndSize(
2021-01-03 06:17:51 +03:00
display->dib->bits, display->dib->ysize * display->dib->linesize);
2010-07-31 06:52:47 +04:00
}
static struct PyMethodDef methods[] = {
2021-05-11 13:16:44 +03:00
{"draw", (PyCFunction)_draw, METH_VARARGS},
{"expose", (PyCFunction)_expose, METH_VARARGS},
{"paste", (PyCFunction)_paste, METH_VARARGS},
{"query_palette", (PyCFunction)_query_palette, METH_VARARGS},
{"getdc", (PyCFunction)_getdc, METH_VARARGS},
{"releasedc", (PyCFunction)_releasedc, METH_VARARGS},
{"frombytes", (PyCFunction)_frombytes, METH_VARARGS},
{"tobytes", (PyCFunction)_tobytes, METH_VARARGS},
2010-07-31 06:52:47 +04:00
{NULL, NULL} /* sentinel */
};
2021-01-03 06:17:51 +03:00
static PyObject *
_getattr_mode(ImagingDisplayObject *self, void *closure) {
2020-05-01 15:08:57 +03:00
return Py_BuildValue("s", self->dib->mode);
}
2021-01-03 06:17:51 +03:00
static PyObject *
_getattr_size(ImagingDisplayObject *self, void *closure) {
2020-05-01 15:08:57 +03:00
return Py_BuildValue("ii", self->dib->xsize, self->dib->ysize);
2010-07-31 06:52:47 +04:00
}
static struct PyGetSetDef getsetters[] = {
2021-01-03 06:17:51 +03:00
{"mode", (getter)_getattr_mode}, {"size", (getter)_getattr_size}, {NULL}};
static PyTypeObject ImagingDisplayType = {
2021-01-03 06:17:51 +03:00
PyVarObject_HEAD_INIT(NULL, 0) "ImagingDisplay", /*tp_name*/
sizeof(ImagingDisplayObject), /*tp_size*/
0, /*tp_itemsize*/
2020-05-01 15:08:57 +03:00
/* methods */
2021-01-03 06:17:51 +03:00
(destructor)_delete, /*tp_dealloc*/
0, /*tp_print*/
0, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare*/
0, /*tp_repr*/
0, /*tp_as_number */
0, /*tp_as_sequence */
0, /*tp_as_mapping */
0, /*tp_hash*/
0, /*tp_call*/
0, /*tp_str*/
0, /*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT, /*tp_flags*/
0, /*tp_doc*/
0, /*tp_traverse*/
0, /*tp_clear*/
0, /*tp_richcompare*/
0, /*tp_weaklistoffset*/
0, /*tp_iter*/
0, /*tp_iternext*/
methods, /*tp_methods*/
0, /*tp_members*/
getsetters, /*tp_getset*/
2010-07-31 06:52:47 +04:00
};
2021-01-03 06:17:51 +03:00
PyObject *
PyImaging_DisplayWin32(PyObject *self, PyObject *args) {
ImagingDisplayObject *display;
2010-07-31 06:52:47 +04:00
char *mode;
int xsize, ysize;
2020-05-10 12:56:36 +03:00
if (!PyArg_ParseTuple(args, "s(ii)", &mode, &xsize, &ysize)) {
2020-05-01 15:08:57 +03:00
return NULL;
2020-05-10 12:56:36 +03:00
}
2010-07-31 06:52:47 +04:00
display = _new(mode, xsize, ysize);
2020-05-10 12:56:36 +03:00
if (display == NULL) {
2020-05-01 15:08:57 +03:00
return NULL;
2020-05-10 12:56:36 +03:00
}
2010-07-31 06:52:47 +04:00
2021-01-03 06:17:51 +03:00
return (PyObject *)display;
2010-07-31 06:52:47 +04:00
}
2021-01-03 06:17:51 +03:00
PyObject *
PyImaging_DisplayModeWin32(PyObject *self, PyObject *args) {
2010-07-31 06:52:47 +04:00
char *mode;
int size[2];
mode = ImagingGetModeDIB(size);
return Py_BuildValue("s(ii)", mode, size[0], size[1]);
}
/* -------------------------------------------------------------------- */
/* Windows screen grabber */
2021-01-03 06:17:51 +03:00
typedef HANDLE(__stdcall *Func_SetThreadDpiAwarenessContext)(HANDLE);
2021-01-03 06:17:51 +03:00
PyObject *
PyImaging_GrabScreenWin32(PyObject *self, PyObject *args) {
int x = 0, y = 0, width, height;
2019-09-20 18:35:08 +03:00
int includeLayeredWindows = 0, all_screens = 0;
2010-07-31 06:52:47 +04:00
HBITMAP bitmap;
BITMAPCOREHEADER core;
HDC screen, screen_copy;
DWORD rop;
2021-01-03 06:17:51 +03:00
PyObject *buffer;
HANDLE dpiAwareness;
HMODULE user32;
Func_SetThreadDpiAwarenessContext SetThreadDpiAwarenessContext_function;
2020-05-10 12:56:36 +03:00
if (!PyArg_ParseTuple(args, "|ii", &includeLayeredWindows, &all_screens)) {
return NULL;
2020-05-10 12:56:36 +03:00
}
2010-07-31 06:52:47 +04:00
/* step 1: create a memory DC large enough to hold the
entire screen */
screen = CreateDC("DISPLAY", NULL, NULL, NULL);
screen_copy = CreateCompatibleDC(screen);
2010-07-31 06:52:47 +04:00
// added in Windows 10 (1607)
// loaded dynamically to avoid link errors
user32 = LoadLibraryA("User32.dll");
SetThreadDpiAwarenessContext_function =
2021-01-03 06:17:51 +03:00
(Func_SetThreadDpiAwarenessContext)GetProcAddress(
user32, "SetThreadDpiAwarenessContext");
if (SetThreadDpiAwarenessContext_function != NULL) {
// DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE = ((DPI_CONTEXT_HANDLE)-3)
2021-01-03 06:17:51 +03:00
dpiAwareness = SetThreadDpiAwarenessContext_function((HANDLE)-3);
}
2019-09-20 18:35:08 +03:00
if (all_screens) {
x = GetSystemMetrics(SM_XVIRTUALSCREEN);
y = GetSystemMetrics(SM_YVIRTUALSCREEN);
width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
height = GetSystemMetrics(SM_CYVIRTUALSCREEN);
} else {
2019-08-17 13:38:54 +03:00
width = GetDeviceCaps(screen, HORZRES);
height = GetDeviceCaps(screen, VERTRES);
}
if (SetThreadDpiAwarenessContext_function != NULL) {
SetThreadDpiAwarenessContext_function(dpiAwareness);
}
FreeLibrary(user32);
2010-07-31 06:52:47 +04:00
bitmap = CreateCompatibleBitmap(screen, width, height);
2020-05-10 12:56:36 +03:00
if (!bitmap) {
2010-07-31 06:52:47 +04:00
goto error;
2020-05-10 12:56:36 +03:00
}
2020-05-10 12:56:36 +03:00
if (!SelectObject(screen_copy, bitmap)) {
2010-07-31 06:52:47 +04:00
goto error;
2020-05-10 12:56:36 +03:00
}
2010-07-31 06:52:47 +04:00
/* step 2: copy bits into memory DC bitmap */
rop = SRCCOPY;
2020-05-10 12:56:36 +03:00
if (includeLayeredWindows) {
rop |= CAPTUREBLT;
2020-05-10 12:56:36 +03:00
}
if (!BitBlt(screen_copy, 0, 0, width, height, screen, x, y, rop)) {
2010-07-31 06:52:47 +04:00
goto error;
2020-05-10 12:56:36 +03:00
}
2010-07-31 06:52:47 +04:00
/* step 3: extract bits from bitmap */
2021-01-03 06:17:51 +03:00
buffer = PyBytes_FromStringAndSize(NULL, height * ((width * 3 + 3) & -4));
2020-05-10 12:56:36 +03:00
if (!buffer) {
2010-07-31 06:52:47 +04:00
return NULL;
2020-05-10 12:56:36 +03:00
}
2010-07-31 06:52:47 +04:00
core.bcSize = sizeof(core);
core.bcWidth = width;
core.bcHeight = height;
core.bcPlanes = 1;
core.bcBitCount = 24;
2021-01-03 06:17:51 +03:00
if (!GetDIBits(
screen_copy,
bitmap,
0,
height,
PyBytes_AS_STRING(buffer),
(BITMAPINFO *)&core,
DIB_RGB_COLORS)) {
2010-07-31 06:52:47 +04:00
goto error;
2020-05-10 12:56:36 +03:00
}
2010-07-31 06:52:47 +04:00
DeleteObject(bitmap);
DeleteDC(screen_copy);
DeleteDC(screen);
return Py_BuildValue("(ii)(ii)N", x, y, width, height, buffer);
2010-07-31 06:52:47 +04:00
error:
PyErr_SetString(PyExc_OSError, "screen grab failed");
2010-07-31 06:52:47 +04:00
DeleteDC(screen_copy);
DeleteDC(screen);
return NULL;
}
2021-01-03 06:17:51 +03:00
static BOOL CALLBACK
list_windows_callback(HWND hwnd, LPARAM lParam) {
PyObject *window_list = (PyObject *)lParam;
PyObject *item;
PyObject *title;
2010-07-31 06:52:47 +04:00
RECT inner, outer;
int title_size;
int status;
2010-07-31 06:52:47 +04:00
/* get window title */
title_size = GetWindowTextLength(hwnd);
if (title_size > 0) {
title = PyUnicode_FromStringAndSize(NULL, title_size);
2020-05-10 12:56:36 +03:00
if (title) {
2021-01-03 06:17:51 +03:00
GetWindowTextW(hwnd, PyUnicode_AS_UNICODE(title), title_size + 1);
2020-05-10 12:56:36 +03:00
}
} else {
title = PyUnicode_FromString("");
2020-05-10 12:56:36 +03:00
}
if (!title) {
2010-07-31 06:52:47 +04:00
return 0;
2020-05-10 12:56:36 +03:00
}
2010-07-31 06:52:47 +04:00
/* get bounding boxes */
GetClientRect(hwnd, &inner);
GetWindowRect(hwnd, &outer);
item = Py_BuildValue(
2021-01-03 06:17:51 +03:00
F_HANDLE "N(iiii)(iiii)",
hwnd,
title,
inner.left,
inner.top,
inner.right,
inner.bottom,
outer.left,
outer.top,
outer.right,
outer.bottom);
2020-05-10 12:56:36 +03:00
if (!item) {
2010-07-31 06:52:47 +04:00
return 0;
2020-05-10 12:56:36 +03:00
}
2010-07-31 06:52:47 +04:00
status = PyList_Append(window_list, item);
Py_DECREF(item);
2020-05-10 12:56:36 +03:00
if (status < 0) {
2010-07-31 06:52:47 +04:00
return 0;
2020-05-10 12:56:36 +03:00
}
2010-07-31 06:52:47 +04:00
return 1;
}
2021-01-03 06:17:51 +03:00
PyObject *
PyImaging_ListWindowsWin32(PyObject *self, PyObject *args) {
PyObject *window_list;
2010-07-31 06:52:47 +04:00
window_list = PyList_New(0);
2020-05-10 12:56:36 +03:00
if (!window_list) {
2010-07-31 06:52:47 +04:00
return NULL;
2020-05-10 12:56:36 +03:00
}
2010-07-31 06:52:47 +04:00
2021-01-03 06:17:51 +03:00
EnumWindows(list_windows_callback, (LPARAM)window_list);
2010-07-31 06:52:47 +04:00
if (PyErr_Occurred()) {
Py_DECREF(window_list);
return NULL;
}
return window_list;
}
/* -------------------------------------------------------------------- */
/* Windows clipboard grabber */
2021-01-03 06:17:51 +03:00
PyObject *
PyImaging_GrabClipboardWin32(PyObject *self, PyObject *args) {
2010-07-31 06:52:47 +04:00
int clip;
HANDLE handle = NULL;
2010-07-31 06:52:47 +04:00
int size;
2021-01-03 06:17:51 +03:00
void *data;
PyObject *result;
UINT format;
2021-01-03 06:17:51 +03:00
UINT formats[] = {CF_DIB, CF_DIBV5, CF_HDROP, RegisterClipboardFormatA("PNG"), 0};
LPCSTR format_names[] = {"DIB", "DIB", "file", "png", NULL};
if (!OpenClipboard(NULL)) {
PyErr_SetString(PyExc_OSError, "failed to open clipboard");
return NULL;
}
// find best format as set by clipboard owner
format = 0;
while (!handle && (format = EnumClipboardFormats(format))) {
for (UINT i = 0; formats[i] != 0; i++) {
if (format == formats[i]) {
handle = GetClipboardData(format);
format = i;
break;
}
}
}
2010-07-31 06:52:47 +04:00
if (!handle) {
CloseClipboard();
return Py_BuildValue("zO", NULL, Py_None);
2010-07-31 06:52:47 +04:00
}
data = GlobalLock(handle);
size = GlobalSize(handle);
2010-07-31 06:52:47 +04:00
result = PyBytes_FromStringAndSize(data, size);
2010-07-31 06:52:47 +04:00
GlobalUnlock(handle);
CloseClipboard();
return Py_BuildValue("zN", format_names[format], result);
2010-07-31 06:52:47 +04:00
}
/* -------------------------------------------------------------------- */
/* Windows class */
#ifndef WM_MOUSEWHEEL
#define WM_MOUSEWHEEL 522
#endif
static int mainloop = 0;
static void
2021-01-03 06:17:51 +03:00
callback_error(const char *handler) {
PyObject *sys_stderr;
2010-07-31 06:52:47 +04:00
sys_stderr = PySys_GetObject("stderr");
if (sys_stderr) {
PyFile_WriteString("*** ImageWin: error in ", sys_stderr);
2021-01-03 06:17:51 +03:00
PyFile_WriteString((char *)handler, sys_stderr);
2010-07-31 06:52:47 +04:00
PyFile_WriteString(":\n", sys_stderr);
}
PyErr_Print();
PyErr_Clear();
}
static LRESULT CALLBACK
2021-01-03 06:17:51 +03:00
windowCallback(HWND wnd, UINT message, WPARAM wParam, LPARAM lParam) {
2010-07-31 06:52:47 +04:00
PAINTSTRUCT ps;
2021-01-03 06:17:51 +03:00
PyObject *callback = NULL;
PyObject *result;
PyThreadState *threadstate;
PyThreadState *current_threadstate;
2010-07-31 06:52:47 +04:00
HDC dc;
RECT rect;
LRESULT status = 0;
/* set up threadstate for messages that calls back into python */
switch (message) {
2021-01-03 06:17:51 +03:00
case WM_CREATE:
mainloop++;
break;
case WM_DESTROY:
mainloop--;
/* fall through... */
case WM_PAINT:
case WM_SIZE:
callback = (PyObject *)GetWindowLongPtr(wnd, 0);
if (callback) {
threadstate =
(PyThreadState *)GetWindowLongPtr(wnd, sizeof(PyObject *));
current_threadstate = PyThreadState_Swap(NULL);
PyEval_RestoreThread(threadstate);
} else {
return DefWindowProc(wnd, message, wParam, lParam);
}
2010-07-31 06:52:47 +04:00
}
/* process message */
switch (message) {
2021-01-03 06:17:51 +03:00
case WM_PAINT:
/* redraw (part of) window. this generates a WCK-style
damage/clear/repair cascade */
BeginPaint(wnd, &ps);
dc = GetDC(wnd);
GetWindowRect(wnd, &rect); /* in screen coordinates */
result = PyObject_CallFunction(
callback,
"siiii",
"damage",
ps.rcPaint.left,
ps.rcPaint.top,
ps.rcPaint.right,
ps.rcPaint.bottom);
if (result) {
Py_DECREF(result);
} else {
callback_error("window damage callback");
}
2010-07-31 06:52:47 +04:00
2021-01-03 06:17:51 +03:00
result = PyObject_CallFunction(
callback,
"s" F_HANDLE "iiii",
"clear",
dc,
0,
0,
rect.right - rect.left,
rect.bottom - rect.top);
if (result) {
Py_DECREF(result);
} else {
callback_error("window clear callback");
}
2010-07-31 06:52:47 +04:00
2021-01-03 06:17:51 +03:00
result = PyObject_CallFunction(
callback,
"s" F_HANDLE "iiii",
"repair",
dc,
0,
0,
rect.right - rect.left,
rect.bottom - rect.top);
if (result) {
Py_DECREF(result);
} else {
callback_error("window repair callback");
}
2010-07-31 06:52:47 +04:00
2021-01-03 06:17:51 +03:00
ReleaseDC(wnd, dc);
EndPaint(wnd, &ps);
break;
2010-07-31 06:52:47 +04:00
2021-01-03 06:17:51 +03:00
case WM_SIZE:
/* resize window */
result = PyObject_CallFunction(
callback, "sii", "resize", LOWORD(lParam), HIWORD(lParam));
if (result) {
InvalidateRect(wnd, NULL, 1);
Py_DECREF(result);
} else {
callback_error("window resize callback");
}
break;
case WM_DESTROY:
/* destroy window */
result = PyObject_CallFunction(callback, "s", "destroy");
if (result) {
Py_DECREF(result);
} else {
callback_error("window destroy callback");
}
Py_DECREF(callback);
break;
2010-07-31 06:52:47 +04:00
2021-01-03 06:17:51 +03:00
default:
status = DefWindowProc(wnd, message, wParam, lParam);
2010-07-31 06:52:47 +04:00
}
if (callback) {
/* restore thread state */
PyEval_SaveThread();
PyThreadState_Swap(threadstate);
}
return status;
}
2021-01-03 06:17:51 +03:00
PyObject *
PyImaging_CreateWindowWin32(PyObject *self, PyObject *args) {
2010-07-31 06:52:47 +04:00
HWND wnd;
WNDCLASS windowClass;
2021-01-03 06:17:51 +03:00
char *title;
PyObject *callback;
2010-07-31 06:52:47 +04:00
int width = 0, height = 0;
2020-05-10 12:56:36 +03:00
if (!PyArg_ParseTuple(args, "sO|ii", &title, &callback, &width, &height)) {
2020-05-01 15:08:57 +03:00
return NULL;
2020-05-10 12:56:36 +03:00
}
2010-07-31 06:52:47 +04:00
2020-05-10 12:56:36 +03:00
if (width <= 0) {
2010-07-31 06:52:47 +04:00
width = CW_USEDEFAULT;
2020-05-10 12:56:36 +03:00
}
if (height <= 0) {
2010-07-31 06:52:47 +04:00
height = CW_USEDEFAULT;
2020-05-10 12:56:36 +03:00
}
2010-07-31 06:52:47 +04:00
/* register toplevel window class */
windowClass.style = CS_CLASSDC;
windowClass.cbClsExtra = 0;
2021-01-03 06:17:51 +03:00
windowClass.cbWndExtra = sizeof(PyObject *) + sizeof(PyThreadState *);
2010-07-31 06:52:47 +04:00
windowClass.hInstance = GetModuleHandle(NULL);
/* windowClass.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1); */
windowClass.hbrBackground = NULL;
windowClass.lpszMenuName = NULL;
windowClass.lpszClassName = "pilWindow";
windowClass.lpfnWndProc = windowCallback;
windowClass.hIcon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(1));
windowClass.hCursor = LoadCursor(NULL, IDC_ARROW); /* CROSS? */
RegisterClass(&windowClass); /* FIXME: check return status */
wnd = CreateWindowEx(
2021-01-03 06:17:51 +03:00
0,
windowClass.lpszClassName,
title,
2010-07-31 06:52:47 +04:00
WS_OVERLAPPEDWINDOW,
2021-01-03 06:17:51 +03:00
CW_USEDEFAULT,
CW_USEDEFAULT,
width,
height,
HWND_DESKTOP,
NULL,
NULL,
NULL);
2010-07-31 06:52:47 +04:00
if (!wnd) {
PyErr_SetString(PyExc_OSError, "failed to create window");
2010-07-31 06:52:47 +04:00
return NULL;
}
/* register window callback */
Py_INCREF(callback);
2021-01-03 06:17:51 +03:00
SetWindowLongPtr(wnd, 0, (LONG_PTR)callback);
SetWindowLongPtr(wnd, sizeof(callback), (LONG_PTR)PyThreadState_Get());
2010-07-31 06:52:47 +04:00
2021-01-03 06:17:51 +03:00
Py_BEGIN_ALLOW_THREADS ShowWindow(wnd, SW_SHOWNORMAL);
2010-07-31 06:52:47 +04:00
SetForegroundWindow(wnd); /* to make sure it's visible */
Py_END_ALLOW_THREADS
2021-01-03 06:17:51 +03:00
return Py_BuildValue(F_HANDLE, wnd);
2010-07-31 06:52:47 +04:00
}
2021-01-03 06:17:51 +03:00
PyObject *
PyImaging_EventLoopWin32(PyObject *self, PyObject *args) {
2010-07-31 06:52:47 +04:00
MSG msg;
2021-01-03 06:17:51 +03:00
Py_BEGIN_ALLOW_THREADS while (mainloop && GetMessage(&msg, NULL, 0, 0)) {
2010-07-31 06:52:47 +04:00
TranslateMessage(&msg);
DispatchMessage(&msg);
}
Py_END_ALLOW_THREADS
2021-01-03 06:17:51 +03:00
Py_INCREF(Py_None);
2010-07-31 06:52:47 +04:00
return Py_None;
}
/* -------------------------------------------------------------------- */
/* windows WMF renderer */
2021-01-03 06:17:51 +03:00
#define GET32(p, o) ((DWORD *)(p + o))[0]
2010-07-31 06:52:47 +04:00
PyObject *
2021-01-03 06:17:51 +03:00
PyImaging_DrawWmf(PyObject *self, PyObject *args) {
2010-07-31 06:52:47 +04:00
HBITMAP bitmap;
HENHMETAFILE meta;
BITMAPCOREHEADER core;
HDC dc;
RECT rect;
2021-01-03 06:17:51 +03:00
PyObject *buffer = NULL;
char *ptr;
2010-07-31 06:52:47 +04:00
2021-01-03 06:17:51 +03:00
char *data;
2020-10-14 22:52:16 +03:00
Py_ssize_t datasize;
2010-07-31 06:52:47 +04:00
int width, height;
int x0, y0, x1, y1;
2021-01-03 06:17:51 +03:00
if (!PyArg_ParseTuple(
args,
"y#(ii)(iiii):_load",
&data,
&datasize,
&width,
&height,
&x0,
&x1,
&y0,
&y1)) {
2010-07-31 06:52:47 +04:00
return NULL;
2020-05-10 12:56:36 +03:00
}
2010-07-31 06:52:47 +04:00
/* step 1: copy metafile contents into METAFILE object */
if (datasize > 22 && GET32(data, 0) == 0x9ac6cdd7) {
/* placeable windows metafile (22-byte aldus header) */
2021-01-03 06:17:51 +03:00
meta = SetWinMetaFileBits(datasize - 22, data + 22, NULL, NULL);
2010-07-31 06:52:47 +04:00
2021-01-03 06:17:51 +03:00
} else if (datasize > 80 && GET32(data, 0) == 1 && GET32(data, 40) == 0x464d4520) {
2010-07-31 06:52:47 +04:00
/* enhanced metafile */
meta = SetEnhMetaFileBits(datasize, data);
} else {
/* unknown meta format */
meta = NULL;
}
if (!meta) {
PyErr_SetString(PyExc_OSError, "cannot load metafile");
2010-07-31 06:52:47 +04:00
return NULL;
}
/* step 2: create bitmap */
core.bcSize = sizeof(core);
core.bcWidth = width;
core.bcHeight = height;
core.bcPlanes = 1;
core.bcBitCount = 24;
dc = CreateCompatibleDC(NULL);
2021-01-03 06:17:51 +03:00
bitmap = CreateDIBSection(dc, (BITMAPINFO *)&core, DIB_RGB_COLORS, &ptr, NULL, 0);
2010-07-31 06:52:47 +04:00
if (!bitmap) {
PyErr_SetString(PyExc_OSError, "cannot create bitmap");
2010-07-31 06:52:47 +04:00
goto error;
}
if (!SelectObject(dc, bitmap)) {
PyErr_SetString(PyExc_OSError, "cannot select bitmap");
2010-07-31 06:52:47 +04:00
goto error;
}
/* step 3: render metafile into bitmap */
rect.left = rect.top = 0;
rect.right = width;
rect.bottom = height;
/* FIXME: make background transparent? configurable? */
FillRect(dc, &rect, GetStockObject(WHITE_BRUSH));
if (!PlayEnhMetaFile(dc, meta, &rect)) {
PyErr_SetString(PyExc_OSError, "cannot render metafile");
2010-07-31 06:52:47 +04:00
goto error;
}
/* step 4: extract bits from bitmap */
GdiFlush();
2021-01-03 06:17:51 +03:00
buffer = PyBytes_FromStringAndSize(ptr, height * ((width * 3 + 3) & -4));
2010-07-31 06:52:47 +04:00
error:
DeleteEnhMetaFile(meta);
2020-05-10 12:56:36 +03:00
if (bitmap) {
2010-07-31 06:52:47 +04:00
DeleteObject(bitmap);
2020-05-10 12:56:36 +03:00
}
2010-07-31 06:52:47 +04:00
DeleteDC(dc);
return buffer;
}
#endif /* _WIN32 */
2019-09-19 19:57:59 +03:00
/* -------------------------------------------------------------------- */
2020-05-01 15:08:57 +03:00
/* X11 support */
2019-09-19 19:57:59 +03:00
#ifdef HAVE_XCB
#include <xcb/xcb.h>
/* -------------------------------------------------------------------- */
/* X11 screen grabber */
2021-01-03 06:17:51 +03:00
PyObject *
PyImaging_GrabScreenX11(PyObject *self, PyObject *args) {
2019-09-19 19:57:59 +03:00
int width, height;
2021-01-03 06:17:51 +03:00
char *display_name;
xcb_connection_t *connection;
2019-09-19 19:57:59 +03:00
int screen_number;
xcb_screen_iterator_t iter;
2021-01-03 06:17:51 +03:00
xcb_screen_t *screen = NULL;
xcb_get_image_reply_t *reply;
xcb_generic_error_t *error;
PyObject *buffer = NULL;
2019-09-19 19:57:59 +03:00
2020-05-10 12:56:36 +03:00
if (!PyArg_ParseTuple(args, "|z", &display_name)) {
2019-09-19 19:57:59 +03:00
return NULL;
2020-05-10 12:56:36 +03:00
}
2019-09-19 19:57:59 +03:00
/* connect to X and get screen data */
connection = xcb_connect(display_name, &screen_number);
if (xcb_connection_has_error(connection)) {
2021-01-03 06:17:51 +03:00
PyErr_Format(
PyExc_OSError,
"X connection failed: error %i",
xcb_connection_has_error(connection));
2019-09-19 19:57:59 +03:00
xcb_disconnect(connection);
return NULL;
}
iter = xcb_setup_roots_iterator(xcb_get_setup(connection));
for (; iter.rem; --screen_number, xcb_screen_next(&iter)) {
if (screen_number == 0) {
screen = iter.data;
break;
}
}
2019-09-20 02:14:35 +03:00
if (screen == NULL || screen->root == 0) {
// this case is usually caught with "X connection failed: error 6" above
2019-09-19 19:57:59 +03:00
xcb_disconnect(connection);
PyErr_SetString(PyExc_OSError, "X screen not found");
2019-09-19 19:57:59 +03:00
return NULL;
}
width = screen->width_in_pixels;
height = screen->height_in_pixels;
/* get image data */
2021-01-03 06:17:51 +03:00
reply = xcb_get_image_reply(
connection,
xcb_get_image(
connection,
XCB_IMAGE_FORMAT_Z_PIXMAP,
screen->root,
0,
0,
width,
height,
0x00ffffff),
&error);
2019-09-19 19:57:59 +03:00
if (reply == NULL) {
2021-01-03 06:17:51 +03:00
PyErr_Format(
PyExc_OSError,
"X get_image failed: error %i (%i, %i, %i)",
error->error_code,
error->major_code,
error->minor_code,
error->resource_id);
2019-09-19 19:57:59 +03:00
free(error);
xcb_disconnect(connection);
return NULL;
}
/* store data in Python buffer */
2019-09-20 02:14:35 +03:00
if (reply->depth == 24) {
2021-01-03 06:17:51 +03:00
buffer = PyBytes_FromStringAndSize(
(char *)xcb_get_image_data(reply), xcb_get_image_data_length(reply));
2019-09-20 02:14:35 +03:00
} else {
PyErr_Format(PyExc_OSError, "unsupported bit depth: %i", reply->depth);
2019-09-20 02:14:35 +03:00
}
2019-09-19 19:57:59 +03:00
free(reply);
xcb_disconnect(connection);
2020-05-10 12:56:36 +03:00
if (!buffer) {
2019-09-19 19:57:59 +03:00
return NULL;
2020-05-10 12:56:36 +03:00
}
2019-09-19 19:57:59 +03:00
return Py_BuildValue("(ii)N", width, height, buffer);
}
#endif /* HAVE_XCB */