diff --git a/tagstudio/src/qt/widgets/thumb_renderer.py b/tagstudio/src/qt/widgets/thumb_renderer.py index 83eb1c579..377a5f730 100644 --- a/tagstudio/src/qt/widgets/thumb_renderer.py +++ b/tagstudio/src/qt/widgets/thumb_renderer.py @@ -28,8 +28,9 @@ from PIL.Image import DecompressionBombError from pillow_heif import register_avif_opener, register_heif_opener from pydub import exceptions -from PySide6.QtCore import QObject, QSize, Qt, Signal -from PySide6.QtGui import QGuiApplication, QPixmap +from PySide6.QtCore import QBuffer, QObject, QSize, Qt, Signal +from PySide6.QtGui import QGuiApplication, QImage, QPainter, QPixmap +from PySide6.QtSvg import QSvgRenderer from src.core.constants import FONT_SAMPLE_SIZES, FONT_SAMPLE_TEXT from src.core.media_types import MediaCategories, MediaType from src.core.palette import ColorType, UiColor, get_ui_color @@ -750,8 +751,33 @@ def _image_vector_thumb(self, filepath: Path, size: int) -> Image.Image: filepath (Path): The path of the file. size (tuple[int,int]): The size of the thumbnail. """ - # TODO: Implement. im: Image.Image = None + # Create an image to draw the svg to and a painter to do the drawing + image: QImage = QImage(size, size, QImage.Format.Format_ARGB32) + image.fill("#1e1e1e") + + # Create an svg renderer, then render to the painter + svg: QSvgRenderer = QSvgRenderer(str(filepath)) + + if not svg.isValid(): + raise UnidentifiedImageError + + painter: QPainter = QPainter(image) + svg.setAspectRatioMode(Qt.AspectRatioMode.KeepAspectRatio) + svg.render(painter) + painter.end() + + # Write the image to a buffer as png + buffer: QBuffer = QBuffer() + buffer.open(QBuffer.OpenModeFlag.ReadWrite) + image.save(buffer, "PNG") + + # Load the image from the buffer + im = Image.new("RGB", (size, size), color="#1e1e1e") + im.paste(Image.open(BytesIO(buffer.data().data()))) + im = im.convert(mode="RGB") + + buffer.close() return im def _model_stl_thumb(self, filepath: Path, size: int) -> Image.Image: @@ -924,6 +950,7 @@ def render( ext, MediaCategories.IMAGE_RAW_TYPES, mime_fallback=True ): image = self._image_raw_thumb(_filepath) + # Vector Images -------------------------------------------- elif MediaCategories.is_ext_in_category( ext, MediaCategories.IMAGE_VECTOR_TYPES, mime_fallback=True ): diff --git a/tagstudio/tests/fixtures/sample.svg b/tagstudio/tests/fixtures/sample.svg new file mode 100644 index 000000000..99c924a86 --- /dev/null +++ b/tagstudio/tests/fixtures/sample.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/tagstudio/tests/qt/__snapshots__/test_thumb_renderer/test_svg_preview.png b/tagstudio/tests/qt/__snapshots__/test_thumb_renderer/test_svg_preview.png new file mode 100644 index 000000000..ebd904314 Binary files /dev/null and b/tagstudio/tests/qt/__snapshots__/test_thumb_renderer/test_svg_preview.png differ diff --git a/tagstudio/tests/qt/test_thumb_renderer.py b/tagstudio/tests/qt/test_thumb_renderer.py new file mode 100644 index 000000000..c9f675955 --- /dev/null +++ b/tagstudio/tests/qt/test_thumb_renderer.py @@ -0,0 +1,21 @@ +# Copyright (C) 2024 Travis Abendshien (CyanVoxel). +# Licensed under the GPL-3.0 License. +# Created for TagStudio: https://github.com/CyanVoxel/TagStudio + +import io +from pathlib import Path + +from PIL import Image +from src.qt.widgets.thumb_renderer import ThumbRenderer +from syrupy.extensions.image import PNGImageSnapshotExtension + + +def test_svg_preview(cwd, snapshot): + file_path: Path = cwd / "fixtures" / "sample.svg" + renderer = ThumbRenderer() + img: Image.Image = renderer._image_vector_thumb(file_path, 200) + + img_bytes = io.BytesIO() + img.save(img_bytes, format="PNG") + img_bytes.seek(0) + assert img_bytes.read() == snapshot(extension_class=PNGImageSnapshotExtension)