Merge pull request #5349 from latosha-maltba/master

This commit is contained in:
Hugo van Kemenade 2021-04-01 11:55:37 +03:00 committed by GitHub
commit 8c852e44f0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 56 additions and 20 deletions

View File

@ -257,8 +257,23 @@ def netpbm_available():
return bool(shutil.which("ppmquant") and shutil.which("ppmtogif")) return bool(shutil.which("ppmquant") and shutil.which("ppmtogif"))
def imagemagick_available(): def magick_command():
return bool(IMCONVERT and shutil.which(IMCONVERT)) if sys.platform == "win32":
magickhome = os.environ.get("MAGICK_HOME", "")
if magickhome:
imagemagick = [os.path.join(magickhome, "convert.exe")]
graphicsmagick = [os.path.join(magickhome, "gm.exe"), "convert"]
else:
imagemagick = None
graphicsmagick = None
else:
imagemagick = ["convert"]
graphicsmagick = ["gm", "convert"]
if imagemagick and shutil.which(imagemagick[0]):
return imagemagick
elif graphicsmagick and shutil.which(graphicsmagick[0]):
return graphicsmagick
def on_appveyor(): def on_appveyor():
@ -296,14 +311,6 @@ def is_mingw():
return sysconfig.get_platform() == "mingw" return sysconfig.get_platform() == "mingw"
if sys.platform == "win32":
IMCONVERT = os.environ.get("MAGICK_HOME", "")
if IMCONVERT:
IMCONVERT = os.path.join(IMCONVERT, "convert.exe")
else:
IMCONVERT = "convert"
class cached_property: class cached_property:
def __init__(self, func): def __init__(self, func):
self.func = func self.func = func

View File

@ -5,9 +5,7 @@ import pytest
from PIL import Image from PIL import Image
from .helper import IMCONVERT, assert_image_equal, hopper, imagemagick_available from .helper import assert_image_equal, hopper, magick_command
_roundtrip = imagemagick_available()
def helper_save_as_palm(tmp_path, mode): def helper_save_as_palm(tmp_path, mode):
@ -23,13 +21,10 @@ def helper_save_as_palm(tmp_path, mode):
assert os.path.getsize(outfile) > 0 assert os.path.getsize(outfile) > 0
def open_with_imagemagick(tmp_path, f): def open_with_magick(magick, tmp_path, f):
if not imagemagick_available():
raise OSError()
outfile = str(tmp_path / "temp.png") outfile = str(tmp_path / "temp.png")
rc = subprocess.call( rc = subprocess.call(
[IMCONVERT, f, outfile], stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT magick + [f, outfile], stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT
) )
if rc: if rc:
raise OSError raise OSError
@ -37,14 +32,15 @@ def open_with_imagemagick(tmp_path, f):
def roundtrip(tmp_path, mode): def roundtrip(tmp_path, mode):
if not _roundtrip: magick = magick_command()
if not magick:
return return
im = hopper(mode) im = hopper(mode)
outfile = str(tmp_path / "temp.palm") outfile = str(tmp_path / "temp.palm")
im.save(outfile) im.save(outfile)
converted = open_with_imagemagick(tmp_path, outfile) converted = open_with_magick(magick, tmp_path, outfile)
assert_image_equal(converted, im) assert_image_equal(converted, im)

View File

@ -18,6 +18,7 @@ All default viewers convert the image to be shown to PNG format.
The following viewers may be registered on Unix-based systems, if the given command is found: The following viewers may be registered on Unix-based systems, if the given command is found:
.. autoclass:: PIL.ImageShow.DisplayViewer .. autoclass:: PIL.ImageShow.DisplayViewer
.. autoclass:: PIL.ImageShow.GmDisplayViewer
.. autoclass:: PIL.ImageShow.EogViewer .. autoclass:: PIL.ImageShow.EogViewer
.. autoclass:: PIL.ImageShow.XVViewer .. autoclass:: PIL.ImageShow.XVViewer

View File

@ -83,6 +83,18 @@ instances, so it will only be used by ``im.show()`` or :py:func:`.ImageShow.show
if none of the other viewers are available. This means that the behaviour of if none of the other viewers are available. This means that the behaviour of
:py:class:`PIL.ImageShow` will stay the same for most Pillow users. :py:class:`PIL.ImageShow` will stay the same for most Pillow users.
ImageShow.GmDisplayViewer
^^^^^^^^^^^^^^^^^^^^^^^^^
If GraphicsMagick is present, this new :py:class:`PIL.ImageShow.Viewer` subclass will
be registered. It uses GraphicsMagick_, an ImageMagick_ fork, to display images.
The GraphicsMagick based viewer has a lower priority than its ImageMagick
counterpart. Thus, if both ImageMagick and GraphicsMagick are installed,
``im.show()`` and :py:func:`.ImageShow.show()` prefer the viewer based on
ImageMagick, i.e the behaviour stays the same for Pillow users having
ImageMagick installed.
Saving TIFF with ICC profile Saving TIFF with ICC profile
^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -143,3 +155,12 @@ PyQt6
Support has been added for PyQt6. If it is installed, it will be used instead of Support has been added for PyQt6. If it is installed, it will be used instead of
PySide6, PyQt5 or PySide2. PySide6, PyQt5 or PySide2.
GraphicsMagick
^^^^^^^^^^^^^^
The test suite can now be run on systems which have GraphicsMagick_ but not
ImageMagick_ installed. If both are installed, the tests prefer ImageMagick.
.. _GraphicsMagick: http://www.graphicsmagick.org/
.. _ImageMagick: https://imagemagick.org/

View File

@ -194,6 +194,15 @@ class DisplayViewer(UnixViewer):
return command, executable return command, executable
class GmDisplayViewer(UnixViewer):
"""The GraphicsMagick ``gm display`` command."""
def get_command_ex(self, file, **options):
executable = "gm"
command = "gm display"
return command, executable
class EogViewer(UnixViewer): class EogViewer(UnixViewer):
"""The GNOME Image Viewer ``eog`` command.""" """The GNOME Image Viewer ``eog`` command."""
@ -220,6 +229,8 @@ class XVViewer(UnixViewer):
if sys.platform not in ("win32", "darwin"): # unixoids if sys.platform not in ("win32", "darwin"): # unixoids
if shutil.which("display"): if shutil.which("display"):
register(DisplayViewer) register(DisplayViewer)
if shutil.which("gm"):
register(GmDisplayViewer)
if shutil.which("eog"): if shutil.which("eog"):
register(EogViewer) register(EogViewer)
if shutil.which("xv"): if shutil.which("xv"):