/* * The Python Imaging Library. * * standard memory mapping interface for the Imaging library * * history: * 1998-03-05 fl added Win32 read mapping * 1999-02-06 fl added "I;16" support * 2003-04-21 fl added PyImaging_MapBuffer primitive * * Copyright (c) 1998-2003 by Secret Labs AB. * Copyright (c) 2003 by Fredrik Lundh. * * See the README file for information on usage and redistribution. */ /* * FIXME: should move the memory mapping primitives into libImaging! */ #include "Python.h" #if PY_VERSION_HEX < 0x01060000 #define PyObject_New PyObject_NEW #define PyObject_Del PyMem_DEL #endif #include "Imaging.h" #ifdef WIN32 #define WIN32_LEAN_AND_MEAN #undef INT8 #undef UINT8 #undef INT16 #undef UINT16 #undef INT32 #undef INT64 #undef UINT32 #include "windows.h" #endif /* compatibility wrappers (defined in _imaging.c) */ extern int PyImaging_CheckBuffer(PyObject* buffer); extern int PyImaging_ReadBuffer(PyObject* buffer, const void** ptr); /* -------------------------------------------------------------------- */ /* Standard mapper */ typedef struct { PyObject_HEAD char* base; int size; int offset; #ifdef WIN32 HANDLE hFile; HANDLE hMap; #endif } ImagingMapperObject; staticforward PyTypeObject ImagingMapperType; ImagingMapperObject* PyImaging_MapperNew(const char* filename, int readonly) { ImagingMapperObject *mapper; ImagingMapperType.ob_type = &PyType_Type; mapper = PyObject_New(ImagingMapperObject, &ImagingMapperType); if (mapper == NULL) return NULL; mapper->base = NULL; mapper->size = mapper->offset = 0; #ifdef WIN32 mapper->hFile = (HANDLE)-1; mapper->hMap = (HANDLE)-1; /* FIXME: currently supports readonly mappings only */ mapper->hFile = CreateFile( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (mapper->hFile == (HANDLE)-1) { PyErr_SetString(PyExc_IOError, "cannot open file"); PyObject_Del(mapper); return NULL; } mapper->hMap = CreateFileMapping( mapper->hFile, NULL, PAGE_READONLY, 0, 0, NULL); if (mapper->hMap == (HANDLE)-1) { CloseHandle(mapper->hFile); PyErr_SetString(PyExc_IOError, "cannot map file"); PyObject_Del(mapper); return NULL; } mapper->base = (char*) MapViewOfFile( mapper->hMap, FILE_MAP_READ, 0, 0, 0); mapper->size = GetFileSize(mapper->hFile, 0); #endif return mapper; } static void mapping_dealloc(ImagingMapperObject* mapper) { #ifdef WIN32 if (mapper->base != 0) UnmapViewOfFile(mapper->base); if (mapper->hMap != (HANDLE)-1) CloseHandle(mapper->hMap); if (mapper->hFile != (HANDLE)-1) CloseHandle(mapper->hFile); mapper->base = 0; mapper->hMap = mapper->hFile = (HANDLE)-1; #endif PyObject_Del(mapper); } /* -------------------------------------------------------------------- */ /* standard file operations */ static PyObject* mapping_read(ImagingMapperObject* mapper, PyObject* args) { PyObject* buf; int size = -1; if (!PyArg_ParseTuple(args, "|i", &size)) return NULL; /* check size */ if (size < 0 || mapper->offset + size > mapper->size) size = mapper->size - mapper->offset; if (size < 0) size = 0; buf = PyString_FromStringAndSize(NULL, size); if (!buf) return NULL; if (size > 0) { memcpy(PyString_AsString(buf), mapper->base + mapper->offset, size); mapper->offset += size; } return buf; } static PyObject* mapping_seek(ImagingMapperObject* mapper, PyObject* args) { int offset; int whence = 0; if (!PyArg_ParseTuple(args, "i|i", &offset, &whence)) return NULL; switch (whence) { case 0: /* SEEK_SET */ mapper->offset = offset; break; case 1: /* SEEK_CUR */ mapper->offset += offset; break; case 2: /* SEEK_END */ mapper->offset = mapper->size + offset; break; default: /* FIXME: raise ValueError? */ break; } Py_INCREF(Py_None); return Py_None; } /* -------------------------------------------------------------------- */ /* map entire image */ extern PyObject*PyImagingNew(Imaging im); static void ImagingDestroyMap(Imaging im) { return; /* nothing to do! */ } static PyObject* mapping_readimage(ImagingMapperObject* mapper, PyObject* args) { int y, size; Imaging im; char* mode; int xsize; int ysize; int stride; int orientation; if (!PyArg_ParseTuple(args, "s(ii)ii", &mode, &xsize, &ysize, &stride, &orientation)) return NULL; if (stride <= 0) { /* FIXME: maybe we should call ImagingNewPrologue instead */ if (!strcmp(mode, "L") || !strcmp(mode, "P")) stride = xsize; else if (!strcmp(mode, "I;16") || !strcmp(mode, "I;16B")) stride = xsize * 2; else stride = xsize * 4; } size = ysize * stride; if (mapper->offset + size > mapper->size) { PyErr_SetString(PyExc_IOError, "image file truncated"); return NULL; } im = ImagingNewPrologue(mode, xsize, ysize); if (!im) return NULL; /* setup file pointers */ if (orientation > 0) for (y = 0; y < ysize; y++) im->image[y] = mapper->base + mapper->offset + y * stride; else for (y = 0; y < ysize; y++) im->image[ysize-y-1] = mapper->base + mapper->offset + y * stride; im->destroy = ImagingDestroyMap; if (!ImagingNewEpilogue(im)) return NULL; mapper->offset += size; return PyImagingNew(im); } static struct PyMethodDef methods[] = { /* standard file interface */ {"read", (PyCFunction)mapping_read, 1}, {"seek", (PyCFunction)mapping_seek, 1}, /* extensions */ {"readimage", (PyCFunction)mapping_readimage, 1}, {NULL, NULL} /* sentinel */ }; static PyObject* mapping_getattr(ImagingMapperObject* self, char* name) { return Py_FindMethod(methods, (PyObject*) self, name); } statichere PyTypeObject ImagingMapperType = { PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ "ImagingMapper", /*tp_name*/ sizeof(ImagingMapperObject), /*tp_size*/ 0, /*tp_itemsize*/ /* methods */ (destructor)mapping_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ (getattrfunc)mapping_getattr, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_compare*/ 0, /*tp_repr*/ 0, /*tp_hash*/ }; PyObject* PyImaging_Mapper(PyObject* self, PyObject* args) { char* filename; if (!PyArg_ParseTuple(args, "s", &filename)) return NULL; return (PyObject*) PyImaging_MapperNew(filename, 1); } /* -------------------------------------------------------------------- */ /* Buffer mapper */ typedef struct ImagingBufferInstance { struct ImagingMemoryInstance im; PyObject* target; } ImagingBufferInstance; static void mapping_destroy_buffer(Imaging im) { ImagingBufferInstance* buffer = (ImagingBufferInstance*) im; Py_XDECREF(buffer->target); } PyObject* PyImaging_MapBuffer(PyObject* self, PyObject* args) { int y, size; Imaging im; char* ptr; int bytes; PyObject* target; char* mode; char* codec; PyObject* bbox; int offset; int xsize, ysize; int stride; int ystep; if (!PyArg_ParseTuple(args, "O(ii)sOi(sii)", &target, &xsize, &ysize, &codec, &bbox, &offset, &mode, &stride, &ystep)) return NULL; if (!PyImaging_CheckBuffer(target)) { PyErr_SetString(PyExc_TypeError, "expected string or buffer"); return NULL; } if (stride <= 0) { if (!strcmp(mode, "L") || !strcmp(mode, "P")) stride = xsize; else if (!strncmp(mode, "I;16", 4)) stride = xsize * 2; else stride = xsize * 4; } size = ysize * stride; /* check buffer size */ bytes = PyImaging_ReadBuffer(target, (const void**) &ptr); if (bytes < 0) { PyErr_SetString(PyExc_ValueError, "buffer has negative size"); return NULL; } if (offset + size > bytes) { PyErr_SetString(PyExc_ValueError, "buffer is not large enough"); return NULL; } im = ImagingNewPrologueSubtype( mode, xsize, ysize, sizeof(ImagingBufferInstance) ); if (!im) return NULL; /* setup file pointers */ if (ystep > 0) for (y = 0; y < ysize; y++) im->image[y] = ptr + offset + y * stride; else for (y = 0; y < ysize; y++) im->image[ysize-y-1] = ptr + offset + y * stride; im->destroy = mapping_destroy_buffer; Py_INCREF(target); ((ImagingBufferInstance*) im)->target = target; if (!ImagingNewEpilogue(im)) return NULL; return PyImagingNew(im); }