diff --git a/PIL/Jpeg2KImagePlugin.py b/PIL/Jpeg2KImagePlugin.py index ff6ca4b35..66069802e 100644 --- a/PIL/Jpeg2KImagePlugin.py +++ b/PIL/Jpeg2KImagePlugin.py @@ -40,8 +40,8 @@ def _parse_codestream(fp): size = (xsiz - xosiz, ysiz - yosiz) if csiz == 1: - if (ssiz[0] & 0x7f) > 8: - mode = 'I' + if (yrsiz[0] & 0x7f) > 8: + mode = 'I;16' else: mode = 'L' elif csiz == 2: @@ -100,7 +100,7 @@ def _parse_jp2_header(fp): size = (width, height) if unkc: if nc == 1 and (bpc & 0x7f) > 8: - mode = 'I' + mode = 'I;16' elif nc == 1: mode = 'L' elif nc == 2: @@ -116,7 +116,7 @@ def _parse_jp2_header(fp): cs = struct.unpack('>I', content[3:7])[0] if cs == 16: # sRGB if nc == 1 and (bpc & 0x7f) > 8: - mode = 'I' + mode = 'I;16' elif nc == 1: mode = 'L' elif nc == 3: @@ -126,7 +126,7 @@ def _parse_jp2_header(fp): break elif cs == 17: # grayscale if nc == 1 and (bpc & 0x7f) > 8: - mode = 'I' + mode = 'I;16' elif nc == 1: mode = 'L' elif nc == 2: diff --git a/Tests/images/16bit.cropped.j2k b/Tests/images/16bit.cropped.j2k new file mode 100644 index 000000000..c12df0cd7 Binary files /dev/null and b/Tests/images/16bit.cropped.j2k differ diff --git a/Tests/images/16bit.cropped.jp2 b/Tests/images/16bit.cropped.jp2 new file mode 100644 index 000000000..0f6685a46 Binary files /dev/null and b/Tests/images/16bit.cropped.jp2 differ diff --git a/Tests/test_file_jpeg2k.py b/Tests/test_file_jpeg2k.py index b662124b4..b763687f7 100644 --- a/Tests/test_file_jpeg2k.py +++ b/Tests/test_file_jpeg2k.py @@ -120,6 +120,42 @@ class TestFileJpeg2k(PillowTestCase): self.assertEqual(j2k.mode, 'RGBA') self.assertEqual(jp2.mode, 'RGBA') + def test_16bit_monochrome_has_correct_mode(self): + + j2k = Image.open('Tests/images/16bit.cropped.j2k') + jp2 = Image.open('Tests/images/16bit.cropped.jp2') + + j2k.load() + jp2.load() + + self.assertEqual(j2k.mode, 'I;16') + self.assertEqual(jp2.mode, 'I;16') + + def test_16bit_monchrome_jp2_like_tiff(self): + + tiff_16bit = Image.open('Tests/images/16bit.cropped.tif') + jp2 = Image.open('Tests/images/16bit.cropped.jp2') + self.assert_image_similar(jp2, tiff_16bit, 1e-3) + + def test_16bit_monchrome_j2k_like_tiff(self): + + tiff_16bit = Image.open('Tests/images/16bit.cropped.tif') + j2k = Image.open('Tests/images/16bit.cropped.j2k') + self.assert_image_similar(j2k, tiff_16bit, 1e-3) + + def test_16bit_j2k_roundtrips(self): + + j2k = Image.open('Tests/images/16bit.cropped.j2k') + im = self.roundtrip(j2k) + self.assert_image_equal(im, j2k) + + def test_16bit_jp2_roundtrips(self): + + jp2 = Image.open('Tests/images/16bit.cropped.jp2') + im = self.roundtrip(jp2) + self.assert_image_equal(im, jp2) + + if __name__ == '__main__': unittest.main() diff --git a/libImaging/Jpeg2KDecode.c b/libImaging/Jpeg2KDecode.c index 76c1d169b..97ec81003 100644 --- a/libImaging/Jpeg2KDecode.c +++ b/libImaging/Jpeg2KDecode.c @@ -160,7 +160,7 @@ j2ku_gray_i(opj_image_t *in, const JPEG2KTILEINFO *tileinfo, case 1: for (y = 0; y < h; ++y) { const UINT8 *data = &tiledata[y * w]; - UINT32 *row = (UINT32 *)im->image[y0 + y] + x0; + UINT16 *row = (UINT16 *)im->image[y0 + y] + x0; for (x = 0; x < w; ++x) *row++ = j2ku_shift(offset + *data++, shift); } @@ -168,7 +168,7 @@ j2ku_gray_i(opj_image_t *in, const JPEG2KTILEINFO *tileinfo, case 2: for (y = 0; y < h; ++y) { const UINT16 *data = (const UINT16 *)&tiledata[2 * y * w]; - UINT32 *row = (UINT32 *)im->image[y0 + y] + x0; + UINT16 *row = (UINT16 *)im->image[y0 + y] + x0; for (x = 0; x < w; ++x) *row++ = j2ku_shift(offset + *data++, shift); } @@ -176,7 +176,7 @@ j2ku_gray_i(opj_image_t *in, const JPEG2KTILEINFO *tileinfo, case 4: for (y = 0; y < h; ++y) { const UINT32 *data = (const UINT32 *)&tiledata[4 * y * w]; - UINT32 *row = (UINT32 *)im->image[y0 + y] + x0; + UINT16 *row = (UINT16 *)im->image[y0 + y] + x0; for (x = 0; x < w; ++x) *row++ = j2ku_shift(offset + *data++, shift); } @@ -516,7 +516,8 @@ j2ku_sycca_rgba(opj_image_t *in, const JPEG2KTILEINFO *tileinfo, static const struct j2k_decode_unpacker j2k_unpackers[] = { { "L", OPJ_CLRSPC_GRAY, 1, j2ku_gray_l }, - { "I", OPJ_CLRSPC_GRAY, 1, j2ku_gray_i }, + { "I;16", OPJ_CLRSPC_GRAY, 1, j2ku_gray_i }, + { "I;16B", OPJ_CLRSPC_GRAY, 1, j2ku_gray_i }, { "LA", OPJ_CLRSPC_GRAY, 2, j2ku_graya_la }, { "RGB", OPJ_CLRSPC_GRAY, 1, j2ku_gray_rgb }, { "RGB", OPJ_CLRSPC_GRAY, 2, j2ku_gray_rgb },