Skip to content

Commit

Permalink
Fixed reading 9, 12 and 14-bit PGM
Browse files Browse the repository at this point in the history
  • Loading branch information
radarhere committed Mar 4, 2022
1 parent 0712535 commit bd32656
Show file tree
Hide file tree
Showing 9 changed files with 42 additions and 20 deletions.
Binary file added Tests/images/12_bit_binary.pgm
Binary file not shown.
Binary file added Tests/images/12_bit_binary_pgm.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/14_bit_binary.pgm
Binary file not shown.
Binary file added Tests/images/14_bit_binary_pgm.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/9_bit_binary.pgm
Binary file not shown.
Binary file added Tests/images/9_bit_binary_pgm.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 4 additions & 3 deletions Tests/test_file_ppm.py
Expand Up @@ -20,14 +20,15 @@ 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:
@pytest.mark.parametrize("depth", ("9", "10", "12", "14"))
def test_less_than_16bit_pgm(depth):
with Image.open("Tests/images/" + depth + "_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")
assert_image_equal_tofile(im, "Tests/images/" + depth + "_bit_binary_pgm.png")


def test_16bit_pgm():
Expand Down
12 changes: 8 additions & 4 deletions src/PIL/PpmImagePlugin.py
Expand Up @@ -115,14 +115,18 @@ def _open(self):
if maxval > 255:
if mode != "L":
raise ValueError(f"Too many colors for band: {token}")
if maxval == 1023:
self.mode = "I"
self.mode = "I"
if maxval == 2 ** 9 - 1:
rawmode = "I;9B"
elif maxval == 2 ** 10 - 1:
rawmode = "I;10B"
elif maxval == 2 ** 12 - 1:
rawmode = "I;12B"
elif maxval == 2 ** 14 - 1:
rawmode = "I;14B"
elif maxval < 2 ** 16:
self.mode = "I"
rawmode = "I;16B"
else:
self.mode = "I"
rawmode = "I;32B"

self._size = xsize, ysize
Expand Down
43 changes: 30 additions & 13 deletions src/libImaging/Unpack.c
Expand Up @@ -1182,22 +1182,36 @@ 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;
#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
out[0] = pixel;
out[1] = pixel >> 8;
#endif
in += 2;
out += 4;
#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(unpackI12B, 12)
UNPACK_IXB(unpackI14B, 14)

static void
copy1(UINT8 *out, const UINT8 *in, int pixels) {
Expand Down Expand Up @@ -1701,7 +1715,10 @@ 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;12B", 16, unpackI12B},
{"I", "I;14B", 16, unpackI14B},
{"I", "I;16", 16, unpackI16},
{"I", "I;16S", 16, unpackI16S},
{"I", "I;16B", 16, unpackI16B},
Expand Down

0 comments on commit bd32656

Please sign in to comment.