Fixed reading 9 and 11-15-bit PGM
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
BIN
Tests/images/ppm/11_bit.pgm
Normal file
BIN
Tests/images/ppm/11_bit.png
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
Tests/images/ppm/12_bit.pgm
Normal file
BIN
Tests/images/ppm/12_bit.png
Normal file
After Width: | Height: | Size: 20 KiB |
BIN
Tests/images/ppm/13_bit.pgm
Normal file
BIN
Tests/images/ppm/13_bit.png
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
Tests/images/ppm/14_bit.pgm
Normal file
BIN
Tests/images/ppm/14_bit.png
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
Tests/images/ppm/15_bit.pgm
Normal file
BIN
Tests/images/ppm/15_bit.png
Normal file
After Width: | Height: | Size: 24 KiB |
BIN
Tests/images/ppm/9_bit.pgm
Normal file
BIN
Tests/images/ppm/9_bit.png
Normal file
After Width: | Height: | Size: 15 KiB |
|
@ -20,14 +20,16 @@ def test_sanity():
|
||||||
assert im.get_format_mimetype() == "image/x-portable-pixmap"
|
assert im.get_format_mimetype() == "image/x-portable-pixmap"
|
||||||
|
|
||||||
|
|
||||||
def test_10bit_pgm():
|
@pytest.mark.parametrize("depth", range(9, 16))
|
||||||
with Image.open("Tests/images/10_bit_binary.pgm") as im:
|
def test_less_than_16bit_pgm(depth):
|
||||||
|
name = "Tests/images/ppm/" + str(depth) + "_bit"
|
||||||
|
with Image.open(name + ".pgm") as im:
|
||||||
im.load()
|
im.load()
|
||||||
assert im.mode == "I"
|
assert im.mode == "I"
|
||||||
assert im.size == (128, 128)
|
assert im.size == (128, 128)
|
||||||
assert im.get_format_mimetype() == "image/x-portable-graymap"
|
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, name + ".png")
|
||||||
|
|
||||||
|
|
||||||
def test_16bit_pgm():
|
def test_16bit_pgm():
|
||||||
|
|
|
@ -115,15 +115,13 @@ class PpmImageFile(ImageFile.ImageFile):
|
||||||
if maxval > 255:
|
if maxval > 255:
|
||||||
if mode != "L":
|
if mode != "L":
|
||||||
raise ValueError(f"Too many colors for band: {token}")
|
raise ValueError(f"Too many colors for band: {token}")
|
||||||
if maxval == 1023:
|
|
||||||
self.mode = "I"
|
self.mode = "I"
|
||||||
rawmode = "I;10B"
|
for bit in range(9, 16):
|
||||||
elif maxval < 2**16:
|
if maxval == 2**bit - 1:
|
||||||
self.mode = "I"
|
break
|
||||||
rawmode = "I;16B"
|
|
||||||
else:
|
else:
|
||||||
self.mode = "I"
|
bit = 16 if maxval < 2**16 else 32
|
||||||
rawmode = "I;32B"
|
rawmode = "I;" + str(bit) + "B"
|
||||||
|
|
||||||
self._size = xsize, ysize
|
self._size = xsize, ysize
|
||||||
self.tile = [("raw", (0, 0, xsize, ysize), self.fp.tell(), (rawmode, 0, 1))]
|
self.tile = [("raw", (0, 0, xsize, ysize), self.fp.tell(), (rawmode, 0, 1))]
|
||||||
|
|
|
@ -1182,22 +1182,39 @@ 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
|
#ifdef WORDS_BIGENDIAN
|
||||||
out[2] = pixel >> 8;
|
#define UNPACK_IXB(NAME, DEPTH) \
|
||||||
out[3] = pixel;
|
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
|
#else
|
||||||
out[0] = pixel;
|
#define UNPACK_IXB(NAME, DEPTH) \
|
||||||
out[1] = pixel >> 8;
|
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
|
#endif
|
||||||
in += 2;
|
|
||||||
out += 4;
|
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
|
static void
|
||||||
copy1(UINT8 *out, const UINT8 *in, int pixels) {
|
copy1(UINT8 *out, const UINT8 *in, int pixels) {
|
||||||
|
@ -1701,7 +1718,13 @@ static struct {
|
||||||
{"I", "I", 32, copy4},
|
{"I", "I", 32, copy4},
|
||||||
{"I", "I;8", 8, unpackI8},
|
{"I", "I;8", 8, unpackI8},
|
||||||
{"I", "I;8S", 8, unpackI8S},
|
{"I", "I;8S", 8, unpackI8S},
|
||||||
|
{"I", "I;9B", 16, unpackI9B},
|
||||||
{"I", "I;10B", 16, unpackI10B},
|
{"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;16", 16, unpackI16},
|
||||||
{"I", "I;16S", 16, unpackI16S},
|
{"I", "I;16S", 16, unpackI16S},
|
||||||
{"I", "I;16B", 16, unpackI16B},
|
{"I", "I;16B", 16, unpackI16B},
|
||||||
|
|