diff --git a/PIL/Jpeg2KImagePlugin.py b/PIL/Jpeg2KImagePlugin.py index cd72107a8..f57f4a784 100644 --- a/PIL/Jpeg2KImagePlugin.py +++ b/PIL/Jpeg2KImagePlugin.py @@ -169,14 +169,14 @@ class Jpeg2KImageFile(ImageFile.ImageFile): if self.reduce: power = 1 << self.reduce adjust = power >> 1 - self.size = ((self.size[0] + adjust) / power, - (self.size[1] + adjust) / power) + self.size = (int((self.size[0] + adjust) / power), + int((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)] + self.tile = [(t[0], (0, 0) + self.size, t[2], t3)] ImageFile.ImageFile.load(self) diff --git a/Tests/run.py b/Tests/run.py index 02b633c90..01a3f3603 100644 --- a/Tests/run.py +++ b/Tests/run.py @@ -2,7 +2,7 @@ from __future__ import print_function # minimal test runner -import glob, os, os.path, sys, tempfile +import glob, os, os.path, sys, tempfile, re try: root = os.path.dirname(__file__) @@ -38,6 +38,8 @@ skipped = [] python_options = " ".join(python_options) tester_options = " ".join(tester_options) +ignore_re = re.compile('^ignore: (.*)$', re.MULTILINE) + for file in files: test, ext = os.path.splitext(os.path.basename(file)) if include and test not in include: @@ -48,7 +50,30 @@ for file in files: out = os.popen("%s %s -u %s %s 2>&1" % ( sys.executable, python_options, file, tester_options )) - result = out.read().strip() + result = out.read() + + # Extract any ignore patterns + ignore_pats = ignore_re.findall(result) + result = ignore_re.sub('', result) + + try: + def fix_re(p): + if not p.startswith('^'): + p = '^' + p + if not p.endswith('$'): + p = p + '$' + return p + + ignore_res = [re.compile(fix_re(p), re.MULTILINE) for p in ignore_pats] + except: + print('(bad ignore patterns %r)' % ignore_pats) + ignore_res = [] + + for r in ignore_res: + result = r.sub('', result) + + result = result.strip() + if result == "ok": result = None elif result == "skip": diff --git a/Tests/test_file_jpeg2k.py b/Tests/test_file_jpeg2k.py index 1230f7977..b11e5e6ab 100644 --- a/Tests/test_file_jpeg2k.py +++ b/Tests/test_file_jpeg2k.py @@ -8,6 +8,10 @@ codecs = dir(Image.core) if "jpeg2k_encoder" not in codecs or "jpeg2k_decoder" not in codecs: skip('JPEG 2000 support not available') +# OpenJPEG 2.0.0 outputs this debugging message sometimes; we should +# ignore it---it doesn't represent a test failure. +ignore('Not enough memory to handle tile data') + test_card = Image.open('Tests/images/test-card.png') test_card.load() diff --git a/Tests/tester.py b/Tests/tester.py index 2c6fa071c..d4309e3e6 100644 --- a/Tests/tester.py +++ b/Tests/tester.py @@ -260,6 +260,11 @@ def skip(msg=None): print("skip") os._exit(0) # don't run exit handlers +def ignore(pattern): + """Tells the driver to ignore messages matching the pattern, for the + duration of the current test.""" + print('ignore: %s' % pattern) + def _setup(): global _logfile def report(): diff --git a/libImaging/Incremental.c b/libImaging/Incremental.c index 9574d51a8..9e7fb38ec 100644 --- a/libImaging/Incremental.c +++ b/libImaging/Incremental.c @@ -130,6 +130,9 @@ codec_thread(void *ptr) 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 @@ -140,8 +143,8 @@ flush_stream(ImagingIncrementalCodec codec) DEBUG("flushing data\n"); - UINT8 *buffer = codec->stream.buffer; - size_t bytes = codec->stream.ptr - codec->stream.buffer; + buffer = codec->stream.buffer; + bytes = codec->stream.ptr - codec->stream.buffer; codec->state->errcode = 0; codec->seekable = INCREMENTAL_CODEC_NOT_SEEKABLE; @@ -645,6 +648,8 @@ 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) @@ -660,7 +665,7 @@ ImagingIncrementalCodecSeek(ImagingIncrementalCodec codec, return -1; } - off_t buffered = codec->stream.top - codec->stream.buffer; + buffered = codec->stream.top - codec->stream.buffer; if (bytes <= buffered) { DEBUG("seek within buffer\n"); diff --git a/libImaging/Jpeg2KDecode.c b/libImaging/Jpeg2KDecode.c index dd20dc738..6b6176c78 100644 --- a/libImaging/Jpeg2KDecode.c +++ b/libImaging/Jpeg2KDecode.c @@ -230,7 +230,7 @@ j2ku_graya_la(opj_image_t *in, const JPEG2KTILEINFO *tileinfo, const UINT8 *adata = &atiledata[acsiz * y * w]; UINT8 *row = (UINT8 *)im->image[y0 + y] + x0 * 4; for (x = 0; x < w; ++x) { - UINT32 word = 0, aword = 0; + UINT32 word = 0, aword = 0, byte; switch (csiz) { case 1: word = *data++; break; @@ -244,7 +244,7 @@ j2ku_graya_la(opj_image_t *in, const JPEG2KTILEINFO *tileinfo, case 4: aword = *(const UINT32 *)adata; adata += 4; break; } - UINT8 byte = j2ku_shift(offset + word, shift); + byte = j2ku_shift(offset + word, shift); row[0] = row[1] = row[2] = byte; row[3] = j2ku_shift(aoffset + aword, ashift); row += 4; @@ -552,9 +552,7 @@ j2k_decode_entry(Imaging im, ImagingCodecState state, } for (n = 1; n < image->numcomps; ++n) { - /* Check that the sample frequency is uniform */ - if (image->comps[0].dx != image->comps[n].dx - || image->comps[0].dy != image->comps[n].dy) { + if (image->comps[n].dx != 1 || image->comps[n].dy != 1) { state->errcode = IMAGING_CODEC_BROKEN; state->state = J2K_STATE_FAILED; goto quick_exit; @@ -612,6 +610,7 @@ j2k_decode_entry(Imaging im, ImagingCodecState state, for (;;) { JPEG2KTILEINFO tile_info; OPJ_BOOL should_continue; + unsigned correction = (1 << params.cp_reduce) - 1; if (!opj_read_tile_header(codec, stream, @@ -629,6 +628,13 @@ j2k_decode_entry(Imaging im, ImagingCodecState state, if (!should_continue) break; + /* Adjust the tile co-ordinates based on the reduction (OpenJPEG + doesn't do this for us) */ + tile_info.x0 = (tile_info.x0 + correction) >> context->reduce; + tile_info.y0 = (tile_info.y0 + correction) >> context->reduce; + tile_info.x1 = (tile_info.x1 + correction) >> context->reduce; + tile_info.y1 = (tile_info.y1 + correction) >> context->reduce; + if (buffer_size < tile_info.data_size) { UINT8 *new = realloc (state->buffer, tile_info.data_size); if (!new) {