aboutsummaryrefslogtreecommitdiff
path: root/.venv/lib/python3.12/site-packages/PIL/ImageShow.py
diff options
context:
space:
mode:
Diffstat (limited to '.venv/lib/python3.12/site-packages/PIL/ImageShow.py')
-rw-r--r--.venv/lib/python3.12/site-packages/PIL/ImageShow.py360
1 files changed, 360 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/PIL/ImageShow.py b/.venv/lib/python3.12/site-packages/PIL/ImageShow.py
new file mode 100644
index 00000000..d62893d9
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/PIL/ImageShow.py
@@ -0,0 +1,360 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# im.show() drivers
+#
+# History:
+# 2008-04-06 fl Created
+#
+# Copyright (c) Secret Labs AB 2008.
+#
+# See the README file for information on usage and redistribution.
+#
+from __future__ import annotations
+
+import abc
+import os
+import shutil
+import subprocess
+import sys
+from shlex import quote
+from typing import Any
+
+from . import Image
+
+_viewers = []
+
+
+def register(viewer: type[Viewer] | Viewer, order: int = 1) -> None:
+ """
+ The :py:func:`register` function is used to register additional viewers::
+
+ from PIL import ImageShow
+ ImageShow.register(MyViewer()) # MyViewer will be used as a last resort
+ ImageShow.register(MySecondViewer(), 0) # MySecondViewer will be prioritised
+ ImageShow.register(ImageShow.XVViewer(), 0) # XVViewer will be prioritised
+
+ :param viewer: The viewer to be registered.
+ :param order:
+ Zero or a negative integer to prepend this viewer to the list,
+ a positive integer to append it.
+ """
+ if isinstance(viewer, type) and issubclass(viewer, Viewer):
+ viewer = viewer()
+ if order > 0:
+ _viewers.append(viewer)
+ else:
+ _viewers.insert(0, viewer)
+
+
+def show(image: Image.Image, title: str | None = None, **options: Any) -> bool:
+ r"""
+ Display a given image.
+
+ :param image: An image object.
+ :param title: Optional title. Not all viewers can display the title.
+ :param \**options: Additional viewer options.
+ :returns: ``True`` if a suitable viewer was found, ``False`` otherwise.
+ """
+ for viewer in _viewers:
+ if viewer.show(image, title=title, **options):
+ return True
+ return False
+
+
+class Viewer:
+ """Base class for viewers."""
+
+ # main api
+
+ def show(self, image: Image.Image, **options: Any) -> int:
+ """
+ The main function for displaying an image.
+ Converts the given image to the target format and displays it.
+ """
+
+ if not (
+ image.mode in ("1", "RGBA")
+ or (self.format == "PNG" and image.mode in ("I;16", "LA"))
+ ):
+ base = Image.getmodebase(image.mode)
+ if image.mode != base:
+ image = image.convert(base)
+
+ return self.show_image(image, **options)
+
+ # hook methods
+
+ format: str | None = None
+ """The format to convert the image into."""
+ options: dict[str, Any] = {}
+ """Additional options used to convert the image."""
+
+ def get_format(self, image: Image.Image) -> str | None:
+ """Return format name, or ``None`` to save as PGM/PPM."""
+ return self.format
+
+ def get_command(self, file: str, **options: Any) -> str:
+ """
+ Returns the command used to display the file.
+ Not implemented in the base class.
+ """
+ msg = "unavailable in base viewer"
+ raise NotImplementedError(msg)
+
+ def save_image(self, image: Image.Image) -> str:
+ """Save to temporary file and return filename."""
+ return image._dump(format=self.get_format(image), **self.options)
+
+ def show_image(self, image: Image.Image, **options: Any) -> int:
+ """Display the given image."""
+ return self.show_file(self.save_image(image), **options)
+
+ def show_file(self, path: str, **options: Any) -> int:
+ """
+ Display given file.
+ """
+ if not os.path.exists(path):
+ raise FileNotFoundError
+ os.system(self.get_command(path, **options)) # nosec
+ return 1
+
+
+# --------------------------------------------------------------------
+
+
+class WindowsViewer(Viewer):
+ """The default viewer on Windows is the default system application for PNG files."""
+
+ format = "PNG"
+ options = {"compress_level": 1, "save_all": True}
+
+ def get_command(self, file: str, **options: Any) -> str:
+ return (
+ f'start "Pillow" /WAIT "{file}" '
+ "&& ping -n 4 127.0.0.1 >NUL "
+ f'&& del /f "{file}"'
+ )
+
+ def show_file(self, path: str, **options: Any) -> int:
+ """
+ Display given file.
+ """
+ if not os.path.exists(path):
+ raise FileNotFoundError
+ subprocess.Popen(
+ self.get_command(path, **options),
+ shell=True,
+ creationflags=getattr(subprocess, "CREATE_NO_WINDOW"),
+ ) # nosec
+ return 1
+
+
+if sys.platform == "win32":
+ register(WindowsViewer)
+
+
+class MacViewer(Viewer):
+ """The default viewer on macOS using ``Preview.app``."""
+
+ format = "PNG"
+ options = {"compress_level": 1, "save_all": True}
+
+ def get_command(self, file: str, **options: Any) -> str:
+ # on darwin open returns immediately resulting in the temp
+ # file removal while app is opening
+ command = "open -a Preview.app"
+ command = f"({command} {quote(file)}; sleep 20; rm -f {quote(file)})&"
+ return command
+
+ def show_file(self, path: str, **options: Any) -> int:
+ """
+ Display given file.
+ """
+ if not os.path.exists(path):
+ raise FileNotFoundError
+ subprocess.call(["open", "-a", "Preview.app", path])
+ executable = sys.executable or shutil.which("python3")
+ if executable:
+ subprocess.Popen(
+ [
+ executable,
+ "-c",
+ "import os, sys, time; time.sleep(20); os.remove(sys.argv[1])",
+ path,
+ ]
+ )
+ return 1
+
+
+if sys.platform == "darwin":
+ register(MacViewer)
+
+
+class UnixViewer(Viewer):
+ format = "PNG"
+ options = {"compress_level": 1, "save_all": True}
+
+ @abc.abstractmethod
+ def get_command_ex(self, file: str, **options: Any) -> tuple[str, str]:
+ pass
+
+ def get_command(self, file: str, **options: Any) -> str:
+ command = self.get_command_ex(file, **options)[0]
+ return f"{command} {quote(file)}"
+
+
+class XDGViewer(UnixViewer):
+ """
+ The freedesktop.org ``xdg-open`` command.
+ """
+
+ def get_command_ex(self, file: str, **options: Any) -> tuple[str, str]:
+ command = executable = "xdg-open"
+ return command, executable
+
+ def show_file(self, path: str, **options: Any) -> int:
+ """
+ Display given file.
+ """
+ if not os.path.exists(path):
+ raise FileNotFoundError
+ subprocess.Popen(["xdg-open", path])
+ return 1
+
+
+class DisplayViewer(UnixViewer):
+ """
+ The ImageMagick ``display`` command.
+ This viewer supports the ``title`` parameter.
+ """
+
+ def get_command_ex(
+ self, file: str, title: str | None = None, **options: Any
+ ) -> tuple[str, str]:
+ command = executable = "display"
+ if title:
+ command += f" -title {quote(title)}"
+ return command, executable
+
+ def show_file(self, path: str, **options: Any) -> int:
+ """
+ Display given file.
+ """
+ if not os.path.exists(path):
+ raise FileNotFoundError
+ args = ["display"]
+ title = options.get("title")
+ if title:
+ args += ["-title", title]
+ args.append(path)
+
+ subprocess.Popen(args)
+ return 1
+
+
+class GmDisplayViewer(UnixViewer):
+ """The GraphicsMagick ``gm display`` command."""
+
+ def get_command_ex(self, file: str, **options: Any) -> tuple[str, str]:
+ executable = "gm"
+ command = "gm display"
+ return command, executable
+
+ def show_file(self, path: str, **options: Any) -> int:
+ """
+ Display given file.
+ """
+ if not os.path.exists(path):
+ raise FileNotFoundError
+ subprocess.Popen(["gm", "display", path])
+ return 1
+
+
+class EogViewer(UnixViewer):
+ """The GNOME Image Viewer ``eog`` command."""
+
+ def get_command_ex(self, file: str, **options: Any) -> tuple[str, str]:
+ executable = "eog"
+ command = "eog -n"
+ return command, executable
+
+ def show_file(self, path: str, **options: Any) -> int:
+ """
+ Display given file.
+ """
+ if not os.path.exists(path):
+ raise FileNotFoundError
+ subprocess.Popen(["eog", "-n", path])
+ return 1
+
+
+class XVViewer(UnixViewer):
+ """
+ The X Viewer ``xv`` command.
+ This viewer supports the ``title`` parameter.
+ """
+
+ def get_command_ex(
+ self, file: str, title: str | None = None, **options: Any
+ ) -> tuple[str, str]:
+ # note: xv is pretty outdated. most modern systems have
+ # imagemagick's display command instead.
+ command = executable = "xv"
+ if title:
+ command += f" -name {quote(title)}"
+ return command, executable
+
+ def show_file(self, path: str, **options: Any) -> int:
+ """
+ Display given file.
+ """
+ if not os.path.exists(path):
+ raise FileNotFoundError
+ args = ["xv"]
+ title = options.get("title")
+ if title:
+ args += ["-name", title]
+ args.append(path)
+
+ subprocess.Popen(args)
+ return 1
+
+
+if sys.platform not in ("win32", "darwin"): # unixoids
+ if shutil.which("xdg-open"):
+ register(XDGViewer)
+ if shutil.which("display"):
+ register(DisplayViewer)
+ if shutil.which("gm"):
+ register(GmDisplayViewer)
+ if shutil.which("eog"):
+ register(EogViewer)
+ if shutil.which("xv"):
+ register(XVViewer)
+
+
+class IPythonViewer(Viewer):
+ """The viewer for IPython frontends."""
+
+ def show_image(self, image: Image.Image, **options: Any) -> int:
+ ipython_display(image)
+ return 1
+
+
+try:
+ from IPython.display import display as ipython_display
+except ImportError:
+ pass
+else:
+ register(IPythonViewer)
+
+
+if __name__ == "__main__":
+ if len(sys.argv) < 2:
+ print("Syntax: python3 ImageShow.py imagefile [title]")
+ sys.exit()
+
+ with Image.open(sys.argv[1]) as im:
+ print(show(im, *sys.argv[2:]))