display.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828
  1. /*
  2. * The Python Imaging Library.
  3. *
  4. * display support (and other windows-related stuff)
  5. *
  6. * History:
  7. * 1996-05-13 fl Windows DIB support
  8. * 1996-05-21 fl Added palette stuff
  9. * 1996-05-28 fl Added display_mode stuff
  10. * 1997-09-21 fl Added draw primitive
  11. * 2001-09-17 fl Added ImagingGrabScreen (from _grabscreen.c)
  12. * 2002-05-12 fl Added ImagingListWindows
  13. * 2002-11-19 fl Added clipboard support
  14. * 2002-11-25 fl Added GetDC/ReleaseDC helpers
  15. * 2003-05-21 fl Added create window support (including window callback)
  16. * 2003-09-05 fl Added fromstring/tostring methods
  17. * 2009-03-14 fl Added WMF support (from pilwmf)
  18. *
  19. * Copyright (c) 1997-2003 by Secret Labs AB.
  20. * Copyright (c) 1996-1997 by Fredrik Lundh.
  21. *
  22. * See the README file for information on usage and redistribution.
  23. */
  24. #include "Python.h"
  25. #include "Imaging.h"
  26. #include "py3.h"
  27. /* -------------------------------------------------------------------- */
  28. /* Windows DIB support */
  29. #ifdef _WIN32
  30. #include "ImDib.h"
  31. #if SIZEOF_VOID_P == 8
  32. #define F_HANDLE "K"
  33. #else
  34. #define F_HANDLE "k"
  35. #endif
  36. typedef struct {
  37. PyObject_HEAD
  38. ImagingDIB dib;
  39. } ImagingDisplayObject;
  40. static PyTypeObject ImagingDisplayType;
  41. static ImagingDisplayObject*
  42. _new(const char* mode, int xsize, int ysize)
  43. {
  44. ImagingDisplayObject *display;
  45. if (PyType_Ready(&ImagingDisplayType) < 0)
  46. return NULL;
  47. display = PyObject_New(ImagingDisplayObject, &ImagingDisplayType);
  48. if (display == NULL)
  49. return NULL;
  50. display->dib = ImagingNewDIB(mode, xsize, ysize);
  51. if (!display->dib) {
  52. Py_DECREF(display);
  53. return NULL;
  54. }
  55. return display;
  56. }
  57. static void
  58. _delete(ImagingDisplayObject* display)
  59. {
  60. if (display->dib)
  61. ImagingDeleteDIB(display->dib);
  62. PyObject_Del(display);
  63. }
  64. static PyObject*
  65. _expose(ImagingDisplayObject* display, PyObject* args)
  66. {
  67. HDC hdc;
  68. if (!PyArg_ParseTuple(args, F_HANDLE, &hdc))
  69. return NULL;
  70. ImagingExposeDIB(display->dib, hdc);
  71. Py_INCREF(Py_None);
  72. return Py_None;
  73. }
  74. static PyObject*
  75. _draw(ImagingDisplayObject* display, PyObject* args)
  76. {
  77. HDC hdc;
  78. int dst[4];
  79. int src[4];
  80. if (!PyArg_ParseTuple(args, F_HANDLE "(iiii)(iiii)", &hdc,
  81. dst+0, dst+1, dst+2, dst+3,
  82. src+0, src+1, src+2, src+3))
  83. return NULL;
  84. ImagingDrawDIB(display->dib, hdc, dst, src);
  85. Py_INCREF(Py_None);
  86. return Py_None;
  87. }
  88. extern Imaging PyImaging_AsImaging(PyObject *op);
  89. static PyObject*
  90. _paste(ImagingDisplayObject* display, PyObject* args)
  91. {
  92. Imaging im;
  93. PyObject* op;
  94. int xy[4];
  95. xy[0] = xy[1] = xy[2] = xy[3] = 0;
  96. if (!PyArg_ParseTuple(args, "O|(iiii)", &op, xy+0, xy+1, xy+2, xy+3))
  97. return NULL;
  98. im = PyImaging_AsImaging(op);
  99. if (!im)
  100. return NULL;
  101. if (xy[2] <= xy[0])
  102. xy[2] = xy[0] + im->xsize;
  103. if (xy[3] <= xy[1])
  104. xy[3] = xy[1] + im->ysize;
  105. ImagingPasteDIB(display->dib, im, xy);
  106. Py_INCREF(Py_None);
  107. return Py_None;
  108. }
  109. static PyObject*
  110. _query_palette(ImagingDisplayObject* display, PyObject* args)
  111. {
  112. HDC hdc;
  113. int status;
  114. if (!PyArg_ParseTuple(args, F_HANDLE, &hdc))
  115. return NULL;
  116. status = ImagingQueryPaletteDIB(display->dib, hdc);
  117. return Py_BuildValue("i", status);
  118. }
  119. static PyObject*
  120. _getdc(ImagingDisplayObject* display, PyObject* args)
  121. {
  122. HWND window;
  123. HDC dc;
  124. if (!PyArg_ParseTuple(args, F_HANDLE, &window))
  125. return NULL;
  126. dc = GetDC(window);
  127. if (!dc) {
  128. PyErr_SetString(PyExc_IOError, "cannot create dc");
  129. return NULL;
  130. }
  131. return Py_BuildValue(F_HANDLE, dc);
  132. }
  133. static PyObject*
  134. _releasedc(ImagingDisplayObject* display, PyObject* args)
  135. {
  136. HWND window;
  137. HDC dc;
  138. if (!PyArg_ParseTuple(args, F_HANDLE F_HANDLE, &window, &dc))
  139. return NULL;
  140. ReleaseDC(window, dc);
  141. Py_INCREF(Py_None);
  142. return Py_None;
  143. }
  144. static PyObject*
  145. _frombytes(ImagingDisplayObject* display, PyObject* args)
  146. {
  147. char* ptr;
  148. int bytes;
  149. #if PY_VERSION_HEX >= 0x03000000
  150. if (!PyArg_ParseTuple(args, "y#:frombytes", &ptr, &bytes))
  151. return NULL;
  152. #else
  153. if (!PyArg_ParseTuple(args, "s#:fromstring", &ptr, &bytes))
  154. return NULL;
  155. #endif
  156. if (display->dib->ysize * display->dib->linesize != bytes) {
  157. PyErr_SetString(PyExc_ValueError, "wrong size");
  158. return NULL;
  159. }
  160. memcpy(display->dib->bits, ptr, bytes);
  161. Py_INCREF(Py_None);
  162. return Py_None;
  163. }
  164. static PyObject*
  165. _tobytes(ImagingDisplayObject* display, PyObject* args)
  166. {
  167. #if PY_VERSION_HEX >= 0x03000000
  168. if (!PyArg_ParseTuple(args, ":tobytes"))
  169. return NULL;
  170. #else
  171. if (!PyArg_ParseTuple(args, ":tostring"))
  172. return NULL;
  173. #endif
  174. return PyBytes_FromStringAndSize(
  175. display->dib->bits, display->dib->ysize * display->dib->linesize
  176. );
  177. }
  178. static struct PyMethodDef methods[] = {
  179. {"draw", (PyCFunction)_draw, 1},
  180. {"expose", (PyCFunction)_expose, 1},
  181. {"paste", (PyCFunction)_paste, 1},
  182. {"query_palette", (PyCFunction)_query_palette, 1},
  183. {"getdc", (PyCFunction)_getdc, 1},
  184. {"releasedc", (PyCFunction)_releasedc, 1},
  185. {"frombytes", (PyCFunction)_frombytes, 1},
  186. {"tobytes", (PyCFunction)_tobytes, 1},
  187. {"fromstring", (PyCFunction)_frombytes, 1},
  188. {"tostring", (PyCFunction)_tobytes, 1},
  189. {NULL, NULL} /* sentinel */
  190. };
  191. static PyObject*
  192. _getattr_mode(ImagingDisplayObject* self, void* closure)
  193. {
  194. return Py_BuildValue("s", self->dib->mode);
  195. }
  196. static PyObject*
  197. _getattr_size(ImagingDisplayObject* self, void* closure)
  198. {
  199. return Py_BuildValue("ii", self->dib->xsize, self->dib->ysize);
  200. }
  201. static struct PyGetSetDef getsetters[] = {
  202. { "mode", (getter) _getattr_mode },
  203. { "size", (getter) _getattr_size },
  204. { NULL }
  205. };
  206. static PyTypeObject ImagingDisplayType = {
  207. PyVarObject_HEAD_INIT(NULL, 0)
  208. "ImagingDisplay", /*tp_name*/
  209. sizeof(ImagingDisplayObject), /*tp_size*/
  210. 0, /*tp_itemsize*/
  211. /* methods */
  212. (destructor)_delete, /*tp_dealloc*/
  213. 0, /*tp_print*/
  214. 0, /*tp_getattr*/
  215. 0, /*tp_setattr*/
  216. 0, /*tp_compare*/
  217. 0, /*tp_repr*/
  218. 0, /*tp_as_number */
  219. 0, /*tp_as_sequence */
  220. 0, /*tp_as_mapping */
  221. 0, /*tp_hash*/
  222. 0, /*tp_call*/
  223. 0, /*tp_str*/
  224. 0, /*tp_getattro*/
  225. 0, /*tp_setattro*/
  226. 0, /*tp_as_buffer*/
  227. Py_TPFLAGS_DEFAULT, /*tp_flags*/
  228. 0, /*tp_doc*/
  229. 0, /*tp_traverse*/
  230. 0, /*tp_clear*/
  231. 0, /*tp_richcompare*/
  232. 0, /*tp_weaklistoffset*/
  233. 0, /*tp_iter*/
  234. 0, /*tp_iternext*/
  235. methods, /*tp_methods*/
  236. 0, /*tp_members*/
  237. getsetters, /*tp_getset*/
  238. };
  239. PyObject*
  240. PyImaging_DisplayWin32(PyObject* self, PyObject* args)
  241. {
  242. ImagingDisplayObject* display;
  243. char *mode;
  244. int xsize, ysize;
  245. if (!PyArg_ParseTuple(args, "s(ii)", &mode, &xsize, &ysize))
  246. return NULL;
  247. display = _new(mode, xsize, ysize);
  248. if (display == NULL)
  249. return NULL;
  250. return (PyObject*) display;
  251. }
  252. PyObject*
  253. PyImaging_DisplayModeWin32(PyObject* self, PyObject* args)
  254. {
  255. char *mode;
  256. int size[2];
  257. mode = ImagingGetModeDIB(size);
  258. return Py_BuildValue("s(ii)", mode, size[0], size[1]);
  259. }
  260. /* -------------------------------------------------------------------- */
  261. /* Windows screen grabber */
  262. typedef HANDLE(__stdcall* Func_SetThreadDpiAwarenessContext)(HANDLE);
  263. PyObject*
  264. PyImaging_GrabScreenWin32(PyObject* self, PyObject* args)
  265. {
  266. int x = 0, y = 0, width, height;
  267. int includeLayeredWindows = 0, all_screens = 0;
  268. HBITMAP bitmap;
  269. BITMAPCOREHEADER core;
  270. HDC screen, screen_copy;
  271. DWORD rop;
  272. PyObject* buffer;
  273. HANDLE dpiAwareness;
  274. HMODULE user32;
  275. Func_SetThreadDpiAwarenessContext SetThreadDpiAwarenessContext_function;
  276. if (!PyArg_ParseTuple(args, "|ii", &includeLayeredWindows, &all_screens))
  277. return NULL;
  278. /* step 1: create a memory DC large enough to hold the
  279. entire screen */
  280. screen = CreateDC("DISPLAY", NULL, NULL, NULL);
  281. screen_copy = CreateCompatibleDC(screen);
  282. // added in Windows 10 (1607)
  283. // loaded dynamically to avoid link errors
  284. user32 = LoadLibraryA("User32.dll");
  285. SetThreadDpiAwarenessContext_function =
  286. (Func_SetThreadDpiAwarenessContext)
  287. GetProcAddress(user32, "SetThreadDpiAwarenessContext");
  288. if (SetThreadDpiAwarenessContext_function != NULL) {
  289. // DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE = ((DPI_CONTEXT_HANDLE)-3)
  290. dpiAwareness = SetThreadDpiAwarenessContext_function((HANDLE) -3);
  291. }
  292. if (all_screens) {
  293. x = GetSystemMetrics(SM_XVIRTUALSCREEN);
  294. y = GetSystemMetrics(SM_YVIRTUALSCREEN);
  295. width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
  296. height = GetSystemMetrics(SM_CYVIRTUALSCREEN);
  297. } else {
  298. width = GetDeviceCaps(screen, HORZRES);
  299. height = GetDeviceCaps(screen, VERTRES);
  300. }
  301. if (SetThreadDpiAwarenessContext_function != NULL) {
  302. SetThreadDpiAwarenessContext_function(dpiAwareness);
  303. }
  304. FreeLibrary(user32);
  305. bitmap = CreateCompatibleBitmap(screen, width, height);
  306. if (!bitmap)
  307. goto error;
  308. if (!SelectObject(screen_copy, bitmap))
  309. goto error;
  310. /* step 2: copy bits into memory DC bitmap */
  311. rop = SRCCOPY;
  312. if (includeLayeredWindows)
  313. rop |= CAPTUREBLT;
  314. if (!BitBlt(screen_copy, 0, 0, width, height, screen, x, y, rop))
  315. goto error;
  316. /* step 3: extract bits from bitmap */
  317. buffer = PyBytes_FromStringAndSize(NULL, height * ((width*3 + 3) & -4));
  318. if (!buffer)
  319. return NULL;
  320. core.bcSize = sizeof(core);
  321. core.bcWidth = width;
  322. core.bcHeight = height;
  323. core.bcPlanes = 1;
  324. core.bcBitCount = 24;
  325. if (!GetDIBits(screen_copy, bitmap, 0, height, PyBytes_AS_STRING(buffer),
  326. (BITMAPINFO*) &core, DIB_RGB_COLORS))
  327. goto error;
  328. DeleteObject(bitmap);
  329. DeleteDC(screen_copy);
  330. DeleteDC(screen);
  331. return Py_BuildValue("(ii)(ii)N", x, y, width, height, buffer);
  332. error:
  333. PyErr_SetString(PyExc_IOError, "screen grab failed");
  334. DeleteDC(screen_copy);
  335. DeleteDC(screen);
  336. return NULL;
  337. }
  338. static BOOL CALLBACK list_windows_callback(HWND hwnd, LPARAM lParam)
  339. {
  340. PyObject* window_list = (PyObject*) lParam;
  341. PyObject* item;
  342. PyObject* title;
  343. RECT inner, outer;
  344. int title_size;
  345. int status;
  346. /* get window title */
  347. title_size = GetWindowTextLength(hwnd);
  348. if (title_size > 0) {
  349. title = PyUnicode_FromStringAndSize(NULL, title_size);
  350. if (title)
  351. GetWindowTextW(hwnd, PyUnicode_AS_UNICODE(title), title_size+1);
  352. } else
  353. title = PyUnicode_FromString("");
  354. if (!title)
  355. return 0;
  356. /* get bounding boxes */
  357. GetClientRect(hwnd, &inner);
  358. GetWindowRect(hwnd, &outer);
  359. item = Py_BuildValue(
  360. F_HANDLE "N(iiii)(iiii)", hwnd, title,
  361. inner.left, inner.top, inner.right, inner.bottom,
  362. outer.left, outer.top, outer.right, outer.bottom
  363. );
  364. if (!item)
  365. return 0;
  366. status = PyList_Append(window_list, item);
  367. Py_DECREF(item);
  368. if (status < 0)
  369. return 0;
  370. return 1;
  371. }
  372. PyObject*
  373. PyImaging_ListWindowsWin32(PyObject* self, PyObject* args)
  374. {
  375. PyObject* window_list;
  376. window_list = PyList_New(0);
  377. if (!window_list)
  378. return NULL;
  379. EnumWindows(list_windows_callback, (LPARAM) window_list);
  380. if (PyErr_Occurred()) {
  381. Py_DECREF(window_list);
  382. return NULL;
  383. }
  384. return window_list;
  385. }
  386. /* -------------------------------------------------------------------- */
  387. /* Windows clipboard grabber */
  388. PyObject*
  389. PyImaging_GrabClipboardWin32(PyObject* self, PyObject* args)
  390. {
  391. int clip;
  392. HANDLE handle;
  393. int size;
  394. void* data;
  395. PyObject* result;
  396. clip = OpenClipboard(NULL);
  397. /* FIXME: check error status */
  398. handle = GetClipboardData(CF_DIB);
  399. if (!handle) {
  400. /* FIXME: add CF_HDROP support to allow cut-and-paste from
  401. the explorer */
  402. CloseClipboard();
  403. Py_INCREF(Py_None);
  404. return Py_None;
  405. }
  406. size = GlobalSize(handle);
  407. data = GlobalLock(handle);
  408. result = PyBytes_FromStringAndSize(data, size);
  409. GlobalUnlock(handle);
  410. CloseClipboard();
  411. return result;
  412. }
  413. /* -------------------------------------------------------------------- */
  414. /* Windows class */
  415. #ifndef WM_MOUSEWHEEL
  416. #define WM_MOUSEWHEEL 522
  417. #endif
  418. static int mainloop = 0;
  419. static void
  420. callback_error(const char* handler)
  421. {
  422. PyObject* sys_stderr;
  423. sys_stderr = PySys_GetObject("stderr");
  424. if (sys_stderr) {
  425. PyFile_WriteString("*** ImageWin: error in ", sys_stderr);
  426. PyFile_WriteString((char*) handler, sys_stderr);
  427. PyFile_WriteString(":\n", sys_stderr);
  428. }
  429. PyErr_Print();
  430. PyErr_Clear();
  431. }
  432. static LRESULT CALLBACK
  433. windowCallback(HWND wnd, UINT message, WPARAM wParam, LPARAM lParam)
  434. {
  435. PAINTSTRUCT ps;
  436. PyObject* callback = NULL;
  437. PyObject* result;
  438. PyThreadState* threadstate;
  439. PyThreadState* current_threadstate;
  440. HDC dc;
  441. RECT rect;
  442. LRESULT status = 0;
  443. /* set up threadstate for messages that calls back into python */
  444. switch (message) {
  445. case WM_CREATE:
  446. mainloop++;
  447. break;
  448. case WM_DESTROY:
  449. mainloop--;
  450. /* fall through... */
  451. case WM_PAINT:
  452. case WM_SIZE:
  453. callback = (PyObject*) GetWindowLongPtr(wnd, 0);
  454. if (callback) {
  455. threadstate = (PyThreadState*)
  456. GetWindowLongPtr(wnd, sizeof(PyObject*));
  457. current_threadstate = PyThreadState_Swap(NULL);
  458. PyEval_RestoreThread(threadstate);
  459. } else
  460. return DefWindowProc(wnd, message, wParam, lParam);
  461. }
  462. /* process message */
  463. switch (message) {
  464. case WM_PAINT:
  465. /* redraw (part of) window. this generates a WCK-style
  466. damage/clear/repair cascade */
  467. BeginPaint(wnd, &ps);
  468. dc = GetDC(wnd);
  469. GetWindowRect(wnd, &rect); /* in screen coordinates */
  470. result = PyObject_CallFunction(
  471. callback, "siiii", "damage",
  472. ps.rcPaint.left, ps.rcPaint.top,
  473. ps.rcPaint.right, ps.rcPaint.bottom
  474. );
  475. if (result)
  476. Py_DECREF(result);
  477. else
  478. callback_error("window damage callback");
  479. result = PyObject_CallFunction(
  480. callback, "s" F_HANDLE "iiii", "clear", dc,
  481. 0, 0, rect.right-rect.left, rect.bottom-rect.top
  482. );
  483. if (result)
  484. Py_DECREF(result);
  485. else
  486. callback_error("window clear callback");
  487. result = PyObject_CallFunction(
  488. callback, "s" F_HANDLE "iiii", "repair", dc,
  489. 0, 0, rect.right-rect.left, rect.bottom-rect.top
  490. );
  491. if (result)
  492. Py_DECREF(result);
  493. else
  494. callback_error("window repair callback");
  495. ReleaseDC(wnd, dc);
  496. EndPaint(wnd, &ps);
  497. break;
  498. case WM_SIZE:
  499. /* resize window */
  500. result = PyObject_CallFunction(
  501. callback, "sii", "resize", LOWORD(lParam), HIWORD(lParam)
  502. );
  503. if (result) {
  504. InvalidateRect(wnd, NULL, 1);
  505. Py_DECREF(result);
  506. } else
  507. callback_error("window resize callback");
  508. break;
  509. case WM_DESTROY:
  510. /* destroy window */
  511. result = PyObject_CallFunction(callback, "s", "destroy");
  512. if (result)
  513. Py_DECREF(result);
  514. else
  515. callback_error("window destroy callback");
  516. Py_DECREF(callback);
  517. break;
  518. default:
  519. status = DefWindowProc(wnd, message, wParam, lParam);
  520. }
  521. if (callback) {
  522. /* restore thread state */
  523. PyEval_SaveThread();
  524. PyThreadState_Swap(threadstate);
  525. }
  526. return status;
  527. }
  528. PyObject*
  529. PyImaging_CreateWindowWin32(PyObject* self, PyObject* args)
  530. {
  531. HWND wnd;
  532. WNDCLASS windowClass;
  533. char* title;
  534. PyObject* callback;
  535. int width = 0, height = 0;
  536. if (!PyArg_ParseTuple(args, "sO|ii", &title, &callback, &width, &height))
  537. return NULL;
  538. if (width <= 0)
  539. width = CW_USEDEFAULT;
  540. if (height <= 0)
  541. height = CW_USEDEFAULT;
  542. /* register toplevel window class */
  543. windowClass.style = CS_CLASSDC;
  544. windowClass.cbClsExtra = 0;
  545. windowClass.cbWndExtra = sizeof(PyObject*) + sizeof(PyThreadState*);
  546. windowClass.hInstance = GetModuleHandle(NULL);
  547. /* windowClass.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1); */
  548. windowClass.hbrBackground = NULL;
  549. windowClass.lpszMenuName = NULL;
  550. windowClass.lpszClassName = "pilWindow";
  551. windowClass.lpfnWndProc = windowCallback;
  552. windowClass.hIcon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(1));
  553. windowClass.hCursor = LoadCursor(NULL, IDC_ARROW); /* CROSS? */
  554. RegisterClass(&windowClass); /* FIXME: check return status */
  555. wnd = CreateWindowEx(
  556. 0, windowClass.lpszClassName, title,
  557. WS_OVERLAPPEDWINDOW,
  558. CW_USEDEFAULT, CW_USEDEFAULT, width, height,
  559. HWND_DESKTOP, NULL, NULL, NULL
  560. );
  561. if (!wnd) {
  562. PyErr_SetString(PyExc_IOError, "failed to create window");
  563. return NULL;
  564. }
  565. /* register window callback */
  566. Py_INCREF(callback);
  567. SetWindowLongPtr(wnd, 0, (LONG_PTR) callback);
  568. SetWindowLongPtr(wnd, sizeof(callback), (LONG_PTR) PyThreadState_Get());
  569. Py_BEGIN_ALLOW_THREADS
  570. ShowWindow(wnd, SW_SHOWNORMAL);
  571. SetForegroundWindow(wnd); /* to make sure it's visible */
  572. Py_END_ALLOW_THREADS
  573. return Py_BuildValue(F_HANDLE, wnd);
  574. }
  575. PyObject*
  576. PyImaging_EventLoopWin32(PyObject* self, PyObject* args)
  577. {
  578. MSG msg;
  579. Py_BEGIN_ALLOW_THREADS
  580. while (mainloop && GetMessage(&msg, NULL, 0, 0)) {
  581. TranslateMessage(&msg);
  582. DispatchMessage(&msg);
  583. }
  584. Py_END_ALLOW_THREADS
  585. Py_INCREF(Py_None);
  586. return Py_None;
  587. }
  588. /* -------------------------------------------------------------------- */
  589. /* windows WMF renderer */
  590. #define GET32(p,o) ((DWORD*)(p+o))[0]
  591. PyObject *
  592. PyImaging_DrawWmf(PyObject* self, PyObject* args)
  593. {
  594. HBITMAP bitmap;
  595. HENHMETAFILE meta;
  596. BITMAPCOREHEADER core;
  597. HDC dc;
  598. RECT rect;
  599. PyObject* buffer = NULL;
  600. char* ptr;
  601. char* data;
  602. int datasize;
  603. int width, height;
  604. int x0, y0, x1, y1;
  605. if (!PyArg_ParseTuple(args, PY_ARG_BYTES_LENGTH"(ii)(iiii):_load", &data, &datasize,
  606. &width, &height, &x0, &x1, &y0, &y1))
  607. return NULL;
  608. /* step 1: copy metafile contents into METAFILE object */
  609. if (datasize > 22 && GET32(data, 0) == 0x9ac6cdd7) {
  610. /* placeable windows metafile (22-byte aldus header) */
  611. meta = SetWinMetaFileBits(datasize-22, data+22, NULL, NULL);
  612. } else if (datasize > 80 && GET32(data, 0) == 1 &&
  613. GET32(data, 40) == 0x464d4520) {
  614. /* enhanced metafile */
  615. meta = SetEnhMetaFileBits(datasize, data);
  616. } else {
  617. /* unknown meta format */
  618. meta = NULL;
  619. }
  620. if (!meta) {
  621. PyErr_SetString(PyExc_IOError, "cannot load metafile");
  622. return NULL;
  623. }
  624. /* step 2: create bitmap */
  625. core.bcSize = sizeof(core);
  626. core.bcWidth = width;
  627. core.bcHeight = height;
  628. core.bcPlanes = 1;
  629. core.bcBitCount = 24;
  630. dc = CreateCompatibleDC(NULL);
  631. bitmap = CreateDIBSection(
  632. dc, (BITMAPINFO*) &core, DIB_RGB_COLORS, &ptr, NULL, 0
  633. );
  634. if (!bitmap) {
  635. PyErr_SetString(PyExc_IOError, "cannot create bitmap");
  636. goto error;
  637. }
  638. if (!SelectObject(dc, bitmap)) {
  639. PyErr_SetString(PyExc_IOError, "cannot select bitmap");
  640. goto error;
  641. }
  642. /* step 3: render metafile into bitmap */
  643. rect.left = rect.top = 0;
  644. rect.right = width;
  645. rect.bottom = height;
  646. /* FIXME: make background transparent? configurable? */
  647. FillRect(dc, &rect, GetStockObject(WHITE_BRUSH));
  648. if (!PlayEnhMetaFile(dc, meta, &rect)) {
  649. PyErr_SetString(PyExc_IOError, "cannot render metafile");
  650. goto error;
  651. }
  652. /* step 4: extract bits from bitmap */
  653. GdiFlush();
  654. buffer = PyBytes_FromStringAndSize(ptr, height * ((width*3 + 3) & -4));
  655. error:
  656. DeleteEnhMetaFile(meta);
  657. if (bitmap)
  658. DeleteObject(bitmap);
  659. DeleteDC(dc);
  660. return buffer;
  661. }
  662. #endif /* _WIN32 */