from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from arcade.texture import ImageData
[docs]
class ImageDataCache:
"""
Simple cache for ImageData objects.
These are usually cached using the absolute path to the file
or some custom unique name if generated from code.
We are not caching by image hash because this defeats the purpose
of this cache. We want to obtain and image based on a value that
can be constructed without knowing the pixel data.
The reasoning for caching the ImageData object instead of the
PIL.Image object is to avoid re-calculating the hash in addition
to eliminating the need to load it and convert the pixel format.
"""
def __init__(self):
self._entries: dict[str, ImageData] = {}
[docs]
def put(self, name: str, image: ImageData):
"""
Add an image to the cache.
An entry can only be cached as either strong or weak, not both.
If and existing entry is found, it will be replaced.
Args:
name: Name of the image
image: ImageData object
"""
from arcade.texture import ImageData
if not isinstance(image, ImageData):
raise TypeError("image must be an instance of ImageData")
self._entries[name] = image
[docs]
def get(self, name: str) -> ImageData | None:
"""
Attempts to retrieve an entry from the cache.
Args:
name: Name of the image
Returns:
ImageData instance or ``None`` if not found
"""
return self._entries.get(name)
[docs]
def delete(self, name: str, raise_if_not_exist: bool = False) -> None:
"""
Attempts to delete an entry from the cache.
Args:
name:
Name of the image
raise_if_not_exist:
If ``True``, raises ``KeyError`` if the entry does not exist
"""
try:
del self._entries[name]
except KeyError:
if raise_if_not_exist:
raise
[docs]
def flush(self):
"""Clears the cache."""
self._entries.clear()
def __len__(self):
return len(self._entries)
def __getitem__(self, name: str) -> ImageData | None:
return self.get(name)
def __setitem__(self, name: str, image: ImageData):
self.put(name, image)
def __delitem__(self, name: str):
self.delete(name, raise_if_not_exist=True)