mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-01-27 09:44:31 +03:00
Merge pull request #3848 from radarhere/pa
Improved palette handling for LA and PA modes
This commit is contained in:
commit
169961649d
|
@ -48,7 +48,7 @@ class TestFileIm(PillowTestCase):
|
||||||
im.seek(n_frames-1)
|
im.seek(n_frames-1)
|
||||||
|
|
||||||
def test_roundtrip(self):
|
def test_roundtrip(self):
|
||||||
for mode in ["RGB", "P"]:
|
for mode in ["RGB", "P", "PA"]:
|
||||||
out = self.tempfile('temp.im')
|
out = self.tempfile('temp.im')
|
||||||
im = hopper(mode)
|
im = hopper(mode)
|
||||||
im.save(out)
|
im.save(out)
|
||||||
|
|
|
@ -489,6 +489,16 @@ class TestFileTiff(PillowTestCase):
|
||||||
self.assert_image_equal_tofile(im,
|
self.assert_image_equal_tofile(im,
|
||||||
"Tests/images/tiff_adobe_deflate.png")
|
"Tests/images/tiff_adobe_deflate.png")
|
||||||
|
|
||||||
|
def test_palette(self):
|
||||||
|
for mode in ["P", "PA"]:
|
||||||
|
outfile = self.tempfile("temp.tif")
|
||||||
|
|
||||||
|
im = hopper(mode)
|
||||||
|
im.save(outfile)
|
||||||
|
|
||||||
|
reloaded = Image.open(outfile)
|
||||||
|
self.assert_image_equal(im.convert("RGB"), reloaded.convert("RGB"))
|
||||||
|
|
||||||
def test_tiff_save_all(self):
|
def test_tiff_save_all(self):
|
||||||
import io
|
import io
|
||||||
import os
|
import os
|
||||||
|
|
|
@ -75,6 +75,15 @@ class TestPickle(PillowTestCase):
|
||||||
protocol=protocol,
|
protocol=protocol,
|
||||||
test_file=test_file)
|
test_file=test_file)
|
||||||
|
|
||||||
|
def test_pickle_pa_mode(self):
|
||||||
|
# Arrange
|
||||||
|
import pickle
|
||||||
|
|
||||||
|
# Act / Assert
|
||||||
|
for protocol in range(0, pickle.HIGHEST_PROTOCOL + 1):
|
||||||
|
self.helper_pickle_string(pickle, protocol, mode="PA")
|
||||||
|
self.helper_pickle_file(pickle, protocol, mode="PA")
|
||||||
|
|
||||||
def test_pickle_l_mode(self):
|
def test_pickle_l_mode(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
import pickle
|
import pickle
|
||||||
|
@ -84,6 +93,24 @@ class TestPickle(PillowTestCase):
|
||||||
self.helper_pickle_string(pickle, protocol, mode="L")
|
self.helper_pickle_string(pickle, protocol, mode="L")
|
||||||
self.helper_pickle_file(pickle, protocol, mode="L")
|
self.helper_pickle_file(pickle, protocol, mode="L")
|
||||||
|
|
||||||
|
def test_pickle_la_mode_with_palette(self):
|
||||||
|
# Arrange
|
||||||
|
import pickle
|
||||||
|
im = Image.open('Tests/images/hopper.jpg')
|
||||||
|
filename = self.tempfile('temp.pkl')
|
||||||
|
im = im.convert("PA")
|
||||||
|
|
||||||
|
# Act / Assert
|
||||||
|
for protocol in range(0, pickle.HIGHEST_PROTOCOL + 1):
|
||||||
|
im.mode = "LA"
|
||||||
|
with open(filename, 'wb') as f:
|
||||||
|
pickle.dump(im, f, protocol)
|
||||||
|
with open(filename, 'rb') as f:
|
||||||
|
loaded_im = pickle.load(f)
|
||||||
|
|
||||||
|
im.mode = "PA"
|
||||||
|
self.assertEqual(im, loaded_im)
|
||||||
|
|
||||||
def test_cpickle_l_mode(self):
|
def test_cpickle_l_mode(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -210,9 +210,9 @@ Instances of the :py:class:`Image` class have the following attributes:
|
||||||
|
|
||||||
.. py:attribute:: palette
|
.. py:attribute:: palette
|
||||||
|
|
||||||
Colour palette table, if any. If mode is “P”, this should be an instance of
|
Colour palette table, if any. If mode is "P" or "PA", this should be an
|
||||||
the :py:class:`~PIL.ImagePalette.ImagePalette` class. Otherwise, it should
|
instance of the :py:class:`~PIL.ImagePalette.ImagePalette` class.
|
||||||
be set to ``None``.
|
Otherwise, it should be set to ``None``.
|
||||||
|
|
||||||
:type: :py:class:`~PIL.ImagePalette.ImagePalette` or ``None``
|
:type: :py:class:`~PIL.ImagePalette.ImagePalette` or ``None``
|
||||||
|
|
||||||
|
|
|
@ -71,6 +71,7 @@ OPEN = {
|
||||||
"RYB3 image": ("RGB", "RYB;T"),
|
"RYB3 image": ("RGB", "RYB;T"),
|
||||||
# extensions
|
# extensions
|
||||||
"LA image": ("LA", "LA;L"),
|
"LA image": ("LA", "LA;L"),
|
||||||
|
"PA image": ("LA", "PA;L"),
|
||||||
"RGBA image": ("RGBA", "RGBA;L"),
|
"RGBA image": ("RGBA", "RGBA;L"),
|
||||||
"RGBX image": ("RGBX", "RGBX;L"),
|
"RGBX image": ("RGBX", "RGBX;L"),
|
||||||
"CMYK image": ("CMYK", "CMYK;L"),
|
"CMYK image": ("CMYK", "CMYK;L"),
|
||||||
|
@ -218,15 +219,16 @@ class ImImageFile(ImageFile.ImageFile):
|
||||||
linear = 0
|
linear = 0
|
||||||
else:
|
else:
|
||||||
greyscale = 0
|
greyscale = 0
|
||||||
if self.mode == "L" or self.mode == "LA":
|
if self.mode in ["L", "LA", "P", "PA"]:
|
||||||
if greyscale:
|
if greyscale:
|
||||||
if not linear:
|
if not linear:
|
||||||
self.lut = [i8(c) for c in palette[:256]]
|
self.lut = [i8(c) for c in palette[:256]]
|
||||||
else:
|
else:
|
||||||
if self.mode == "L":
|
if self.mode in ["L", "P"]:
|
||||||
self.mode = self.rawmode = "P"
|
self.mode = self.rawmode = "P"
|
||||||
elif self.mode == "LA":
|
elif self.mode in ["LA", "PA"]:
|
||||||
self.mode = self.rawmode = "PA"
|
self.mode = "PA"
|
||||||
|
self.rawmode = "PA;L"
|
||||||
self.palette = ImagePalette.raw("RGB;L", palette)
|
self.palette = ImagePalette.raw("RGB;L", palette)
|
||||||
elif self.mode == "RGB":
|
elif self.mode == "RGB":
|
||||||
if not greyscale or not linear:
|
if not greyscale or not linear:
|
||||||
|
@ -340,10 +342,10 @@ def _save(im, fp, filename):
|
||||||
fp.write(("Name: %s\r\n" % filename).encode('ascii'))
|
fp.write(("Name: %s\r\n" % filename).encode('ascii'))
|
||||||
fp.write(("Image size (x*y): %d*%d\r\n" % im.size).encode('ascii'))
|
fp.write(("Image size (x*y): %d*%d\r\n" % im.size).encode('ascii'))
|
||||||
fp.write(("File size (no of images): %d\r\n" % frames).encode('ascii'))
|
fp.write(("File size (no of images): %d\r\n" % frames).encode('ascii'))
|
||||||
if im.mode == "P":
|
if im.mode in ["P", "PA"]:
|
||||||
fp.write(b"Lut: 1\r\n")
|
fp.write(b"Lut: 1\r\n")
|
||||||
fp.write(b"\000" * (511-fp.tell()) + b"\032")
|
fp.write(b"\000" * (511-fp.tell()) + b"\032")
|
||||||
if im.mode == "P":
|
if im.mode in ["P", "PA"]:
|
||||||
fp.write(im.im.getpalette("RGB", "RGB;L")) # 768 bytes
|
fp.write(im.im.getpalette("RGB", "RGB;L")) # 768 bytes
|
||||||
ImageFile._save(im, fp, [("raw", (0, 0)+im.size, 0, (rawmode, 0, -1))])
|
ImageFile._save(im, fp, [("raw", (0, 0)+im.size, 0, (rawmode, 0, -1))])
|
||||||
|
|
||||||
|
|
|
@ -715,7 +715,7 @@ class Image(object):
|
||||||
self.mode = mode
|
self.mode = mode
|
||||||
self._size = size
|
self._size = size
|
||||||
self.im = core.new(mode, size)
|
self.im = core.new(mode, size)
|
||||||
if mode in ("L", "P") and palette:
|
if mode in ("L", "LA", "P", "PA") and palette:
|
||||||
self.putpalette(palette)
|
self.putpalette(palette)
|
||||||
self.frombytes(data)
|
self.frombytes(data)
|
||||||
|
|
||||||
|
|
|
@ -1357,7 +1357,7 @@ class TiffImageFile(ImageFile.ImageFile):
|
||||||
|
|
||||||
# fixup palette descriptor
|
# fixup palette descriptor
|
||||||
|
|
||||||
if self.mode == "P":
|
if self.mode in ["P", "PA"]:
|
||||||
palette = [o8(b // 256) for b in self.tag_v2[COLORMAP]]
|
palette = [o8(b // 256) for b in self.tag_v2[COLORMAP]]
|
||||||
self.palette = ImagePalette.raw("RGB;L", b"".join(palette))
|
self.palette = ImagePalette.raw("RGB;L", b"".join(palette))
|
||||||
|
|
||||||
|
@ -1483,7 +1483,7 @@ def _save(im, fp, filename):
|
||||||
|
|
||||||
ifd[PHOTOMETRIC_INTERPRETATION] = photo
|
ifd[PHOTOMETRIC_INTERPRETATION] = photo
|
||||||
|
|
||||||
if im.mode == "P":
|
if im.mode in ["P", "PA"]:
|
||||||
lut = im.im.getpalette("RGB", "RGB;L")
|
lut = im.im.getpalette("RGB", "RGB;L")
|
||||||
ifd[COLORMAP] = tuple(i8(v) * 256 for v in lut)
|
ifd[COLORMAP] = tuple(i8(v) * 256 for v in lut)
|
||||||
# data orientation
|
# data orientation
|
||||||
|
|
|
@ -1588,7 +1588,7 @@ _putpalette(ImagingObject* self, PyObject* args)
|
||||||
|
|
||||||
ImagingPaletteDelete(self->image->palette);
|
ImagingPaletteDelete(self->image->palette);
|
||||||
|
|
||||||
strcpy(self->image->mode, "P");
|
strcpy(self->image->mode, strlen(self->image->mode) == 2 ? "PA" : "P");
|
||||||
|
|
||||||
self->image->palette = ImagingPaletteNew("RGB");
|
self->image->palette = ImagingPaletteNew("RGB");
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user