diff --git a/PIL/Jpeg2KImagePlugin.py b/PIL/Jpeg2KImagePlugin.py index 36e15b762..cd72107a8 100644 --- a/PIL/Jpeg2KImagePlugin.py +++ b/PIL/Jpeg2KImagePlugin.py @@ -153,11 +153,15 @@ class Jpeg2KImageFile(ImageFile.ImageFile): self.reduce = 0 self.layers = 0 + fd = -1 if hasattr(self.fp, "fileno"): - fd = self.fp.fileno() - + try: + fd = self.fp.fileno() + except: + fd = -1 + self.tile = [('jpeg2k', (0, 0) + self.size, 0, (self.codec, self.reduce, self.layers, fd))] @@ -167,6 +171,12 @@ class Jpeg2KImageFile(ImageFile.ImageFile): adjust = power >> 1 self.size = ((self.size[0] + adjust) / power, (self.size[1] + adjust) / power) + + if self.tile: + # Update the reduce and layers settings + t = self.tile[0] + t3 = (t[3][0], self.reduce, self.layers, t[3][3]) + self.tile = [(t[0], t[1], t[2], t3)] ImageFile.ImageFile.load(self) @@ -200,7 +210,10 @@ def _save(im, fp, filename): fd = -1 if hasattr(fp, "fileno"): - fd = fp.fileno() + try: + fd = fp.fileno() + except: + fd = -1 im.encoderconfig = ( offset, diff --git a/decode.c b/decode.c index f1e4aeaba..77038cc2c 100644 --- a/decode.c +++ b/decode.c @@ -827,7 +827,7 @@ PyImaging_Jpeg2KDecoderNew(PyObject* self, PyObject* args) context->format = codec_format; context->reduce = reduce; context->layers = layers; - + return (PyObject*) decoder; } #endif /* HAVE_OPENJPEG */ diff --git a/encode.c b/encode.c index 0c444bfc3..ecb6ba95e 100644 --- a/encode.c +++ b/encode.c @@ -885,7 +885,7 @@ PyImaging_Jpeg2KEncoderNew(PyObject *self, PyObject *args) else return NULL; - encoder = PyImaging_EncoderNew(sizeof(JPEG2KENCODESTATE)); + encoder = PyImaging_EncoderNew(sizeof(JPEG2KENCODESTATE)); if (!encoder) return NULL; @@ -906,6 +906,24 @@ PyImaging_Jpeg2KEncoderNew(PyObject *self, PyObject *args) &context->tile_size_x, &context->tile_size_y); + /* Error on illegal tile offsets */ + if (context->tile_size_x && context->tile_size_y) { + if (context->tile_offset_x <= context->offset_x - context->tile_size_x + || context->tile_offset_y <= context->offset_y - context->tile_size_y) { + PyErr_SetString(PyExc_ValueError, + "JPEG 2000 tile offset too small; top left tile must " + "intersect image area"); + } + + if (context->tile_offset_x > context->offset_x + || context->tile_offset_y > context->offset_y) { + PyErr_SetString(PyExc_ValueError, + "JPEG 2000 tile offset too large to cover image area"); + Py_DECREF(encoder); + return NULL; + } + } + if (quality_layers && PySequence_Check(quality_layers)) { context->quality_is_in_db = strcmp (quality_mode, "dB") == 0; context->quality_layers = quality_layers; diff --git a/libImaging/Incremental.c b/libImaging/Incremental.c index 8e42b2e64..9574d51a8 100644 --- a/libImaging/Incremental.c +++ b/libImaging/Incremental.c @@ -93,8 +93,12 @@ 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); @@ -107,8 +111,12 @@ 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); @@ -335,6 +343,11 @@ ImagingIncrementalCodecPushBuffer(ImagingIncrementalCodec codec, 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 */ diff --git a/libImaging/Jpeg2KDecode.c b/libImaging/Jpeg2KDecode.c index a39c700ed..d68f23165 100644 --- a/libImaging/Jpeg2KDecode.c +++ b/libImaging/Jpeg2KDecode.c @@ -91,7 +91,7 @@ static void j2ku_gray_l(opj_image_t *in, const JPEG2KTILEINFO *tileinfo, const UINT8 *tiledata, Imaging im) { - unsigned x0 = tileinfo->x0, y0 = tileinfo->y0; + unsigned x0 = tileinfo->x0 - in->x0, y0 = tileinfo->y0 - in->y0; unsigned w = tileinfo->x1 - tileinfo->x0; unsigned h = tileinfo->y1 - tileinfo->y0; @@ -139,7 +139,7 @@ static void j2ku_gray_rgb(opj_image_t *in, const JPEG2KTILEINFO *tileinfo, const UINT8 *tiledata, Imaging im) { - unsigned x0 = tileinfo->x0, y0 = tileinfo->y0; + unsigned x0 = tileinfo->x0 - in->x0, y0 = tileinfo->y0 - in->y0; unsigned w = tileinfo->x1 - tileinfo->x0; unsigned h = tileinfo->y1 - tileinfo->y0; @@ -199,7 +199,7 @@ static void j2ku_graya_la(opj_image_t *in, const JPEG2KTILEINFO *tileinfo, const UINT8 *tiledata, Imaging im) { - unsigned x0 = tileinfo->x0, y0 = tileinfo->y0; + unsigned x0 = tileinfo->x0 - in->x0, y0 = tileinfo->y0 - in->y0; unsigned w = tileinfo->x1 - tileinfo->x0; unsigned h = tileinfo->y1 - tileinfo->y0; @@ -256,7 +256,7 @@ static void j2ku_srgb_rgb(opj_image_t *in, const JPEG2KTILEINFO *tileinfo, const UINT8 *tiledata, Imaging im) { - unsigned x0 = tileinfo->x0, y0 = tileinfo->y0; + unsigned x0 = tileinfo->x0 - in->x0, y0 = tileinfo->y0 - in->y0; unsigned w = tileinfo->x1 - tileinfo->x0; unsigned h = tileinfo->y1 - tileinfo->y0; @@ -308,7 +308,7 @@ static void j2ku_sycc_rgb(opj_image_t *in, const JPEG2KTILEINFO *tileinfo, const UINT8 *tiledata, Imaging im) { - unsigned x0 = tileinfo->x0, y0 = tileinfo->y0; + unsigned x0 = tileinfo->x0 - in->x0, y0 = tileinfo->y0 - in->y0; unsigned w = tileinfo->x1 - tileinfo->x0; unsigned h = tileinfo->y1 - tileinfo->y0; @@ -363,7 +363,7 @@ static void j2ku_srgba_rgba(opj_image_t *in, const JPEG2KTILEINFO *tileinfo, const UINT8 *tiledata, Imaging im) { - unsigned x0 = tileinfo->x0, y0 = tileinfo->y0; + unsigned x0 = tileinfo->x0 - in->x0, y0 = tileinfo->y0 - in->y0; unsigned w = tileinfo->x1 - tileinfo->x0; unsigned h = tileinfo->y1 - tileinfo->y0; @@ -414,7 +414,7 @@ static void j2ku_sycca_rgba(opj_image_t *in, const JPEG2KTILEINFO *tileinfo, const UINT8 *tiledata, Imaging im) { - unsigned x0 = tileinfo->x0, y0 = tileinfo->y0; + unsigned x0 = tileinfo->x0 - in->x0, y0 = tileinfo->y0 - in->y0; unsigned w = tileinfo->x1 - tileinfo->x0; unsigned h = tileinfo->y1 - tileinfo->y0; @@ -517,7 +517,7 @@ j2k_decode_entry(Imaging im, ImagingCodecState state, opj_stream_set_read_function(stream, j2k_read); opj_stream_set_skip_function(stream, j2k_skip); - opj_stream_set_user_data(stream, context->decoder); + opj_stream_set_user_data(stream, decoder); /* Setup decompression context */ context->error_msg = NULL; @@ -650,6 +650,20 @@ j2k_decode_entry(Imaging im, ImagingCodecState state, goto quick_exit; } + /* Check the tile bounds; if the tile is outside the image area, + or if it has a negative width or height (i.e. the coordinates are + swapped), bail. */ + if (tile_info.x0 >= tile_info.x1 + || tile_info.y0 >= tile_info.y1 + || tile_info.x0 < image->x0 + || tile_info.y0 < image->y0 + || tile_info.x1 - image->x0 > im->xsize + || tile_info.y1 - image->y0 > im->ysize) { + state->errcode = IMAGING_CODEC_BROKEN; + state->state = J2K_STATE_FAILED; + goto quick_exit; + } + unpack(image, &tile_info, state->buffer, im); } diff --git a/libImaging/Jpeg2KEncode.c b/libImaging/Jpeg2KEncode.c index 6bf25def8..d013ffa7f 100644 --- a/libImaging/Jpeg2KEncode.c +++ b/libImaging/Jpeg2KEncode.c @@ -254,7 +254,7 @@ j2k_encode_entry(Imaging im, ImagingCodecState state, opj_stream_set_skip_function(stream, j2k_skip); opj_stream_set_seek_function(stream, j2k_seek); - opj_stream_set_user_data(stream, context->encoder); + opj_stream_set_user_data(stream, encoder); /* Setup an opj_image */ if (strcmp (im->mode, "L") == 0) { @@ -425,8 +425,11 @@ j2k_encode_entry(Imaging im, ImagingCodecState state, } /* Write each tile */ - tiles_x = (im->xsize + tile_width - 1) / tile_width; - tiles_y = (im->ysize + tile_height - 1) / tile_height; + tiles_x = (im->xsize + (params.image_offset_x0 - params.cp_tx0) + + tile_width - 1) / tile_width; + tiles_y = (im->ysize + (params.image_offset_y0 - params.cp_ty0) + + tile_height - 1) / tile_height; + num_tiles = tiles_x * tiles_y; state->buffer = malloc (tile_width * tile_height * components); diff --git a/selftest.py b/selftest.py index 1f905b9a7..248cb3937 100644 --- a/selftest.py +++ b/selftest.py @@ -192,6 +192,7 @@ if __name__ == "__main__": check_module("PIL CORE", "PIL._imaging") check_module("TKINTER", "PIL._imagingtk") check_codec("JPEG", "jpeg") + check_codec("JPEG 2000", "jpeg2k") check_codec("ZLIB (PNG/ZIP)", "zip") check_codec("LIBTIFF", "libtiff") check_module("FREETYPE2", "PIL._imagingft")