removes Pillow dependency, updates Image component

This commit is contained in:
Mose Müller 2024-07-09 07:52:18 +02:00
parent 29558758af
commit 44d5a98449
3 changed files with 597 additions and 557 deletions

1100
poetry.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -15,7 +15,6 @@ toml = "^0.10.2"
python-socketio = "^5.8.0" python-socketio = "^5.8.0"
confz = "^2.0.0" confz = "^2.0.0"
pint = "^0.22" pint = "^0.22"
pillow = "^10.0.0"
websocket-client = "^1.7.0" websocket-client = "^1.7.0"
aiohttp = "^3.9.3" aiohttp = "^3.9.3"

View File

@ -5,8 +5,6 @@ from pathlib import Path
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from urllib.request import urlopen from urllib.request import urlopen
import PIL.Image # type: ignore[import-untyped]
from pydase.data_service.data_service import DataService from pydase.data_service.data_service import DataService
if TYPE_CHECKING: if TYPE_CHECKING:
@ -16,9 +14,7 @@ logger = logging.getLogger(__name__)
class Image(DataService): class Image(DataService):
def __init__( def __init__(self) -> None:
self,
) -> None:
super().__init__() super().__init__()
self._value: str = "" self._value: str = ""
self._format: str = "" self._format: str = ""
@ -32,8 +28,14 @@ class Image(DataService):
return self._format return self._format
def load_from_path(self, path: Path | str) -> None: def load_from_path(self, path: Path | str) -> None:
with PIL.Image.open(path) as image: with open(path, "rb") as image_file:
self._load_from_pil(image) image_data = image_file.read()
format_ = self._get_image_format_from_bytes(image_data)
if format_ is None:
logger.error("Unsupported image format. Skipping...")
return
value_ = base64.b64encode(image_data)
self._load_from_base64(value_, format_)
def load_from_matplotlib_figure(self, fig: "Figure", format_: str = "png") -> None: def load_from_matplotlib_figure(self, fig: "Figure", format_: str = "png") -> None:
buffer = io.BytesIO() buffer = io.BytesIO()
@ -42,12 +44,18 @@ class Image(DataService):
self._load_from_base64(value_, format_) self._load_from_base64(value_, format_)
def load_from_url(self, url: str) -> None: def load_from_url(self, url: str) -> None:
image = PIL.Image.open(urlopen(url)) with urlopen(url) as response:
self._load_from_pil(image) image_data = response.read()
format_ = self._get_image_format_from_bytes(image_data)
if format_ is None:
logger.error("Unsupported image format. Skipping...")
return
value_ = base64.b64encode(image_data)
self._load_from_base64(value_, format_)
def load_from_base64(self, value_: bytes, format_: str | None = None) -> None: def load_from_base64(self, value_: bytes, format_: str | None = None) -> None:
if format_ is None: if format_ is None:
format_ = self._get_image_format_from_bytes(value_) format_ = self._get_image_format_from_bytes(base64.b64decode(value_))
if format_ is None: if format_ is None:
logger.warning( logger.warning(
"Format of passed byte string could not be determined. Skipping..." "Format of passed byte string could not be determined. Skipping..."
@ -60,19 +68,14 @@ class Image(DataService):
self._value = value self._value = value
self._format = format_ self._format = format_
def _load_from_pil(self, image: PIL.Image.Image) -> None:
if image.format is not None:
format_ = image.format
buffer = io.BytesIO()
image.save(buffer, format=format_)
value_ = base64.b64encode(buffer.getvalue())
self._load_from_base64(value_, format_)
else:
logger.error("Image format is 'None'. Skipping...")
def _get_image_format_from_bytes(self, value_: bytes) -> str | None: def _get_image_format_from_bytes(self, value_: bytes) -> str | None:
image_data = base64.b64decode(value_) format_map = {
# Create a writable memory buffer for the image b"\xff\xd8": "JPEG",
image_buffer = io.BytesIO(image_data) b"\x89PNG": "PNG",
# Read the image from the buffer and return format b"GIF": "GIF",
return PIL.Image.open(image_buffer).format b"RIFF": "WEBP",
}
for signature, format_name in format_map.items():
if value_.startswith(signature):
return format_name
return None