mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-11-10 19:56:47 +03:00
380 lines
8.7 KiB
C
380 lines
8.7 KiB
C
|
/*
|
||
|
* 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 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);
|
||
|
}
|
||
|
|