Source code for napari.utils.notebook_display
import base64
import html
from io import BytesIO
from warnings import warn
try:
    from lxml.etree import ParserError
    from lxml.html import document_fromstring
    from lxml.html.clean import Cleaner
    lxml_unavailable = False
except ImportError:
    lxml_unavailable = True
from napari.utils.io import imsave_png
__all__ = ['NotebookScreenshot', 'nbscreenshot']
[docs]
class NotebookScreenshot:
    """Display napari screenshot in the jupyter notebook.
    Functions returning an object with a _repr_png_() method
    will displayed as a rich image in the jupyter notebook.
    https://ipython.readthedocs.io/en/stable/api/generated/IPython.display.html
    Parameters
    ----------
    viewer : napari.Viewer
        The napari viewer.
    canvas_only : bool, optional
        If False include the napari viewer frame in the screenshot,
        and if True then take screenshot of just the image display canvas.
        By default, False.
    alt_text : str, optional
        Image description alternative text, for screenreader accessibility.
        Good alt-text describes the image and any text within the image
        in no more than three short, complete sentences.
        By default, None.
    Examples
    --------
    >>> import napari
    >>> from napari.utils import nbscreenshot
    >>> from skimage.data import chelsea
    >>> viewer = napari.view_image(chelsea(), name='chelsea-the-cat')
    >>> nbscreenshot(viewer)
    # screenshot just the canvas without the napari viewer framing it
    >>> nbscreenshot(viewer, canvas_only=True)
    """
    def __init__(
        self,
        viewer,
        *,
        canvas_only=False,
        alt_text=None,
    ) -> None:
        """Initialize screenshot object.
        Parameters
        ----------
        viewer : napari.Viewer
            The napari viewer
        canvas_only : bool, optional
            If False include the napari viewer frame in the screenshot,
            and if True then take screenshot of just the image display canvas.
            By default, False.
        alt_text : str, optional
            Image description alternative text, for screenreader accessibility.
            Good alt-text describes the image and any text within the image
            in no more than three short, complete sentences.
        """
        self.viewer = viewer
        self.canvas_only = canvas_only
        self.image = None
        self.alt_text = self._clean_alt_text(alt_text)
    def _clean_alt_text(self, alt_text):
        """Clean user input to prevent script injection."""
        if alt_text is not None:
            if lxml_unavailable:
                warn(
                    'The lxml_html_clean library is not installed, and is '
                    'required to sanitize alt text for napari screenshots. '
                    'Alt Text will be stripped altogether.'
                )
                return None
            # cleaner won't recognize escaped script tags, so always unescape
            # to be safe
            alt_text = html.unescape(str(alt_text))
            cleaner = Cleaner()
            try:
                doc = document_fromstring(alt_text)
                alt_text = cleaner.clean_html(doc).text_content()
            except ParserError:
                warn(
                    'The provided alt text does not constitute valid html, so it was discarded.',
                    stacklevel=3,
                )
                alt_text = ''
            if alt_text == '':
                alt_text = None
        return alt_text
    def _repr_png_(self):
        """PNG representation of the viewer object for IPython.
        Returns
        -------
        In memory binary stream containing PNG screenshot image.
        """
        from napari._qt.qt_event_loop import get_qapp
        get_qapp().processEvents()
        self.image = self.viewer.screenshot(
            canvas_only=self.canvas_only, flash=False
        )
        with BytesIO() as file_obj:
            imsave_png(file_obj, self.image)
            file_obj.seek(0)
            png = file_obj.read()
        return png
    def _repr_html_(self):
        png = self._repr_png_()
        url = 'data:image/png;base64,' + base64.b64encode(png).decode('utf-8')
        _alt = html.escape(self.alt_text) if self.alt_text is not None else ''
        return f'<img src="{url}" alt="{_alt}"></img>' 
nbscreenshot = NotebookScreenshot