diff --git a/frontend/src/components/GenericComponent.tsx b/frontend/src/components/GenericComponent.tsx
index 38af0c6..be09e98 100644
--- a/frontend/src/components/GenericComponent.tsx
+++ b/frontend/src/components/GenericComponent.tsx
@@ -160,6 +160,7 @@ export const GenericComponent = React.memo(
readOnly={attribute.readonly}
docString={attribute.doc}
// Add any other specific props for the ImageComponent here
+ format={attribute.value['format']['value'] as string}
/>
);
} else {
diff --git a/frontend/src/components/ImageComponent.tsx b/frontend/src/components/ImageComponent.tsx
index 61a1519..2c3dece 100644
--- a/frontend/src/components/ImageComponent.tsx
+++ b/frontend/src/components/ImageComponent.tsx
@@ -9,33 +9,36 @@ interface ImageComponentProps {
value: string;
readOnly: boolean;
docString: string;
- // Define your component specific props here
+ format: string;
}
export const ImageComponent = React.memo((props: ImageComponentProps) => {
const renderCount = useRef(0);
- const { name, parentPath, value, docString } = props;
- // Your component logic here
+ const { name, parentPath, value, docString, format } = props;
useEffect(() => {
renderCount.current++;
- console.log(value);
});
return (
- {process.env.NODE_ENV === 'development' && (
-
Render count: {renderCount.current}
- )}
-
- {/* Your component JSX here */}
{name}
-
+
+ {process.env.NODE_ENV === 'development' && (
+ Render count: {renderCount.current}
+ )}
+
+ {/* Your component JSX here */}
+ {format === '' && value === '' ? (
+ No image set in the backend.
+ ) : (
+
+ )}
);
diff --git a/src/pydase/components/image.py b/src/pydase/components/image.py
index e170296..8d94ddf 100644
--- a/src/pydase/components/image.py
+++ b/src/pydase/components/image.py
@@ -1,4 +1,9 @@
-from typing import Any
+import base64
+import io
+from pathlib import Path
+
+import PIL.Image
+from loguru import logger
from pydase.data_service.data_service import DataService
@@ -6,13 +11,43 @@ from pydase.data_service.data_service import DataService
class Image(DataService):
def __init__(
self,
- value: bytes | str = "",
) -> None:
- self.value = value
+ self._value: str = ""
+ self._format: str = ""
super().__init__()
- def __setattr__(self, __name: str, __value: Any) -> None:
- if __name == "value":
- if isinstance(__value, bytes):
- __value = __value.decode()
- return super().__setattr__(__name, __value)
+ @property
+ def value(self) -> str:
+ return self._value
+
+ @property
+ def format(self) -> str:
+ return self._format
+
+ def load_from_path(self, path: Path | str) -> None:
+ with PIL.Image.open(path) as image:
+ self._load_from_PIL_Image(image)
+
+ def load_from_base64(self, value: bytes) -> None:
+ if isinstance(value, bytes):
+ # Decode the base64 string
+ image_data = base64.b64decode(value)
+
+ # Create a writable memory buffer for the image
+ image_buffer = io.BytesIO(image_data)
+
+ # Read the image from the buffer
+ image = PIL.Image.open(image_buffer)
+ self._load_from_PIL_Image(image)
+
+ def _load_from_PIL_Image(self, image: PIL.Image.Image) -> None:
+ if isinstance(image, PIL.Image.Image):
+ if image.format is not None:
+ self._format = image.format
+ buffered = io.BytesIO()
+ image.save(buffered, format=self._format)
+ img_base64 = base64.b64encode(buffered.getvalue())
+
+ self._value = img_base64.decode()
+ else:
+ logger.error("Image format is 'None'. Skipping...")