Skip to content

Commit fff9676

Browse files
authored
feat: add cached thumb quaity and resolution settings (#1101)
1 parent 7a8d34e commit fff9676

File tree

4 files changed

+41
-12
lines changed

4 files changed

+41
-12
lines changed

src/tagstudio/core/global_settings.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@
2424
DEFAULT_THUMB_CACHE_SIZE = 500 # Number in MiB
2525
MIN_THUMB_CACHE_SIZE = 10 # Number in MiB
2626

27+
# See: https://pillow.readthedocs.io/en/stable/handbook/image-file-formats.html#webp-saving
28+
DEFAULT_CACHED_IMAGE_QUALITY = 80
29+
DEFAULT_CACHED_IMAGE_RES = 256
30+
2731

2832
class Theme(IntEnum):
2933
DARK = 0
@@ -56,6 +60,8 @@ class GlobalSettings(BaseModel):
5660
open_last_loaded_on_startup: bool = Field(default=True)
5761
generate_thumbs: bool = Field(default=True)
5862
thumb_cache_size: float = Field(default=DEFAULT_THUMB_CACHE_SIZE)
63+
cached_thumb_quality: int = Field(default=DEFAULT_CACHED_IMAGE_QUALITY)
64+
cached_thumb_resolution: int = Field(default=DEFAULT_CACHED_IMAGE_RES)
5965
autoplay: bool = Field(default=True)
6066
loop: bool = Field(default=True)
6167
show_filenames_in_grid: bool = Field(default=True)

src/tagstudio/qt/cache_manager.py

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from PIL import Image
1313

1414
from tagstudio.core.constants import THUMB_CACHE_NAME, TS_FOLDER_NAME
15-
from tagstudio.core.global_settings import DEFAULT_THUMB_CACHE_SIZE
15+
from tagstudio.core.global_settings import DEFAULT_CACHED_IMAGE_QUALITY, DEFAULT_THUMB_CACHE_SIZE
1616

1717
logger = structlog.get_logger(__name__)
1818

@@ -24,26 +24,31 @@ def __init__(self, path: Path, size: int):
2424

2525

2626
class CacheManager:
27-
MAX_FOLDER_SIZE = 10 # Number in MiB
27+
MAX_FOLDER_SIZE = 10 # Absolute maximum size of a folder, number in MiB
2828
STAT_MULTIPLIER = 1_000_000 # Multiplier to apply to file stats (bytes) to get user units (MiB)
2929

3030
def __init__(
3131
self,
3232
library_dir: Path,
3333
max_size: int | float = DEFAULT_THUMB_CACHE_SIZE,
34+
img_quality: int = DEFAULT_CACHED_IMAGE_QUALITY,
3435
):
3536
"""A class for managing frontend caches, such as for file thumbnails.
3637
3738
Args:
3839
library_dir(Path): The path of the folder containing the .TagStudio library folder.
3940
max_size: (int | float) The maximum size of the cache, in MiB.
41+
img_quality: (int) The image quality value to save PIL images (0-100, default=80)
4042
"""
4143
self._lock = RLock()
4244
self.cache_path = library_dir / TS_FOLDER_NAME / THUMB_CACHE_NAME
4345
self.max_size: int = max(
4446
math.floor(max_size * CacheManager.STAT_MULTIPLIER),
4547
math.floor(CacheManager.MAX_FOLDER_SIZE * CacheManager.STAT_MULTIPLIER),
4648
)
49+
self.img_quality = (
50+
img_quality if img_quality >= 0 and img_quality <= 100 else DEFAULT_CACHED_IMAGE_QUALITY
51+
)
4752

4853
self.folders: list[CacheFolder] = []
4954
self.current_size = 0
@@ -127,12 +132,20 @@ def save_image(self, image: Image.Image, file_name: Path, mode: str = "RGBA"):
127132
with self._lock as _lock:
128133
cache_folder: CacheFolder = self._get_current_folder()
129134
file_path = cache_folder.path / file_name
130-
image.save(file_path, mode=mode)
135+
try:
136+
image.save(file_path, mode=mode, quality=self.img_quality)
131137

132-
size = file_path.stat().st_size
133-
cache_folder.size += size
134-
self.current_size += size
135-
self._cull_folders()
138+
size = file_path.stat().st_size
139+
cache_folder.size += size
140+
self.current_size += size
141+
self._cull_folders()
142+
except FileNotFoundError:
143+
logger.warn(
144+
"[CacheManager] Failed to save cached image, was the folder deleted on disk?",
145+
folder=file_path,
146+
)
147+
if not cache_folder.path.exists():
148+
self.folders.remove(cache_folder)
136149

137150
def _create_folder(self) -> CacheFolder:
138151
with self._lock as _lock:

src/tagstudio/qt/ts_qt.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1697,7 +1697,11 @@ def open_library(self, path: Path) -> None:
16971697
open_status = LibraryStatus(
16981698
success=False, library_path=path, message=type(e).__name__, msg_description=str(e)
16991699
)
1700-
self.cache_manager = CacheManager(path, max_size=self.settings.thumb_cache_size)
1700+
self.cache_manager = CacheManager(
1701+
path,
1702+
max_size=self.settings.thumb_cache_size,
1703+
img_quality=self.settings.cached_thumb_quality,
1704+
)
17011705
logger.info(
17021706
f"[Config] Thumbnail Cache Size: {format_size(self.settings.thumb_cache_size)}",
17031707
)

src/tagstudio/qt/widgets/thumb_renderer.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
FONT_SAMPLE_TEXT,
5656
)
5757
from tagstudio.core.exceptions import NoRendererError
58+
from tagstudio.core.global_settings import DEFAULT_CACHED_IMAGE_RES
5859
from tagstudio.core.library.ignore import Ignore
5960
from tagstudio.core.media_types import MediaCategories, MediaType
6061
from tagstudio.core.palette import UI_COLORS, ColorType, UiColor, get_ui_color
@@ -94,16 +95,21 @@ class ThumbRenderer(QObject):
9495
rm: ResourceManager = ResourceManager()
9596
updated = Signal(float, QPixmap, QSize, Path)
9697
updated_ratio = Signal(float)
97-
98-
cached_img_res: int = 256 # TODO: Pull this from config
99-
cached_img_ext: str = ".webp" # TODO: Pull this from config
98+
cached_img_ext: str = ".webp"
10099

101100
def __init__(self, driver: "QtDriver", library: "Library") -> None:
102101
"""Initialize the class."""
103102
super().__init__()
104103
self.driver = driver
105104
self.lib = library
106105

106+
settings_res = self.driver.settings.cached_thumb_resolution
107+
self.cached_img_res = (
108+
settings_res
109+
if settings_res >= 16 and settings_res <= 2048
110+
else DEFAULT_CACHED_IMAGE_RES
111+
)
112+
107113
# Cached thumbnail elements.
108114
# Key: Size + Pixel Ratio Tuple + Radius Scale
109115
# (Ex. (512, 512, 1.25, 4))
@@ -1404,7 +1410,7 @@ def fetch_cached_image(file_name: Path):
14041410
image = self._render(
14051411
timestamp,
14061412
filepath,
1407-
(ThumbRenderer.cached_img_res, ThumbRenderer.cached_img_res),
1413+
(self.cached_img_res, self.cached_img_res),
14081414
1,
14091415
is_grid_thumb,
14101416
save_to_file=file_name,

0 commit comments

Comments
 (0)