diff --git a/Tests/images/10_bit_binary.pgm b/Tests/images/10_bit_binary.pgm new file mode 100644 index 000000000..ab3126600 Binary files /dev/null and b/Tests/images/10_bit_binary.pgm differ diff --git a/Tests/images/10_bit_binary_pgm.png b/Tests/images/10_bit_binary_pgm.png new file mode 100644 index 000000000..8d95da30d Binary files /dev/null and b/Tests/images/10_bit_binary_pgm.png differ diff --git a/Tests/test_file_ppm.py b/Tests/test_file_ppm.py index 0e4f1ba68..6d3e0ab86 100644 --- a/Tests/test_file_ppm.py +++ b/Tests/test_file_ppm.py @@ -20,6 +20,16 @@ def test_sanity(): assert im.get_format_mimetype() == "image/x-portable-pixmap" +def test_10bit_pgm(): + with Image.open("Tests/images/10_bit_binary.pgm") as im: + im.load() + assert im.mode == "I" + assert im.size == (128, 128) + assert im.get_format_mimetype() == "image/x-portable-graymap" + + assert_image_equal_tofile(im, "Tests/images/10_bit_binary_pgm.png") + + def test_16bit_pgm(): with Image.open("Tests/images/16_bit_binary.pgm") as im: im.load() diff --git a/src/PIL/PpmImagePlugin.py b/src/PIL/PpmImagePlugin.py index 9e962cac8..414e22c6c 100644 --- a/src/PIL/PpmImagePlugin.py +++ b/src/PIL/PpmImagePlugin.py @@ -113,9 +113,12 @@ class PpmImageFile(ImageFile.ImageFile): elif ix == 2: # token is maxval maxval = token if maxval > 255: - if not mode == "L": + if mode != "L": raise ValueError(f"Too many colors for band: {token}") - if maxval < 2**16: + if maxval == 1023: + self.mode = "I" + rawmode = "I;10B" + elif maxval < 2**16: self.mode = "I" rawmode = "I;16B" else: diff --git a/src/libImaging/Unpack.c b/src/libImaging/Unpack.c index 4f9838fa8..694acb07b 100644 --- a/src/libImaging/Unpack.c +++ b/src/libImaging/Unpack.c @@ -1182,6 +1182,23 @@ unpackI12_I16(UINT8 *out, const UINT8 *in, int pixels) { } } +static void +unpackI10B(UINT8 *out, const UINT8 *in, int pixels) { + int i, pixel; + for (i = 0; i < pixels; i++) { + pixel = ((in[0] << 8) + in[1]) << 6; +#ifdef WORDS_BIGENDIAN + out[2] = pixel >> 8; + out[3] = pixel; +#else + out[0] = pixel; + out[1] = pixel >> 8; +#endif + in += 2; + out += 4; + } +} + static void copy1(UINT8 *out, const UINT8 *in, int pixels) { /* L, P */ @@ -1684,6 +1701,7 @@ static struct { {"I", "I", 32, copy4}, {"I", "I;8", 8, unpackI8}, {"I", "I;8S", 8, unpackI8S}, + {"I", "I;10B", 16, unpackI10B}, {"I", "I;16", 16, unpackI16}, {"I", "I;16S", 16, unpackI16S}, {"I", "I;16B", 16, unpackI16B},