Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed reading 9 to 15-bit PGM #6107

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Binary file added Tests/images/ppm/10_bit.pgm
Binary file not shown.
Binary file added Tests/images/ppm/10_bit.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Tests/images/ppm/11_bit.pgm
Binary file not shown.
Binary file added Tests/images/ppm/11_bit.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Tests/images/ppm/12_bit.pgm
Binary file not shown.
Binary file added Tests/images/ppm/12_bit.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Tests/images/ppm/13_bit.pgm
Binary file not shown.
Binary file added Tests/images/ppm/13_bit.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Tests/images/ppm/14_bit.pgm
Binary file not shown.
Binary file added Tests/images/ppm/14_bit.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Tests/images/ppm/15_bit.pgm
Binary file not shown.
Binary file added Tests/images/ppm/15_bit.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Tests/images/ppm/9_bit.pgm
Binary file not shown.
Binary file added Tests/images/ppm/9_bit.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 12 additions & 0 deletions Tests/test_file_ppm.py
Expand Up @@ -20,6 +20,18 @@ def test_sanity():
assert im.get_format_mimetype() == "image/x-portable-pixmap"


@pytest.mark.parametrize("depth", range(9, 16))
def test_less_than_16bit_pgm(depth):
name = "Tests/images/ppm/" + str(depth) + "_bit"
with Image.open(name + ".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, name + ".png")


def test_16bit_pgm():
with Image.open("Tests/images/16_bit_binary.pgm") as im:
im.load()
Expand Down
13 changes: 7 additions & 6 deletions src/PIL/PpmImagePlugin.py
Expand Up @@ -113,14 +113,15 @@ def _open(self):
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:
self.mode = "I"
rawmode = "I;16B"
self.mode = "I"
for bit in range(9, 16):
if maxval == 2**bit - 1:
break
else:
self.mode = "I"
rawmode = "I;32B"
bit = 16 if maxval < 2**16 else 32
rawmode = "I;" + str(bit) + "B"

self._size = xsize, ysize
self.tile = [("raw", (0, 0, xsize, ysize), self.fp.tell(), (rawmode, 0, 1))]
Expand Down
41 changes: 41 additions & 0 deletions src/libImaging/Unpack.c
Expand Up @@ -1182,6 +1182,40 @@ unpackI12_I16(UINT8 *out, const UINT8 *in, int pixels) {
}
}

#ifdef WORDS_BIGENDIAN
#define UNPACK_IXB(NAME, DEPTH) \
static void NAME(UINT8 *out, const UINT8 *in, int pixels) { \
int i, pixel; \
for (i = 0; i < pixels; i++) { \
pixel = ((in[0] << 8) + in[1]) << (16 - DEPTH); \
out[2] = pixel >> 8; \
out[3] = pixel; \
in += 2; \
out += 4; \
} \
}
#else
#define UNPACK_IXB(NAME, DEPTH) \
static void NAME(UINT8 *out, const UINT8 *in, int pixels) { \
int i, pixel; \
for (i = 0; i < pixels; i++) { \
pixel = ((in[0] << 8) + in[1]) << (16 - DEPTH); \
out[0] = pixel; \
out[1] = pixel >> 8; \
in += 2; \
out += 4; \
} \
}
#endif

UNPACK_IXB(unpackI9B, 9)
UNPACK_IXB(unpackI10B, 10)
UNPACK_IXB(unpackI11B, 11)
UNPACK_IXB(unpackI12B, 12)
UNPACK_IXB(unpackI13B, 13)
UNPACK_IXB(unpackI14B, 14)
UNPACK_IXB(unpackI15B, 15)

static void
copy1(UINT8 *out, const UINT8 *in, int pixels) {
/* L, P */
Expand Down Expand Up @@ -1684,6 +1718,13 @@ static struct {
{"I", "I", 32, copy4},
{"I", "I;8", 8, unpackI8},
{"I", "I;8S", 8, unpackI8S},
{"I", "I;9B", 16, unpackI9B},
{"I", "I;10B", 16, unpackI10B},
{"I", "I;11B", 16, unpackI11B},
{"I", "I;12B", 16, unpackI12B},
{"I", "I;13B", 16, unpackI13B},
{"I", "I;14B", 16, unpackI14B},
{"I", "I;15B", 16, unpackI15B},
{"I", "I;16", 16, unpackI16},
{"I", "I;16S", 16, unpackI16S},
{"I", "I;16B", 16, unpackI16B},
Expand Down