mirror of
				https://github.com/python-pillow/Pillow.git
				synced 2025-11-04 09:57:43 +03:00 
			
		
		
		
	Initial take for removing the Incremental decoder due to threading issues. J2k tests pass, other tests fail
This commit is contained in:
		
							parent
							
								
									9f48b1e3d6
								
							
						
					
					
						commit
						d3b0413780
					
				| 
						 | 
					@ -185,53 +185,59 @@ class ImageFile(Image.Image):
 | 
				
			||||||
            except AttributeError:
 | 
					            except AttributeError:
 | 
				
			||||||
                prefix = b""
 | 
					                prefix = b""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            for d, e, o, a in self.tile:
 | 
					            for decoder_name, extents, offset, args in self.tile:
 | 
				
			||||||
                d = Image._getdecoder(self.mode, d, a, self.decoderconfig)
 | 
					                decoder = Image._getdecoder(self.mode, decoder_name,
 | 
				
			||||||
                seek(o)
 | 
					                                      args, self.decoderconfig)
 | 
				
			||||||
 | 
					                seek(offset)
 | 
				
			||||||
                try:
 | 
					                try:
 | 
				
			||||||
                    d.setimage(self.im, e)
 | 
					                    decoder.setimage(self.im, extents)
 | 
				
			||||||
                except ValueError:
 | 
					                except ValueError:
 | 
				
			||||||
                    continue
 | 
					                    continue
 | 
				
			||||||
                b = prefix
 | 
					                if decoder.pulls_fd:
 | 
				
			||||||
                while True:
 | 
					                    decoder.setfd(self.fp)
 | 
				
			||||||
                    try:
 | 
					                    status, err_code = decoder.decode(b"")
 | 
				
			||||||
                        s = read(self.decodermaxblock)
 | 
					                else:
 | 
				
			||||||
                    except (IndexError, struct.error):  # truncated png/gif
 | 
					                    b = prefix
 | 
				
			||||||
                        if LOAD_TRUNCATED_IMAGES:
 | 
					                    while True:
 | 
				
			||||||
 | 
					                        try:
 | 
				
			||||||
 | 
					                            s = read(self.decodermaxblock)
 | 
				
			||||||
 | 
					                        except (IndexError, struct.error):  # truncated png/gif
 | 
				
			||||||
 | 
					                            if LOAD_TRUNCATED_IMAGES:
 | 
				
			||||||
 | 
					                                break
 | 
				
			||||||
 | 
					                            else:
 | 
				
			||||||
 | 
					                                raise IOError("image file is truncated")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        if not s and not decoder.handles_eof:  # truncated jpeg
 | 
				
			||||||
 | 
					                            self.tile = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            # JpegDecode needs to clean things up here either way
 | 
				
			||||||
 | 
					                            # If we don't destroy the decompressor,
 | 
				
			||||||
 | 
					                            # we have a memory leak.
 | 
				
			||||||
 | 
					                            decoder.cleanup()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            if LOAD_TRUNCATED_IMAGES:
 | 
				
			||||||
 | 
					                                break
 | 
				
			||||||
 | 
					                            else:
 | 
				
			||||||
 | 
					                                raise IOError("image file is truncated "
 | 
				
			||||||
 | 
					                                              "(%d bytes not processed)" % len(b))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        b = b + s
 | 
				
			||||||
 | 
					                        n, err_code = decoder.decode(b)
 | 
				
			||||||
 | 
					                        if n < 0:
 | 
				
			||||||
                            break
 | 
					                            break
 | 
				
			||||||
                        else:
 | 
					 | 
				
			||||||
                            raise IOError("image file is truncated")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    if not s and not d.handles_eof:  # truncated jpeg
 | 
					 | 
				
			||||||
                        self.tile = []
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                        # JpegDecode needs to clean things up here either way
 | 
					 | 
				
			||||||
                        # If we don't destroy the decompressor,
 | 
					 | 
				
			||||||
                        # we have a memory leak.
 | 
					 | 
				
			||||||
                        d.cleanup()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                        if LOAD_TRUNCATED_IMAGES:
 | 
					 | 
				
			||||||
                            break
 | 
					 | 
				
			||||||
                        else:
 | 
					 | 
				
			||||||
                            raise IOError("image file is truncated "
 | 
					 | 
				
			||||||
                                          "(%d bytes not processed)" % len(b))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    b = b + s
 | 
					 | 
				
			||||||
                    n, e = d.decode(b)
 | 
					 | 
				
			||||||
                    if n < 0:
 | 
					 | 
				
			||||||
                        break
 | 
					 | 
				
			||||||
                    b = b[n:]
 | 
					                    b = b[n:]
 | 
				
			||||||
 | 
					                    
 | 
				
			||||||
                # Need to cleanup here to prevent leaks in PyPy
 | 
					                # Need to cleanup here to prevent leaks in PyPy
 | 
				
			||||||
                d.cleanup()
 | 
					                decoder.cleanup()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.tile = []
 | 
					        self.tile = []
 | 
				
			||||||
        self.readonly = readonly
 | 
					        self.readonly = readonly
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.fp = None  # might be shared
 | 
					        self.fp = None  # might be shared
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if not self.map and not LOAD_TRUNCATED_IMAGES and e < 0:
 | 
					        if not self.map and not LOAD_TRUNCATED_IMAGES and err_code < 0:
 | 
				
			||||||
            # still raised if decoder fails to return anything
 | 
					            # still raised if decoder fails to return anything
 | 
				
			||||||
            raise_ioerror(e)
 | 
					            raise_ioerror(err_code)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # post processing
 | 
					        # post processing
 | 
				
			||||||
        if hasattr(self, "tile_post_rotate"):
 | 
					        if hasattr(self, "tile_post_rotate"):
 | 
				
			||||||
| 
						 | 
					@ -465,11 +471,15 @@ def _save(im, fp, tile, bufsize=0):
 | 
				
			||||||
            if o > 0:
 | 
					            if o > 0:
 | 
				
			||||||
                fp.seek(o, 0)
 | 
					                fp.seek(o, 0)
 | 
				
			||||||
            e.setimage(im.im, b)
 | 
					            e.setimage(im.im, b)
 | 
				
			||||||
            while True:
 | 
					            if e.pushes_fd:
 | 
				
			||||||
                l, s, d = e.encode(bufsize)
 | 
					                e.setfd(fp)
 | 
				
			||||||
                fp.write(d)
 | 
					                l,s = e.encode_to_pyfd()
 | 
				
			||||||
                if s:
 | 
					            else:
 | 
				
			||||||
                    break
 | 
					                while True:
 | 
				
			||||||
 | 
					                    l, s, d = e.encode(bufsize)
 | 
				
			||||||
 | 
					                    fp.write(d)
 | 
				
			||||||
 | 
					                    if s:
 | 
				
			||||||
 | 
					                        break
 | 
				
			||||||
            if s < 0:
 | 
					            if s < 0:
 | 
				
			||||||
                raise IOError("encoder error %d when writing image file" % s)
 | 
					                raise IOError("encoder error %d when writing image file" % s)
 | 
				
			||||||
            e.cleanup()
 | 
					            e.cleanup()
 | 
				
			||||||
| 
						 | 
					@ -480,7 +490,11 @@ def _save(im, fp, tile, bufsize=0):
 | 
				
			||||||
            if o > 0:
 | 
					            if o > 0:
 | 
				
			||||||
                fp.seek(o, 0)
 | 
					                fp.seek(o, 0)
 | 
				
			||||||
            e.setimage(im.im, b)
 | 
					            e.setimage(im.im, b)
 | 
				
			||||||
            s = e.encode_to_file(fh, bufsize)
 | 
					            if e.pushes_fd:
 | 
				
			||||||
 | 
					                e.setfd(fp)
 | 
				
			||||||
 | 
					                e.encode_to_pyfd()
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                s = e.encode_to_file(fh, bufsize)
 | 
				
			||||||
            if s < 0:
 | 
					            if s < 0:
 | 
				
			||||||
                raise IOError("encoder error %d when writing image file" % s)
 | 
					                raise IOError("encoder error %d when writing image file" % s)
 | 
				
			||||||
            e.cleanup()
 | 
					            e.cleanup()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -192,7 +192,7 @@ class Jpeg2KImageFile(ImageFile.ImageFile):
 | 
				
			||||||
                length = -1
 | 
					                length = -1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.tile = [('jpeg2k', (0, 0) + self.size, 0,
 | 
					        self.tile = [('jpeg2k', (0, 0) + self.size, 0,
 | 
				
			||||||
                      (self.codec, self.reduce, self.layers, fd, length))]
 | 
					                      (self.codec, self.reduce, self.layers, fd, length, self.fp))]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def load(self):
 | 
					    def load(self):
 | 
				
			||||||
        if self.reduce:
 | 
					        if self.reduce:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										108
									
								
								decode.c
									
									
									
									
									
								
							
							
						
						
									
										108
									
								
								decode.c
									
									
									
									
									
								
							| 
						 | 
					@ -52,7 +52,8 @@ typedef struct {
 | 
				
			||||||
    struct ImagingCodecStateInstance state;
 | 
					    struct ImagingCodecStateInstance state;
 | 
				
			||||||
    Imaging im;
 | 
					    Imaging im;
 | 
				
			||||||
    PyObject* lock;
 | 
					    PyObject* lock;
 | 
				
			||||||
    int     handles_eof;
 | 
					    int handles_eof;
 | 
				
			||||||
 | 
					    int pulls_fd;
 | 
				
			||||||
} ImagingDecoderObject;
 | 
					} ImagingDecoderObject;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static PyTypeObject ImagingDecoderType;
 | 
					static PyTypeObject ImagingDecoderType;
 | 
				
			||||||
