mirror of
				https://github.com/python-pillow/Pillow.git
				synced 2025-11-04 09:57:43 +03:00 
			
		
		
		
	Merge pull request #5224 from radarhere/mapper
This commit is contained in:
		
						commit
						f15f573e51
					
				| 
						 | 
				
			
			@ -4,10 +4,6 @@ import pytest
 | 
			
		|||
 | 
			
		||||
from PIL import Image
 | 
			
		||||
 | 
			
		||||
from .helper import is_win32
 | 
			
		||||
 | 
			
		||||
pytestmark = pytest.mark.skipif(is_win32(), reason="Win32 does not call map_buffer")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_overflow():
 | 
			
		||||
    # There is the potential to overflow comparisons in map.c
 | 
			
		||||
| 
						 | 
				
			
			@ -27,6 +23,13 @@ def test_overflow():
 | 
			
		|||
    Image.MAX_IMAGE_PIXELS = max_pixels
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_tobytes():
 | 
			
		||||
    # Previously raised an access violation on Windows
 | 
			
		||||
    with Image.open("Tests/images/l2rgb_read.bmp") as im:
 | 
			
		||||
        with pytest.raises((ValueError, MemoryError, OSError)):
 | 
			
		||||
            im.tobytes()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.skipif(sys.maxsize <= 2 ** 32, reason="Requires 64-bit system")
 | 
			
		||||
def test_ysize():
 | 
			
		||||
    numpy = pytest.importorskip("numpy", reason="NumPy not installed")
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -192,21 +192,11 @@ class ImageFile(Image.Image):
 | 
			
		|||
                and args[0] in Image._MAPMODES
 | 
			
		||||
            ):
 | 
			
		||||
                try:
 | 
			
		||||
                    if hasattr(Image.core, "map"):
 | 
			
		||||
                        # use built-in mapper  WIN32 only
 | 
			
		||||
                        self.map = Image.core.map(self.filename)
 | 
			
		||||
                        self.map.seek(offset)
 | 
			
		||||
                        self.im = self.map.readimage(
 | 
			
		||||
                            self.mode, self.size, args[1], args[2]
 | 
			
		||||
                        )
 | 
			
		||||
                    else:
 | 
			
		||||
                    # use mmap, if possible
 | 
			
		||||
                    import mmap
 | 
			
		||||
 | 
			
		||||
                    with open(self.filename) as fp:
 | 
			
		||||
                            self.map = mmap.mmap(
 | 
			
		||||
                                fp.fileno(), 0, access=mmap.ACCESS_READ
 | 
			
		||||
                            )
 | 
			
		||||
                        self.map = mmap.mmap(fp.fileno(), 0, access=mmap.ACCESS_READ)
 | 
			
		||||
                    self.im = Image.core.map_buffer(
 | 
			
		||||
                        self.map, self.size, decoder_name, offset, args
 | 
			
		||||
                    )
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3973,8 +3973,6 @@ PyPath_Create(ImagingObject *self, PyObject *args);
 | 
			
		|||
extern PyObject *
 | 
			
		||||
PyOutline_Create(ImagingObject *self, PyObject *args);
 | 
			
		||||
 | 
			
		||||
extern PyObject *
 | 
			
		||||
PyImaging_Mapper(PyObject *self, PyObject *args);
 | 
			
		||||
extern PyObject *
 | 
			
		||||
PyImaging_MapBuffer(PyObject *self, PyObject *args);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -4030,9 +4028,6 @@ static PyMethodDef functions[] = {
 | 
			
		|||
 | 
			
		||||
/* Memory mapping */
 | 
			
		||||
#ifdef WITH_MAPPING
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
    {"map", (PyCFunction)PyImaging_Mapper, 1},
 | 
			
		||||
#endif
 | 
			
		||||
    {"map_buffer", (PyCFunction)PyImaging_MapBuffer, 1},
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										260
									
								
								src/map.c
									
									
									
									
									
								
							
							
						
						
									
										260
									
								
								src/map.c
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -28,269 +28,9 @@ PyImaging_CheckBuffer(PyObject *buffer);
 | 
			
		|||
extern int
 | 
			
		||||
PyImaging_GetBuffer(PyObject *buffer, Py_buffer *view);
 | 
			
		||||
 | 
			
		||||
/* -------------------------------------------------------------------- */
 | 
			
		||||
/* Standard mapper */
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    PyObject_HEAD char *base;
 | 
			
		||||
    int size;
 | 
			
		||||
    int offset;
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
    HANDLE hFile;
 | 
			
		||||
    HANDLE hMap;
 | 
			
		||||
#endif
 | 
			
		||||
} ImagingMapperObject;
 | 
			
		||||
 | 
			
		||||
static PyTypeObject ImagingMapperType;
 | 
			
		||||
 | 
			
		||||
ImagingMapperObject *
 | 
			
		||||
PyImaging_MapperNew(const char *filename, int readonly) {
 | 
			
		||||
    ImagingMapperObject *mapper;
 | 
			
		||||
 | 
			
		||||
    if (PyType_Ready(&ImagingMapperType) < 0) {
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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_OSError, "cannot open file");
 | 
			
		||||
        Py_DECREF(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_OSError, "cannot map file");
 | 
			
		||||
        Py_DECREF(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 = PyBytes_FromStringAndSize(NULL, size);
 | 
			
		||||
    if (!buf) {
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (size > 0) {
 | 
			
		||||
        memcpy(PyBytes_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_OSError, "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;
 | 
			
		||||
 | 
			
		||||
    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 PyTypeObject ImagingMapperType = {
 | 
			
		||||
    PyVarObject_HEAD_INIT(NULL, 0) "ImagingMapper", /*tp_name*/
 | 
			
		||||
    sizeof(ImagingMapperObject),                    /*tp_size*/
 | 
			
		||||
    0,                                              /*tp_itemsize*/
 | 
			
		||||
    /* methods */
 | 
			
		||||
    (destructor)mapping_dealloc, /*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*/
 | 
			
		||||
    0,                           /*tp_getset*/
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
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 */
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue
	
	Block a user