mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-12-03 16:24:24 +03:00
Apply encoder options when saving multiple PNG frames (#9300)
This commit is contained in:
commit
77e16b1030
|
|
@ -1,5 +1,6 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from io import BytesIO
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
|
@ -718,6 +719,25 @@ def test_apng_save_size(tmp_path: Path) -> None:
|
|||
assert reloaded.size == (200, 200)
|
||||
|
||||
|
||||
def test_compress_level() -> None:
|
||||
compress_level_sizes = {}
|
||||
for compress_level in (0, 9):
|
||||
out = BytesIO()
|
||||
|
||||
im = Image.new("L", (100, 100))
|
||||
im.save(
|
||||
out,
|
||||
"PNG",
|
||||
save_all=True,
|
||||
append_images=[Image.new("L", (200, 200))],
|
||||
compress_level=compress_level,
|
||||
)
|
||||
|
||||
compress_level_sizes[compress_level] = len(out.getvalue())
|
||||
|
||||
assert compress_level_sizes[0] > compress_level_sizes[9]
|
||||
|
||||
|
||||
def test_seek_after_close() -> None:
|
||||
im = Image.open("Tests/images/apng/delay.png")
|
||||
im.seek(1)
|
||||
|
|
|
|||
|
|
@ -1154,6 +1154,15 @@ class _fdat:
|
|||
self.seq_num += 1
|
||||
|
||||
|
||||
def _apply_encoderinfo(im: Image.Image, encoderinfo: dict[str, Any]) -> None:
|
||||
im.encoderconfig = (
|
||||
encoderinfo.get("optimize", False),
|
||||
encoderinfo.get("compress_level", -1),
|
||||
encoderinfo.get("compress_type", -1),
|
||||
encoderinfo.get("dictionary", b""),
|
||||
)
|
||||
|
||||
|
||||
class _Frame(NamedTuple):
|
||||
im: Image.Image
|
||||
bbox: tuple[int, int, int, int] | None
|
||||
|
|
@ -1247,10 +1256,10 @@ def _write_multiple_frames(
|
|||
|
||||
# default image IDAT (if it exists)
|
||||
if default_image:
|
||||
if im.mode != mode:
|
||||
im = im.convert(mode)
|
||||
default_im = im if im.mode == mode else im.convert(mode)
|
||||
_apply_encoderinfo(default_im, im.encoderinfo)
|
||||
ImageFile._save(
|
||||
im,
|
||||
default_im,
|
||||
cast(IO[bytes], _idat(fp, chunk)),
|
||||
[ImageFile._Tile("zip", (0, 0) + im.size, 0, rawmode)],
|
||||
)
|
||||
|
|
@ -1284,6 +1293,7 @@ def _write_multiple_frames(
|
|||
)
|
||||
seq_num += 1
|
||||
# frame data
|
||||
_apply_encoderinfo(im_frame, im.encoderinfo)
|
||||
if frame == 0 and not default_image:
|
||||
# first frame must be in IDAT chunks for backwards compatibility
|
||||
ImageFile._save(
|
||||
|
|
@ -1359,14 +1369,6 @@ def _save(
|
|||
bits = 4
|
||||
outmode += f";{bits}"
|
||||
|
||||
# encoder options
|
||||
im.encoderconfig = (
|
||||
im.encoderinfo.get("optimize", False),
|
||||
im.encoderinfo.get("compress_level", -1),
|
||||
im.encoderinfo.get("compress_type", -1),
|
||||
im.encoderinfo.get("dictionary", b""),
|
||||
)
|
||||
|
||||
# get the corresponding PNG mode
|
||||
try:
|
||||
rawmode, bit_depth, color_type = _OUTMODES[outmode]
|
||||
|
|
@ -1496,6 +1498,7 @@ def _save(
|
|||
im, fp, chunk, mode, rawmode, default_image, append_images
|
||||
)
|
||||
if single_im:
|
||||
_apply_encoderinfo(single_im, im.encoderinfo)
|
||||
ImageFile._save(
|
||||
single_im,
|
||||
cast(IO[bytes], _idat(fp, chunk)),
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user