Added progress callback to AVIF

This commit is contained in:
Andrew Murray 2025-04-21 13:33:15 +10:00
parent 09e4df10af
commit 5da88ea931
7 changed files with 66 additions and 30 deletions

View File

@ -1,5 +1,6 @@
from __future__ import annotations
import os
from io import BytesIO
from pathlib import Path
@ -710,11 +711,9 @@ def test_save_all_progress() -> None:
out = BytesIO()
progress = []
def callback(state):
def callback(state) -> None:
if state["image_filename"]:
state["image_filename"] = (
state["image_filename"].replace("\\", "/").split("Tests/images/")[-1]
)
state["image_filename"] = os.path.basename(state["image_filename"])
progress.append(state)
Image.new("RGB", (1, 1)).save(out, "PNG", save_all=True, progress=callback)
@ -741,7 +740,7 @@ def test_save_all_progress() -> None:
expected.append(
{
"image_index": i,
"image_filename": "apng/single_frame.png",
"image_filename": "single_frame.png",
"completed_frames": i + 1,
"total_frames": 7,
}
@ -750,7 +749,7 @@ def test_save_all_progress() -> None:
expected.append(
{
"image_index": 2,
"image_filename": "apng/delay.png",
"image_filename": "delay.png",
"completed_frames": i + 3,
"total_frames": 7,
}

View File

@ -217,6 +217,52 @@ class TestFileAvif:
with Image.open(blob) as im:
im.load()
def test_save_all_progress(self) -> None:
out = BytesIO()
progress = []
def callback(state) -> None:
if state["image_filename"]:
state["image_filename"] = os.path.basename(state["image_filename"])
progress.append(state)
Image.new("RGB", (1, 1)).save(out, "AVIF", save_all=True, progress=callback)
assert progress == [
{
"image_index": 0,
"image_filename": None,
"completed_frames": 1,
"total_frames": 1,
}
]
out = BytesIO()
progress = []
with Image.open("Tests/images/avif/star.avifs") as im:
im2 = Image.new(im.mode, im.size)
im.save(out, "AVIF", save_all=True, append_images=[im2], progress=callback)
expected = []
for i in range(5):
expected.append(
{
"image_index": 0,
"image_filename": "star.avifs",
"completed_frames": i + 1,
"total_frames": 6,
}
)
expected.append(
{
"image_index": 1,
"image_filename": None,
"completed_frames": 6,
"total_frames": 6,
}
)
assert progress == expected
def test_background_from_gif(self, tmp_path: Path) -> None:
with Image.open("Tests/images/chi.gif") as im:
original_value = im.convert("RGB").getpixel((1, 1))

View File

@ -1,5 +1,6 @@
from __future__ import annotations
import os
import warnings
from collections.abc import Generator
from io import BytesIO
@ -296,15 +297,13 @@ def test_roundtrip_save_all_1(tmp_path: Path) -> None:
assert reloaded.getpixel((0, 0)) == 255
def test_save_all_progress():
def test_save_all_progress() -> None:
out = BytesIO()
progress = []
def callback(state):
def callback(state) -> None:
if state["image_filename"]:
state["image_filename"] = (
state["image_filename"].replace("\\", "/").split("Tests/images/")[-1]
)
state["image_filename"] = os.path.basename(state["image_filename"])
progress.append(state)
Image.new("RGB", (1, 1)).save(out, "GIF", save_all=True, progress=callback)
@ -324,7 +323,7 @@ def test_save_all_progress():
im = Image.new("RGB", im2.size)
im.save(out, "GIF", save_all=True, append_images=[im2], progress=callback)
expected = [
expected: list[dict[str, int | str | None]] = [
{
"image_index": 0,
"image_filename": None,

View File

@ -178,11 +178,9 @@ def test_save_all_progress() -> None:
out = BytesIO()
progress = []
def callback(state):
def callback(state) -> None:
if state["image_filename"]:
state["image_filename"] = (
state["image_filename"].replace("\\", "/").split("Tests/images/")[-1]
)
state["image_filename"] = os.path.basename(state["image_filename"])
progress.append(state)
Image.new("RGB", (1, 1)).save(out, "PDF", save_all=True, progress=callback)

View File

@ -797,13 +797,9 @@ class TestFileTiff:
out = BytesIO()
progress = []
def callback(state):
def callback(state) -> None:
if state["image_filename"]:
state["image_filename"] = (
state["image_filename"]
.replace("\\", "/")
.split("Tests/images/")[-1]
)
state["image_filename"] = os.path.basename(state["image_filename"])
progress.append(state)
Image.new("RGB", (1, 1)).save(out, "TIFF", save_all=True, progress=callback)

View File

@ -1,5 +1,6 @@
from __future__ import annotations
import os
import re
import sys
import warnings
@ -129,18 +130,13 @@ class TestFileWebp:
with pytest.raises(ValueError):
_webp.WebPEncode(im.getim(), False, 0, 0, "", 4, 0, b"", "")
@skip_unless_feature("webp_anim")
def test_save_all_progress(self) -> None:
out = BytesIO()
progress = []
def callback(state):
def callback(state) -> None:
if state["image_filename"]:
state["image_filename"] = (
state["image_filename"]
.replace("\\", "/")
.split("Tests/images/")[-1]
)
state["image_filename"] = os.path.basename(state["image_filename"])
progress.append(state)
Image.new("RGB", (1, 1)).save(out, "WEBP", save_all=True, progress=callback)

View File

@ -236,8 +236,9 @@ def _save(
frame_duration = 0
cur_idx = im.tell()
is_single_frame = total == 1
progress = info.get("progress")
try:
for ims in [im] + append_images:
for i, ims in enumerate([im] + append_images):
# Get number of frames in this image
nfr = getattr(ims, "n_frames", 1)
@ -268,6 +269,7 @@ def _save(
# Update frame index
frame_idx += 1
im._save_all_progress(progress, ims, i, frame_idx, total)
if not save_all:
break