>>> image.save('copy.png',save_all=True)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\...\.venv\Lib\site-packages\PIL\Image.py", line 2459, in save
save_handler(self, fp, filename)
File "C:\...\.venv\Lib\site-packages\PIL\PngImagePlugin.py", line 1230, in _save_all
_save(im, fp, filename, save_all=True)
File "C:\...\.venv\Lib\site-packages\PIL\PngImagePlugin.py", line 1408, in _save
im = _write_multiple_frames(
^^^^^^^^^^^^^^^^^^^^^^^
File "C:\...\.venv\Lib\site-packages\PIL\PngImagePlugin.py", line 1117, in _write_multiple_frames
im_frame = im_frame.convert(rawmode)
^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\...\.venv\Lib\site-packages\PIL\Image.py", line 1087, in convert
im = self.im.convert(mode, dither)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ValueError: conversion not supported
The image isn't mine to share, but it's a P mode image with only 9 colors. This causes it to hit this bit of code:
|
if mode == "P": |
|
# |
|
# attempt to minimize storage requirements for palette images |
|
if "bits" in im.encoderinfo: |
|
# number of bits specified by user |
|
colors = min(1 << im.encoderinfo["bits"], 256) |
|
else: |
|
# check palette contents |
|
if im.palette: |
|
colors = max(min(len(im.palette.getdata()[1]) // 3, 256), 1) |
|
else: |
|
colors = 256 |
|
|
|
if colors <= 16: |
|
if colors <= 2: |
|
bits = 1 |
|
elif colors <= 4: |
|
bits = 2 |
|
else: |
|
bits = 4 |
|
mode = f"{mode};{bits}" |
Which changes mode to P;4. Then when getting the output rawmode:
|
rawmode, mode = _OUTMODES[mode] |
|
_OUTMODES = { |
|
# supported PIL modes, and corresponding rawmodes/bits/color combinations |
|
"1": ("1", b"\x01\x00"), |
|
"L;1": ("L;1", b"\x01\x00"), |
|
"L;2": ("L;2", b"\x02\x00"), |
|
"L;4": ("L;4", b"\x04\x00"), |
|
"L": ("L", b"\x08\x00"), |
|
"LA": ("LA", b"\x08\x04"), |
|
"I": ("I;16B", b"\x10\x00"), |
|
"I;16": ("I;16B", b"\x10\x00"), |
|
"I;16B": ("I;16B", b"\x10\x00"), |
|
"P;1": ("P;1", b"\x01\x03"), |
|
"P;2": ("P;2", b"\x02\x03"), |
|
"P;4": ("P;4", b"\x04\x03"), |
|
"P": ("P", b"\x08\x03"), |
|
"RGB": ("RGB", b"\x08\x02"), |
|
"RGBA": ("RGBA", b"\x08\x06"), |
|
} |
It gets a rawmode of P;4. This would all be fine, except I passed True for the save_all parameter, which causes a branch here:
|
if save_all: |
|
im = _write_multiple_frames( |
|
im, fp, chunk, rawmode, default_image, append_images |
|
) |
|
if im: |
|
ImageFile._save(im, _idat(fp, chunk), [("zip", (0, 0) + im.size, 0, rawmode)]) |
Inside _write_multiple_frames is this bit of code:
|
if im_frame.mode == rawmode: |
|
im_frame = im_frame.copy() |
|
else: |
|
im_frame = im_frame.convert(rawmode) |
Now since the actual image mode is P, but the requested rawmode is P;4, it tries to convert from P to P;4, which fails, because Image.convert() takes modes, not rawmodes, and P;4 is not a valid mode.
This method also attempts to convert to a rawmode a bit further on as well:
|
if default_image: |
|
if im.mode != rawmode: |
|
im = im.convert(rawmode) |
A basic search of the rest of Pillow's code only shows one other instance of ".convert(rawmode)" (in WebPImagePlugin), but it's okay in that case because the rawmode is set on the prior line to be either "RGB" or "RGBA".
The image isn't mine to share, but it's a
Pmode image with only 9 colors. This causes it to hit this bit of code:Pillow/src/PIL/PngImagePlugin.py
Lines 1265 to 1285 in 8b14ed7
Which changes
modetoP;4. Then when getting the output rawmode:Pillow/src/PIL/PngImagePlugin.py
Line 1297 in 8b14ed7
Pillow/src/PIL/PngImagePlugin.py
Lines 1052 to 1069 in 8b14ed7
It gets a rawmode of
P;4. This would all be fine, except I passedTruefor thesave_allparameter, which causes a branch here:Pillow/src/PIL/PngImagePlugin.py
Lines 1415 to 1420 in 8b14ed7
Inside
_write_multiple_framesis this bit of code:Pillow/src/PIL/PngImagePlugin.py
Lines 1122 to 1125 in 8b14ed7
Now since the actual image mode is
P, but the requested rawmode isP;4, it tries to convert fromPtoP;4, which fails, becauseImage.convert()takes modes, not rawmodes, andP;4is not a valid mode.This method also attempts to convert to a rawmode a bit further on as well:
Pillow/src/PIL/PngImagePlugin.py
Lines 1186 to 1188 in 8b14ed7
A basic search of the rest of Pillow's code only shows one other instance of ".convert(rawmode)" (in
WebPImagePlugin), but it's okay in that case because the rawmode is set on the prior line to be either "RGB" or "RGBA".