Open 16-bit grayscale PNGs as I;16
Before Width: | Height: | Size: 578 B |
BIN
Tests/images/16_bit_binary_pgm.tiff
Normal file
Before Width: | Height: | Size: 298 KiB |
BIN
Tests/images/cmx3g8_wv_1998.260_0745_mcidas.tiff
Normal file
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 180 B |
BIN
Tests/images/imagedraw_rectangle_I.tiff
Normal file
|
@ -19,7 +19,7 @@ def test_valid_file() -> None:
|
|||
# https://ghrc.nsstc.nasa.gov/hydro/details/cmx3g8
|
||||
# https://ghrc.nsstc.nasa.gov/pub/fieldCampaigns/camex3/cmx3g8/browse/
|
||||
test_file = "Tests/images/cmx3g8_wv_1998.260_0745_mcidas.ara"
|
||||
saved_file = "Tests/images/cmx3g8_wv_1998.260_0745_mcidas.png"
|
||||
saved_file = "Tests/images/cmx3g8_wv_1998.260_0745_mcidas.tiff"
|
||||
|
||||
# Act
|
||||
with Image.open(test_file) as im:
|
||||
|
|
|
@ -102,7 +102,7 @@ class TestFilePng:
|
|||
im = hopper(mode)
|
||||
im.save(test_file)
|
||||
with Image.open(test_file) as reloaded:
|
||||
if mode in ("I;16", "I;16B"):
|
||||
if mode in ("I", "I;16B"):
|
||||
reloaded = reloaded.convert(mode)
|
||||
assert_image_equal(reloaded, im)
|
||||
|
||||
|
@ -304,8 +304,8 @@ class TestFilePng:
|
|||
assert im.getcolors() == [(100, (0, 0, 0, 0))]
|
||||
|
||||
def test_save_grayscale_transparency(self, tmp_path: Path) -> None:
|
||||
for mode, num_transparent in {"1": 1994, "L": 559, "I": 559}.items():
|
||||
in_file = "Tests/images/" + mode.lower() + "_trns.png"
|
||||
for mode, num_transparent in {"1": 1994, "L": 559, "I;16": 559}.items():
|
||||
in_file = "Tests/images/" + mode.split(";")[0].lower() + "_trns.png"
|
||||
with Image.open(in_file) as im:
|
||||
assert im.mode == mode
|
||||
assert im.info["transparency"] == 255
|
||||
|
|
|
@ -88,7 +88,7 @@ def test_16bit_pgm() -> None:
|
|||
assert im.size == (20, 100)
|
||||
assert im.get_format_mimetype() == "image/x-portable-graymap"
|
||||
|
||||
assert_image_equal_tofile(im, "Tests/images/16_bit_binary_pgm.png")
|
||||
assert_image_equal_tofile(im, "Tests/images/16_bit_binary_pgm.tiff")
|
||||
|
||||
|
||||
def test_16bit_pgm_write(tmp_path: Path) -> None:
|
||||
|
|
|
@ -148,9 +148,7 @@ def test_kernel_not_enough_coefficients() -> None:
|
|||
@pytest.mark.parametrize("mode", ("L", "LA", "I", "RGB", "CMYK"))
|
||||
def test_consistency_3x3(mode: str) -> None:
|
||||
with Image.open("Tests/images/hopper.bmp") as source:
|
||||
reference_name = "hopper_emboss"
|
||||
reference_name += "_I.png" if mode == "I" else ".bmp"
|
||||
with Image.open("Tests/images/" + reference_name) as reference:
|
||||
with Image.open("Tests/images/hopper_emboss.bmp") as reference:
|
||||
kernel = ImageFilter.Kernel(
|
||||
(3, 3),
|
||||
# fmt: off
|
||||
|
@ -160,23 +158,13 @@ def test_consistency_3x3(mode: str) -> None:
|
|||
# fmt: on
|
||||
0.3,
|
||||
)
|
||||
source = source.split() * 2
|
||||
reference = reference.split() * 2
|
||||
|
||||
if mode == "I":
|
||||
source = source[0].convert(mode)
|
||||
else:
|
||||
source = Image.merge(mode, source[: len(mode)])
|
||||
reference = Image.merge(mode, reference[: len(mode)])
|
||||
assert_image_equal(source.filter(kernel), reference)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("mode", ("L", "LA", "I", "RGB", "CMYK"))
|
||||
def test_consistency_5x5(mode: str) -> None:
|
||||
with Image.open("Tests/images/hopper.bmp") as source:
|
||||
reference_name = "hopper_emboss_more"
|
||||
reference_name += "_I.png" if mode == "I" else ".bmp"
|
||||
with Image.open("Tests/images/" + reference_name) as reference:
|
||||
with Image.open("Tests/images/hopper_emboss_more.bmp") as reference:
|
||||
kernel = ImageFilter.Kernel(
|
||||
(5, 5),
|
||||
# fmt: off
|
||||
|
@ -188,14 +176,6 @@ def test_consistency_5x5(mode: str) -> None:
|
|||
# fmt: on
|
||||
0.3,
|
||||
)
|
||||
source = source.split() * 2
|
||||
reference = reference.split() * 2
|
||||
|
||||
if mode == "I":
|
||||
source = source[0].convert(mode)
|
||||
else:
|
||||
source = Image.merge(mode, source[: len(mode)])
|
||||
reference = Image.merge(mode, reference[: len(mode)])
|
||||
assert_image_equal(source.filter(kernel), reference)
|
||||
|
||||
|
||||
|
|
|
@ -753,7 +753,7 @@ def test_rectangle_I16(bbox: Coords) -> None:
|
|||
draw.rectangle(bbox, outline=0xFFFF)
|
||||
|
||||
# Assert
|
||||
assert_image_equal_tofile(im.convert("I"), "Tests/images/imagedraw_rectangle_I.png")
|
||||
assert_image_equal_tofile(im, "Tests/images/imagedraw_rectangle_I.tiff")
|
||||
|
||||
|
||||
@pytest.mark.parametrize("bbox", BBOX)
|
||||
|
|
|
@ -978,7 +978,7 @@ class Image:
|
|||
delete_trns = False
|
||||
# transparency handling
|
||||
if has_transparency:
|
||||
if (self.mode in ("1", "L", "I") and mode in ("LA", "RGBA")) or (
|
||||
if (self.mode in ("1", "L", "I", "I;16") and mode in ("LA", "RGBA")) or (
|
||||
self.mode == "RGB" and mode == "RGBA"
|
||||
):
|
||||
# Use transparent conversion to promote from transparent
|
||||
|
|
|
@ -62,7 +62,7 @@ _MODES = {
|
|||
(2, 0): ("L", "L;2"),
|
||||
(4, 0): ("L", "L;4"),
|
||||
(8, 0): ("L", "L"),
|
||||
(16, 0): ("I", "I;16B"),
|
||||
(16, 0): ("I;16", "I;16B"),
|
||||
# Truecolour
|
||||
(8, 2): ("RGB", "RGB"),
|
||||
(16, 2): ("RGB", "RGB;16B"),
|
||||
|
@ -467,7 +467,7 @@ class PngStream(ChunkStream):
|
|||
# otherwise, we have a byte string with one alpha value
|
||||
# for each palette entry
|
||||
self.im_info["transparency"] = s
|
||||
elif self.im_mode in ("1", "L", "I"):
|
||||
elif self.im_mode in ("1", "L", "I;16"):
|
||||
self.im_info["transparency"] = i16(s)
|
||||
elif self.im_mode == "RGB":
|
||||
self.im_info["transparency"] = i16(s), i16(s, 2), i16(s, 4)
|
||||
|
@ -1356,7 +1356,7 @@ def _save(im, fp, filename, chunk=putchunk, save_all=False):
|
|||
transparency = max(0, min(255, transparency))
|
||||
alpha = b"\xFF" * transparency + b"\0"
|
||||
chunk(fp, b"tRNS", alpha[:alpha_bytes])
|
||||
elif im.mode in ("1", "L", "I"):
|
||||
elif im.mode in ("1", "L", "I", "I;16"):
|
||||
transparency = max(0, min(65535, transparency))
|
||||
chunk(fp, b"tRNS", o16(transparency))
|
||||
elif im.mode == "RGB":
|
||||
|
|
|
@ -878,6 +878,18 @@ I16B_L(UINT8 *out, const UINT8 *in, int xsize) {
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
I16_RGB(UINT8 *out, const UINT8 *in, int xsize) {
|
||||
int x;
|
||||
for (x = 0; x < xsize; x++, in += 2) {
|
||||
UINT8 v = in[1] == 0 ? in[0] : 255;
|
||||
*out++ = v;
|
||||
*out++ = v;
|
||||
*out++ = v;
|
||||
*out++ = 255;
|
||||
}
|
||||
}
|
||||
|
||||
static struct {
|
||||
const char *from;
|
||||
const char *to;
|
||||
|
@ -978,6 +990,7 @@ static struct {
|
|||
|
||||
{"I", "I;16", I_I16L},
|
||||
{"I;16", "I", I16L_I},
|
||||
{"I;16", "RGB", I16_RGB},
|
||||
{"L", "I;16", L_I16L},
|
||||
{"I;16", "L", I16L_L},
|
||||
|
||||
|
@ -1678,6 +1691,7 @@ ImagingConvertTransparent(Imaging imIn, const char *mode, int r, int g, int b) {
|
|||
convert = rgb2rgba;
|
||||
} else if ((strcmp(imIn->mode, "1") == 0 ||
|
||||
strcmp(imIn->mode, "I") == 0 ||
|
||||
strcmp(imIn->mode, "I;16") == 0 ||
|
||||
strcmp(imIn->mode, "L") == 0
|
||||
) && (
|
||||
strcmp(mode, "RGBA") == 0 ||
|
||||
|
@ -1687,6 +1701,8 @@ ImagingConvertTransparent(Imaging imIn, const char *mode, int r, int g, int b) {
|
|||
convert = bit2rgb;
|
||||
} else if (strcmp(imIn->mode, "I") == 0) {
|
||||
convert = i2rgb;
|
||||
} else if (strcmp(imIn->mode, "I;16") == 0) {
|
||||
convert = I16_RGB;
|
||||
} else {
|
||||
convert = l2rgb;
|
||||
}
|
||||
|
|