diff --git a/Tests/test_imagewin_pointers.py b/Tests/test_imagewin_pointers.py new file mode 100644 index 000000000..f8886f55b --- /dev/null +++ b/Tests/test_imagewin_pointers.py @@ -0,0 +1,111 @@ +from helper import unittest, PillowTestCase, hopper +from PIL import Image, ImageWin + +import sys +import ctypes +from io import BytesIO + +# see https://github.com/python-pillow/Pillow/pull/1431#issuecomment-144692652 + +if sys.platform.startswith('win32'): + import ctypes.wintypes + + class BITMAPFILEHEADER(ctypes.Structure): + _pack_ = 2 + _fields_ = [ + ('bfType', ctypes.wintypes.WORD), + ('bfSize', ctypes.wintypes.DWORD), + ('bfReserved1', ctypes.wintypes.WORD), + ('bfReserved2', ctypes.wintypes.WORD), + ('bfOffBits', ctypes.wintypes.DWORD), + ] + + class BITMAPINFOHEADER(ctypes.Structure): + _pack_ = 2 + _fields_ = [ + ('biSize', ctypes.wintypes.DWORD), + ('biWidth', ctypes.wintypes.LONG), + ('biHeight', ctypes.wintypes.LONG), + ('biPlanes', ctypes.wintypes.WORD), + ('biBitCount', ctypes.wintypes.WORD), + ('biCompression', ctypes.wintypes.DWORD), + ('biSizeImage', ctypes.wintypes.DWORD), + ('biXPelsPerMeter', ctypes.wintypes.LONG), + ('biYPelsPerMeter', ctypes.wintypes.LONG), + ('biClrUsed', ctypes.wintypes.DWORD), + ('biClrImportant', ctypes.wintypes.DWORD), + ] + + BI_RGB = 0 + DIB_RGB_COLORS = 0 + + memcpy = ctypes.cdll.msvcrt.memcpy + memcpy.argtypes = [ ctypes.c_void_p, ctypes.c_void_p, ctypes.c_size_t ] + + CreateCompatibleDC = ctypes.windll.gdi32.CreateCompatibleDC + CreateCompatibleDC.argtypes = [ ctypes.wintypes.HDC ] + CreateCompatibleDC.restype = ctypes.wintypes.HDC + + DeleteDC = ctypes.windll.gdi32.DeleteDC + DeleteDC.argtypes = [ ctypes.wintypes.HDC ] + + SelectObject = ctypes.windll.gdi32.SelectObject + SelectObject.argtypes = [ ctypes.wintypes.HDC, ctypes.wintypes.HGDIOBJ ] + SelectObject.restype = ctypes.wintypes.HGDIOBJ + + DeleteObject = ctypes.windll.gdi32.DeleteObject + DeleteObject.argtypes = [ ctypes.wintypes.HGDIOBJ ] + + CreateDIBSection = ctypes.windll.gdi32.CreateDIBSection + CreateDIBSection.argtypes = [ ctypes.wintypes.HDC, ctypes.c_void_p, ctypes.c_uint, ctypes.POINTER(ctypes.c_void_p), ctypes.wintypes.HANDLE, ctypes.wintypes.DWORD ] + CreateDIBSection.restype = ctypes.wintypes.HBITMAP + + + def serialize_dib(bi, pixels): + bf = BITMAPFILEHEADER() + bf.bfType = 0x4d42 + bf.bfOffBits = ctypes.sizeof(bf) + bi.biSize + bf.bfSize = bf.bfOffBits + bi.biSizeImage + bf.bfReserved1 = bf.bfReserved2 = 0 + + buf = (ctypes.c_byte * bf.bfSize)() + bp = ctypes.addressof(buf) + memcpy(bp, ctypes.byref(bf), ctypes.sizeof(bf)) + memcpy(bp + ctypes.sizeof(bf), ctypes.byref(bi), bi.biSize) + memcpy(bp + bf.bfOffBits, pixels, bi.biSizeImage) + return bytearray(buf) + + class TestImageWinPointers(PillowTestCase): + def test_pointer(self): + im = hopper() + (width, height) =im.size + opath = self.tempfile('temp.png') + imdib = ImageWin.Dib(im) + + hdr = BITMAPINFOHEADER() + hdr.biSize = ctypes.sizeof(hdr) + hdr.biWidth = width + hdr.biHeight = height + hdr.biPlanes = 1 + hdr.biBitCount = 32 + hdr.biCompression = BI_RGB + hdr.biSizeImage = width * height * 4 + hdr.biClrUsed = 0 + hdr.biClrImportant = 0 + + hdc = CreateCompatibleDC(None) + #print('hdc:',hex(hdc)) + pixels = ctypes.c_void_p() + dib = CreateDIBSection(hdc, ctypes.byref(hdr), DIB_RGB_COLORS, ctypes.byref(pixels), None, 0) + SelectObject(hdc, dib) + + imdib.expose(hdc) + bitmap = serialize_dib(hdr, pixels) + DeleteObject(dib) + DeleteDC(hdc) + + reloaded = Image.open(BytesIO(bitmap)).save(opath) + +if __name__ == '__main__': + unittest.main() + diff --git a/display.c b/display.c index e10d72c0d..9f493344e 100644 --- a/display.c +++ b/display.c @@ -35,6 +35,12 @@ #include "ImDib.h" +#if SIZEOF_VOID_P == 8 +#define F_HANDLE "K" +#else +#define F_HANDLE "k" +#endif + typedef struct { PyObject_HEAD ImagingDIB dib; @@ -74,8 +80,8 @@ _delete(ImagingDisplayObject* display) static PyObject* _expose(ImagingDisplayObject* display, PyObject* args) { - int hdc; - if (!PyArg_ParseTuple(args, "i", &hdc)) + HDC hdc; + if (!PyArg_ParseTuple(args, F_HANDLE, &hdc)) return NULL; ImagingExposeDIB(display->dib, hdc); @@ -87,10 +93,10 @@ _expose(ImagingDisplayObject* display, PyObject* args) static PyObject* _draw(ImagingDisplayObject* display, PyObject* args) { - int hdc; + HDC hdc; int dst[4]; int src[4]; - if (!PyArg_ParseTuple(args, "i(iiii)(iiii)", &hdc, + 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)) return NULL; @@ -131,10 +137,10 @@ _paste(ImagingDisplayObject* display, PyObject* args) static PyObject* _query_palette(ImagingDisplayObject* display, PyObject* args) { - int hdc; + HDC hdc; int status; - if (!PyArg_ParseTuple(args, "i", &hdc)) + if (!PyArg_ParseTuple(args, F_HANDLE, &hdc)) return NULL; status = ImagingQueryPaletteDIB(display->dib, hdc); @@ -145,30 +151,31 @@ _query_palette(ImagingDisplayObject* display, PyObject* args) static PyObject* _getdc(ImagingDisplayObject* display, PyObject* args) { - int window; + HWND window; HDC dc; - if (!PyArg_ParseTuple(args, "i", &window)) + if (!PyArg_ParseTuple(args, F_HANDLE, &window)) return NULL; - dc = GetDC((HWND) window); + dc = GetDC(window); if (!dc) { PyErr_SetString(PyExc_IOError, "cannot create dc"); return NULL; } - return Py_BuildValue("i", (int) dc); + return Py_BuildValue(F_HANDLE, dc); } static PyObject* _releasedc(ImagingDisplayObject* display, PyObject* args) { - int window, dc; + HWND window; + HDC dc; - if (!PyArg_ParseTuple(args, "ii", &window, &dc)) + if (!PyArg_ParseTuple(args, F_HANDLE F_HANDLE, &window, &dc)) return NULL; - ReleaseDC((HWND) window, (HDC) dc); + ReleaseDC(window, dc); Py_INCREF(Py_None); return Py_None; @@ -386,7 +393,7 @@ static BOOL CALLBACK list_windows_callback(HWND hwnd, LPARAM lParam) if (title_size > 0) { title = PyUnicode_FromStringAndSize(NULL, title_size); if (title) - GetWindowText(hwnd, PyUnicode_AS_UNICODE(title), title_size+1); + GetWindowTextW(hwnd, PyUnicode_AS_UNICODE(title), title_size+1); } else title = PyUnicode_FromString(""); if (!title) @@ -397,7 +404,7 @@ static BOOL CALLBACK list_windows_callback(HWND hwnd, LPARAM lParam) GetWindowRect(hwnd, &outer); item = Py_BuildValue( - "nN(iiii)(iiii)", (Py_ssize_t) hwnd, title, + F_HANDLE "N(iiii)(iiii)", hwnd, title, inner.left, inner.top, inner.right, inner.bottom, outer.left, outer.top, outer.right, outer.bottom ); @@ -600,10 +607,10 @@ windowCallback(HWND wnd, UINT message, WPARAM wParam, LPARAM lParam) /* fall through... */ case WM_PAINT: case WM_SIZE: - callback = (PyObject*) GetWindowLong(wnd, 0); + callback = (PyObject*) GetWindowLongPtr(wnd, 0); if (callback) { threadstate = (PyThreadState*) - GetWindowLong(wnd, sizeof(PyObject*)); + GetWindowLongPtr(wnd, sizeof(PyObject*)); current_threadstate = PyThreadState_Swap(NULL); PyEval_RestoreThread(threadstate); } else @@ -631,7 +638,7 @@ windowCallback(HWND wnd, UINT message, WPARAM wParam, LPARAM lParam) callback_error("window damage callback"); result = PyObject_CallFunction( - callback, "siiiii", "clear", (int) dc, + callback, "s" F_HANDLE "iiii", "clear", dc, 0, 0, rect.right-rect.left, rect.bottom-rect.top ); if (result) @@ -640,7 +647,7 @@ windowCallback(HWND wnd, UINT message, WPARAM wParam, LPARAM lParam) callback_error("window clear callback"); result = PyObject_CallFunction( - callback, "siiiii", "repair", (int) dc, + callback, "s" F_HANDLE "iiii", "repair", dc, 0, 0, rect.right-rect.left, rect.bottom-rect.top ); if (result) @@ -741,7 +748,7 @@ PyImaging_CreateWindowWin32(PyObject* self, PyObject* args) SetForegroundWindow(wnd); /* to make sure it's visible */ Py_END_ALLOW_THREADS - return Py_BuildValue("n", (Py_ssize_t) wnd); + return Py_BuildValue(F_HANDLE, wnd); } PyObject* diff --git a/libImaging/Dib.c b/libImaging/Dib.c index 55de7d9a5..e8ce3e713 100644 --- a/libImaging/Dib.c +++ b/libImaging/Dib.c @@ -228,7 +228,7 @@ ImagingPasteDIB(ImagingDIB dib, Imaging im, int xy[4]) } void -ImagingExposeDIB(ImagingDIB dib, int dc) +ImagingExposeDIB(ImagingDIB dib, void *dc) { /* Copy bitmap to display */ @@ -238,7 +238,7 @@ ImagingExposeDIB(ImagingDIB dib, int dc) } void -ImagingDrawDIB(ImagingDIB dib, int dc, int dst[4], int src[4]) +ImagingDrawDIB(ImagingDIB dib, void *dc, int dst[4], int src[4]) { /* Copy bitmap to printer/display */ @@ -258,7 +258,7 @@ ImagingDrawDIB(ImagingDIB dib, int dc, int dst[4], int src[4]) } int -ImagingQueryPaletteDIB(ImagingDIB dib, int dc) +ImagingQueryPaletteDIB(ImagingDIB dib, void *dc) { /* Install bitmap palette */ diff --git a/libImaging/ImDib.h b/libImaging/ImDib.h index 55ecb35aa..e5a2cc0f6 100644 --- a/libImaging/ImDib.h +++ b/libImaging/ImDib.h @@ -43,10 +43,10 @@ extern ImagingDIB ImagingNewDIB(const char *mode, int xsize, int ysize); extern void ImagingDeleteDIB(ImagingDIB im); -extern void ImagingDrawDIB(ImagingDIB dib, int dc, int dst[4], int src[4]); -extern void ImagingExposeDIB(ImagingDIB dib, int dc); +extern void ImagingDrawDIB(ImagingDIB dib, void *dc, int dst[4], int src[4]); +extern void ImagingExposeDIB(ImagingDIB dib, void *dc); -extern int ImagingQueryPaletteDIB(ImagingDIB dib, int dc); +extern int ImagingQueryPaletteDIB(ImagingDIB dib, void *dc); extern void ImagingPasteDIB(ImagingDIB dib, Imaging im, int xy[4]);