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 __future__ import annotations
|
||||||
|
|
||||||
|
from io import BytesIO
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
@ -718,6 +719,25 @@ def test_apng_save_size(tmp_path: Path) -> None:
|
||||||
assert reloaded.size == (200, 200)
|
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:
|
def test_seek_after_close() -> None:
|
||||||
im = Image.open("Tests/images/apng/delay.png")
|
im = Image.open("Tests/images/apng/delay.png")
|
||||||
im.seek(1)
|
im.seek(1)
|
||||||
|
|
|
||||||
|
|
@ -1154,6 +1154,15 @@ class _fdat:
|
||||||
self.seq_num += 1
|
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):
|
class _Frame(NamedTuple):
|
||||||
im: Image.Image
|
im: Image.Image
|
||||||
bbox: tuple[int, int, int, int] | None
|
bbox: tuple[int, int, int, int] | None
|
||||||
|
|
@ -1247,10 +1256,10 @@ def _write_multiple_frames(
|
||||||
|
|
||||||
# default image IDAT (if it exists)
|
# default image IDAT (if it exists)
|
||||||
if default_image:
|
if default_image:
|
||||||
if im.mode != mode:
|
default_im = im if im.mode == mode else im.convert(mode)
|
||||||
im = im.convert(mode)
|
_apply_encoderinfo(default_im, im.encoderinfo)
|
||||||
ImageFile._save(
|
ImageFile._save(
|
||||||
im,
|
default_im,
|
||||||
cast(IO[bytes], _idat(fp, chunk)),
|
cast(IO[bytes], _idat(fp, chunk)),
|
||||||
[ImageFile._Tile("zip", (0, 0) + im.size, 0, rawmode)],
|
[ImageFile._Tile("zip", (0, 0) + im.size, 0, rawmode)],
|
||||||
)
|
)
|
||||||
|
|
@ -1284,6 +1293,7 @@ def _write_multiple_frames(
|
||||||
)
|
)
|
||||||
seq_num += 1
|
seq_num += 1
|
||||||
# frame data
|
# frame data
|
||||||
|
_apply_encoderinfo(im_frame, im.encoderinfo)
|
||||||
if frame == 0 and not default_image:
|
if frame == 0 and not default_image:
|
||||||
# first frame must be in IDAT chunks for backwards compatibility
|
# first frame must be in IDAT chunks for backwards compatibility
|
||||||
ImageFile._save(
|
ImageFile._save(
|
||||||
|
|
@ -1359,14 +1369,6 @@ def _save(
|
||||||
bits = 4
|
bits = 4
|
||||||
outmode += f";{bits}"
|
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
|
# get the corresponding PNG mode
|
||||||
try:
|
try:
|
||||||
rawmode, bit_depth, color_type = _OUTMODES[outmode]
|
rawmode, bit_depth, color_type = _OUTMODES[outmode]
|
||||||
|
|
@ -1496,6 +1498,7 @@ def _save(
|
||||||
im, fp, chunk, mode, rawmode, default_image, append_images
|
im, fp, chunk, mode, rawmode, default_image, append_images
|
||||||
)
|
)
|
||||||
if single_im:
|
if single_im:
|
||||||
|
_apply_encoderinfo(single_im, im.encoderinfo)
|
||||||
ImageFile._save(
|
ImageFile._save(
|
||||||
single_im,
|
single_im,
|
||||||
cast(IO[bytes], _idat(fp, chunk)),
|
cast(IO[bytes], _idat(fp, chunk)),
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user