From a609ef4a7ede3983f69e207768276c33b47bf973 Mon Sep 17 00:00:00 2001 From: Yosof Badr <23705518+YosofBadr@users.noreply.github.com> Date: Mon, 15 Jun 2026 16:19:45 +0200 Subject: [PATCH] fix: Thumbnail support for WEBP files inside ZIP --- src/tagstudio/qt/previews/renderer.py | 8 ++++-- tests/qt/test_thumb_renderer.py | 39 +++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 tests/qt/test_thumb_renderer.py diff --git a/src/tagstudio/qt/previews/renderer.py b/src/tagstudio/qt/previews/renderer.py index 866e3df31..620566226 100644 --- a/src/tagstudio/qt/previews/renderer.py +++ b/src/tagstudio/qt/previews/renderer.py @@ -949,7 +949,9 @@ def __cover_from_comic_info( if cover is not None: pages = [f for f in archive.namelist() if f != "ComicInfo.xml"] page_name = pages[int(unwrap(cover.get("Image")))] - if page_name.endswith((".png", ".jpg", ".jpeg", ".gif", ".bmp", ".svg")): + if page_name.lower().endswith( + (".png", ".jpg", ".jpeg", ".gif", ".bmp", ".svg", ".webp") + ): image_data = archive.read(page_name) im = Image.open(BytesIO(image_data)) @@ -1006,7 +1008,9 @@ def __first_image(archive: _Archive) -> Image.Image | None: Image: The first renderable image in the archive. """ for file_name in archive.namelist(): - if file_name.lower().endswith((".png", ".jpg", ".jpeg", ".gif", ".bmp", ".svg")): + if file_name.lower().endswith( + (".png", ".jpg", ".jpeg", ".gif", ".bmp", ".svg", ".webp") + ): image_data = archive.read(file_name) return Image.open(BytesIO(image_data)) diff --git a/tests/qt/test_thumb_renderer.py b/tests/qt/test_thumb_renderer.py new file mode 100644 index 000000000..2015b244b --- /dev/null +++ b/tests/qt/test_thumb_renderer.py @@ -0,0 +1,39 @@ +# SPDX-FileCopyrightText: (c) TagStudio Contributors +# SPDX-License-Identifier: GPL-3.0-only + + +from io import BytesIO +from pathlib import Path +from zipfile import ZipFile + +from PIL import Image + +from tagstudio.qt.previews.renderer import ThumbRenderer + + +def _write_webp_archive(archive_path: Path) -> None: + image_data = BytesIO() + Image.new("RGB", (2, 2), "red").save(image_data, format="WEBP") + + with ZipFile(archive_path, "w") as archive: + archive.writestr("cover.webp", image_data.getvalue()) + + +def test_archive_thumb_extracts_webp_image(tmp_path: Path): + archive_path = tmp_path / "webp_only.zip" + _write_webp_archive(archive_path) + + thumbnail = ThumbRenderer._archive_thumb(archive_path, ".zip") + + assert thumbnail is not None + assert thumbnail.size == (2, 2) + + +def test_epub_cover_extracts_webp_image_from_cbz(tmp_path: Path): + archive_path = tmp_path / "webp_only.cbz" + _write_webp_archive(archive_path) + + thumbnail = ThumbRenderer._epub_cover(archive_path, ".cbz") + + assert thumbnail is not None + assert thumbnail.size == (2, 2)