Source code for plotpy.widgets.imagefile

# -*- coding: utf-8 -*-
#
# Licensed under the terms of the BSD 3-Clause
# (see plotpy/LICENSE for details)

"""
Image file dialog helpers
-------------------------

Overview
^^^^^^^^

The :py:mod:``.imagefile`` module provides helper functions for opening and
saving image files using Qt dialogs and plotpy's I/O features.

Ready-to-use open/save dialogs:

    :py:func:`.imagefile.exec_image_save_dialog`
        Executes an image save dialog box (QFileDialog.getSaveFileName)
    :py:func:`.imagefile.exec_image_open_dialog`
        Executes an image open dialog box (QFileDialog.getOpenFileName)
    :py:func:`.imagefile.exec_images_open_dialog`
        Executes an image*s* open dialog box (QFileDialog.getOpenFileNames)

Reference
^^^^^^^^^

.. autofunction:: exec_image_save_dialog
.. autofunction:: exec_image_open_dialog
.. autofunction:: exec_images_open_dialog
"""

from __future__ import annotations

import os.path as osp
import sys

import numpy as np
from qtpy import QtWidgets as QW
from qtpy.QtWidgets import QWidget  # only to help intersphinx find QWidget

from plotpy import io
from plotpy.config import _


# ===============================================================================
# Ready-to-use open/save dialogs
# ===============================================================================
[docs] def exec_image_save_dialog( parent: QWidget, data: np.ndarray, template: dict | None = None, basedir: str = "", app_name: str | None = None, ) -> str | None: """Executes an image save dialog box (QFileDialog.getSaveFileName) Args: parent: parent widget (None means no parent) data: image pixel array data template: image template (pydicom dataset) for DICOM files basedir: base directory ('' means current directory) app_name: application name (used as a title for an eventual error message box in case something goes wrong when saving image) Returns: Filename if dialog is accepted, None otherwise """ saved_in, saved_out, saved_err = sys.stdin, sys.stdout, sys.stderr sys.stdout = None filename, _filter = QW.QFileDialog.getSaveFileName( parent, _("Save as"), basedir, io.iohandler.get_filters("save", dtype=data.dtype, template=template), ) sys.stdin, sys.stdout, sys.stderr = saved_in, saved_out, saved_err if filename: filename = str(filename) kwargs = {} if osp.splitext(filename)[1].lower() == ".dcm": kwargs["template"] = template try: io.imwrite(filename, data, **kwargs) return filename except Exception as msg: import traceback traceback.print_exc() message = _("{filename} could not be written:\n{msg}").format( filename=osp.basename(filename), msg=msg ) QW.QMessageBox.critical( parent, _("Error") if app_name is None else app_name, message ) return
[docs] def exec_image_open_dialog( parent: QWidget, basedir: str = "", app_name: str | None = None, to_grayscale: bool = True, dtype: np.dtype | None = None, ) -> tuple[str, np.ndarray] | None: """Executes an image open dialog box (QFileDialog.getOpenFileName) Args: parent: parent widget (None means no parent) basedir: base directory ('' means current directory) app_name: application name (used as a title for an eventual error message box in case something goes wrong when saving image) to_grayscale (bool | None): convert image to grayscale dtype: data type of the image Returns: (filename, data) tuple if dialog is accepted, None otherwise """ saved_in, saved_out, saved_err = sys.stdin, sys.stdout, sys.stderr sys.stdout = None filename, _filter = QW.QFileDialog.getOpenFileName( parent, _("Open"), basedir, io.iohandler.get_filters("load", dtype=dtype) ) sys.stdin, sys.stdout, sys.stderr = saved_in, saved_out, saved_err filename = str(filename) try: data = io.imread(filename, to_grayscale=to_grayscale) except Exception as msg: import traceback traceback.print_exc() message = _("{filename} could not be opened:\n{msg}").format( filename=osp.basename(filename), msg=msg ) QW.QMessageBox.critical( parent, _("Error") if app_name is None else app_name, message ) return return filename, data
[docs] def exec_images_open_dialog( parent: QWidget, basedir: str = "", app_name: str | None = None, to_grayscale: bool = True, dtype: np.dtype | None = None, ) -> list[tuple[str, np.ndarray]] | None: """Executes an image*s* open dialog box (QFileDialog.getOpenFileNames) Args: parent: parent widget (None means no parent) basedir: base directory ('' means current directory) app_name: application name (used as a title for an eventual error message box in case something goes wrong when saving image) to_grayscale (bool | None): convert image to grayscale dtype: data type Returns: (filename, data) tuples if dialog is accepted, None otherwise """ saved_in, saved_out, saved_err = sys.stdin, sys.stdout, sys.stderr sys.stdout = None filenames, _filter = QW.QFileDialog.getOpenFileNames( parent, _("Open"), basedir, io.iohandler.get_filters("load", dtype=dtype) ) sys.stdin, sys.stdout, sys.stderr = saved_in, saved_out, saved_err filenames = [str(fname) for fname in list(filenames)] for filename in filenames: try: data = io.imread(filename, to_grayscale=to_grayscale) except Exception as msg: import traceback traceback.print_exc() message = _("{filename} could not be opened:\n{msg}").format( filename=osp.basename(filename), msg=msg ) QW.QMessageBox.critical( parent, _("Error") if app_name is None else app_name, message ) return yield filename, data