| 
						 | 
					@ -97,6 +98,10 @@ PyImaging_DecoderNew(int contextsize)
 | 
				
			||||||
    /* Most decoders don't want to handle EOF themselves */
 | 
					    /* Most decoders don't want to handle EOF themselves */
 | 
				
			||||||
    decoder->handles_eof = 0;
 | 
					    decoder->handles_eof = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* set if the decoder needs to pull data from the fd, instead of
 | 
				
			||||||
 | 
					       having it pushed */
 | 
				
			||||||
 | 
					    decoder->pulls_fd = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return decoder;
 | 
					    return decoder;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -108,6 +113,7 @@ _dealloc(ImagingDecoderObject* decoder)
 | 
				
			||||||
    free(decoder->state.buffer);
 | 
					    free(decoder->state.buffer);
 | 
				
			||||||
    free(decoder->state.context);
 | 
					    free(decoder->state.context);
 | 
				
			||||||
    Py_XDECREF(decoder->lock);
 | 
					    Py_XDECREF(decoder->lock);
 | 
				
			||||||
 | 
					    Py_XDECREF(decoder->state.fd);
 | 
				
			||||||
    PyObject_Del(decoder);
 | 
					    PyObject_Del(decoder);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -121,11 +127,15 @@ _decode(ImagingDecoderObject* decoder, PyObject* args)
 | 
				
			||||||
    if (!PyArg_ParseTuple(args, PY_ARG_BYTES_LENGTH, &buffer, &bufsize))
 | 
					    if (!PyArg_ParseTuple(args, PY_ARG_BYTES_LENGTH, &buffer, &bufsize))
 | 
				
			||||||
        return NULL;
 | 
					        return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ImagingSectionEnter(&cookie);
 | 
					    if (!decoder->pulls_fd) {
 | 
				
			||||||
 | 
					        ImagingSectionEnter(&cookie);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    status = decoder->decode(decoder->im, &decoder->state, buffer, bufsize);
 | 
					    status = decoder->decode(decoder->im, &decoder->state, buffer, bufsize);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ImagingSectionLeave(&cookie);
 | 
					    if (!decoder->pulls_fd) {
 | 
				
			||||||
 | 
					        ImagingSectionLeave(&cookie);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return Py_BuildValue("ii", status, decoder->state.errcode);
 | 
					    return Py_BuildValue("ii", status, decoder->state.errcode);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -210,16 +220,42 @@ _setimage(ImagingDecoderObject* decoder, PyObject* args)
 | 
				
			||||||
    return Py_None;
 | 
					    return Py_None;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static PyObject*
 | 
				
			||||||
 | 
					_setfd(ImagingDecoderObject* decoder, PyObject* args)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    PyObject* fd;
 | 
				
			||||||
 | 
					    ImagingCodecState state;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!PyArg_ParseTuple(args, "O", &fd))
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    state = &decoder->state;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Py_XINCREF(fd);
 | 
				
			||||||
 | 
					    state->fd = fd;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    Py_INCREF(Py_None);
 | 
				
			||||||
 | 
					    return Py_None;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static PyObject *
 | 
					static PyObject *
 | 
				
			||||||
_get_handles_eof(ImagingDecoderObject *decoder)
 | 
					_get_handles_eof(ImagingDecoderObject *decoder)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    return PyBool_FromLong(decoder->handles_eof);
 | 
					    return PyBool_FromLong(decoder->handles_eof);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static PyObject *
 | 
				
			||||||
 | 
					_get_pulls_fd(ImagingDecoderObject *decoder)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return PyBool_FromLong(decoder->pulls_fd);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct PyMethodDef methods[] = {
 | 
					static struct PyMethodDef methods[] = {
 | 
				
			||||||
    {"decode", (PyCFunction)_decode, 1},
 | 
					    {"decode", (PyCFunction)_decode, 1},
 | 
				
			||||||
    {"cleanup", (PyCFunction)_decode_cleanup, 1},
 | 
					    {"cleanup", (PyCFunction)_decode_cleanup, 1},
 | 
				
			||||||
    {"setimage", (PyCFunction)_setimage, 1},
 | 
					    {"setimage", (PyCFunction)_setimage, 1},
 | 
				
			||||||
 | 
					    {"setfd", (PyCFunction)_setfd, 1},
 | 
				
			||||||
    {NULL, NULL} /* sentinel */
 | 
					    {NULL, NULL} /* sentinel */
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -227,6 +263,9 @@ static struct PyGetSetDef getseters[] = {
 | 
				
			||||||
    {"handles_eof", (getter)_get_handles_eof, NULL,
 | 
					    {"handles_eof", (getter)_get_handles_eof, NULL,
 | 
				
			||||||
     "True if this decoder expects to handle EOF itself.",
 | 
					     "True if this decoder expects to handle EOF itself.",
 | 
				
			||||||
     NULL},
 | 
					     NULL},
 | 
				
			||||||
 | 
					   {"pulls_fd", (getter)_get_pulls_fd, NULL,
 | 
				
			||||||
 | 
					     "True if this decoder expects to pull from self.fd itself.",
 | 
				
			||||||
 | 
					     NULL},
 | 
				
			||||||
    {NULL, NULL, NULL, NULL, NULL} /* sentinel */
 | 
					    {NULL, NULL, NULL, NULL, NULL} /* sentinel */
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -811,6 +850,8 @@ PyImaging_Jpeg2KDecoderNew(PyObject* self, PyObject* args)
 | 
				
			||||||
    int layers = 0;
 | 
					    int layers = 0;
 | 
				
			||||||
    int fd = -1;
 | 
					    int fd = -1;
 | 
				
			||||||
    PY_LONG_LONG length = -1;
 | 
					    PY_LONG_LONG length = -1;
 | 
				
			||||||
 | 
					    PyObject * py_fd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!PyArg_ParseTuple(args, "ss|iiiL", &mode, &format,
 | 
					    if (!PyArg_ParseTuple(args, "ss|iiiL", &mode, &format,
 | 
				
			||||||
                          &reduce, &layers, &fd, &length))
 | 
					                          &reduce, &layers, &fd, &length))
 | 
				
			||||||
        return NULL;
 | 
					        return NULL;
 | 
				
			||||||
| 
						 | 
					@ -829,11 +870,12 @@ PyImaging_Jpeg2KDecoderNew(PyObject* self, PyObject* args)
 | 
				
			||||||
        return NULL;
 | 
					        return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    decoder->handles_eof = 1;
 | 
					    decoder->handles_eof = 1;
 | 
				
			||||||
 | 
					    decoder->pulls_fd = 1;
 | 
				
			||||||
    decoder->decode = ImagingJpeg2KDecode;
 | 
					    decoder->decode = ImagingJpeg2KDecode;
 | 
				
			||||||
    decoder->cleanup = ImagingJpeg2KDecodeCleanup;
 | 
					    decoder->cleanup = ImagingJpeg2KDecodeCleanup;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    context = (JPEG2KDECODESTATE *)decoder->state.context;
 | 
					    context = (JPEG2KDECODESTATE *)decoder->state.context;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
    context->fd = fd;
 | 
					    context->fd = fd;
 | 
				
			||||||
    context->length = (off_t)length;
 | 
					    context->length = (off_t)length;
 | 
				
			||||||
    context->format = codec_format;
 | 
					    context->format = codec_format;
 | 
				
			||||||
| 
						 | 
					@ -843,3 +885,61 @@ PyImaging_Jpeg2KDecoderNew(PyObject* self, PyObject* args)
 | 
				
			||||||
    return (PyObject*) decoder;
 | 
					    return (PyObject*) decoder;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif /* HAVE_OPENJPEG */
 | 
					#endif /* HAVE_OPENJPEG */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Py_ssize_t 
 | 
				
			||||||
 | 
					_imaging_read_pyFd(PyObject *fd, char* dest, Py_ssize_t bytes)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /* dest should be a buffer bytes long, returns length of read
 | 
				
			||||||
 | 
					       -1 on error */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    PyObject *result;
 | 
				
			||||||
 | 
					    char *buffer;
 | 
				
			||||||
 | 
					    Py_ssize_t length;
 | 
				
			||||||
 | 
					    int bytes_result;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    result = PyObject_CallMethod(fd, "read", "n", bytes);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bytes_result = PyBytes_AsStringAndSize(result, &buffer, &length);
 | 
				
			||||||
 | 
					    if (bytes_result == -1) { 
 | 
				
			||||||
 | 
					        goto err;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    if (length > bytes) {
 | 
				
			||||||
 | 
					        goto err;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    memcpy(dest, buffer, length); 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Py_DECREF(result);
 | 
				
			||||||
 | 
					    return length;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 err:
 | 
				
			||||||
 | 
					    Py_DECREF(result);
 | 
				
			||||||
 | 
					    return -1;  
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					_imaging_seek_pyFd(PyObject *fd, Py_ssize_t offset, int whence)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    PyObject *result;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    result = PyObject_CallMethod(fd, "seek", "ni", offset, whence);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Py_DECREF(result);   
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Py_ssize_t
 | 
				
			||||||
 | 
					_imaging_tell_pyFd(PyObject *fd)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    PyObject *result;
 | 
				
			||||||
 | 
					    Py_ssize_t location;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    result = PyObject_CallMethod(fd, "tell", NULL);
 | 
				
			||||||
 | 
					    location = PyInt_AsSsize_t(result);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Py_DECREF(result);
 | 
				
			||||||
 | 
					    return location;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										80
									
								
								encode.c
									
									
									
									
									
								
							
							
						
						
									
										80
									
								
								encode.c
									
									
									
									
									
								
							| 
						 | 
					@ -44,6 +44,7 @@ typedef struct {
 | 
				
			||||||
    struct ImagingCodecStateInstance state;
 | 
					    struct ImagingCodecStateInstance state;
 | 
				
			||||||
    Imaging im;
 | 
					    Imaging im;
 | 
				
			||||||
    PyObject* lock;
 | 
					    PyObject* lock;
 | 
				
			||||||
 | 
					    int pushes_fd;
 | 
				
			||||||
} ImagingEncoderObject;
 | 
					} ImagingEncoderObject;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static PyTypeObject ImagingEncoderType;
 | 
					static PyTypeObject ImagingEncoderType;
 | 
				
			||||||
| 
						 | 
					@ -84,6 +85,7 @@ PyImaging_EncoderNew(int contextsize)
 | 
				
			||||||
    /* Target image */
 | 
					    /* Target image */
 | 
				
			||||||
    encoder->lock = NULL;
 | 
					    encoder->lock = NULL;
 | 
				
			||||||
    encoder->im = NULL;
 | 
					    encoder->im = NULL;
 | 
				
			||||||
 | 
					    encoder->pushes_fd = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return encoder;
 | 
					    return encoder;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -96,6 +98,7 @@ _dealloc(ImagingEncoderObject* encoder)
 | 
				
			||||||
    free(encoder->state.buffer);
 | 
					    free(encoder->state.buffer);
 | 
				
			||||||
    free(encoder->state.context);
 | 
					    free(encoder->state.context);
 | 
				
			||||||
    Py_XDECREF(encoder->lock);
 | 
					    Py_XDECREF(encoder->lock);
 | 
				
			||||||
 | 
					    Py_XDECREF(encoder->state.fd);
 | 
				
			||||||
    PyObject_Del(encoder);
 | 
					    PyObject_Del(encoder);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -143,6 +146,27 @@ _encode(ImagingEncoderObject* encoder, PyObject* args)
 | 
				
			||||||
    return result;
 | 
					    return result;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static PyObject*
 | 
				
			||||||
 | 
					_encode_to_pyfd(ImagingEncoderObject* encoder, PyObject* args)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    PyObject *result;
 | 
				
			||||||
 | 
					    int status;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!encoder->pushes_fd) {
 | 
				
			||||||
 | 
					        // UNDONE, appropriate errcode???
 | 
				
			||||||
 | 
					        result = Py_BuildValue("ii", 0, IMAGING_CODEC_CONFIG);;
 | 
				
			||||||
 | 
					        return result;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    status = encoder->encode(encoder->im, &encoder->state,
 | 
				
			||||||
 | 
					                             (UINT8*) NULL, 0);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    result = Py_BuildValue("ii", status, encoder->state.errcode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static PyObject*
 | 
					static PyObject*
 | 
				
			||||||
_encode_to_file(ImagingEncoderObject* encoder, PyObject* args)
 | 
					_encode_to_file(ImagingEncoderObject* encoder, PyObject* args)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -254,14 +278,47 @@ _setimage(ImagingEncoderObject* encoder, PyObject* args)
 | 
				
			||||||
    return Py_None;
 | 
					    return Py_None;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static PyObject*
 | 
				
			||||||
 | 
					_setfd(ImagingEncoderObject* encoder, PyObject* args)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    PyObject* fd;
 | 
				
			||||||
 | 
					    ImagingCodecState state;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!PyArg_ParseTuple(args, "O", &fd))
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    state = &encoder->state;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Py_XINCREF(fd);
 | 
				
			||||||
 | 
					    state->fd = fd;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    Py_INCREF(Py_None);
 | 
				
			||||||
 | 
					    return Py_None;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static PyObject *
 | 
				
			||||||
 | 
					_get_pushes_fd(ImagingEncoderObject *encoder)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return PyBool_FromLong(encoder->pushes_fd);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct PyMethodDef methods[] = {
 | 
					static struct PyMethodDef methods[] = {
 | 
				
			||||||
    {"encode", (PyCFunction)_encode, 1},
 | 
					    {"encode", (PyCFunction)_encode, 1},
 | 
				
			||||||
    {"cleanup", (PyCFunction)_encode_cleanup, 1},
 | 
					    {"cleanup", (PyCFunction)_encode_cleanup, 1},
 | 
				
			||||||
    {"encode_to_file", (PyCFunction)_encode_to_file, 1},
 | 
					    {"encode_to_file", (PyCFunction)_encode_to_file, 1},
 | 
				
			||||||
 | 
					    {"encode_to_pyfd", (PyCFunction)_encode_to_pyfd, 1},
 | 
				
			||||||
    {"setimage", (PyCFunction)_setimage, 1},
 | 
					    {"setimage", (PyCFunction)_setimage, 1},
 | 
				
			||||||
 | 
					    {"setfd", (PyCFunction)_setfd, 1},
 | 
				
			||||||
    {NULL, NULL} /* sentinel */
 | 
					    {NULL, NULL} /* sentinel */
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct PyGetSetDef getseters[] = {
 | 
				
			||||||
 | 
					   {"pushes_fd", (getter)_get_pushes_fd, NULL,
 | 
				
			||||||
 | 
					     "True if this decoder expects to push directly to self.fd",
 | 
				
			||||||
 | 
					     NULL},
 | 
				
			||||||
 | 
					    {NULL, NULL, NULL, NULL, NULL} /* sentinel */
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static PyTypeObject ImagingEncoderType = {
 | 
					static PyTypeObject ImagingEncoderType = {
 | 
				
			||||||
    PyVarObject_HEAD_INIT(NULL, 0)
 | 
					    PyVarObject_HEAD_INIT(NULL, 0)
 | 
				
			||||||
    "ImagingEncoder",               /*tp_name*/
 | 
					    "ImagingEncoder",               /*tp_name*/
 | 
				
			||||||
| 
						 | 
					@ -293,7 +350,7 @@ static PyTypeObject ImagingEncoderType = {
 | 
				
			||||||
    0,                          /*tp_iternext*/
 | 
					    0,                          /*tp_iternext*/
 | 
				
			||||||
    methods,                    /*tp_methods*/
 | 
					    methods,                    /*tp_methods*/
 | 
				
			||||||
    0,                          /*tp_members*/
 | 
					    0,                          /*tp_members*/
 | 
				
			||||||
    0,                          /*tp_getset*/
 | 
					    getseters,                  /*tp_getset*/
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* -------------------------------------------------------------------- */
 | 
					/* -------------------------------------------------------------------- */
 | 
				
			||||||
| 
						 | 
					@ -916,6 +973,7 @@ PyImaging_Jpeg2KEncoderNew(PyObject *self, PyObject *args)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    encoder->encode = ImagingJpeg2KEncode;
 | 
					    encoder->encode = ImagingJpeg2KEncode;
 | 
				
			||||||
    encoder->cleanup = ImagingJpeg2KEncodeCleanup;
 | 
					    encoder->cleanup = ImagingJpeg2KEncodeCleanup;
 | 
				
			||||||
 | 
					    encoder->pushes_fd = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    context = (JPEG2KENCODESTATE *)encoder->state.context;
 | 
					    context = (JPEG2KENCODESTATE *)encoder->state.context;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -923,6 +981,7 @@ PyImaging_Jpeg2KEncoderNew(PyObject *self, PyObject *args)
 | 
				
			||||||
    context->format = codec_format;
 | 
					    context->format = codec_format;
 | 
				
			||||||
    context->offset_x = context->offset_y = 0;
 | 
					    context->offset_x = context->offset_y = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    j2k_decode_coord_tuple(offset, &context->offset_x, &context->offset_y);
 | 
					    j2k_decode_coord_tuple(offset, &context->offset_x, &context->offset_y);
 | 
				
			||||||
    j2k_decode_coord_tuple(tile_offset,
 | 
					    j2k_decode_coord_tuple(tile_offset,
 | 
				
			||||||
                           &context->tile_offset_x,
 | 
					                           &context->tile_offset_x,
 | 
				
			||||||
| 
						 | 
					@ -973,6 +1032,25 @@ PyImaging_Jpeg2KEncoderNew(PyObject *self, PyObject *args)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Py_ssize_t 
 | 
				
			||||||
 | 
					_imaging_write_pyFd(PyObject *fd, char* src, Py_ssize_t bytes)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    PyObject *result;
 | 
				
			||||||
 | 
					    PyObject *byteObj;
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					    byteObj = PyBytes_FromStringAndSize(src, bytes);
 | 
				
			||||||
 | 
					    result = PyObject_CallMethod(fd, "write", "O", byteObj);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Py_DECREF(byteObj);
 | 
				
			||||||
 | 
					    Py_DECREF(result);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return bytes;
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Local Variables:
 | 
					 * Local Variables:
 | 
				
			||||||
 * c-basic-offset: 4
 | 
					 * c-basic-offset: 4
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -486,33 +486,16 @@ struct ImagingCodecStateInstance {
 | 
				
			||||||
    int bits, bytes;
 | 
					    int bits, bytes;
 | 
				
			||||||
    UINT8 *buffer;
 | 
					    UINT8 *buffer;
 | 
				
			||||||
    void *context;
 | 
					    void *context;
 | 
				
			||||||
 | 
					    PyObject *fd;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Incremental encoding/decoding support */
 | 
					 | 
				
			||||||
typedef struct ImagingIncrementalCodecStruct *ImagingIncrementalCodec;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef int (*ImagingIncrementalCodecEntry)(Imaging im, 
 | 
					extern Py_ssize_t _imaging_read_pyFd(PyObject *fd, char* dest, Py_ssize_t bytes);
 | 
				
			||||||
                                            ImagingCodecState state,
 | 
					extern Py_ssize_t _imaging_write_pyFd(PyObject *fd, char* src, Py_ssize_t bytes);
 | 
				
			||||||
                                            ImagingIncrementalCodec codec);
 | 
					extern int _imaging_seek_pyFd(PyObject *fd, Py_ssize_t offset, int whence);
 | 
				
			||||||
 | 
					extern Py_ssize_t _imaging_tell_pyFd(PyObject *fd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum {
 | 
					 | 
				
			||||||
  INCREMENTAL_CODEC_READ = 1,
 | 
					 | 
				
			||||||
  INCREMENTAL_CODEC_WRITE = 2
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum {
 | 
					 | 
				
			||||||
  INCREMENTAL_CODEC_NOT_SEEKABLE = 0,
 | 
					 | 
				
			||||||
  INCREMENTAL_CODEC_SEEKABLE = 1
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
extern ImagingIncrementalCodec ImagingIncrementalCodecCreate(ImagingIncrementalCodecEntry codec_entry, Imaging im, ImagingCodecState state, int read_or_write, int seekable, int fd);
 | 
					 | 
				
			||||||
extern void ImagingIncrementalCodecDestroy(ImagingIncrementalCodec codec);
 | 
					 | 
				
			||||||
extern int ImagingIncrementalCodecPushBuffer(ImagingIncrementalCodec codec, UINT8 *buf, int bytes);
 | 
					 | 
				
			||||||
extern Py_ssize_t ImagingIncrementalCodecRead(ImagingIncrementalCodec codec, void *buffer, size_t bytes);
 | 
					 | 
				
			||||||
extern off_t ImagingIncrementalCodecSkip(ImagingIncrementalCodec codec, off_t bytes);
 | 
					 | 
				
			||||||
extern Py_ssize_t ImagingIncrementalCodecWrite(ImagingIncrementalCodec codec, const void *buffer, size_t bytes);
 | 
					 | 
				
			||||||
extern off_t ImagingIncrementalCodecSeek(ImagingIncrementalCodec codec, off_t bytes);
 | 
					 | 
				
			||||||
extern size_t ImagingIncrementalCodecBytesInBuffer(ImagingIncrementalCodec codec);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Errcodes */
 | 
					/* Errcodes */
 | 
				
			||||||
#define	IMAGING_CODEC_END	 1
 | 
					#define	IMAGING_CODEC_END	 1
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,687 +0,0 @@
 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * The Python Imaging Library
 | 
					 | 
				
			||||||
 * $Id$
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * incremental decoding adaptor.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Copyright (c) 2014 Coriolis Systems Limited
 | 
					 | 
				
			||||||
 * Copyright (c) 2014 Alastair Houghton
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "Imaging.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* The idea behind this interface is simple: the actual decoding proceeds in
 | 
					 | 
				
			||||||
   a thread, which is run in lock step with the main thread.  Whenever the
 | 
					 | 
				
			||||||
   ImagingIncrementalCodecRead() call runs short on data, it suspends the
 | 
					 | 
				
			||||||
   decoding thread and wakes the main thread.  Conversely, the
 | 
					 | 
				
			||||||
   ImagingIncrementalCodecPushBuffer() call suspends the main thread and wakes
 | 
					 | 
				
			||||||
   the decoding thread, providing a buffer of data.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   The two threads are never running simultaneously, so there is no need for
 | 
					 | 
				
			||||||
   any addition synchronisation measures outside of this file.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   Note also that we start the thread suspended (on Windows), or make it
 | 
					 | 
				
			||||||
   immediately wait (other platforms), so that it's possible to initialise
 | 
					 | 
				
			||||||
   things before the thread starts running.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   This interface is useful to allow PIL to interact efficiently with any
 | 
					 | 
				
			||||||
   third-party imaging library that does not support suspendable reads;
 | 
					 | 
				
			||||||
   one example is OpenJPEG (which is used for J2K support).  The TIFF library
 | 
					 | 
				
			||||||
   might also benefit from using this code.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   Note that if using this module, you want to set handles_eof on your
 | 
					 | 
				
			||||||
   decoder to true.  Why?  Because otherwise ImageFile.load() will abort,
 | 
					 | 
				
			||||||
   thinking that the image is truncated, whereas generally you want it to
 | 
					 | 
				
			||||||
   pass the EOF condition (0 bytes to read) through to your code. */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Additional complication: *Some* codecs need to seek; this is fine if
 | 
					 | 
				
			||||||
   there is a file descriptor, but if we're buffering data it becomes
 | 
					 | 
				
			||||||
   awkward.  The incremental adaptor now contains code to handle these
 | 
					 | 
				
			||||||
   two cases. */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef _WIN32
 | 
					 | 
				
			||||||
#include <process.h>
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
#include <pthread.h>
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define DEBUG_INCREMENTAL 0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#if DEBUG_INCREMENTAL
 | 
					 | 
				
			||||||
#define DEBUG(...) printf(__VA_ARGS__)
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
#define DEBUG(...)
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct ImagingIncrementalCodecStruct {
 | 
					 | 
				
			||||||
#ifdef _WIN32
 | 
					 | 
				
			||||||
  HANDLE            hCodecEvent;
 | 
					 | 
				
			||||||
  HANDLE            hDataEvent;
 | 
					 | 
				
			||||||
  HANDLE            hThread;
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
  pthread_mutex_t   start_mutex;
 | 
					 | 
				
			||||||
  pthread_cond_t    start_cond;
 | 
					 | 
				
			||||||
  pthread_mutex_t   codec_mutex;
 | 
					 | 
				
			||||||
  pthread_cond_t    codec_cond;
 | 
					 | 
				
			||||||
  pthread_mutex_t   data_mutex;
 | 
					 | 
				
			||||||
  pthread_cond_t    data_cond;
 | 
					 | 
				
			||||||
  pthread_t         thread;
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
  ImagingIncrementalCodecEntry  entry;
 | 
					 | 
				
			||||||
  Imaging                       im;
 | 
					 | 
				
			||||||
  ImagingCodecState             state;
 | 
					 | 
				
			||||||
  struct {
 | 
					 | 
				
			||||||
    int    fd;
 | 
					 | 
				
			||||||
    UINT8 *buffer;      /* Base of buffer */
 | 
					 | 
				
			||||||
    UINT8 *ptr;         /* Current pointer in buffer */
 | 
					 | 
				
			||||||
    UINT8 *top;         /* Highest point in buffer we've used */
 | 
					 | 
				
			||||||
    UINT8 *end;         /* End of buffer */
 | 
					 | 
				
			||||||
  } stream;
 | 
					 | 
				
			||||||
  int                           read_or_write;
 | 
					 | 
				
			||||||
  int                           seekable;
 | 
					 | 
				
			||||||
  int                           started;
 | 
					 | 
				
			||||||
  int                           result;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void flush_stream(ImagingIncrementalCodec codec);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#if _WIN32
 | 
					 | 
				
			||||||
static unsigned int __stdcall
 | 
					 | 
				
			||||||
codec_thread(void *ptr)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  ImagingIncrementalCodec codec = (ImagingIncrementalCodec)ptr;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  DEBUG("Entering thread\n");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  codec->result = codec->entry(codec->im, codec->state, codec);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  DEBUG("Leaving thread (%d)\n", codec->result);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  flush_stream(codec);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  SetEvent(codec->hCodecEvent);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
static void *
 | 
					 | 
				
			||||||
codec_thread(void *ptr)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  ImagingIncrementalCodec codec = (ImagingIncrementalCodec)ptr;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  DEBUG("Entering thread\n");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  codec->result = codec->entry(codec->im, codec->state, codec);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  DEBUG("Leaving thread (%d)\n", codec->result);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  flush_stream(codec);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  pthread_mutex_lock(&codec->codec_mutex);
 | 
					 | 
				
			||||||
  pthread_cond_signal(&codec->codec_cond);
 | 
					 | 
				
			||||||
  pthread_mutex_unlock(&codec->codec_mutex);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return NULL;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
flush_stream(ImagingIncrementalCodec codec)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  UINT8 *buffer;
 | 
					 | 
				
			||||||
  size_t bytes;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  /* This is to flush data from the write buffer for a seekable write
 | 
					 | 
				
			||||||
     codec. */
 | 
					 | 
				
			||||||
  if (codec->read_or_write != INCREMENTAL_CODEC_WRITE
 | 
					 | 
				
			||||||
      || codec->state->errcode != IMAGING_CODEC_END
 | 
					 | 
				
			||||||
      || !codec->seekable
 | 
					 | 
				
			||||||
      || codec->stream.fd >= 0)
 | 
					 | 
				
			||||||
    return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  DEBUG("flushing data\n");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  buffer = codec->stream.buffer;
 | 
					 | 
				
			||||||
  bytes = codec->stream.ptr - codec->stream.buffer;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  codec->state->errcode = 0;
 | 
					 | 
				
			||||||
  codec->seekable = INCREMENTAL_CODEC_NOT_SEEKABLE;
 | 
					 | 
				
			||||||
  codec->stream.buffer = codec->stream.ptr = codec->stream.end
 | 
					 | 
				
			||||||
    = codec->stream.top = NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  ImagingIncrementalCodecWrite(codec, buffer, bytes);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  codec->state->errcode = IMAGING_CODEC_END;
 | 
					 | 
				
			||||||
  codec->result = (int)ImagingIncrementalCodecBytesInBuffer(codec);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  free(buffer);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Create a new incremental codec */
 | 
					 | 
				
			||||||
ImagingIncrementalCodec
 | 
					 | 
				
			||||||
ImagingIncrementalCodecCreate(ImagingIncrementalCodecEntry codec_entry,
 | 
					 | 
				
			||||||
                              Imaging im,
 | 
					 | 
				
			||||||
                              ImagingCodecState state,
 | 
					 | 
				
			||||||
                              int read_or_write,
 | 
					 | 
				
			||||||
                              int seekable,
 | 
					 | 
				
			||||||
                              int fd)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    /* malloc check ok, small constant allocation */  
 | 
					 | 
				
			||||||
  ImagingIncrementalCodec codec = (ImagingIncrementalCodec)malloc(sizeof(struct ImagingIncrementalCodecStruct));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  codec->entry = codec_entry;
 | 
					 | 
				
			||||||
  codec->im = im;
 | 
					 | 
				
			||||||
  codec->state = state;
 | 
					 | 
				
			||||||
  codec->result = 0;
 | 
					 | 
				
			||||||
  codec->stream.fd = fd;
 | 
					 | 
				
			||||||
  codec->stream.buffer = codec->stream.ptr = codec->stream.end
 | 
					 | 
				
			||||||
    = codec->stream.top = NULL;
 | 
					 | 
				
			||||||
  codec->started = 0;
 | 
					 | 
				
			||||||
  codec->seekable = seekable;
 | 
					 | 
				
			||||||
  codec->read_or_write = read_or_write;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (fd >= 0)
 | 
					 | 
				
			||||||
    lseek(fd, 0, SEEK_SET);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  /* System specific set-up */
 | 
					 | 
				
			||||||
#if _WIN32
 | 
					 | 
				
			||||||
  codec->hCodecEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (!codec->hCodecEvent) {
 | 
					 | 
				
			||||||
    free(codec);
 | 
					 | 
				
			||||||
    return NULL;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  codec->hDataEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (!codec->hDataEvent) {
 | 
					 | 
				
			||||||
    CloseHandle(codec->hCodecEvent);
 | 
					 | 
				
			||||||
    free(codec);
 | 
					 | 
				
			||||||
    return NULL;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  codec->hThread = _beginthreadex(NULL, 0, codec_thread, codec,
 | 
					 | 
				
			||||||
                                    CREATE_SUSPENDED, NULL);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (!codec->hThread) {
 | 
					 | 
				
			||||||
    CloseHandle(codec->hCodecEvent);
 | 
					 | 
				
			||||||
    CloseHandle(codec->hDataEvent);
 | 
					 | 
				
			||||||
    free(codec);
 | 
					 | 
				
			||||||
    return NULL;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
  if (pthread_mutex_init(&codec->start_mutex, NULL)) {
 | 
					 | 
				
			||||||
    free (codec);
 | 
					 | 
				
			||||||
    return NULL;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (pthread_mutex_init(&codec->codec_mutex, NULL)) {
 | 
					 | 
				
			||||||
    pthread_mutex_destroy(&codec->start_mutex);
 | 
					 | 
				
			||||||
    free(codec);
 | 
					 | 
				
			||||||
    return NULL;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (pthread_mutex_init(&codec->data_mutex, NULL)) {
 | 
					 | 
				
			||||||
    pthread_mutex_destroy(&codec->start_mutex);
 | 
					 | 
				
			||||||
    pthread_mutex_destroy(&codec->codec_mutex);
 | 
					 | 
				
			||||||
    free(codec);
 | 
					 | 
				
			||||||
    return NULL;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (pthread_cond_init(&codec->start_cond, NULL)) {
 | 
					 | 
				
			||||||
    pthread_mutex_destroy(&codec->start_mutex);
 | 
					 | 
				
			||||||
    pthread_mutex_destroy(&codec->codec_mutex);
 | 
					 | 
				
			||||||
    pthread_mutex_destroy(&codec->data_mutex);
 | 
					 | 
				
			||||||
    free(codec);
 | 
					 | 
				
			||||||
    return NULL;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (pthread_cond_init(&codec->codec_cond, NULL)) {
 | 
					 | 
				
			||||||
    pthread_mutex_destroy(&codec->start_mutex);
 | 
					 | 
				
			||||||
    pthread_mutex_destroy(&codec->codec_mutex);
 | 
					 | 
				
			||||||
    pthread_mutex_destroy(&codec->data_mutex);
 | 
					 | 
				
			||||||
    pthread_cond_destroy(&codec->start_cond);
 | 
					 | 
				
			||||||
    free(codec);
 | 
					 | 
				
			||||||
    return NULL;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (pthread_cond_init(&codec->data_cond, NULL)) {
 | 
					 | 
				
			||||||
    pthread_mutex_destroy(&codec->start_mutex);
 | 
					 | 
				
			||||||
    pthread_mutex_destroy(&codec->codec_mutex);
 | 
					 | 
				
			||||||
    pthread_mutex_destroy(&codec->data_mutex);
 | 
					 | 
				
			||||||
    pthread_cond_destroy(&codec->start_cond);
 | 
					 | 
				
			||||||
    pthread_cond_destroy(&codec->codec_cond);
 | 
					 | 
				
			||||||
    free(codec);
 | 
					 | 
				
			||||||
    return NULL;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (pthread_create(&codec->thread, NULL, codec_thread, codec)) {
 | 
					 | 
				
			||||||
    pthread_mutex_destroy(&codec->start_mutex);
 | 
					 | 
				
			||||||
    pthread_mutex_destroy(&codec->codec_mutex);
 | 
					 | 
				
			||||||
    pthread_mutex_destroy(&codec->data_mutex);
 | 
					 | 
				
			||||||
    pthread_cond_destroy(&codec->start_cond);
 | 
					 | 
				
			||||||
    pthread_cond_destroy(&codec->codec_cond);
 | 
					 | 
				
			||||||
    pthread_cond_destroy(&codec->data_cond);
 | 
					 | 
				
			||||||
    free(codec);
 | 
					 | 
				
			||||||
    return NULL;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return codec;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Destroy an incremental codec */
 | 
					 | 
				
			||||||
void
 | 
					 | 
				
			||||||
ImagingIncrementalCodecDestroy(ImagingIncrementalCodec codec)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  DEBUG("destroying\n");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (!codec->started) {
 | 
					 | 
				
			||||||
#ifdef _WIN32
 | 
					 | 
				
			||||||
    ResumeThread(codec->hThread);
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
    pthread_cond_signal(&codec->start_cond);
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
    codec->started = 1;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifndef _WIN32
 | 
					 | 
				
			||||||
  pthread_mutex_lock(&codec->data_mutex);
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (codec->seekable && codec->stream.fd < 0)
 | 
					 | 
				
			||||||
    free (codec->stream.buffer);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  codec->stream.buffer = codec->stream.ptr = codec->stream.end
 | 
					 | 
				
			||||||
    = codec->stream.top = NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef _WIN32
 | 
					 | 
				
			||||||
  SetEvent(codec->hDataEvent);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  WaitForSingleObject(codec->hThread, INFINITE);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  CloseHandle(codec->hThread);
 | 
					 | 
				
			||||||
  CloseHandle(codec->hCodecEvent);
 | 
					 | 
				
			||||||
  CloseHandle(codec->hDataEvent);
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
  pthread_cond_signal(&codec->data_cond);
 | 
					 | 
				
			||||||
  pthread_mutex_unlock(&codec->data_mutex);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  pthread_join(codec->thread, NULL);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  pthread_mutex_destroy(&codec->start_mutex);
 | 
					 | 
				
			||||||
  pthread_mutex_destroy(&codec->codec_mutex);
 | 
					 | 
				
			||||||
  pthread_mutex_destroy(&codec->data_mutex);
 | 
					 | 
				
			||||||
  pthread_cond_destroy(&codec->start_cond);
 | 
					 | 
				
			||||||
  pthread_cond_destroy(&codec->codec_cond);
 | 
					 | 
				
			||||||
  pthread_cond_destroy(&codec->data_cond);
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
  free (codec);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Push a data buffer for an incremental codec */
 | 
					 | 
				
			||||||
int
 | 
					 | 
				
			||||||
ImagingIncrementalCodecPushBuffer(ImagingIncrementalCodec codec,
 | 
					 | 
				
			||||||
                                  UINT8 *buf, int bytes)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  if (!codec->started) {
 | 
					 | 
				
			||||||
    DEBUG("starting\n");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef _WIN32
 | 
					 | 
				
			||||||
    ResumeThread(codec->hThread);
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
    pthread_cond_signal(&codec->start_cond);
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
    codec->started = 1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* Wait for the thread to ask for data */
 | 
					 | 
				
			||||||
#ifdef _WIN32
 | 
					 | 
				
			||||||
    WaitForSingleObject(codec->hCodecEvent, INFINITE);
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
    pthread_mutex_lock(&codec->codec_mutex);
 | 
					 | 
				
			||||||
    pthread_cond_wait(&codec->codec_cond, &codec->codec_mutex);
 | 
					 | 
				
			||||||
    pthread_mutex_unlock(&codec->codec_mutex);
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
    if (codec->result < 0) {
 | 
					 | 
				
			||||||
      DEBUG("got result %d\n", codec->result);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      return codec->result;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  /* Codecs using an fd don't need data, so when we get here, we're done */
 | 
					 | 
				
			||||||
  if (codec->stream.fd >= 0) {
 | 
					 | 
				
			||||||
    DEBUG("got result %d\n", codec->result);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return codec->result;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  DEBUG("providing %p, %d\n", buf, bytes);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifndef _WIN32
 | 
					 | 
				
			||||||
  pthread_mutex_lock(&codec->data_mutex);
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (codec->read_or_write == INCREMENTAL_CODEC_READ
 | 
					 | 
				
			||||||
      && codec->seekable && codec->stream.fd < 0) {
 | 
					 | 
				
			||||||
    /* In this specific case, we append to a buffer we allocate ourselves */
 | 
					 | 
				
			||||||
    size_t old_size = codec->stream.end - codec->stream.buffer;
 | 
					 | 
				
			||||||
    size_t new_size = codec->stream.end - codec->stream.buffer + bytes;
 | 
					 | 
				
			||||||
    UINT8 *new;
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    if (old_size > SIZE_MAX - bytes) {
 | 
					 | 
				
			||||||
       codec->state->errcode = IMAGING_CODEC_MEMORY;
 | 
					 | 
				
			||||||
#ifndef _WIN32
 | 
					 | 
				
			||||||
      pthread_mutex_unlock(&codec->data_mutex);
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
      return -1;
 | 
					 | 
				
			||||||
    }       
 | 
					 | 
				
			||||||
    /* malloc check ok, overflow checked */
 | 
					 | 
				
			||||||
    new = (UINT8 *)realloc (codec->stream.buffer, new_size);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (!new) {
 | 
					 | 
				
			||||||
      codec->state->errcode = IMAGING_CODEC_MEMORY;
 | 
					 | 
				
			||||||
#ifndef _WIN32
 | 
					 | 
				
			||||||
      pthread_mutex_unlock(&codec->data_mutex);
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
      return -1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    codec->stream.ptr = codec->stream.ptr - codec->stream.buffer + new;
 | 
					 | 
				
			||||||
    codec->stream.end = new + new_size;
 | 
					 | 
				
			||||||
    codec->stream.buffer = new;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    memcpy(new + old_size, buf, bytes);
 | 
					 | 
				
			||||||
  } else {
 | 
					 | 
				
			||||||
    codec->stream.buffer = codec->stream.ptr = buf;
 | 
					 | 
				
			||||||
    codec->stream.end = buf + bytes;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef _WIN32
 | 
					 | 
				
			||||||
  SetEvent(codec->hDataEvent);
 | 
					 | 
				
			||||||
  WaitForSingleObject(codec->hCodecEvent, INFINITE);
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
  pthread_cond_signal(&codec->data_cond);
 | 
					 | 
				
			||||||
  pthread_mutex_unlock(&codec->data_mutex);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  pthread_mutex_lock(&codec->codec_mutex);
 | 
					 | 
				
			||||||
  pthread_cond_wait(&codec->codec_cond, &codec->codec_mutex);
 | 
					 | 
				
			||||||
  pthread_mutex_unlock(&codec->codec_mutex);
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  DEBUG("got result %d\n", codec->result);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return codec->result;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
size_t
 | 
					 | 
				
			||||||
ImagingIncrementalCodecBytesInBuffer(ImagingIncrementalCodec codec)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  return codec->stream.ptr - codec->stream.buffer;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Py_ssize_t
 | 
					 | 
				
			||||||
ImagingIncrementalCodecRead(ImagingIncrementalCodec codec,
 | 
					 | 
				
			||||||
                             void *buffer, size_t bytes)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  UINT8 *ptr = (UINT8 *)buffer;
 | 
					 | 
				
			||||||
  size_t done = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (codec->read_or_write == INCREMENTAL_CODEC_WRITE) {
 | 
					 | 
				
			||||||
    DEBUG("attempt to read from write codec\n");
 | 
					 | 
				
			||||||
    return -1;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  DEBUG("reading (want %llu bytes)\n", (unsigned long long)bytes);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (codec->stream.fd >= 0) {
 | 
					 | 
				
			||||||
    Py_ssize_t ret = read(codec->stream.fd, buffer, bytes);
 | 
					 | 
				
			||||||
    DEBUG("read %lld bytes from fd\n", (long long)ret);
 | 
					 | 
				
			||||||
    return ret;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifndef _WIN32
 | 
					 | 
				
			||||||
  pthread_mutex_lock(&codec->data_mutex);
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
  while (bytes) {
 | 
					 | 
				
			||||||
    size_t todo = bytes;
 | 
					 | 
				
			||||||
    size_t remaining = codec->stream.end - codec->stream.ptr;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (!remaining) {
 | 
					 | 
				
			||||||
      DEBUG("waiting for data\n");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifndef _WIN32
 | 
					 | 
				
			||||||
      pthread_mutex_lock(&codec->codec_mutex);
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
      codec->result = (int)(codec->stream.ptr - codec->stream.buffer);
 | 
					 | 
				
			||||||
#if _WIN32
 | 
					 | 
				
			||||||
      SetEvent(codec->hCodecEvent);
 | 
					 | 
				
			||||||
      WaitForSingleObject(codec->hDataEvent, INFINITE);
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
      pthread_cond_signal(&codec->codec_cond);
 | 
					 | 
				
			||||||
      pthread_mutex_unlock(&codec->codec_mutex);
 | 
					 | 
				
			||||||
      pthread_cond_wait(&codec->data_cond, &codec->data_mutex);
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      remaining = codec->stream.end - codec->stream.ptr;
 | 
					 | 
				
			||||||
      codec->stream.top = codec->stream.end;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      DEBUG("got %llu bytes\n", (unsigned long long)remaining);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (todo > remaining)
 | 
					 | 
				
			||||||
      todo = remaining;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (!todo)
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    memcpy (ptr, codec->stream.ptr, todo);
 | 
					 | 
				
			||||||
    codec->stream.ptr += todo;
 | 
					 | 
				
			||||||
    bytes -= todo;
 | 
					 | 
				
			||||||
    done += todo;
 | 
					 | 
				
			||||||
    ptr += todo;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
#ifndef _WIN32
 | 
					 | 
				
			||||||
  pthread_mutex_unlock(&codec->data_mutex);
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  DEBUG("read total %llu bytes\n", (unsigned long long)done);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return done;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
off_t
 | 
					 | 
				
			||||||
ImagingIncrementalCodecSkip(ImagingIncrementalCodec codec,
 | 
					 | 
				
			||||||
                            off_t bytes)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  off_t done = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  DEBUG("skipping (want %llu bytes)\n", (unsigned long long)bytes);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  /* In write mode, explicitly fill with zeroes */
 | 
					 | 
				
			||||||
  if (codec->read_or_write == INCREMENTAL_CODEC_WRITE) {
 | 
					 | 
				
			||||||
    static const UINT8 zeroes[256] = { 0 };
 | 
					 | 
				
			||||||
    off_t done = 0;
 | 
					 | 
				
			||||||
    while (bytes) {
 | 
					 | 
				
			||||||
      size_t todo = (size_t)(bytes > 256 ? 256 : bytes);
 | 
					 | 
				
			||||||
      Py_ssize_t written = ImagingIncrementalCodecWrite(codec, zeroes, todo);
 | 
					 | 
				
			||||||
      if (written <= 0)
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
      done += written;
 | 
					 | 
				
			||||||
      bytes -= written;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return done;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (codec->stream.fd >= 0)
 | 
					 | 
				
			||||||
    return lseek(codec->stream.fd, bytes, SEEK_CUR);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifndef _WIN32
 | 
					 | 
				
			||||||
  pthread_mutex_lock(&codec->data_mutex);
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
  while (bytes) {
 | 
					 | 
				
			||||||
    off_t todo = bytes;
 | 
					 | 
				
			||||||
    off_t remaining = codec->stream.end - codec->stream.ptr;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (!remaining) {
 | 
					 | 
				
			||||||
      DEBUG("waiting for data\n");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifndef _WIN32
 | 
					 | 
				
			||||||
      pthread_mutex_lock(&codec->codec_mutex);
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
      codec->result = (int)(codec->stream.ptr - codec->stream.buffer);
 | 
					 | 
				
			||||||
#if _WIN32
 | 
					 | 
				
			||||||
      SetEvent(codec->hCodecEvent);
 | 
					 | 
				
			||||||
      WaitForSingleObject(codec->hDataEvent, INFINITE);
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
      pthread_cond_signal(&codec->codec_cond);
 | 
					 | 
				
			||||||
      pthread_mutex_unlock(&codec->codec_mutex);
 | 
					 | 
				
			||||||
      pthread_cond_wait(&codec->data_cond, &codec->data_mutex);
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      remaining = codec->stream.end - codec->stream.ptr;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (todo > remaining)
 | 
					 | 
				
			||||||
      todo = remaining;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (!todo)
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    codec->stream.ptr += todo;
 | 
					 | 
				
			||||||
    bytes -= todo;
 | 
					 | 
				
			||||||
    done += todo;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
#ifndef _WIN32
 | 
					 | 
				
			||||||
  pthread_mutex_unlock(&codec->data_mutex);
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  DEBUG("skipped total %llu bytes\n", (unsigned long long)done);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return done;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Py_ssize_t
 | 
					 | 
				
			||||||
ImagingIncrementalCodecWrite(ImagingIncrementalCodec codec,
 | 
					 | 
				
			||||||
                             const void *buffer, size_t bytes)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  const UINT8 *ptr = (const UINT8 *)buffer;
 | 
					 | 
				
			||||||
  size_t done = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (codec->read_or_write == INCREMENTAL_CODEC_READ) {
 | 
					 | 
				
			||||||
    DEBUG("attempt to write from read codec\n");
 | 
					 | 
				
			||||||
    return -1;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  DEBUG("write (have %llu bytes)\n", (unsigned long long)bytes);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (codec->stream.fd >= 0)
 | 
					 | 
				
			||||||
    return write(codec->stream.fd, buffer, bytes);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifndef _WIN32
 | 
					 | 
				
			||||||
  pthread_mutex_lock(&codec->data_mutex);
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
  while (bytes) {
 | 
					 | 
				
			||||||
    size_t todo = bytes;
 | 
					 | 
				
			||||||
    size_t remaining = codec->stream.end - codec->stream.ptr;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (!remaining) {
 | 
					 | 
				
			||||||
      if (codec->seekable && codec->stream.fd < 0) {
 | 
					 | 
				
			||||||
        /* In this case, we maintain the stream buffer ourselves */
 | 
					 | 
				
			||||||
        size_t old_size = codec->stream.top - codec->stream.buffer;
 | 
					 | 
				
			||||||
        size_t new_size = (old_size + bytes + 65535) & ~65535;
 | 
					 | 
				
			||||||
        UINT8 *new = (UINT8 *)realloc(codec->stream.buffer, new_size);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (!new) {
 | 
					 | 
				
			||||||
          codec->state->errcode = IMAGING_CODEC_MEMORY;
 | 
					 | 
				
			||||||
#ifndef _WIN32
 | 
					 | 
				
			||||||
          pthread_mutex_unlock(&codec->data_mutex);
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
          return done == 0 ? -1 : done;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        codec->stream.ptr = codec->stream.ptr - codec->stream.buffer + new;
 | 
					 | 
				
			||||||
        codec->stream.buffer = new;
 | 
					 | 
				
			||||||
        codec->stream.end = new + new_size;
 | 
					 | 
				
			||||||
        codec->stream.top = new + old_size;
 | 
					 | 
				
			||||||
      } else {
 | 
					 | 
				
			||||||
        DEBUG("waiting for space\n");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifndef _WIN32
 | 
					 | 
				
			||||||
        pthread_mutex_lock(&codec->codec_mutex);
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
        codec->result = (int)(codec->stream.ptr - codec->stream.buffer);
 | 
					 | 
				
			||||||
#if _WIN32
 | 
					 | 
				
			||||||
        SetEvent(codec->hCodecEvent);
 | 
					 | 
				
			||||||
        WaitForSingleObject(codec->hDataEvent, INFINITE);
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
        pthread_cond_signal(&codec->codec_cond);
 | 
					 | 
				
			||||||
        pthread_mutex_unlock(&codec->codec_mutex);
 | 
					 | 
				
			||||||
        pthread_cond_wait(&codec->data_cond, &codec->data_mutex);
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      remaining = codec->stream.end - codec->stream.ptr;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      DEBUG("got %llu bytes\n", (unsigned long long)remaining);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (todo > remaining)
 | 
					 | 
				
			||||||
      todo = remaining;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (!todo)
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    memcpy (codec->stream.ptr, ptr, todo);
 | 
					 | 
				
			||||||
    codec->stream.ptr += todo;
 | 
					 | 
				
			||||||
    bytes -= todo;
 | 
					 | 
				
			||||||
    done += todo;
 | 
					 | 
				
			||||||
    ptr += todo;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (codec->stream.ptr > codec->stream.top)
 | 
					 | 
				
			||||||
    codec->stream.top = codec->stream.ptr;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifndef _WIN32
 | 
					 | 
				
			||||||
  pthread_mutex_unlock(&codec->data_mutex);
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  DEBUG("wrote total %llu bytes\n", (unsigned long long)done);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return done;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
off_t
 | 
					 | 
				
			||||||
ImagingIncrementalCodecSeek(ImagingIncrementalCodec codec,
 | 
					 | 
				
			||||||
                            off_t bytes)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  off_t buffered;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  DEBUG("seeking (going to %llu bytes)\n", (unsigned long long)bytes);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (codec->stream.fd >= 0)
 | 
					 | 
				
			||||||
    return lseek(codec->stream.fd, bytes, SEEK_SET);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (!codec->seekable) {
 | 
					 | 
				
			||||||
    DEBUG("attempt to seek non-seekable stream\n");
 | 
					 | 
				
			||||||
    return -1;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (bytes < 0) {
 | 
					 | 
				
			||||||
    DEBUG("attempt to seek before stream start\n");
 | 
					 | 
				
			||||||
    return -1;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
  buffered = codec->stream.top - codec->stream.buffer;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (bytes <= buffered) {
 | 
					 | 
				
			||||||
    DEBUG("seek within buffer\n");
 | 
					 | 
				
			||||||
    codec->stream.ptr = codec->stream.buffer + bytes;
 | 
					 | 
				
			||||||
    return bytes;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return buffered + ImagingIncrementalCodecSkip(codec, bytes - buffered);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -10,6 +10,9 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <openjpeg.h>
 | 
					#include <openjpeg.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 1MB for now */
 | 
				
			||||||
 | 
					#define BUFFER_SIZE OPJ_J2K_STREAM_CHUNK_SIZE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* -------------------------------------------------------------------- */
 | 
					/* -------------------------------------------------------------------- */
 | 
				
			||||||
/* Decoder								*/
 | 
					/* Decoder								*/
 | 
				
			||||||
/* -------------------------------------------------------------------- */
 | 
					/* -------------------------------------------------------------------- */
 | 
				
			||||||
| 
						 | 
					@ -20,6 +23,9 @@ typedef struct {
 | 
				
			||||||
    /* File descriptor, if available; otherwise, -1 */
 | 
					    /* File descriptor, if available; otherwise, -1 */
 | 
				
			||||||
    int fd;
 | 
					    int fd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* File pointer, when opened */
 | 
				
			||||||
 | 
					    FILE * pfile;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Length of data, if available; otherwise, -1 */
 | 
					    /* Length of data, if available; otherwise, -1 */
 | 
				
			||||||
    off_t length;
 | 
					    off_t length;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -34,8 +40,7 @@ typedef struct {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* PRIVATE CONTEXT (set by decoder) */
 | 
					    /* PRIVATE CONTEXT (set by decoder) */
 | 
				
			||||||
    const char    *error_msg;
 | 
					    const char    *error_msg;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
    ImagingIncrementalCodec decoder;
 | 
					 | 
				
			||||||
} JPEG2KDECODESTATE;
 | 
					} JPEG2KDECODESTATE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* -------------------------------------------------------------------- */
 | 
					/* -------------------------------------------------------------------- */
 | 
				
			||||||
| 
						 | 
					@ -48,6 +53,9 @@ typedef struct {
 | 
				
			||||||
    /* File descriptor, if available; otherwise, -1 */
 | 
					    /* File descriptor, if available; otherwise, -1 */
 | 
				
			||||||
    int           fd;
 | 
					    int           fd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* File pointer, when opened */
 | 
				
			||||||
 | 
					    FILE * pfile;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Specify the desired format */
 | 
					    /* Specify the desired format */
 | 
				
			||||||
    OPJ_CODEC_FORMAT format;
 | 
					    OPJ_CODEC_FORMAT format;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -83,7 +91,7 @@ typedef struct {
 | 
				
			||||||
    /* PRIVATE CONTEXT (set by decoder) */
 | 
					    /* PRIVATE CONTEXT (set by decoder) */
 | 
				
			||||||
    const char    *error_msg;
 | 
					    const char    *error_msg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ImagingIncrementalCodec encoder;
 | 
					
 | 
				
			||||||
} JPEG2KENCODESTATE;
 | 
					} JPEG2KENCODESTATE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -46,9 +46,9 @@ j2k_error(const char *msg, void *client_data)
 | 
				
			||||||
static OPJ_SIZE_T
 | 
					static OPJ_SIZE_T
 | 
				
			||||||
j2k_read(void *p_buffer, OPJ_SIZE_T p_nb_bytes, void *p_user_data)
 | 
					j2k_read(void *p_buffer, OPJ_SIZE_T p_nb_bytes, void *p_user_data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    ImagingIncrementalCodec decoder = (ImagingIncrementalCodec)p_user_data;
 | 
					    ImagingCodecState state = (ImagingCodecState)p_user_data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    size_t len = ImagingIncrementalCodecRead(decoder, p_buffer, p_nb_bytes);
 | 
					    size_t len = _imaging_read_pyFd(state->fd, p_buffer, p_nb_bytes);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return len ? len : (OPJ_SIZE_T)-1;
 | 
					    return len ? len : (OPJ_SIZE_T)-1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -56,8 +56,10 @@ j2k_read(void *p_buffer, OPJ_SIZE_T p_nb_bytes, void *p_user_data)
 | 
				
			||||||
static OPJ_OFF_T
 | 
					static OPJ_OFF_T
 | 
				
			||||||
j2k_skip(OPJ_OFF_T p_nb_bytes, void *p_user_data)
 | 
					j2k_skip(OPJ_OFF_T p_nb_bytes, void *p_user_data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    ImagingIncrementalCodec decoder = (ImagingIncrementalCodec)p_user_data;
 | 
					    ImagingCodecState state = (ImagingCodecState)p_user_data;
 | 
				
			||||||
    off_t pos = ImagingIncrementalCodecSkip(decoder, p_nb_bytes);
 | 
					
 | 
				
			||||||
 | 
					    _imaging_seek_pyFd(state->fd, p_nb_bytes, SEEK_CUR);
 | 
				
			||||||
 | 
					    off_t pos = _imaging_tell_pyFd(state->fd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return pos ? pos : (OPJ_OFF_T)-1;
 | 
					    return pos ? pos : (OPJ_OFF_T)-1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -545,8 +547,7 @@ enum {
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int
 | 
					static int
 | 
				
			||||||
j2k_decode_entry(Imaging im, ImagingCodecState state,
 | 
					j2k_decode_entry(Imaging im, ImagingCodecState state)
 | 
				
			||||||
                 ImagingIncrementalCodec decoder)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    JPEG2KDECODESTATE *context = (JPEG2KDECODESTATE *) state->context;
 | 
					    JPEG2KDECODESTATE *context = (JPEG2KDECODESTATE *) state->context;
 | 
				
			||||||
    opj_stream_t *stream = NULL;
 | 
					    opj_stream_t *stream = NULL;
 | 
				
			||||||
| 
						 | 
					@ -558,22 +559,35 @@ j2k_decode_entry(Imaging im, ImagingCodecState state,
 | 
				
			||||||
    size_t buffer_size = 0;
 | 
					    size_t buffer_size = 0;
 | 
				
			||||||
    unsigned n;
 | 
					    unsigned n;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    stream = opj_stream_default_create(OPJ_TRUE);
 | 
					    // fastpath of using a filepointer, and not our own shufflers.
 | 
				
			||||||
 | 
					    /*    if (context->fp) {
 | 
				
			||||||
 | 
					        context->pfile = fdopen(context->fp, 'rb');
 | 
				
			||||||
 | 
					        stream = opj_stream_create_default_file_stream(pfile, OPJ_TRUE);
 | 
				
			||||||
 | 
					         if (!stream) {
 | 
				
			||||||
 | 
					            state->errcode = IMAGING_CODEC_BROKEN;
 | 
				
			||||||
 | 
					            state->state = J2K_STATE_FAILED;
 | 
				
			||||||
 | 
					            goto quick_exit;
 | 
				
			||||||
 | 
					        }       
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					    */     // Using our own shufflers.
 | 
				
			||||||
 | 
					        //stream = opj_stream_default_create(OPJ_TRUE);
 | 
				
			||||||
 | 
					        stream = opj_stream_create(BUFFER_SIZE, OPJ_TRUE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!stream) {
 | 
					        if (!stream) {
 | 
				
			||||||
        state->errcode = IMAGING_CODEC_BROKEN;
 | 
					            state->errcode = IMAGING_CODEC_BROKEN;
 | 
				
			||||||
        state->state = J2K_STATE_FAILED;
 | 
					            state->state = J2K_STATE_FAILED;
 | 
				
			||||||
        goto quick_exit;
 | 
					            goto quick_exit;
 | 
				
			||||||
    }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    opj_stream_set_read_function(stream, j2k_read);
 | 
					        opj_stream_set_read_function(stream, j2k_read);
 | 
				
			||||||
    opj_stream_set_skip_function(stream, j2k_skip);
 | 
					        opj_stream_set_skip_function(stream, j2k_skip);
 | 
				
			||||||
 | 
					        /* }*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* OpenJPEG 2.0 doesn't have OPJ_VERSION_MAJOR */
 | 
					    /* OpenJPEG 2.0 doesn't have OPJ_VERSION_MAJOR */
 | 
				
			||||||
#ifndef OPJ_VERSION_MAJOR
 | 
					#ifndef OPJ_VERSION_MAJOR
 | 
				
			||||||
    opj_stream_set_user_data(stream, decoder);
 | 
					    opj_stream_set_user_data(stream, state);
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
    opj_stream_set_user_data(stream, decoder, NULL);
 | 
					    opj_stream_set_user_data(stream, state, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Hack: if we don't know the length, the largest file we can
 | 
					    /* Hack: if we don't know the length, the largest file we can
 | 
				
			||||||
       possibly support is 4GB.  We can't go larger than this, because
 | 
					       possibly support is 4GB.  We can't go larger than this, because
 | 
				
			||||||
| 
						 | 
					@ -749,6 +763,12 @@ j2k_decode_entry(Imaging im, ImagingCodecState state,
 | 
				
			||||||
    state->state = J2K_STATE_DONE;
 | 
					    state->state = J2K_STATE_DONE;
 | 
				
			||||||
    state->errcode = IMAGING_CODEC_END;
 | 
					    state->errcode = IMAGING_CODEC_END;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (context->pfile) {
 | 
				
			||||||
 | 
					        if(fclose(context->pfile)){
 | 
				
			||||||
 | 
					            context->pfile = NULL;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 quick_exit:
 | 
					 quick_exit:
 | 
				
			||||||
    if (codec)
 | 
					    if (codec)
 | 
				
			||||||
        opj_destroy_codec(codec);
 | 
					        opj_destroy_codec(codec);
 | 
				
			||||||
| 
						 | 
					@ -765,26 +785,27 @@ ImagingJpeg2KDecode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    JPEG2KDECODESTATE *context = (JPEG2KDECODESTATE *) state->context;
 | 
					    JPEG2KDECODESTATE *context = (JPEG2KDECODESTATE *) state->context;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (bytes){
 | 
				
			||||||
 | 
					        state->errcode = IMAGING_CODEC_BROKEN;
 | 
				
			||||||
 | 
					        state->state = J2K_STATE_FAILED;
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }       
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (state->state == J2K_STATE_DONE || state->state == J2K_STATE_FAILED)
 | 
					    if (state->state == J2K_STATE_DONE || state->state == J2K_STATE_FAILED)
 | 
				
			||||||
        return -1;
 | 
					        return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (state->state == J2K_STATE_START) {
 | 
					    if (state->state == J2K_STATE_START) {
 | 
				
			||||||
        context->decoder = ImagingIncrementalCodecCreate(j2k_decode_entry,
 | 
					 | 
				
			||||||
                                                         im, state,
 | 
					 | 
				
			||||||
                                                         INCREMENTAL_CODEC_READ,
 | 
					 | 
				
			||||||
                                                         INCREMENTAL_CODEC_NOT_SEEKABLE,
 | 
					 | 
				
			||||||
                                                         context->fd);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (!context->decoder) {
 | 
					 | 
				
			||||||
            state->errcode = IMAGING_CODEC_BROKEN;
 | 
					 | 
				
			||||||
            state->state = J2K_STATE_FAILED;
 | 
					 | 
				
			||||||
            return -1;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        state->state = J2K_STATE_DECODING;
 | 
					        state->state = J2K_STATE_DECODING;
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					        return j2k_decode_entry(im, state);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return ImagingIncrementalCodecPushBuffer(context->decoder, buf, bytes);
 | 
					    if (state->state == J2K_STATE_DECODING) {
 | 
				
			||||||
 | 
					        state->errcode = IMAGING_CODEC_BROKEN;
 | 
				
			||||||
 | 
					        state->state = J2K_STATE_FAILED;
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return -1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* -------------------------------------------------------------------- */
 | 
					/* -------------------------------------------------------------------- */
 | 
				
			||||||
| 
						 | 
					@ -798,13 +819,13 @@ ImagingJpeg2KDecodeCleanup(ImagingCodecState state) {
 | 
				
			||||||
    if (context->error_msg)
 | 
					    if (context->error_msg)
 | 
				
			||||||
        free ((void *)context->error_msg);
 | 
					        free ((void *)context->error_msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (context->decoder)
 | 
					    /*   if (context->decoder)*/
 | 
				
			||||||
        ImagingIncrementalCodecDestroy(context->decoder);
 | 
					        
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    context->error_msg = NULL;
 | 
					    context->error_msg = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Prevent multiple calls to ImagingIncrementalCodecDestroy */
 | 
					    /* Prevent multiple calls to ImagingIncrementalCodecDestroy */
 | 
				
			||||||
    context->decoder = NULL;
 | 
					    //context->decoder = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return -1;
 | 
					    return -1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -36,6 +36,12 @@ j2k_error(const char *msg, void *client_data)
 | 
				
			||||||
    state->error_msg = strdup(msg);
 | 
					    state->error_msg = strdup(msg);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					j2k_warn(const char *msg, void *client_data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // Null handler
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* -------------------------------------------------------------------- */
 | 
					/* -------------------------------------------------------------------- */
 | 
				
			||||||
/* Buffer output stream                                                 */
 | 
					/* Buffer output stream                                                 */
 | 
				
			||||||
/* -------------------------------------------------------------------- */
 | 
					/* -------------------------------------------------------------------- */
 | 
				
			||||||
| 
						 | 
					@ -43,26 +49,41 @@ j2k_error(const char *msg, void *client_data)
 | 
				
			||||||
static OPJ_SIZE_T
 | 
					static OPJ_SIZE_T
 | 
				
			||||||
j2k_write(void *p_buffer, OPJ_SIZE_T p_nb_bytes, void *p_user_data)
 | 
					j2k_write(void *p_buffer, OPJ_SIZE_T p_nb_bytes, void *p_user_data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    ImagingIncrementalCodec encoder = (ImagingIncrementalCodec)p_user_data;
 | 
					    ImagingCodecState state = (ImagingCodecState)p_user_data;
 | 
				
			||||||
    size_t len = ImagingIncrementalCodecWrite(encoder, p_buffer, p_nb_bytes);
 | 
					    int result;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return len ? len : (OPJ_SIZE_T)-1;
 | 
					    result = _imaging_write_pyFd(state->fd, p_buffer, p_nb_bytes);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return result ? result : (OPJ_SIZE_T)-1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static OPJ_OFF_T
 | 
					static OPJ_OFF_T
 | 
				
			||||||
j2k_skip(OPJ_OFF_T p_nb_bytes, void *p_user_data)
 | 
					j2k_skip(OPJ_OFF_T p_nb_bytes, void *p_user_data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    ImagingIncrementalCodec encoder = (ImagingIncrementalCodec)p_user_data;
 | 
					    ImagingCodecState state = (ImagingCodecState)p_user_data;
 | 
				
			||||||
    off_t pos = ImagingIncrementalCodecSkip(encoder, p_nb_bytes);
 | 
					    char *buffer;
 | 
				
			||||||
 | 
					    int result;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return pos ? pos : (OPJ_OFF_T)-1;
 | 
					    /* Explicitly write zeros */
 | 
				
			||||||
 | 
					    buffer = calloc(p_nb_bytes,1);
 | 
				
			||||||
 | 
					    if (!buffer) {
 | 
				
			||||||
 | 
					        return (OPJ_OFF_T)-1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    result = _imaging_write_pyFd(state->fd, buffer, p_nb_bytes);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    free(buffer);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    return result ? result : p_nb_bytes;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static OPJ_BOOL
 | 
					static OPJ_BOOL
 | 
				
			||||||
j2k_seek(OPJ_OFF_T p_nb_bytes, void *p_user_data)
 | 
					j2k_seek(OPJ_OFF_T p_nb_bytes, void *p_user_data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    ImagingIncrementalCodec encoder = (ImagingIncrementalCodec)p_user_data;
 | 
					    ImagingCodecState state = (ImagingCodecState)p_user_data;
 | 
				
			||||||
    off_t pos = ImagingIncrementalCodecSeek(encoder, p_nb_bytes);
 | 
					    int ignored = _imaging_seek_pyFd(state->fd, p_nb_bytes, SEEK_SET);
 | 
				
			||||||
 | 
					    off_t pos = _imaging_tell_pyFd(state->fd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return pos == p_nb_bytes;
 | 
					    return pos == p_nb_bytes;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -244,8 +265,7 @@ j2k_set_cinema_params(Imaging im, int components, opj_cparameters_t *params)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int
 | 
					static int
 | 
				
			||||||
j2k_encode_entry(Imaging im, ImagingCodecState state,
 | 
					j2k_encode_entry(Imaging im, ImagingCodecState state)
 | 
				
			||||||
                 ImagingIncrementalCodec encoder)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    JPEG2KENCODESTATE *context = (JPEG2KENCODESTATE *)state->context;
 | 
					    JPEG2KENCODESTATE *context = (JPEG2KENCODESTATE *)state->context;
 | 
				
			||||||
    opj_stream_t *stream = NULL;
 | 
					    opj_stream_t *stream = NULL;
 | 
				
			||||||
| 
						 | 
					@ -266,11 +286,8 @@ j2k_encode_entry(Imaging im, ImagingCodecState state,
 | 
				
			||||||
    unsigned prec = 8;
 | 
					    unsigned prec = 8;
 | 
				
			||||||
    unsigned bpp = 8;
 | 
					    unsigned bpp = 8;
 | 
				
			||||||
    unsigned _overflow_scale_factor;
 | 
					    unsigned _overflow_scale_factor;
 | 
				
			||||||
    /* SIZE_MAX is not working in the conditionals unless it's a typed
 | 
					 | 
				
			||||||
       variable */
 | 
					 | 
				
			||||||
    unsigned _SIZE__MAX = SIZE_MAX;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    stream = opj_stream_default_create(OPJ_FALSE);
 | 
					    stream = opj_stream_create(BUFFER_SIZE, OPJ_FALSE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!stream) {
 | 
					    if (!stream) {
 | 
				
			||||||
        state->errcode = IMAGING_CODEC_BROKEN;
 | 
					        state->errcode = IMAGING_CODEC_BROKEN;
 | 
				
			||||||
| 
						 | 
					@ -284,9 +301,9 @@ j2k_encode_entry(Imaging im, ImagingCodecState state,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* OpenJPEG 2.0 doesn't have OPJ_VERSION_MAJOR */
 | 
					    /* OpenJPEG 2.0 doesn't have OPJ_VERSION_MAJOR */
 | 
				
			||||||
#ifndef OPJ_VERSION_MAJOR
 | 
					#ifndef OPJ_VERSION_MAJOR
 | 
				
			||||||
    opj_stream_set_user_data(stream, encoder);
 | 
					    opj_stream_set_user_data(stream, state);
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
    opj_stream_set_user_data(stream, encoder, NULL);
 | 
					    opj_stream_set_user_data(stream, state, NULL);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Setup an opj_image */
 | 
					    /* Setup an opj_image */
 | 
				
			||||||
| 
						 | 
					@ -465,6 +482,8 @@ j2k_encode_entry(Imaging im, ImagingCodecState state,
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    opj_set_error_handler(codec, j2k_error, context);
 | 
					    opj_set_error_handler(codec, j2k_error, context);
 | 
				
			||||||
 | 
					    opj_set_info_handler(codec, j2k_warn, context);
 | 
				
			||||||
 | 
					    opj_set_warning_handler(codec, j2k_warn, context);
 | 
				
			||||||
    opj_setup_encoder(codec, ¶ms, image);
 | 
					    opj_setup_encoder(codec, ¶ms, image);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Start encoding */
 | 
					    /* Start encoding */
 | 
				
			||||||
| 
						 | 
					@ -483,10 +502,10 @@ j2k_encode_entry(Imaging im, ImagingCodecState state,
 | 
				
			||||||
    /* check for integer overflow for the malloc line, checking any expression
 | 
					    /* check for integer overflow for the malloc line, checking any expression
 | 
				
			||||||
       that may multiply either tile_width or tile_height */
 | 
					       that may multiply either tile_width or tile_height */
 | 
				
			||||||
    _overflow_scale_factor = components * prec;
 | 
					    _overflow_scale_factor = components * prec;
 | 
				
			||||||
    if (( tile_width > _SIZE__MAX / _overflow_scale_factor ) ||
 | 
					    if (( tile_width > UINT_MAX / _overflow_scale_factor ) ||
 | 
				
			||||||
        ( tile_height > _SIZE__MAX / _overflow_scale_factor ) ||
 | 
					        ( tile_height > UINT_MAX / _overflow_scale_factor ) ||
 | 
				
			||||||
        ( tile_width > _SIZE__MAX / (tile_height * _overflow_scale_factor )) ||
 | 
					        ( tile_width > UINT_MAX / (tile_height * _overflow_scale_factor )) ||
 | 
				
			||||||
        ( tile_height > _SIZE__MAX / (tile_width * _overflow_scale_factor ))) {
 | 
					        ( tile_height > UINT_MAX / (tile_width * _overflow_scale_factor ))) {
 | 
				
			||||||
        state->errcode = IMAGING_CODEC_BROKEN;
 | 
					        state->errcode = IMAGING_CODEC_BROKEN;
 | 
				
			||||||
        state->state = J2K_STATE_FAILED;
 | 
					        state->state = J2K_STATE_FAILED;
 | 
				
			||||||
        goto quick_exit;
 | 
					        goto quick_exit;
 | 
				
			||||||
| 
						 | 
					@ -548,7 +567,7 @@ j2k_encode_entry(Imaging im, ImagingCodecState state,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    state->errcode = IMAGING_CODEC_END;
 | 
					    state->errcode = IMAGING_CODEC_END;
 | 
				
			||||||
    state->state = J2K_STATE_DONE;
 | 
					    state->state = J2K_STATE_DONE;
 | 
				
			||||||
    ret = (int)ImagingIncrementalCodecBytesInBuffer(encoder);
 | 
					    ret = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 quick_exit:
 | 
					 quick_exit:
 | 
				
			||||||
    if (codec)
 | 
					    if (codec)
 | 
				
			||||||
| 
						 | 
					@ -570,26 +589,13 @@ ImagingJpeg2KEncode(Imaging im, ImagingCodecState state, UINT8 *buf, int bytes)
 | 
				
			||||||
        return -1;
 | 
					        return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (state->state == J2K_STATE_START) {
 | 
					    if (state->state == J2K_STATE_START) {
 | 
				
			||||||
        int seekable = (context->format != OPJ_CODEC_J2K
 | 
					 | 
				
			||||||
                        ? INCREMENTAL_CODEC_SEEKABLE
 | 
					 | 
				
			||||||
                        : INCREMENTAL_CODEC_NOT_SEEKABLE);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        context->encoder = ImagingIncrementalCodecCreate(j2k_encode_entry,
 | 
					 | 
				
			||||||
                                                         im, state,
 | 
					 | 
				
			||||||
                                                         INCREMENTAL_CODEC_WRITE,
 | 
					 | 
				
			||||||
                                                         seekable,
 | 
					 | 
				
			||||||
                                                         context->fd);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (!context->encoder) {
 | 
					 | 
				
			||||||
            state->errcode = IMAGING_CODEC_BROKEN;
 | 
					 | 
				
			||||||
            state->state = J2K_STATE_FAILED;
 | 
					 | 
				
			||||||
            return -1;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        state->state = J2K_STATE_ENCODING;
 | 
					        state->state = J2K_STATE_ENCODING;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return j2k_encode_entry(im, state);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return ImagingIncrementalCodecPushBuffer(context->encoder, buf, bytes);
 | 
					    return -1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* -------------------------------------------------------------------- */
 | 
					/* -------------------------------------------------------------------- */
 | 
				
			||||||
| 
						 | 
					@ -600,19 +606,16 @@ int
 | 
				
			||||||
ImagingJpeg2KEncodeCleanup(ImagingCodecState state) {
 | 
					ImagingJpeg2KEncodeCleanup(ImagingCodecState state) {
 | 
				
			||||||
    JPEG2KENCODESTATE *context = (JPEG2KENCODESTATE *)state->context;
 | 
					    JPEG2KENCODESTATE *context = (JPEG2KENCODESTATE *)state->context;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (context->quality_layers && context->encoder)
 | 
					    if (context->quality_layers) {
 | 
				
			||||||
        Py_DECREF(context->quality_layers);
 | 
					        Py_XDECREF(context->quality_layers);
 | 
				
			||||||
 | 
					        context->quality_layers = NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (context->error_msg)
 | 
					    if (context->error_msg)
 | 
				
			||||||
        free ((void *)context->error_msg);
 | 
					        free ((void *)context->error_msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    context->error_msg = NULL;
 | 
					    context->error_msg = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (context->encoder)
 | 
					 | 
				
			||||||
        ImagingIncrementalCodecDestroy(context->encoder);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* Prevent multiple calls to ImagingIncrementalCodecDestroy */
 | 
					 | 
				
			||||||
    context->encoder = NULL;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return -1;
 | 
					    return -1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										4
									
								
								setup.py
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								setup.py
									
									
									
									
									
								
							| 
						 | 
					@ -35,8 +35,8 @@ _LIB_IMAGING = (
 | 
				
			||||||
    "QuantHash", "QuantHeap", "PcdDecode", "PcxDecode", "PcxEncode", "Point",
 | 
					    "QuantHash", "QuantHeap", "PcdDecode", "PcxDecode", "PcxEncode", "Point",
 | 
				
			||||||
    "RankFilter", "RawDecode", "RawEncode", "Storage", "SunRleDecode",
 | 
					    "RankFilter", "RawDecode", "RawEncode", "Storage", "SunRleDecode",
 | 
				
			||||||
    "TgaRleDecode", "Unpack", "UnpackYCC", "UnsharpMask", "XbmDecode",
 | 
					    "TgaRleDecode", "Unpack", "UnpackYCC", "UnsharpMask", "XbmDecode",
 | 
				
			||||||
    "XbmEncode", "ZipDecode", "ZipEncode", "TiffDecode", "Incremental",
 | 
					    "XbmEncode", "ZipDecode", "ZipEncode", "TiffDecode", "Jpeg2KDecode",
 | 
				
			||||||
    "Jpeg2KDecode", "Jpeg2KEncode", "BoxBlur", "QuantPngQuant")
 | 
					    "Jpeg2KEncode", "BoxBlur", "QuantPngQuant")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEBUG = False
 | 
					DEBUG = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user