image.py 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455
  1. import base64
  2. import io
  3. import time
  4. from pathlib import Path
  5. from typing import Union
  6. from .. import optional_features
  7. from .mixins.source_element import SourceElement
  8. try:
  9. from PIL.Image import Image as PIL_Image
  10. optional_features.register('pillow')
  11. except ImportError:
  12. pass
  13. class Image(SourceElement, component='image.js'):
  14. PIL_CONVERT_FORMAT = 'PNG'
  15. def __init__(self, source: Union[str, Path, 'PIL_Image'] = '') -> None:
  16. """Image
  17. Displays an image.
  18. This element is based on Quasar's `QImg <https://quasar.dev/vue-components/img>`_ component.
  19. :param source: the source of the image; can be a URL, local file path, a base64 string or a PIL image
  20. """
  21. super().__init__(source=source)
  22. def set_source(self, source: Union[str, Path, 'PIL_Image']) -> None:
  23. return super().set_source(source)
  24. def _set_props(self, source: Union[str, Path, 'PIL_Image']) -> None:
  25. if optional_features.has('pillow') and isinstance(source, PIL_Image):
  26. source = pil_to_base64(source, self.PIL_CONVERT_FORMAT)
  27. super()._set_props(source)
  28. def force_reload(self) -> None:
  29. """Force the image to reload from the source."""
  30. self._props['t'] = time.time()
  31. self.update()
  32. def pil_to_base64(pil_image: 'PIL_Image', image_format: str) -> str:
  33. """Convert a PIL image to a base64 string which can be used as image source.
  34. :param pil_image: the PIL image
  35. :param image_format: the image format
  36. :return: the base64 string
  37. """
  38. buffer = io.BytesIO()
  39. pil_image.save(buffer, image_format)
  40. base64_encoded = base64.b64encode(buffer.getvalue())
  41. base64_string = base64_encoded.decode('utf-8')
  42. return f'data:image/{image_format.lower()};base64,{base64_string}'