mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-01-12 18:26: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,30 +291,32 @@ class TestFilePng(PillowTestCase):
|
|||
self.assert_image(im, "RGBA", (10, 10))
|
||||
self.assertEqual(im.getcolors(), [(100, (0, 0, 0, 0))])
|
||||
|
||||
def test_save_l_transparency(self):
|
||||
# There are 559 transparent pixels in l_trns.png.
|
||||
num_transparent = 559
|
||||
def test_save_greyscale_transparency(self):
|
||||
for mode, num_transparent in {
|
||||
"1": 1994,
|
||||
"L": 559,
|
||||
"I": 559,
|
||||
}.items():
|
||||
in_file = "Tests/images/"+mode.lower()+"_trns.png"
|
||||
im = Image.open(in_file)
|
||||
self.assertEqual(im.mode, mode)
|
||||
self.assertEqual(im.info["transparency"], 255)
|
||||
|
||||
in_file = "Tests/images/l_trns.png"
|
||||
im = Image.open(in_file)
|
||||
self.assertEqual(im.mode, "L")
|
||||
self.assertEqual(im.info["transparency"], 255)
|
||||
im_rgba = im.convert('RGBA')
|
||||
self.assertEqual(
|
||||
im_rgba.getchannel("A").getcolors()[0][0], num_transparent)
|
||||
|
||||
im_rgba = im.convert('RGBA')
|
||||
self.assertEqual(
|
||||
im_rgba.getchannel("A").getcolors()[0][0], num_transparent)
|
||||
test_file = self.tempfile("temp.png")
|
||||
im.save(test_file)
|
||||
|
||||
test_file = self.tempfile("temp.png")
|
||||
im.save(test_file)
|
||||
test_im = Image.open(test_file)
|
||||
self.assertEqual(test_im.mode, mode)
|
||||
self.assertEqual(test_im.info["transparency"], 255)
|
||||
self.assert_image_equal(im, test_im)
|
||||
|
||||
test_im = Image.open(test_file)
|
||||
self.assertEqual(test_im.mode, "L")
|
||||
self.assertEqual(test_im.info["transparency"], 255)
|
||||
self.assert_image_equal(im, test_im)
|
||||
|
||||
test_im_rgba = test_im.convert('RGBA')
|
||||
self.assertEqual(
|
||||
test_im_rgba.getchannel('A').getcolors()[0][0], num_transparent)
|
||||
test_im_rgba = test_im.convert('RGBA')
|
||||
self.assertEqual(
|
||||
test_im_rgba.getchannel('A').getcolors()[0][0], num_transparent)
|
||||
|
||||
def test_save_rgb_single_transparency(self):
|
||||
in_file = "Tests/images/caption_6_33_22.png"
|
||||
|
|
|
@ -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,
|
||||
or a byte string with alpha values for each palette entry.
|
||||
|
||||
For ``L`` and ``RGB`` images, the color that represents full transparent
|
||||
pixels in this image.
|
||||
For ``1``, ``L``, ``I`` and ``RGB`` images, the color that represents
|
||||
full transparent pixels in this 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
|
||||
compressed chunks are limited to a decompressed size of
|
||||
``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.
|
||||
|
||||
**transparency**
|
||||
For ``P``, ``L``, and ``RGB`` images, this option controls what
|
||||
color image to mark as transparent.
|
||||
For ``P``, ``1``, ``L``, ``I``, and ``RGB`` images, this option controls
|
||||
what color from the image to mark as transparent.
|
||||
|
||||
For ``P`` images, this can be a either the palette index,
|
||||
or a byte string with alpha values for each palette entry.
|
||||
|
|
|
@ -950,7 +950,7 @@ class Image(object):
|
|||
delete_trns = False
|
||||
# transparency handling
|
||||
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
|
||||
# color to an alpha channel.
|
||||
new_im = self._new(self.im.convert_transparent(
|
||||
|
|
|
@ -54,19 +54,24 @@ _MAGIC = b"\211PNG\r\n\032\n"
|
|||
|
||||
_MODES = {
|
||||
# supported bits/color combinations, and corresponding modes/rawmodes
|
||||
# Greyscale
|
||||
(1, 0): ("1", "1"),
|
||||
(2, 0): ("L", "L;2"),
|
||||
(4, 0): ("L", "L;4"),
|
||||
(8, 0): ("L", "L"),
|
||||
(16, 0): ("I", "I;16B"),
|
||||
# Truecolour
|
||||
(8, 2): ("RGB", "RGB"),
|
||||
(16, 2): ("RGB", "RGB;16B"),
|
||||
# Indexed-colour
|
||||
(1, 3): ("P", "P;1"),
|
||||
(2, 3): ("P", "P;2"),
|
||||
(4, 3): ("P", "P;4"),
|
||||
(8, 3): ("P", "P"),
|
||||
# Greyscale with alpha
|
||||
(8, 4): ("LA", "LA"),
|
||||
(16, 4): ("RGBA", "LA;16B"), # LA;16B->LA not yet available
|
||||
# Truecolour with alpha
|
||||
(8, 6): ("RGBA", "RGBA"),
|
||||
(16, 6): ("RGBA", "RGBA;16B"),
|
||||
}
|
||||
|
@ -386,7 +391,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 == "L":
|
||||
elif self.im_mode in ("1", "L", "I"):
|
||||
self.im_info["transparency"] = i16(s)
|
||||
elif self.im_mode == "RGB":
|
||||
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))
|
||||
alpha = b'\xFF' * transparency + b'\0'
|
||||
chunk(fp, b"tRNS", alpha[:alpha_bytes])
|
||||
elif im.mode == "L":
|
||||
elif im.mode in ("1", "L", "I"):
|
||||
transparency = max(0, min(65535, transparency))
|
||||
chunk(fp, b"tRNS", o16(transparency))
|
||||
elif im.mode == "RGB":
|
||||
|
|
|
@ -592,6 +592,22 @@ i2f(UINT8* out_, const UINT8* in_, int xsize)
|
|||
*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 */
|
||||
/* ------------- */
|
||||
|
@ -807,11 +823,14 @@ static struct {
|
|||
|
||||
{ "La", "LA", la2lA },
|
||||
|
||||
{ "I", "L", i2l },
|
||||
{ "I", "F", i2f },
|
||||
{ "I", "L", i2l },
|
||||
{ "I", "F", i2f },
|
||||
{ "I", "RGB", i2rgb },
|
||||
{ "I", "RGBA", i2rgb },
|
||||
{ "I", "RGBX", i2rgb },
|
||||
|
||||
{ "F", "L", f2l },
|
||||
{ "F", "I", f2i },
|
||||
{ "F", "L", f2l },
|
||||
{ "F", "I", f2i },
|
||||
|
||||
{ "RGB", "1", rgb2bit },
|
||||
{ "RGB", "L", rgb2l },
|
||||
|
@ -1385,6 +1404,8 @@ ImagingConvertTransparent(Imaging imIn, const char *mode,
|
|||
}
|
||||
|
||||
if (!((strcmp(imIn->mode, "RGB") == 0 ||
|
||||
strcmp(imIn->mode, "1") == 0 ||
|
||||
strcmp(imIn->mode, "I") == 0 ||
|
||||
strcmp(imIn->mode, "L") == 0)
|
||||
&& strcmp(mode, "RGBA") == 0))
|
||||
#ifdef notdef
|
||||
|
@ -1403,7 +1424,13 @@ ImagingConvertTransparent(Imaging imIn, const char *mode,
|
|||
if (strcmp(imIn->mode, "RGB") == 0) {
|
||||
convert = rgb2rgba;
|
||||
} else {
|
||||
convert = l2rgb;
|
||||
if (strcmp(imIn->mode, "1") == 0) {
|
||||
convert = bit2rgb;
|
||||
} else if (strcmp(imIn->mode, "I") == 0) {
|
||||
convert = i2rgb;
|
||||
} else {
|
||||
convert = l2rgb;
|
||||
}
|
||||
g = b = r;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user