Source code for edifice.base_components.image_aspect

from __future__ import annotations

import typing as tp

from edifice.qt import QT_VERSION

if QT_VERSION == "PyQt6" and not tp.TYPE_CHECKING:
    from PyQt6 import QtCore, QtGui, QtWidgets
else:
    from PySide6 import QtCore, QtGui, QtWidgets

from .base_components import CommandType, Element, QtWidgetElement, _image_descriptor_to_pixmap, _WidgetTree


class _ScaledLabel(QtWidgets.QLabel):
    """
    https://stackoverflow.com/questions/72188903/pyside6-how-do-i-resize-a-qlabel-without-loosing-the-size-aspect-ratio
    """

    def __init__(self, *args, **kwargs):
        QtWidgets.QLabel.__init__(self)
        self._pixmap: QtGui.QPixmap | None = None
        self._aspect_ratio_mode: QtCore.Qt.AspectRatioMode | None = None
        self._rescale()

    def resizeEvent(self, event):
        self._rescale()

    def _rescale(self):
        if self._pixmap is not None:
            match self._aspect_ratio_mode:
                case None:
                    self.setPixmap(self._pixmap)
                case aspect_ratio_mode:
                    self.setPixmap(
                        self._pixmap.scaled(
                            self.frameSize(),
                            aspect_ratio_mode,
                            QtCore.Qt.TransformationMode.SmoothTransformation,
                        ),
                    )

    def _setPixmap(self, pixmap: QtGui.QPixmap):
        if not pixmap:
            return
        self._pixmap = pixmap
        self._rescale()

    def _setAspectRatioMode(self, aspect_ratio_mode: QtCore.Qt.AspectRatioMode | None):
        self._aspect_ratio_mode = aspect_ratio_mode
        self._rescale()


[docs] class Image(QtWidgetElement): """Render an image. * Underlying Qt Widget `QLabel <https://doc.qt.io/qtforpython-6/PySide6/QtWidgets/QLabel.html>`_ To render a 3-dimensional :code:`uint8` :code:`numpy` array as an image, see :class:`edifice.extra.NumpyImage`. Args: src: One of: * A path to an image file. * A `QImage <https://doc.qt.io/qtforpython-6/PySide6/QtGui/QImage.html>`_. * A `QPixmap <https://doc.qt.io/qtforpython-6/PySide6/QtGui/QPixmap.html>`_. aspect_ratio_mode: The aspect ratio mode of the image. * :code:`None` for a fixed image which doesn’t scale. * An `AspectRatioMode <https://doc.qt.io/qtforpython-6/PySide6/QtCore/Qt.html#PySide6.QtCore.Qt.AspectRatioMode>`_ to specify how the image should scale. """
[docs] def __init__( self, src: str | QtGui.QImage | QtGui.QPixmap, aspect_ratio_mode: None | QtCore.Qt.AspectRatioMode = None, **kwargs, ): super().__init__(**kwargs) self._register_props( { "src": src, "aspect_ratio_mode": aspect_ratio_mode, }, ) self.underlying: _ScaledLabel | None = None
def _initialize(self): self.underlying = _ScaledLabel() self.underlying.setObjectName(str(id(self))) def _qt_update_commands( self, widget_trees: dict[Element, _WidgetTree], newprops, ): if self.underlying is None: self._initialize() assert self.underlying is not None commands = super()._qt_update_commands_super(widget_trees, newprops, self.underlying, None) if "src" in newprops: commands.append(CommandType(self.underlying._setPixmap, _image_descriptor_to_pixmap(newprops.src))) if "aspect_ratio_mode" in newprops: commands.append(CommandType(self.underlying._setAspectRatioMode, newprops.aspect_ratio_mode)) return commands