mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-01-13 02:36:17 +03:00
Added transparency for all PNG greyscale modes
This commit is contained in:
parent
e6db8dee0c
commit
4a5666f1f4
BIN
Tests/images/1_trns.png
Normal file
BIN
Tests/images/1_trns.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 612 B |
BIN
Tests/images/i_trns.png
Normal file
BIN
Tests/images/i_trns.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
|
@ -291,13 +291,15 @@ class TestFilePng(PillowTestCase):
|
||||||
self.assert_image(im, "RGBA", (10, 10))
|
self.assert_image(im, "RGBA", (10, 10))
|
||||||
self.assertEqual(im.getcolors(), [(100, (0, 0, 0, 0))])
|
self.assertEqual(im.getcolors(), [(100, (0, 0, 0, 0))])
|
||||||
|
|
||||||
def test_save_l_transparency(self):
|
def test_save_greyscale_transparency(self):
|
||||||
# There are 559 transparent pixels in l_trns.png.
|
for mode, num_transparent in {
|
||||||
num_transparent = 559
|
"1": 1994,
|
||||||
|
"L": 559,
|
||||||
in_file = "Tests/images/l_trns.png"
|
"I": 559,
|
||||||
|
}.items():
|
||||||
|
in_file = "Tests/images/"+mode.lower()+"_trns.png"
|
||||||
im = Image.open(in_file)
|
im = Image.open(in_file)
|
||||||
self.assertEqual(im.mode, "L")
|
self.assertEqual(im.mode, mode)
|
||||||
self.assertEqual(im.info["transparency"], 255)
|
self.assertEqual(im.info["transparency"], 255)
|
||||||
|
|
||||||
im_rgba = im.convert('RGBA')
|
im_rgba = im.convert('RGBA')
|
||||||
|
@ -308,7 +310,7 @@ class TestFilePng(PillowTestCase):
|
||||||
im.save(test_file)
|
im.save(test_file)
|
||||||
|
|
||||||
test_im = Image.open(test_file)
|
test_im = Image.open(test_file)
|
||||||
self.assertEqual(test_im.mode, "L")
|
self.assertEqual(test_im.mode, mode)
|
||||||
self.assertEqual(test_im.info["transparency"], 255)
|
self.assertEqual(test_im.info["transparency"], 255)
|
||||||
self.assert_image_equal(im, test_im)
|
self.assert_image_equal(im, test_im)
|
||||||
|
|
||||||
|
|
|
@ -490,12 +490,12 @@ The :py:meth:`~PIL.Image.Image.open` method sets the following
|
||||||
For ``P`` images: Either the palette index for full transparent pixels,
|
For ``P`` images: Either the palette index for full transparent pixels,
|
||||||
or a byte string with alpha values for each palette entry.
|
or a byte string with alpha values for each palette entry.
|
||||||
|
|
||||||
For ``L`` and ``RGB`` images, the color that represents full transparent
|
For ``1``, ``L``, ``I`` and ``RGB`` images, the color that represents
|
||||||
pixels in this image.
|
full transparent pixels in this image.
|
||||||
|
|
||||||
This key is omitted if the image is not a transparent palette image.
|
This key is omitted if the image is not a transparent palette image.
|
||||||
|
|
||||||
``Open`` also sets ``Image.text`` to a dictionary of the values of the
|
``open`` also sets ``Image.text`` to a dictionary of the values of the
|
||||||
``tEXt``, ``zTXt``, and ``iTXt`` chunks of the PNG image. Individual
|
``tEXt``, ``zTXt``, and ``iTXt`` chunks of the PNG image. Individual
|
||||||
compressed chunks are limited to a decompressed size of
|
compressed chunks are limited to a decompressed size of
|
||||||
``PngImagePlugin.MAX_TEXT_CHUNK``, by default 1MB, to prevent
|
``PngImagePlugin.MAX_TEXT_CHUNK``, by default 1MB, to prevent
|
||||||
|
@ -511,8 +511,8 @@ The :py:meth:`~PIL.Image.Image.save` method supports the following options:
|
||||||
encoder settings.
|
encoder settings.
|
||||||
|
|
||||||
**transparency**
|
**transparency**
|
||||||
For ``P``, ``L``, and ``RGB`` images, this option controls what
|
For ``P``, ``1``, ``L``, ``I``, and ``RGB`` images, this option controls
|
||||||
color image to mark as transparent.
|
what color from the image to mark as transparent.
|
||||||
|
|
||||||
For ``P`` images, this can be a either the palette index,
|
For ``P`` images, this can be a either the palette index,
|
||||||
or a byte string with alpha values for each palette entry.
|
or a byte string with alpha values for each palette entry.
|
||||||
|
|
|
@ -950,7 +950,7 @@ class Image(object):
|
||||||
delete_trns = False
|
delete_trns = False
|
||||||
# transparency handling
|
# transparency handling
|
||||||
if has_transparency:
|
if has_transparency:
|
||||||
if self.mode in ('L', 'RGB') and mode == 'RGBA':
|
if self.mode in ('1', 'L', 'I', 'RGB') and mode == 'RGBA':
|
||||||
# Use transparent conversion to promote from transparent
|
# Use transparent conversion to promote from transparent
|
||||||
# color to an alpha channel.
|
# color to an alpha channel.
|
||||||
new_im = self._new(self.im.convert_transparent(
|
new_im = self._new(self.im.convert_transparent(
|
||||||
|
|
|
@ -54,19 +54,24 @@ _MAGIC = b"\211PNG\r\n\032\n"
|
||||||
|
|
||||||
_MODES = {
|
_MODES = {
|
||||||
# supported bits/color combinations, and corresponding modes/rawmodes
|
# supported bits/color combinations, and corresponding modes/rawmodes
|
||||||
|
# Greyscale
|
||||||
(1, 0): ("1", "1"),
|
(1, 0): ("1", "1"),
|
||||||
(2, 0): ("L", "L;2"),
|
(2, 0): ("L", "L;2"),
|
||||||
(4, 0): ("L", "L;4"),
|
(4, 0): ("L", "L;4"),
|
||||||
(8, 0): ("L", "L"),
|
(8, 0): ("L", "L"),
|
||||||
(16, 0): ("I", "I;16B"),
|
(16, 0): ("I", "I;16B"),
|
||||||
|
# Truecolour
|
||||||
(8, 2): ("RGB", "RGB"),
|
(8, 2): ("RGB", "RGB"),
|
||||||
(16, 2): ("RGB", "RGB;16B"),
|
(16, 2): ("RGB", "RGB;16B"),
|
||||||
|
# Indexed-colour
|
||||||
(1, 3): ("P", "P;1"),
|
(1, 3): ("P", "P;1"),
|
||||||
(2, 3): ("P", "P;2"),
|
(2, 3): ("P", "P;2"),
|
||||||
(4, 3): ("P", "P;4"),
|
(4, 3): ("P", "P;4"),
|
||||||
(8, 3): ("P", "P"),
|
(8, 3): ("P", "P"),
|
||||||
|
# Greyscale with alpha
|
||||||
(8, 4): ("LA", "LA"),
|
(8, 4): ("LA", "LA"),
|
||||||
(16, 4): ("RGBA", "LA;16B"), # LA;16B->LA not yet available
|
(16, 4): ("RGBA", "LA;16B"), # LA;16B->LA not yet available
|
||||||
|
# Truecolour with alpha
|
||||||
(8, 6): ("RGBA", "RGBA"),
|
(8, 6): ("RGBA", "RGBA"),
|
||||||
(16, 6): ("RGBA", "RGBA;16B"),
|
(16, 6): ("RGBA", "RGBA;16B"),
|
||||||
}
|
}
|
||||||
|
@ -386,7 +391,7 @@ class PngStream(ChunkStream):
|
||||||
# otherwise, we have a byte string with one alpha value
|
# otherwise, we have a byte string with one alpha value
|
||||||
# for each palette entry
|
# for each palette entry
|
||||||
self.im_info["transparency"] = s
|
self.im_info["transparency"] = s
|
||||||
elif self.im_mode == "L":
|
elif self.im_mode in ("1", "L", "I"):
|
||||||
self.im_info["transparency"] = i16(s)
|
self.im_info["transparency"] = i16(s)
|
||||||
elif self.im_mode == "RGB":
|
elif self.im_mode == "RGB":
|
||||||
self.im_info["transparency"] = i16(s), i16(s[2:]), i16(s[4:])
|
self.im_info["transparency"] = i16(s), i16(s[2:]), i16(s[4:])
|
||||||
|
@ -841,7 +846,7 @@ def _save(im, fp, filename, chunk=putchunk):
|
||||||
transparency = max(0, min(255, transparency))
|
transparency = max(0, min(255, transparency))
|
||||||
alpha = b'\xFF' * transparency + b'\0'
|
alpha = b'\xFF' * transparency + b'\0'
|
||||||
chunk(fp, b"tRNS", alpha[:alpha_bytes])
|
chunk(fp, b"tRNS", alpha[:alpha_bytes])
|
||||||
elif im.mode == "L":
|
elif im.mode in ("1", "L", "I"):
|
||||||
transparency = max(0, min(65535, transparency))
|
transparency = max(0, min(65535, transparency))
|
||||||
chunk(fp, b"tRNS", o16(transparency))
|
chunk(fp, b"tRNS", o16(transparency))
|
||||||
elif im.mode == "RGB":
|
elif im.mode == "RGB":
|
||||||
|
|
|
@ -592,6 +592,22 @@ i2f(UINT8* out_, const UINT8* in_, int xsize)
|
||||||
*out++ = (FLOAT32) *in++;
|
*out++ = (FLOAT32) *in++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
i2rgb(UINT8* out, const UINT8* in_, int xsize)
|
||||||
|
{
|
||||||
|
int x;
|
||||||
|
INT32* in = (INT32*) in_;
|
||||||
|
for (x = 0; x < xsize; x++, in++, out+=4) {
|
||||||
|
if (*in <= 0)
|
||||||
|
out[0] = out[1] = out[2] = 0;
|
||||||
|
else if (*in >= 255)
|
||||||
|
out[0] = out[1] = out[2] = 255;
|
||||||
|
else
|
||||||
|
out[0] = out[1] = out[2] = (UINT8) *in;
|
||||||
|
out[3] = 255;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* ------------- */
|
/* ------------- */
|
||||||
/* F conversions */
|
/* F conversions */
|
||||||
/* ------------- */
|
/* ------------- */
|
||||||
|
@ -809,6 +825,9 @@ static struct {
|
||||||
|
|
||||||
{ "I", "L", i2l },
|
{ "I", "L", i2l },
|
||||||
{ "I", "F", i2f },
|
{ "I", "F", i2f },
|
||||||
|
{ "I", "RGB", i2rgb },
|
||||||
|
{ "I", "RGBA", i2rgb },
|
||||||
|
{ "I", "RGBX", i2rgb },
|
||||||
|
|
||||||
{ "F", "L", f2l },
|
{ "F", "L", f2l },
|
||||||
{ "F", "I", f2i },
|
{ "F", "I", f2i },
|
||||||
|
@ -1385,6 +1404,8 @@ ImagingConvertTransparent(Imaging imIn, const char *mode,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!((strcmp(imIn->mode, "RGB") == 0 ||
|
if (!((strcmp(imIn->mode, "RGB") == 0 ||
|
||||||
|
strcmp(imIn->mode, "1") == 0 ||
|
||||||
|
strcmp(imIn->mode, "I") == 0 ||
|
||||||
strcmp(imIn->mode, "L") == 0)
|
strcmp(imIn->mode, "L") == 0)
|
||||||
&& strcmp(mode, "RGBA") == 0))
|
&& strcmp(mode, "RGBA") == 0))
|
||||||
#ifdef notdef
|
#ifdef notdef
|
||||||
|
@ -1402,8 +1423,14 @@ ImagingConvertTransparent(Imaging imIn, const char *mode,
|
||||||
|
|
||||||
if (strcmp(imIn->mode, "RGB") == 0) {
|
if (strcmp(imIn->mode, "RGB") == 0) {
|
||||||
convert = rgb2rgba;
|
convert = rgb2rgba;
|
||||||
|
} else {
|
||||||
|
if (strcmp(imIn->mode, "1") == 0) {
|
||||||
|
convert = bit2rgb;
|
||||||
|
} else if (strcmp(imIn->mode, "I") == 0) {
|
||||||
|
convert = i2rgb;
|
||||||
} else {
|
} else {
|
||||||
convert = l2rgb;
|
convert = l2rgb;
|
||||||
|
}
|
||||||
g = b = r;
|
g = b = r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user