mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-01-25 00:34:14 +03:00
Merge remote-tracking branch 'upstream/master' into ellipse
This commit is contained in:
commit
7dedb1402f
4
.github/workflows/lint.yml
vendored
4
.github/workflows/lint.yml
vendored
|
@ -16,7 +16,7 @@ jobs:
|
|||
- uses: actions/checkout@v2
|
||||
|
||||
- name: pip cache
|
||||
uses: actions/cache@v1
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: lint-pip-${{ hashFiles('**/setup.py') }}
|
||||
|
@ -46,4 +46,6 @@ jobs:
|
|||
|
||||
- name: Lint
|
||||
run: tox -e lint
|
||||
env:
|
||||
PRE_COMMIT_COLOR: always
|
||||
|
||||
|
|
4
.github/workflows/macos-install.sh
vendored
4
.github/workflows/macos-install.sh
vendored
|
@ -2,7 +2,7 @@
|
|||
|
||||
set -e
|
||||
|
||||
brew install libtiff libjpeg openjpeg libimagequant webp little-cms2 freetype
|
||||
brew install libtiff libjpeg openjpeg libimagequant webp little-cms2 freetype openblas
|
||||
|
||||
PYTHONOPTIMIZE=0 pip install cffi
|
||||
pip install coverage
|
||||
|
@ -11,6 +11,8 @@ pip install -U pytest
|
|||
pip install -U pytest-cov
|
||||
pip install pyroma
|
||||
pip install test-image-results
|
||||
|
||||
echo -e "[openblas]\nlibraries = openblas\nlibrary_dirs = /usr/local/opt/openblas/lib" >> ~/.numpy-site.cfg
|
||||
pip install numpy
|
||||
|
||||
# extra test images
|
||||
|
|
5
.github/workflows/test-windows.yml
vendored
5
.github/workflows/test-windows.yml
vendored
|
@ -52,6 +52,11 @@ jobs:
|
|||
python-version: ${{ matrix.python-version }}
|
||||
architecture: ${{ matrix.architecture }}
|
||||
|
||||
- name: Set up TCL
|
||||
if: "contains(matrix.python-version, 'pypy')"
|
||||
run: Write-Host "::set-env name=TCL_LIBRARY::$env:pythonLocation\tcl\tcl8.5"
|
||||
shell: pwsh
|
||||
|
||||
- name: Print build system information
|
||||
run: python .github/workflows/system-info.py
|
||||
|
||||
|
|
33
CHANGES.rst
33
CHANGES.rst
|
@ -5,6 +5,36 @@ Changelog (Pillow)
|
|||
7.2.0 (unreleased)
|
||||
------------------
|
||||
|
||||
- Fixed loading non-RGBA mode APNGs with dispose background #4742
|
||||
[radarhere]
|
||||
|
||||
- Deprecated _showxv #4714
|
||||
[radarhere]
|
||||
|
||||
- Deprecate Image.show(command="...") #4646
|
||||
[nulano, hugovk, radarhere]
|
||||
|
||||
- Updated JPEG magic number #4707
|
||||
[Cykooz, radarhere]
|
||||
|
||||
- Change STRIPBYTECOUNTS to LONG if necessary when saving #4626
|
||||
[radarhere, hugovk]
|
||||
|
||||
- Write JFIF header when saving JPEG #4639
|
||||
[radarhere]
|
||||
|
||||
- Replaced tiff_jpeg with jpeg compression when saving TIFF images #4627
|
||||
[radarhere]
|
||||
|
||||
- Writing TIFF tags: improved BYTE, added UNDEFINED #4605
|
||||
[radarhere]
|
||||
|
||||
- Consider transparency when pasting text on an RGBA image #4566
|
||||
[radarhere]
|
||||
|
||||
- Added method argument to single frame WebP saving #4547
|
||||
[radarhere]
|
||||
|
||||
- Use ImageFileDirectory_v2 in Image.Exif #4637
|
||||
[radarhere]
|
||||
|
||||
|
@ -44,6 +74,9 @@ Changelog (Pillow)
|
|||
- Fix pickling WebP #4561
|
||||
[hugovk, radarhere]
|
||||
|
||||
- Replace IOError and WindowsError aliases with OSError #4536
|
||||
[hugovk, radarhere]
|
||||
|
||||
7.1.2 (2020-04-25)
|
||||
------------------
|
||||
|
||||
|
|
|
@ -165,12 +165,6 @@ def assert_tuple_approx_equal(actuals, targets, threshold, msg):
|
|||
assert value, msg + ": " + repr(actuals) + " != " + repr(targets)
|
||||
|
||||
|
||||
def skip_known_bad_test(msg=None):
|
||||
# Skip if PILLOW_RUN_KNOWN_BAD is not true in the environment.
|
||||
if not os.environ.get("PILLOW_RUN_KNOWN_BAD", False):
|
||||
pytest.skip(msg or "Known bad test")
|
||||
|
||||
|
||||
def skip_unless_feature(feature):
|
||||
reason = "%s not available" % feature
|
||||
return pytest.mark.skipif(not features.check(feature), reason=reason)
|
||||
|
|
BIN
Tests/images/apng/dispose_op_background_p_mode.png
Normal file
BIN
Tests/images/apng/dispose_op_background_p_mode.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
BIN
Tests/images/imagedraw_wide_line_larger_than_int.png
Normal file
BIN
Tests/images/imagedraw_wide_line_larger_than_int.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 557 B |
BIN
Tests/images/text_mono.gif
Normal file
BIN
Tests/images/text_mono.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
BIN
Tests/images/transparent_background_text.png
Normal file
BIN
Tests/images/transparent_background_text.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
|
@ -1,4 +1,5 @@
|
|||
import io
|
||||
import re
|
||||
|
||||
import pytest
|
||||
from PIL import features
|
||||
|
@ -21,6 +22,27 @@ def test_check():
|
|||
assert features.check_feature(feature) == features.check(feature)
|
||||
|
||||
|
||||
def test_version():
|
||||
# Check the correctness of the convenience function
|
||||
# and the format of version numbers
|
||||
|
||||
def test(name, function):
|
||||
version = features.version(name)
|
||||
if not features.check(name):
|
||||
assert version is None
|
||||
else:
|
||||
assert function(name) == version
|
||||
if name != "PIL":
|
||||
assert version is None or re.search(r"\d+(\.\d+)*$", version)
|
||||
|
||||
for module in features.modules:
|
||||
test(module, features.version_module)
|
||||
for codec in features.codecs:
|
||||
test(codec, features.version_codec)
|
||||
for feature in features.features:
|
||||
test(feature, features.version_feature)
|
||||
|
||||
|
||||
@skip_unless_feature("webp")
|
||||
def test_webp_transparency():
|
||||
assert features.check("transp_webp") != _webp.WebPDecoderBuggyAlpha()
|
||||
|
@ -37,9 +59,22 @@ def test_webp_anim():
|
|||
assert features.check("webp_anim") == _webp.HAVE_WEBPANIM
|
||||
|
||||
|
||||
@skip_unless_feature("libjpeg_turbo")
|
||||
def test_libjpeg_turbo_version():
|
||||
assert re.search(r"\d+\.\d+\.\d+$", features.version("libjpeg_turbo"))
|
||||
|
||||
|
||||
@skip_unless_feature("libimagequant")
|
||||
def test_libimagequant_version():
|
||||
assert re.search(r"\d+\.\d+\.\d+$", features.version("libimagequant"))
|
||||
|
||||
|
||||
def test_check_modules():
|
||||
for feature in features.modules:
|
||||
assert features.check_module(feature) in [True, False]
|
||||
|
||||
|
||||
def test_check_codecs():
|
||||
for feature in features.codecs:
|
||||
assert features.check_codec(feature) in [True, False]
|
||||
|
||||
|
@ -64,6 +99,8 @@ def test_unsupported_codec():
|
|||
# Act / Assert
|
||||
with pytest.raises(ValueError):
|
||||
features.check_codec(codec)
|
||||
with pytest.raises(ValueError):
|
||||
features.version_codec(codec)
|
||||
|
||||
|
||||
def test_unsupported_module():
|
||||
|
@ -72,6 +109,8 @@ def test_unsupported_module():
|
|||
# Act / Assert
|
||||
with pytest.raises(ValueError):
|
||||
features.check_module(module)
|
||||
with pytest.raises(ValueError):
|
||||
features.version_module(module)
|
||||
|
||||
|
||||
def test_pilinfo():
|
||||
|
|
|
@ -104,6 +104,13 @@ def test_apng_dispose_region():
|
|||
assert im.getpixel((64, 32)) == (0, 255, 0, 255)
|
||||
|
||||
|
||||
def test_apng_dispose_op_background_p_mode():
|
||||
with Image.open("Tests/images/apng/dispose_op_background_p_mode.png") as im:
|
||||
im.seek(1)
|
||||
im.load()
|
||||
assert im.size == (128, 64)
|
||||
|
||||
|
||||
def test_apng_blend():
|
||||
with Image.open("Tests/images/apng/blend_op_source_solid.png") as im:
|
||||
im.seek(im.n_frames - 1)
|
||||
|
@ -494,6 +501,26 @@ def test_apng_save_disposal(tmp_path):
|
|||
assert im.getpixel((64, 32)) == (0, 255, 0, 255)
|
||||
|
||||
|
||||
def test_apng_save_disposal_previous(tmp_path):
|
||||
test_file = str(tmp_path / "temp.png")
|
||||
size = (128, 64)
|
||||
transparent = Image.new("RGBA", size, (0, 0, 0, 0))
|
||||
red = Image.new("RGBA", size, (255, 0, 0, 255))
|
||||
green = Image.new("RGBA", size, (0, 255, 0, 255))
|
||||
|
||||
# test APNG_DISPOSE_OP_NONE
|
||||
transparent.save(
|
||||
test_file,
|
||||
save_all=True,
|
||||
append_images=[red, green],
|
||||
disposal=PngImagePlugin.APNG_DISPOSE_OP_PREVIOUS,
|
||||
)
|
||||
with Image.open(test_file) as im:
|
||||
im.seek(2)
|
||||
assert im.getpixel((0, 0)) == (0, 255, 0, 255)
|
||||
assert im.getpixel((64, 32)) == (0, 255, 0, 255)
|
||||
|
||||
|
||||
def test_apng_save_blend(tmp_path):
|
||||
test_file = str(tmp_path / "temp.png")
|
||||
size = (128, 64)
|
||||
|
|
|
@ -2,14 +2,14 @@ import io
|
|||
import sys
|
||||
|
||||
import pytest
|
||||
from PIL import IcnsImagePlugin, Image
|
||||
from PIL import IcnsImagePlugin, Image, features
|
||||
|
||||
from .helper import assert_image_equal, assert_image_similar
|
||||
|
||||
# sample icon file
|
||||
TEST_FILE = "Tests/images/pillow.icns"
|
||||
|
||||
ENABLE_JPEG2K = hasattr(Image.core, "jp2klib_version")
|
||||
ENABLE_JPEG2K = features.check_codec("jpg_2000")
|
||||
|
||||
|
||||
def test_sanity():
|
||||
|
@ -55,6 +55,19 @@ def test_save_append_images(tmp_path):
|
|||
assert_image_equal(reread, provided_im)
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.platform != "darwin", reason="Requires macOS")
|
||||
def test_save_fp():
|
||||
fp = io.BytesIO()
|
||||
|
||||
with Image.open(TEST_FILE) as im:
|
||||
im.save(fp, format="ICNS")
|
||||
|
||||
with Image.open(fp) as reread:
|
||||
assert reread.mode == "RGBA"
|
||||
assert reread.size == (1024, 1024)
|
||||
assert reread.format == "ICNS"
|
||||
|
||||
|
||||
def test_sizes():
|
||||
# Check that we can load all of the sizes, and that the final pixel
|
||||
# dimensions are as expected
|
||||
|
|
|
@ -3,7 +3,14 @@ import re
|
|||
from io import BytesIO
|
||||
|
||||
import pytest
|
||||
from PIL import ExifTags, Image, ImageFile, JpegImagePlugin
|
||||
from PIL import (
|
||||
ExifTags,
|
||||
Image,
|
||||
ImageFile,
|
||||
JpegImagePlugin,
|
||||
UnidentifiedImageError,
|
||||
features,
|
||||
)
|
||||
|
||||
from .helper import (
|
||||
assert_image,
|
||||
|
@ -41,7 +48,7 @@ class TestFileJpeg:
|
|||
def test_sanity(self):
|
||||
|
||||
# internal version number
|
||||
assert re.search(r"\d+\.\d+$", Image.core.jpeglib_version)
|
||||
assert re.search(r"\d+\.\d+$", features.version_codec("jpg"))
|
||||
|
||||
with Image.open(TEST_FILE) as im:
|
||||
im.load()
|
||||
|
@ -90,9 +97,12 @@ class TestFileJpeg:
|
|||
]
|
||||
assert k > 0.9
|
||||
|
||||
def test_dpi(self):
|
||||
@pytest.mark.parametrize(
|
||||
"test_image_path", [TEST_FILE, "Tests/images/pil_sample_cmyk.jpg"],
|
||||
)
|
||||
def test_dpi(self, test_image_path):
|
||||
def test(xdpi, ydpi=None):
|
||||
with Image.open(TEST_FILE) as im:
|
||||
with Image.open(test_image_path) as im:
|
||||
im = self.roundtrip(im, dpi=(xdpi, ydpi or xdpi))
|
||||
return im.info.get("dpi")
|
||||
|
||||
|
@ -706,6 +716,24 @@ class TestFileJpeg:
|
|||
with Image.open("Tests/images/icc-after-SOF.jpg") as im:
|
||||
assert im.info["icc_profile"] == b"profile"
|
||||
|
||||
def test_jpeg_magic_number(self):
|
||||
size = 4097
|
||||
buffer = BytesIO(b"\xFF" * size) # Many xFF bytes
|
||||
buffer.max_pos = 0
|
||||
orig_read = buffer.read
|
||||
|
||||
def read(n=-1):
|
||||
res = orig_read(n)
|
||||
buffer.max_pos = max(buffer.max_pos, buffer.tell())
|
||||
return res
|
||||
|
||||
buffer.read = read
|
||||
with pytest.raises(UnidentifiedImageError):
|
||||
Image.open(buffer)
|
||||
|
||||
# Assert the entire file has not been read
|
||||
assert 0 < buffer.max_pos < size
|
||||
|
||||
|
||||
@pytest.mark.skipif(not is_win32(), reason="Windows only")
|
||||
@skip_unless_feature("jpg")
|
||||
|
|
|
@ -2,7 +2,7 @@ import re
|
|||
from io import BytesIO
|
||||
|
||||
import pytest
|
||||
from PIL import Image, ImageFile, Jpeg2KImagePlugin
|
||||
from PIL import Image, ImageFile, Jpeg2KImagePlugin, features
|
||||
|
||||
from .helper import (
|
||||
assert_image_equal,
|
||||
|
@ -35,7 +35,7 @@ def roundtrip(im, **options):
|
|||
|
||||
def test_sanity():
|
||||
# Internal version number
|
||||
assert re.search(r"\d+\.\d+\.\d+$", Image.core.jp2klib_version)
|
||||
assert re.search(r"\d+\.\d+\.\d+$", features.version_codec("jpg_2000"))
|
||||
|
||||
with Image.open("Tests/images/test-card-lossless.jp2") as im:
|
||||
px = im.load()
|
||||
|
|
|
@ -3,11 +3,12 @@ import io
|
|||
import itertools
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
from collections import namedtuple
|
||||
from ctypes import c_float
|
||||
|
||||
import pytest
|
||||
from PIL import Image, ImageFilter, TiffImagePlugin, TiffTags
|
||||
from PIL import Image, ImageFilter, TiffImagePlugin, TiffTags, features
|
||||
|
||||
from .helper import (
|
||||
assert_image_equal,
|
||||
|
@ -47,6 +48,9 @@ class LibTiffTestCase:
|
|||
|
||||
|
||||
class TestFileLibTiff(LibTiffTestCase):
|
||||
def test_version(self):
|
||||
assert re.search(r"\d+\.\d+\.\d+$", features.version_codec("libtiff"))
|
||||
|
||||
def test_g4_tiff(self, tmp_path):
|
||||
"""Test the ordinary file path load path"""
|
||||
|
||||
|
@ -203,6 +207,7 @@ class TestFileLibTiff(LibTiffTestCase):
|
|||
del core_items[tag]
|
||||
except KeyError:
|
||||
pass
|
||||
del core_items[320] # colormap is special, tested below
|
||||
|
||||
# Type codes:
|
||||
# 2: "ascii",
|
||||
|
@ -299,9 +304,6 @@ class TestFileLibTiff(LibTiffTestCase):
|
|||
)
|
||||
continue
|
||||
|
||||
if libtiff and isinstance(value, bytes):
|
||||
value = value.decode()
|
||||
|
||||
assert reloaded_value == value
|
||||
|
||||
# Test with types
|
||||
|
@ -322,6 +324,17 @@ class TestFileLibTiff(LibTiffTestCase):
|
|||
)
|
||||
TiffImagePlugin.WRITE_LIBTIFF = False
|
||||
|
||||
def test_xmlpacket_tag(self, tmp_path):
|
||||
TiffImagePlugin.WRITE_LIBTIFF = True
|
||||
|
||||
out = str(tmp_path / "temp.tif")
|
||||
hopper().save(out, tiffinfo={700: b"xmlpacket tag"})
|
||||
TiffImagePlugin.WRITE_LIBTIFF = False
|
||||
|
||||
with Image.open(out) as reloaded:
|
||||
if 700 in reloaded.tag_v2:
|
||||
assert reloaded.tag_v2[700] == b"xmlpacket tag"
|
||||
|
||||
def test_int_dpi(self, tmp_path):
|
||||
# issue #1765
|
||||
im = hopper("RGB")
|
||||
|
@ -448,6 +461,14 @@ class TestFileLibTiff(LibTiffTestCase):
|
|||
assert size_compressed > size_jpeg
|
||||
assert size_jpeg > size_jpeg_30
|
||||
|
||||
def test_tiff_jpeg_compression(self, tmp_path):
|
||||
im = hopper("RGB")
|
||||
out = str(tmp_path / "temp.tif")
|
||||
im.save(out, compression="tiff_jpeg")
|
||||
|
||||
with Image.open(out) as reloaded:
|
||||
assert reloaded.info["compression"] == "jpeg"
|
||||
|
||||
def test_quality(self, tmp_path):
|
||||
im = hopper("RGB")
|
||||
out = str(tmp_path / "temp.tif")
|
||||
|
@ -471,6 +492,18 @@ class TestFileLibTiff(LibTiffTestCase):
|
|||
with Image.open(out) as im2:
|
||||
assert_image_equal(im, im2)
|
||||
|
||||
def test_palette_save(self, tmp_path):
|
||||
im = hopper("P")
|
||||
out = str(tmp_path / "temp.tif")
|
||||
|
||||
TiffImagePlugin.WRITE_LIBTIFF = True
|
||||
im.save(out)
|
||||
TiffImagePlugin.WRITE_LIBTIFF = False
|
||||
|
||||
with Image.open(out) as reloaded:
|
||||
# colormap/palette tag
|
||||
assert len(reloaded.tag_v2[320]) == 768
|
||||
|
||||
def xtest_bw_compression_w_rgb(self, tmp_path):
|
||||
""" This test passes, but when running all tests causes a failure due
|
||||
to output on stderr from the error thrown by libtiff. We need to
|
||||
|
@ -667,6 +700,26 @@ class TestFileLibTiff(LibTiffTestCase):
|
|||
TiffImagePlugin.READ_LIBTIFF = False
|
||||
assert icc == icc_libtiff
|
||||
|
||||
def test_write_icc(self, tmp_path):
|
||||
def check_write(libtiff):
|
||||
TiffImagePlugin.WRITE_LIBTIFF = libtiff
|
||||
|
||||
with Image.open("Tests/images/hopper.iccprofile.tif") as img:
|
||||
icc_profile = img.info["icc_profile"]
|
||||
|
||||
out = str(tmp_path / "temp.tif")
|
||||
img.save(out, icc_profile=icc_profile)
|
||||
with Image.open(out) as reloaded:
|
||||
assert icc_profile == reloaded.info["icc_profile"]
|
||||
|
||||
libtiffs = []
|
||||
if Image.core.libtiff_support_custom_tags:
|
||||
libtiffs.append(True)
|
||||
libtiffs.append(False)
|
||||
|
||||
for libtiff in libtiffs:
|
||||
check_write(libtiff)
|
||||
|
||||
def test_multipage_compression(self):
|
||||
with Image.open("Tests/images/compression.tif") as im:
|
||||
|
||||
|
|
|
@ -4,13 +4,7 @@ import subprocess
|
|||
import pytest
|
||||
from PIL import Image
|
||||
|
||||
from .helper import (
|
||||
IMCONVERT,
|
||||
assert_image_equal,
|
||||
hopper,
|
||||
imagemagick_available,
|
||||
skip_known_bad_test,
|
||||
)
|
||||
from .helper import IMCONVERT, assert_image_equal, hopper, imagemagick_available
|
||||
|
||||
_roundtrip = imagemagick_available()
|
||||
|
||||
|
@ -62,13 +56,13 @@ def test_monochrome(tmp_path):
|
|||
roundtrip(tmp_path, mode)
|
||||
|
||||
|
||||
@pytest.mark.xfail(reason="Palm P image is wrong")
|
||||
def test_p_mode(tmp_path):
|
||||
# Arrange
|
||||
mode = "P"
|
||||
|
||||
# Act / Assert
|
||||
helper_save_as_palm(tmp_path, mode)
|
||||
skip_known_bad_test("Palm P image is wrong")
|
||||
roundtrip(tmp_path, mode)
|
||||
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ import zlib
|
|||
from io import BytesIO
|
||||
|
||||
import pytest
|
||||
from PIL import Image, ImageFile, PngImagePlugin
|
||||
from PIL import Image, ImageFile, PngImagePlugin, features
|
||||
|
||||
from .helper import (
|
||||
PillowLeakTestCase,
|
||||
|
@ -73,7 +73,7 @@ class TestFilePng:
|
|||
def test_sanity(self, tmp_path):
|
||||
|
||||
# internal version number
|
||||
assert re.search(r"\d+\.\d+\.\d+(\.\d+)?$", Image.core.zlib_version)
|
||||
assert re.search(r"\d+\.\d+\.\d+(\.\d+)?$", features.version_codec("zlib"))
|
||||
|
||||
test_file = str(tmp_path / "temp.png")
|
||||
|
||||
|
|
|
@ -156,6 +156,23 @@ def test_write_metadata(tmp_path):
|
|||
assert value == reloaded[tag], "%s didn't roundtrip" % tag
|
||||
|
||||
|
||||
def test_change_stripbytecounts_tag_type(tmp_path):
|
||||
out = str(tmp_path / "temp.tiff")
|
||||
with Image.open("Tests/images/hopper.tif") as im:
|
||||
info = im.tag_v2
|
||||
|
||||
# Resize the image so that STRIPBYTECOUNTS will be larger than a SHORT
|
||||
im = im.resize((500, 500))
|
||||
|
||||
# STRIPBYTECOUNTS can be a SHORT or a LONG
|
||||
info.tagtype[TiffImagePlugin.STRIPBYTECOUNTS] = TiffTags.SHORT
|
||||
|
||||
im.save(out, tiffinfo=info)
|
||||
|
||||
with Image.open(out) as reloaded:
|
||||
assert reloaded.tag_v2.tagtype[TiffImagePlugin.STRIPBYTECOUNTS] == TiffTags.LONG
|
||||
|
||||
|
||||
def test_no_duplicate_50741_tag():
|
||||
assert TAG_IDS["MakerNoteSafety"] == 50741
|
||||
assert TAG_IDS["BestQualityScale"] == 50780
|
||||
|
@ -319,13 +336,13 @@ def test_empty_values():
|
|||
|
||||
def test_PhotoshopInfo(tmp_path):
|
||||
with Image.open("Tests/images/issue_2278.tif") as im:
|
||||
assert len(im.tag_v2[34377]) == 1
|
||||
assert isinstance(im.tag_v2[34377][0], bytes)
|
||||
assert len(im.tag_v2[34377]) == 70
|
||||
assert isinstance(im.tag_v2[34377], bytes)
|
||||
out = str(tmp_path / "temp.tiff")
|
||||
im.save(out)
|
||||
with Image.open(out) as reloaded:
|
||||
assert len(reloaded.tag_v2[34377]) == 1
|
||||
assert isinstance(reloaded.tag_v2[34377][0], bytes)
|
||||
assert len(reloaded.tag_v2[34377]) == 70
|
||||
assert isinstance(reloaded.tag_v2[34377], bytes)
|
||||
|
||||
|
||||
def test_too_many_entries():
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
import io
|
||||
import re
|
||||
|
||||
import pytest
|
||||
from PIL import Image, WebPImagePlugin
|
||||
from PIL import Image, WebPImagePlugin, features
|
||||
|
||||
from .helper import (
|
||||
assert_image_similar,
|
||||
|
@ -36,6 +39,7 @@ class TestFileWebp:
|
|||
def test_version(self):
|
||||
_webp.WebPDecoderVersion()
|
||||
_webp.WebPDecoderBuggyAlpha()
|
||||
assert re.search(r"\d+\.\d+\.\d+$", features.version_module("webp"))
|
||||
|
||||
def test_read_rgb(self):
|
||||
"""
|
||||
|
@ -54,15 +58,10 @@ class TestFileWebp:
|
|||
# dwebp -ppm ../../Tests/images/hopper.webp -o hopper_webp_bits.ppm
|
||||
assert_image_similar_tofile(image, "Tests/images/hopper_webp_bits.ppm", 1.0)
|
||||
|
||||
def test_write_rgb(self, tmp_path):
|
||||
"""
|
||||
Can we write a RGB mode file to webp without error.
|
||||
Does it have the bits we expect?
|
||||
"""
|
||||
|
||||
def _roundtrip(self, tmp_path, mode, epsilon, args={}):
|
||||
temp_file = str(tmp_path / "temp.webp")
|
||||
|
||||
hopper(self.rgb_mode).save(temp_file)
|
||||
hopper(mode).save(temp_file, **args)
|
||||
with Image.open(temp_file) as image:
|
||||
assert image.mode == self.rgb_mode
|
||||
assert image.size == (128, 128)
|
||||
|
@ -70,18 +69,38 @@ class TestFileWebp:
|
|||
image.load()
|
||||
image.getdata()
|
||||
|
||||
# generated with: dwebp -ppm temp.webp -o hopper_webp_write.ppm
|
||||
assert_image_similar_tofile(
|
||||
image, "Tests/images/hopper_webp_write.ppm", 12.0
|
||||
)
|
||||
if mode == self.rgb_mode:
|
||||
# generated with: dwebp -ppm temp.webp -o hopper_webp_write.ppm
|
||||
assert_image_similar_tofile(
|
||||
image, "Tests/images/hopper_webp_write.ppm", 12.0
|
||||
)
|
||||
|
||||
# This test asserts that the images are similar. If the average pixel
|
||||
# difference between the two images is less than the epsilon value,
|
||||
# then we're going to accept that it's a reasonable lossy version of
|
||||
# the image. The old lena images for WebP are showing ~16 on
|
||||
# Ubuntu, the jpegs are showing ~18.
|
||||
target = hopper(self.rgb_mode)
|
||||
assert_image_similar(image, target, 12.0)
|
||||
# the image.
|
||||
target = hopper(mode)
|
||||
if mode != self.rgb_mode:
|
||||
target = target.convert(self.rgb_mode)
|
||||
assert_image_similar(image, target, epsilon)
|
||||
|
||||
def test_write_rgb(self, tmp_path):
|
||||
"""
|
||||
Can we write a RGB mode file to webp without error?
|
||||
Does it have the bits we expect?
|
||||
"""
|
||||
|
||||
self._roundtrip(tmp_path, self.rgb_mode, 12.5)
|
||||
|
||||
def test_write_method(self, tmp_path):
|
||||
self._roundtrip(tmp_path, self.rgb_mode, 12.0, {"method": 6})
|
||||
|
||||
buffer_no_args = io.BytesIO()
|
||||
hopper().save(buffer_no_args, format="WEBP")
|
||||
|
||||
buffer_method = io.BytesIO()
|
||||
hopper().save(buffer_method, format="WEBP", method=6)
|
||||
assert buffer_no_args.getbuffer() != buffer_method.getbuffer()
|
||||
|
||||
def test_write_unsupported_mode_L(self, tmp_path):
|
||||
"""
|
||||
|
@ -89,18 +108,7 @@ class TestFileWebp:
|
|||
similar to the original file.
|
||||
"""
|
||||
|
||||
temp_file = str(tmp_path / "temp.webp")
|
||||
hopper("L").save(temp_file)
|
||||
with Image.open(temp_file) as image:
|
||||
assert image.mode == self.rgb_mode
|
||||
assert image.size == (128, 128)
|
||||
assert image.format == "WEBP"
|
||||
|
||||
image.load()
|
||||
image.getdata()
|
||||
target = hopper("L").convert(self.rgb_mode)
|
||||
|
||||
assert_image_similar(image, target, 10.0)
|
||||
self._roundtrip(tmp_path, "L", 10.0)
|
||||
|
||||
def test_write_unsupported_mode_P(self, tmp_path):
|
||||
"""
|
||||
|
@ -108,18 +116,7 @@ class TestFileWebp:
|
|||
similar to the original file.
|
||||
"""
|
||||
|
||||
temp_file = str(tmp_path / "temp.webp")
|
||||
hopper("P").save(temp_file)
|
||||
with Image.open(temp_file) as image:
|
||||
assert image.mode == self.rgb_mode
|
||||
assert image.size == (128, 128)
|
||||
assert image.format == "WEBP"
|
||||
|
||||
image.load()
|
||||
image.getdata()
|
||||
target = hopper("P").convert(self.rgb_mode)
|
||||
|
||||
assert_image_similar(image, target, 50.0)
|
||||
self._roundtrip(tmp_path, "P", 50.0)
|
||||
|
||||
def test_WebPEncode_with_invalid_args(self):
|
||||
"""
|
||||
|
|
|
@ -5,7 +5,7 @@ import tempfile
|
|||
|
||||
import PIL
|
||||
import pytest
|
||||
from PIL import Image, ImageDraw, ImagePalette, UnidentifiedImageError
|
||||
from PIL import Image, ImageDraw, ImagePalette, ImageShow, UnidentifiedImageError
|
||||
|
||||
from .helper import (
|
||||
assert_image_equal,
|
||||
|
@ -585,6 +585,22 @@ class TestImage:
|
|||
expected = Image.new(mode, (100, 100), color)
|
||||
assert_image_equal(im.convert(mode), expected)
|
||||
|
||||
def test_showxv_deprecation(self):
|
||||
class TestViewer(ImageShow.Viewer):
|
||||
def show_image(self, image, **options):
|
||||
return True
|
||||
|
||||
viewer = TestViewer()
|
||||
ImageShow.register(viewer, -1)
|
||||
|
||||
im = Image.new("RGB", (50, 50), "white")
|
||||
|
||||
with pytest.warns(DeprecationWarning):
|
||||
Image._showxv(im)
|
||||
|
||||
# Restore original state
|
||||
ImageShow._viewers.pop(0)
|
||||
|
||||
def test_no_resource_warning_on_save(self, tmp_path):
|
||||
# https://github.com/python-pillow/Pillow/issues/835
|
||||
# Arrange
|
||||
|
@ -664,6 +680,18 @@ class TestImage:
|
|||
except OSError as e:
|
||||
assert str(e) == "buffer overrun when reading image file"
|
||||
|
||||
def test_show_deprecation(self, monkeypatch):
|
||||
monkeypatch.setattr(Image, "_show", lambda *args, **kwargs: None)
|
||||
|
||||
im = Image.new("RGB", (50, 50), "white")
|
||||
|
||||
with pytest.warns(None) as raised:
|
||||
im.show()
|
||||
assert not raised
|
||||
|
||||
with pytest.warns(DeprecationWarning):
|
||||
im.show(command="mock")
|
||||
|
||||
|
||||
class MockEncoder:
|
||||
pass
|
||||
|
|
|
@ -236,7 +236,7 @@ class TestImagingPaste:
|
|||
[
|
||||
(127, 191, 254, 191),
|
||||
(111, 207, 206, 110),
|
||||
(127, 254, 127, 0),
|
||||
(255, 255, 255, 0) if mode == "RGBA" else (127, 254, 127, 0),
|
||||
(207, 207, 239, 239),
|
||||
(191, 191, 190, 191),
|
||||
(207, 206, 111, 112),
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import pytest
|
||||
from PIL import Image, ImageMath, ImageMode
|
||||
|
||||
from .helper import convert_to_comparable
|
||||
from .helper import convert_to_comparable, skip_unless_feature
|
||||
|
||||
codecs = dir(Image.core)
|
||||
|
||||
|
@ -254,9 +254,7 @@ def test_mode_F():
|
|||
compare_reduce_with_box(im, factor)
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
"jpeg2k_decoder" not in codecs, reason="JPEG 2000 support not available"
|
||||
)
|
||||
@skip_unless_feature("jpg_2000")
|
||||
def test_jpeg2k():
|
||||
with Image.open("Tests/images/test-card-lossless.jp2") as im:
|
||||
assert im.reduce(2).size == (320, 240)
|
||||
|
|
|
@ -218,7 +218,7 @@ class TestImagingCoreResampleAccuracy:
|
|||
assert_image_equal(im, ref)
|
||||
|
||||
|
||||
class CoreResampleConsistencyTest:
|
||||
class TestCoreResampleConsistency:
|
||||
def make_case(self, mode, fill):
|
||||
im = Image.new(mode, (512, 9), fill)
|
||||
return im.resize((9, 512), Image.LANCZOS), im.load()[0, 0]
|
||||
|
@ -253,7 +253,7 @@ class CoreResampleConsistencyTest:
|
|||
self.run_case(self.make_case("F", 1.192093e-07))
|
||||
|
||||
|
||||
class CoreResampleAlphaCorrectTest:
|
||||
class TestCoreResampleAlphaCorrect:
|
||||
def make_levels_case(self, mode):
|
||||
i = Image.new(mode, (256, 16))
|
||||
px = i.load()
|
||||
|
@ -274,7 +274,7 @@ class CoreResampleAlphaCorrectTest:
|
|||
len(used_colors), y
|
||||
)
|
||||
|
||||
@pytest.mark.skip("Current implementation isn't precise enough")
|
||||
@pytest.mark.xfail(reason="Current implementation isn't precise enough")
|
||||
def test_levels_rgba(self):
|
||||
case = self.make_levels_case("RGBA")
|
||||
self.run_levels_case(case.resize((512, 32), Image.BOX))
|
||||
|
@ -283,7 +283,7 @@ class CoreResampleAlphaCorrectTest:
|
|||
self.run_levels_case(case.resize((512, 32), Image.BICUBIC))
|
||||
self.run_levels_case(case.resize((512, 32), Image.LANCZOS))
|
||||
|
||||
@pytest.mark.skip("Current implementation isn't precise enough")
|
||||
@pytest.mark.xfail(reason="Current implementation isn't precise enough")
|
||||
def test_levels_la(self):
|
||||
case = self.make_levels_case("LA")
|
||||
self.run_levels_case(case.resize((512, 32), Image.BOX))
|
||||
|
@ -329,7 +329,7 @@ class CoreResampleAlphaCorrectTest:
|
|||
self.run_dirty_case(case.resize((20, 20), Image.LANCZOS), (255,))
|
||||
|
||||
|
||||
class CoreResamplePassesTest:
|
||||
class TestCoreResamplePasses:
|
||||
@contextmanager
|
||||
def count(self, diff):
|
||||
count = Image.core.get_stats()["new_count"]
|
||||
|
@ -372,7 +372,7 @@ class CoreResamplePassesTest:
|
|||
assert_image_similar(with_box, cropped, 0.1)
|
||||
|
||||
|
||||
class CoreResampleCoefficientsTest:
|
||||
class TestCoreResampleCoefficients:
|
||||
def test_reduce(self):
|
||||
test_color = 254
|
||||
|
||||
|
@ -401,7 +401,7 @@ class CoreResampleCoefficientsTest:
|
|||
assert histogram[0x100 * 3 + 0xFF] == 0x10000
|
||||
|
||||
|
||||
class CoreResampleBoxTest:
|
||||
class TestCoreResampleBox:
|
||||
def test_wrong_arguments(self):
|
||||
im = hopper()
|
||||
for resample in (
|
||||
|
|
|
@ -4,7 +4,7 @@ import re
|
|||
from io import BytesIO
|
||||
|
||||
import pytest
|
||||
from PIL import Image, ImageMode
|
||||
from PIL import Image, ImageMode, features
|
||||
|
||||
from .helper import assert_image, assert_image_equal, assert_image_similar, hopper
|
||||
|
||||
|
@ -46,7 +46,7 @@ def test_sanity():
|
|||
assert list(map(type, v)) == [str, str, str, str]
|
||||
|
||||
# internal version number
|
||||
assert re.search(r"\d+\.\d+$", ImageCms.core.littlecms_version)
|
||||
assert re.search(r"\d+\.\d+$", features.version_module("littlecms2"))
|
||||
|
||||
skip_missing()
|
||||
i = ImageCms.profileToProfile(hopper(), SRGB, SRGB)
|
||||
|
|
|
@ -5,7 +5,7 @@ from PIL import Image, ImageColor, ImageDraw, ImageFont
|
|||
|
||||
from .helper import (
|
||||
assert_image_equal,
|
||||
assert_image_similar,
|
||||
assert_image_similar_tofile,
|
||||
hopper,
|
||||
skip_unless_feature,
|
||||
)
|
||||
|
@ -71,7 +71,7 @@ def helper_arc(bbox, start, end):
|
|||
draw.arc(bbox, start, end)
|
||||
|
||||
# Assert
|
||||
assert_image_similar(im, Image.open("Tests/images/imagedraw_arc.png"), 1)
|
||||
assert_image_similar_tofile(im, "Tests/images/imagedraw_arc.png", 1)
|
||||
|
||||
|
||||
def test_arc1():
|
||||
|
@ -110,20 +110,19 @@ def test_arc_no_loops():
|
|||
draw.arc(BBOX1, start=start, end=end)
|
||||
|
||||
# Assert
|
||||
assert_image_similar(im, Image.open("Tests/images/imagedraw_arc_no_loops.png"), 1)
|
||||
assert_image_similar_tofile(im, "Tests/images/imagedraw_arc_no_loops.png", 1)
|
||||
|
||||
|
||||
def test_arc_width():
|
||||
# Arrange
|
||||
im = Image.new("RGB", (W, H))
|
||||
draw = ImageDraw.Draw(im)
|
||||
expected = "Tests/images/imagedraw_arc_width.png"
|
||||
|
||||
# Act
|
||||
draw.arc(BBOX1, 10, 260, width=5)
|
||||
|
||||
# Assert
|
||||
assert_image_similar(im, Image.open(expected), 1)
|
||||
assert_image_similar_tofile(im, "Tests/images/imagedraw_arc_width.png", 1)
|
||||
|
||||
|
||||
def test_arc_width_pieslice_large():
|
||||
|
@ -131,26 +130,24 @@ def test_arc_width_pieslice_large():
|
|||
# Arrange
|
||||
im = Image.new("RGB", (W, H))
|
||||
draw = ImageDraw.Draw(im)
|
||||
expected = "Tests/images/imagedraw_arc_width_pieslice.png"
|
||||
|
||||
# Act
|
||||
draw.arc(BBOX1, 10, 260, fill="yellow", width=100)
|
||||
|
||||
# Assert
|
||||
assert_image_similar(im, Image.open(expected), 1)
|
||||
assert_image_similar_tofile(im, "Tests/images/imagedraw_arc_width_pieslice.png", 1)
|
||||
|
||||
|
||||
def test_arc_width_fill():
|
||||
# Arrange
|
||||
im = Image.new("RGB", (W, H))
|
||||
draw = ImageDraw.Draw(im)
|
||||
expected = "Tests/images/imagedraw_arc_width_fill.png"
|
||||
|
||||
# Act
|
||||
draw.arc(BBOX1, 10, 260, fill="yellow", width=5)
|
||||
|
||||
# Assert
|
||||
assert_image_similar(im, Image.open(expected), 1)
|
||||
assert_image_similar_tofile(im, "Tests/images/imagedraw_arc_width_fill.png", 1)
|
||||
|
||||
|
||||
def test_arc_width_non_whole_angle():
|
||||
|
@ -163,7 +160,7 @@ def test_arc_width_non_whole_angle():
|
|||
draw.arc(BBOX1, 10, 259.5, width=5)
|
||||
|
||||
# Assert
|
||||
assert_image_similar(im, Image.open(expected), 1)
|
||||
assert_image_similar_tofile(im, expected, 1)
|
||||
|
||||
|
||||
def test_arc_high():
|
||||
|
@ -203,7 +200,7 @@ def helper_chord(mode, bbox, start, end):
|
|||
draw.chord(bbox, start, end, fill="red", outline="yellow")
|
||||
|
||||
# Assert
|
||||
assert_image_similar(im, Image.open(expected), 1)
|
||||
assert_image_similar_tofile(im, expected, 1)
|
||||
|
||||
|
||||
def test_chord1():
|
||||
|
@ -220,26 +217,24 @@ def test_chord_width():
|
|||
# Arrange
|
||||
im = Image.new("RGB", (W, H))
|
||||
draw = ImageDraw.Draw(im)
|
||||
expected = "Tests/images/imagedraw_chord_width.png"
|
||||
|
||||
# Act
|
||||
draw.chord(BBOX1, 10, 260, outline="yellow", width=5)
|
||||
|
||||
# Assert
|
||||
assert_image_similar(im, Image.open(expected), 1)
|
||||
assert_image_similar_tofile(im, "Tests/images/imagedraw_chord_width.png", 1)
|
||||
|
||||
|
||||
def test_chord_width_fill():
|
||||
# Arrange
|
||||
im = Image.new("RGB", (W, H))
|
||||
draw = ImageDraw.Draw(im)
|
||||
expected = "Tests/images/imagedraw_chord_width_fill.png"
|
||||
|
||||
# Act
|
||||
draw.chord(BBOX1, 10, 260, fill="red", outline="yellow", width=5)
|
||||
|
||||
# Assert
|
||||
assert_image_similar(im, Image.open(expected), 1)
|
||||
assert_image_similar_tofile(im, "Tests/images/imagedraw_chord_width_fill.png", 1)
|
||||
|
||||
|
||||
def test_chord_zero_width():
|
||||
|
@ -277,7 +272,7 @@ def helper_ellipse(mode, bbox):
|
|||
draw.ellipse(bbox, fill="green", outline="blue")
|
||||
|
||||
# Assert
|
||||
assert_image_similar(im, Image.open(expected), 1)
|
||||
assert_image_similar_tofile(im, expected, 1)
|
||||
|
||||
|
||||
def test_ellipse1():
|
||||
|
@ -299,8 +294,8 @@ def test_ellipse_translucent():
|
|||
draw.ellipse(BBOX1, fill=(0, 255, 0, 127))
|
||||
|
||||
# Assert
|
||||
expected = Image.open("Tests/images/imagedraw_ellipse_translucent.png")
|
||||
assert_image_similar(im, expected, 1)
|
||||
expected = "Tests/images/imagedraw_ellipse_translucent.png"
|
||||
assert_image_similar_tofile(im, expected, 1)
|
||||
|
||||
|
||||
def test_ellipse_edge():
|
||||
|
@ -312,7 +307,7 @@ def test_ellipse_edge():
|
|||
draw.ellipse(((0, 0), (W - 1, H - 1)), fill="white")
|
||||
|
||||
# Assert
|
||||
assert_image_similar(im, Image.open("Tests/images/imagedraw_ellipse_edge.png"), 1)
|
||||
assert_image_similar_tofile(im, "Tests/images/imagedraw_ellipse_edge.png", 1)
|
||||
|
||||
|
||||
def test_ellipse_symmetric():
|
||||
|
@ -330,39 +325,36 @@ def test_ellipse_width():
|
|||
# Arrange
|
||||
im = Image.new("RGB", (W, H))
|
||||
draw = ImageDraw.Draw(im)
|
||||
expected = "Tests/images/imagedraw_ellipse_width.png"
|
||||
|
||||
# Act
|
||||
draw.ellipse(BBOX1, outline="blue", width=5)
|
||||
|
||||
# Assert
|
||||
assert_image_similar(im, Image.open(expected), 1)
|
||||
assert_image_similar_tofile(im, "Tests/images/imagedraw_ellipse_width.png", 1)
|
||||
|
||||
|
||||
def test_ellipse_width_large():
|
||||
# Arrange
|
||||
im = Image.new("RGB", (500, 500))
|
||||
draw = ImageDraw.Draw(im)
|
||||
expected = "Tests/images/imagedraw_ellipse_width_large.png"
|
||||
|
||||
# Act
|
||||
draw.ellipse((25, 25, 475, 475), outline="blue", width=75)
|
||||
|
||||
# Assert
|
||||
assert_image_similar(im, Image.open(expected), 1)
|
||||
assert_image_similar_tofile(im, "Tests/images/imagedraw_ellipse_width_large.png", 1)
|
||||
|
||||
|
||||
def test_ellipse_width_fill():
|
||||
# Arrange
|
||||
im = Image.new("RGB", (W, H))
|
||||
draw = ImageDraw.Draw(im)
|
||||
expected = "Tests/images/imagedraw_ellipse_width_fill.png"
|
||||
|
||||
# Act
|
||||
draw.ellipse(BBOX1, fill="green", outline="blue", width=5)
|
||||
|
||||
# Assert
|
||||
assert_image_similar(im, Image.open(expected), 1)
|
||||
assert_image_similar_tofile(im, "Tests/images/imagedraw_ellipse_width_fill.png", 1)
|
||||
|
||||
|
||||
def test_ellipse_zero_width():
|
||||
|
@ -484,7 +476,7 @@ def helper_pieslice(bbox, start, end):
|
|||
draw.pieslice(bbox, start, end, fill="white", outline="blue")
|
||||
|
||||
# Assert
|
||||
assert_image_similar(im, Image.open("Tests/images/imagedraw_pieslice.png"), 1)
|
||||
assert_image_similar_tofile(im, "Tests/images/imagedraw_pieslice.png", 1)
|
||||
|
||||
|
||||
def test_pieslice1():
|
||||
|
@ -501,13 +493,12 @@ def test_pieslice_width():
|
|||
# Arrange
|
||||
im = Image.new("RGB", (W, H))
|
||||
draw = ImageDraw.Draw(im)
|
||||
expected = "Tests/images/imagedraw_pieslice_width.png"
|
||||
|
||||
# Act
|
||||
draw.pieslice(BBOX1, 10, 260, outline="blue", width=5)
|
||||
|
||||
# Assert
|
||||
assert_image_similar(im, Image.open(expected), 1)
|
||||
assert_image_similar_tofile(im, "Tests/images/imagedraw_pieslice_width.png", 1)
|
||||
|
||||
|
||||
def test_pieslice_width_fill():
|
||||
|
@ -520,7 +511,7 @@ def test_pieslice_width_fill():
|
|||
draw.pieslice(BBOX1, 10, 260, fill="white", outline="blue", width=5)
|
||||
|
||||
# Assert
|
||||
assert_image_similar(im, Image.open(expected), 1)
|
||||
assert_image_similar_tofile(im, expected, 1)
|
||||
|
||||
|
||||
def test_pieslice_zero_width():
|
||||
|
@ -644,13 +635,12 @@ def test_big_rectangle():
|
|||
im = Image.new("RGB", (W, H))
|
||||
bbox = [(-1, -1), (W + 1, H + 1)]
|
||||
draw = ImageDraw.Draw(im)
|
||||
expected = "Tests/images/imagedraw_big_rectangle.png"
|
||||
|
||||
# Act
|
||||
draw.rectangle(bbox, fill="orange")
|
||||
|
||||
# Assert
|
||||
assert_image_similar(im, Image.open(expected), 1)
|
||||
assert_image_similar_tofile(im, "Tests/images/imagedraw_big_rectangle.png", 1)
|
||||
|
||||
|
||||
def test_rectangle_width():
|
||||
|
@ -951,13 +941,25 @@ def test_wide_line_dot():
|
|||
# Arrange
|
||||
im = Image.new("RGB", (W, H))
|
||||
draw = ImageDraw.Draw(im)
|
||||
expected = "Tests/images/imagedraw_wide_line_dot.png"
|
||||
|
||||
# Act
|
||||
draw.line([(50, 50), (50, 50)], width=3)
|
||||
|
||||
# Assert
|
||||
assert_image_similar(im, Image.open(expected), 1)
|
||||
assert_image_similar_tofile(im, "Tests/images/imagedraw_wide_line_dot.png", 1)
|
||||
|
||||
|
||||
def test_wide_line_larger_than_int():
|
||||
# Arrange
|
||||
im = Image.new("RGB", (W, H))
|
||||
draw = ImageDraw.Draw(im)
|
||||
expected = "Tests/images/imagedraw_wide_line_larger_than_int.png"
|
||||
|
||||
# Act
|
||||
draw.line([(0, 0), (32768, 32768)], width=3)
|
||||
|
||||
# Assert
|
||||
assert_image_similar_tofile(im, expected, 1)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
|
@ -1044,13 +1046,12 @@ def test_wide_line_dot():
|
|||
def test_line_joint(xy):
|
||||
im = Image.new("RGB", (500, 325))
|
||||
draw = ImageDraw.Draw(im)
|
||||
expected = "Tests/images/imagedraw_line_joint_curve.png"
|
||||
|
||||
# Act
|
||||
draw.line(xy, GRAY, 50, "curve")
|
||||
|
||||
# Assert
|
||||
assert_image_similar(im, Image.open(expected), 3)
|
||||
assert_image_similar_tofile(im, "Tests/images/imagedraw_line_joint_curve.png", 3)
|
||||
|
||||
|
||||
def test_textsize_empty_string():
|
||||
|
@ -1091,8 +1092,8 @@ def test_stroke():
|
|||
draw.text((10, 10), "A", "#f00", font, stroke_width=2, stroke_fill=stroke_fill)
|
||||
|
||||
# Assert
|
||||
assert_image_similar(
|
||||
im, Image.open("Tests/images/imagedraw_stroke_" + suffix + ".png"), 3.1
|
||||
assert_image_similar_tofile(
|
||||
im, "Tests/images/imagedraw_stroke_" + suffix + ".png", 3.1
|
||||
)
|
||||
|
||||
|
||||
|
@ -1107,9 +1108,7 @@ def test_stroke_descender():
|
|||
draw.text((10, 0), "y", "#f00", font, stroke_width=2, stroke_fill="#0f0")
|
||||
|
||||
# Assert
|
||||
assert_image_similar(
|
||||
im, Image.open("Tests/images/imagedraw_stroke_descender.png"), 6.76
|
||||
)
|
||||
assert_image_similar_tofile(im, "Tests/images/imagedraw_stroke_descender.png", 6.76)
|
||||
|
||||
|
||||
@skip_unless_feature("freetype2")
|
||||
|
@ -1125,9 +1124,7 @@ def test_stroke_multiline():
|
|||
)
|
||||
|
||||
# Assert
|
||||
assert_image_similar(
|
||||
im, Image.open("Tests/images/imagedraw_stroke_multiline.png"), 3.3
|
||||
)
|
||||
assert_image_similar_tofile(im, "Tests/images/imagedraw_stroke_multiline.png", 3.3)
|
||||
|
||||
|
||||
def test_same_color_outline():
|
||||
|
@ -1166,4 +1163,4 @@ def test_same_color_outline():
|
|||
expected = "Tests/images/imagedraw_outline_{}_{}.png".format(
|
||||
operation, mode
|
||||
)
|
||||
assert_image_similar(im, Image.open(expected), 1)
|
||||
assert_image_similar_tofile(im, expected, 1)
|
||||
|
|
|
@ -7,10 +7,11 @@ import sys
|
|||
from io import BytesIO
|
||||
|
||||
import pytest
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
from PIL import Image, ImageDraw, ImageFont, features
|
||||
|
||||
from .helper import (
|
||||
assert_image_equal,
|
||||
assert_image_equal_tofile,
|
||||
assert_image_similar,
|
||||
assert_image_similar_tofile,
|
||||
is_pypy,
|
||||
|
@ -40,7 +41,7 @@ class TestImageFont:
|
|||
|
||||
@classmethod
|
||||
def setup_class(self):
|
||||
freetype = distutils.version.StrictVersion(ImageFont.core.freetype2_version)
|
||||
freetype = distutils.version.StrictVersion(features.version_module("freetype2"))
|
||||
|
||||
self.metrics = self.METRICS["Default"]
|
||||
for conditions, metrics in self.METRICS.items():
|
||||
|
@ -67,7 +68,7 @@ class TestImageFont:
|
|||
)
|
||||
|
||||
def test_sanity(self):
|
||||
assert re.search(r"\d+\.\d+\.\d+$", ImageFont.core.freetype2_version)
|
||||
assert re.search(r"\d+\.\d+\.\d+$", features.version_module("freetype2"))
|
||||
|
||||
def test_font_properties(self):
|
||||
ttf = self.get_font()
|
||||
|
@ -150,6 +151,18 @@ class TestImageFont:
|
|||
|
||||
assert_image_equal(img_path, img_filelike)
|
||||
|
||||
def test_transparent_background(self):
|
||||
im = Image.new(mode="RGBA", size=(300, 100))
|
||||
draw = ImageDraw.Draw(im)
|
||||
ttf = self.get_font()
|
||||
|
||||
txt = "Hello World!"
|
||||
draw.text((10, 10), txt, font=ttf)
|
||||
|
||||
target = "Tests/images/transparent_background_text.png"
|
||||
with Image.open(target) as target_img:
|
||||
assert_image_similar(im, target_img, 4.09)
|
||||
|
||||
def test_textsize_equal(self):
|
||||
im = Image.new(mode="RGB", size=(300, 100))
|
||||
draw = ImageDraw.Draw(im)
|
||||
|
@ -442,7 +455,7 @@ class TestImageFont:
|
|||
with pytest.raises(UnicodeEncodeError):
|
||||
font.getsize("’")
|
||||
|
||||
@pytest.mark.skipif(is_pypy(), reason="failing on PyPy")
|
||||
@pytest.mark.xfail(is_pypy(), reason="failing on PyPy with Raqm")
|
||||
def test_unicode_extended(self):
|
||||
# issue #3777
|
||||
text = "A\u278A\U0001F12B"
|
||||
|
@ -607,7 +620,7 @@ class TestImageFont:
|
|||
def test_variation_get(self):
|
||||
font = self.get_font()
|
||||
|
||||
freetype = distutils.version.StrictVersion(ImageFont.core.freetype2_version)
|
||||
freetype = distutils.version.StrictVersion(features.version_module("freetype2"))
|
||||
if freetype < "2.9.1":
|
||||
with pytest.raises(NotImplementedError):
|
||||
font.get_variation_names()
|
||||
|
@ -679,7 +692,7 @@ class TestImageFont:
|
|||
def test_variation_set_by_name(self):
|
||||
font = self.get_font()
|
||||
|
||||
freetype = distutils.version.StrictVersion(ImageFont.core.freetype2_version)
|
||||
freetype = distutils.version.StrictVersion(features.version_module("freetype2"))
|
||||
if freetype < "2.9.1":
|
||||
with pytest.raises(NotImplementedError):
|
||||
font.set_variation_by_name("Bold")
|
||||
|
@ -703,7 +716,7 @@ class TestImageFont:
|
|||
def test_variation_set_by_axes(self):
|
||||
font = self.get_font()
|
||||
|
||||
freetype = distutils.version.StrictVersion(ImageFont.core.freetype2_version)
|
||||
freetype = distutils.version.StrictVersion(features.version_module("freetype2"))
|
||||
if freetype < "2.9.1":
|
||||
with pytest.raises(NotImplementedError):
|
||||
font.set_variation_by_axes([100])
|
||||
|
@ -724,3 +737,19 @@ class TestImageFont:
|
|||
@skip_unless_feature("raqm")
|
||||
class TestImageFont_RaqmLayout(TestImageFont):
|
||||
LAYOUT_ENGINE = ImageFont.LAYOUT_RAQM
|
||||
|
||||
|
||||
def test_render_mono_size():
|
||||
# issue 4177
|
||||
|
||||
if distutils.version.StrictVersion(ImageFont.core.freetype2_version) < "2.4":
|
||||
pytest.skip("Different metrics")
|
||||
|
||||
im = Image.new("P", (100, 30), "white")
|
||||
draw = ImageDraw.Draw(im)
|
||||
ttf = ImageFont.truetype(
|
||||
"Tests/fonts/DejaVuSans.ttf", 18, layout_engine=ImageFont.LAYOUT_BASIC
|
||||
)
|
||||
|
||||
draw.text((10, 10), "r" * 10, "black", ttf)
|
||||
assert_image_equal_tofile(im, "Tests/images/text_mono.gif")
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
from PIL import Image, ImageGrab
|
||||
|
||||
from .helper import assert_image
|
||||
from .helper import assert_image, assert_image_equal_tofile, skip_unless_feature
|
||||
|
||||
|
||||
class TestImageGrab:
|
||||
|
@ -22,7 +23,7 @@ class TestImageGrab:
|
|||
im = ImageGrab.grab(bbox=(10, 20, 50, 80))
|
||||
assert_image(im, im.mode, (40, 60))
|
||||
|
||||
@pytest.mark.skipif(not Image.core.HAVE_XCB, reason="requires XCB")
|
||||
@skip_unless_feature("xcb")
|
||||
def test_grab_x11(self):
|
||||
try:
|
||||
if sys.platform not in ("win32", "darwin"):
|
||||
|
@ -45,7 +46,7 @@ class TestImageGrab:
|
|||
ImageGrab.grab(xdisplay="")
|
||||
assert str(e.value).startswith("Pillow was built without XCB support")
|
||||
|
||||
@pytest.mark.skipif(not Image.core.HAVE_XCB, reason="requires XCB")
|
||||
@skip_unless_feature("xcb")
|
||||
def test_grab_invalid_xdisplay(self):
|
||||
with pytest.raises(OSError) as e:
|
||||
ImageGrab.grab(xdisplay="error.test:0.0")
|
||||
|
@ -71,3 +72,27 @@ $bmp = New-Object Drawing.Bitmap 200, 200
|
|||
|
||||
im = ImageGrab.grabclipboard()
|
||||
assert_image(im, im.mode, im.size)
|
||||
|
||||
@pytest.mark.skipif(sys.platform != "win32", reason="Windows only")
|
||||
def test_grabclipboard_file(self):
|
||||
p = subprocess.Popen(["powershell", "-command", "-"], stdin=subprocess.PIPE)
|
||||
p.stdin.write(rb'Set-Clipboard -Path "Tests\images\hopper.gif"')
|
||||
p.communicate()
|
||||
|
||||
im = ImageGrab.grabclipboard()
|
||||
assert len(im) == 1
|
||||
assert os.path.samefile(im[0], "Tests/images/hopper.gif")
|
||||
|
||||
@pytest.mark.skipif(sys.platform != "win32", reason="Windows only")
|
||||
def test_grabclipboard_png(self):
|
||||
p = subprocess.Popen(["powershell", "-command", "-"], stdin=subprocess.PIPE)
|
||||
p.stdin.write(
|
||||
rb"""$bytes = [System.IO.File]::ReadAllBytes("Tests\images\hopper.png")
|
||||
$ms = new-object System.IO.MemoryStream(, $bytes)
|
||||
[Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
|
||||
[Windows.Forms.Clipboard]::SetData("PNG", $ms)"""
|
||||
)
|
||||
p.communicate()
|
||||
|
||||
im = ImageGrab.grabclipboard()
|
||||
assert_image_equal_tofile(im, "Tests/images/hopper.png")
|
||||
|
|
|
@ -17,19 +17,21 @@ def test_register():
|
|||
ImageShow._viewers.pop()
|
||||
|
||||
|
||||
def test_viewer_show():
|
||||
@pytest.mark.parametrize(
|
||||
"order", [-1, 0],
|
||||
)
|
||||
def test_viewer_show(order):
|
||||
class TestViewer(ImageShow.Viewer):
|
||||
methodCalled = False
|
||||
|
||||
def show_image(self, image, **options):
|
||||
self.methodCalled = True
|
||||
return True
|
||||
|
||||
viewer = TestViewer()
|
||||
ImageShow.register(viewer, -1)
|
||||
ImageShow.register(viewer, order)
|
||||
|
||||
for mode in ("1", "I;16", "LA", "RGB", "RGBA"):
|
||||
with hopper() as im:
|
||||
viewer.methodCalled = False
|
||||
with hopper(mode) as im:
|
||||
assert ImageShow.show(im)
|
||||
assert viewer.methodCalled
|
||||
|
||||
|
|
84
docs/PIL.rst
84
docs/PIL.rst
|
@ -4,98 +4,89 @@ PIL Package (autodoc of remaining modules)
|
|||
Reference for modules whose documentation has not yet been ported or written
|
||||
can be found here.
|
||||
|
||||
:mod:`BdfFontFile` Module
|
||||
-------------------------
|
||||
:mod:`PIL` Module
|
||||
-----------------
|
||||
|
||||
.. py:module:: PIL
|
||||
|
||||
.. autoexception:: UnidentifiedImageError
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`~PIL.BdfFontFile` Module
|
||||
------------------------------
|
||||
|
||||
.. automodule:: PIL.BdfFontFile
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`ContainerIO` Module
|
||||
-------------------------
|
||||
:mod:`~PIL.ContainerIO` Module
|
||||
------------------------------
|
||||
|
||||
.. automodule:: PIL.ContainerIO
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`FontFile` Module
|
||||
----------------------
|
||||
:mod:`~PIL.FontFile` Module
|
||||
---------------------------
|
||||
|
||||
.. automodule:: PIL.FontFile
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`GdImageFile` Module
|
||||
-------------------------
|
||||
:mod:`~PIL.GdImageFile` Module
|
||||
------------------------------
|
||||
|
||||
.. automodule:: PIL.GdImageFile
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`GimpGradientFile` Module
|
||||
------------------------------
|
||||
:mod:`~PIL.GimpGradientFile` Module
|
||||
-----------------------------------
|
||||
|
||||
.. automodule:: PIL.GimpGradientFile
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`GimpPaletteFile` Module
|
||||
-----------------------------
|
||||
:mod:`~PIL.GimpPaletteFile` Module
|
||||
----------------------------------
|
||||
|
||||
.. automodule:: PIL.GimpPaletteFile
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
.. intentionally skipped documenting this because it's not documented anywhere
|
||||
|
||||
:mod:`ImageDraw2` Module
|
||||
------------------------
|
||||
:mod:`~PIL.ImageDraw2` Module
|
||||
-----------------------------
|
||||
|
||||
.. automodule:: PIL.ImageDraw2
|
||||
:members:
|
||||
:member-order: bysource
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`ImageShow` Module
|
||||
-----------------------
|
||||
|
||||
.. automodule:: PIL.ImageShow
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`ImageTransform` Module
|
||||
----------------------------
|
||||
:mod:`~PIL.ImageTransform` Module
|
||||
---------------------------------
|
||||
|
||||
.. automodule:: PIL.ImageTransform
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`JpegPresets` Module
|
||||
-------------------------
|
||||
|
||||
.. automodule:: PIL.JpegPresets
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`PaletteFile` Module
|
||||
-------------------------
|
||||
:mod:`~PIL.PaletteFile` Module
|
||||
------------------------------
|
||||
|
||||
.. automodule:: PIL.PaletteFile
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`PcfFontFile` Module
|
||||
-------------------------
|
||||
:mod:`~PIL.PcfFontFile` Module
|
||||
------------------------------
|
||||
|
||||
.. automodule:: PIL.PcfFontFile
|
||||
:members:
|
||||
|
@ -125,27 +116,18 @@ can be found here.
|
|||
:show-inheritance:
|
||||
|
||||
|
||||
:mod:`TarIO` Module
|
||||
-------------------
|
||||
:mod:`~PIL.TarIO` Module
|
||||
------------------------
|
||||
|
||||
.. automodule:: PIL.TarIO
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`WalImageFile` Module
|
||||
--------------------------
|
||||
:mod:`~PIL.WalImageFile` Module
|
||||
-------------------------------
|
||||
|
||||
.. automodule:: PIL.WalImageFile
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`_binary` Module
|
||||
---------------------
|
||||
|
||||
.. automodule:: PIL._binary
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ import sphinx_rtd_theme
|
|||
# -- General configuration ------------------------------------------------
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
# needs_sphinx = '1.0'
|
||||
needs_sphinx = "2.4"
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
|
|
|
@ -12,13 +12,30 @@ Deprecated features
|
|||
Below are features which are considered deprecated. Where appropriate,
|
||||
a ``DeprecationWarning`` is issued.
|
||||
|
||||
Image.show command parameter
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. deprecated:: 7.2.0
|
||||
|
||||
The ``command`` parameter was deprecated and will be removed in a future release.
|
||||
Use a subclass of ``ImageShow.Viewer`` instead.
|
||||
|
||||
Image._showxv
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
.. deprecated:: 7.2.0
|
||||
|
||||
``Image._showxv`` has been deprecated. Use :py:meth:`~PIL.Image.Image.show`
|
||||
instead. If custom behaviour is required, use :py:meth:`~PIL.ImageShow.register` to add
|
||||
a custom :py:class:`~PIL.ImageShow.Viewer` class.
|
||||
|
||||
ImageFile.raise_ioerror
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. deprecated:: 7.2.0
|
||||
|
||||
``IOError`` was merged into ``OSError`` in Python 3.3. So, ``ImageFile.raise_ioerror``
|
||||
is now deprecated and will be removed in a future released. Use
|
||||
is now deprecated and will be removed in a future release. Use
|
||||
``ImageFile.raise_oserror`` instead.
|
||||
|
||||
PILLOW_VERSION constant
|
||||
|
|
|
@ -249,8 +249,8 @@ class DXT1Decoder(ImageFile.PyDecoder):
|
|||
def decode(self, buffer):
|
||||
try:
|
||||
self.set_as_raw(_dxt1(self.fd, self.state.xsize, self.state.ysize))
|
||||
except struct.error:
|
||||
raise OSError("Truncated DDS file")
|
||||
except struct.error as e:
|
||||
raise OSError("Truncated DDS file") from e
|
||||
return 0, 0
|
||||
|
||||
|
||||
|
@ -260,8 +260,8 @@ class DXT5Decoder(ImageFile.PyDecoder):
|
|||
def decode(self, buffer):
|
||||
try:
|
||||
self.set_as_raw(_dxt5(self.fd, self.state.xsize, self.state.ysize))
|
||||
except struct.error:
|
||||
raise OSError("Truncated DDS file")
|
||||
except struct.error as e:
|
||||
raise OSError("Truncated DDS file") from e
|
||||
return 0, 0
|
||||
|
||||
|
||||
|
|
|
@ -121,39 +121,47 @@ Filters
|
|||
For geometry operations that may map multiple input pixels to a single output
|
||||
pixel, the Python Imaging Library provides different resampling *filters*.
|
||||
|
||||
``NEAREST``
|
||||
.. py:currentmodule:: PIL.Image
|
||||
|
||||
.. data:: NEAREST
|
||||
|
||||
Pick one nearest pixel from the input image. Ignore all other input pixels.
|
||||
|
||||
``BOX``
|
||||
.. data:: BOX
|
||||
|
||||
Each pixel of source image contributes to one pixel of the
|
||||
destination image with identical weights.
|
||||
For upscaling is equivalent of ``NEAREST``.
|
||||
For upscaling is equivalent of :data:`NEAREST`.
|
||||
This filter can only be used with the :py:meth:`~PIL.Image.Image.resize`
|
||||
and :py:meth:`~PIL.Image.Image.thumbnail` methods.
|
||||
|
||||
.. versionadded:: 3.4.0
|
||||
|
||||
``BILINEAR``
|
||||
.. data:: BILINEAR
|
||||
|
||||
For resize calculate the output pixel value using linear interpolation
|
||||
on all pixels that may contribute to the output value.
|
||||
For other transformations linear interpolation over a 2x2 environment
|
||||
in the input image is used.
|
||||
|
||||
``HAMMING``
|
||||
Produces a sharper image than ``BILINEAR``, doesn't have dislocations
|
||||
on local level like with ``BOX``.
|
||||
.. data:: HAMMING
|
||||
|
||||
Produces a sharper image than :data:`BILINEAR`, doesn't have dislocations
|
||||
on local level like with :data:`BOX`.
|
||||
This filter can only be used with the :py:meth:`~PIL.Image.Image.resize`
|
||||
and :py:meth:`~PIL.Image.Image.thumbnail` methods.
|
||||
|
||||
.. versionadded:: 3.4.0
|
||||
|
||||
``BICUBIC``
|
||||
.. data:: BICUBIC
|
||||
|
||||
For resize calculate the output pixel value using cubic interpolation
|
||||
on all pixels that may contribute to the output value.
|
||||
For other transformations cubic interpolation over a 4x4 environment
|
||||
in the input image is used.
|
||||
|
||||
``LANCZOS``
|
||||
.. data:: LANCZOS
|
||||
|
||||
Calculate the output pixel value using a high-quality Lanczos filter (a
|
||||
truncated sinc) on all pixels that may contribute to the output value.
|
||||
This filter can only be used with the :py:meth:`~PIL.Image.Image.resize`
|
||||
|
@ -165,19 +173,19 @@ pixel, the Python Imaging Library provides different resampling *filters*.
|
|||
Filters comparison table
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
+------------+-------------+-----------+-------------+
|
||||
| Filter | Downscaling | Upscaling | Performance |
|
||||
| | quality | quality | |
|
||||
+============+=============+===========+=============+
|
||||
|``NEAREST`` | | | ⭐⭐⭐⭐⭐ |
|
||||
+------------+-------------+-----------+-------------+
|
||||
|``BOX`` | ⭐ | | ⭐⭐⭐⭐ |
|
||||
+------------+-------------+-----------+-------------+
|
||||
|``BILINEAR``| ⭐ | ⭐ | ⭐⭐⭐ |
|
||||
+------------+-------------+-----------+-------------+
|
||||
|``HAMMING`` | ⭐⭐ | | ⭐⭐⭐ |
|
||||
+------------+-------------+-----------+-------------+
|
||||
|``BICUBIC`` | ⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐ |
|
||||
+------------+-------------+-----------+-------------+
|
||||
|``LANCZOS`` | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐ |
|
||||
+------------+-------------+-----------+-------------+
|
||||
+----------------+-------------+-----------+-------------+
|
||||
| Filter | Downscaling | Upscaling | Performance |
|
||||
| | quality | quality | |
|
||||
+================+=============+===========+=============+
|
||||
|:data:`NEAREST` | | | ⭐⭐⭐⭐⭐ |
|
||||
+----------------+-------------+-----------+-------------+
|
||||
|:data:`BOX` | ⭐ | | ⭐⭐⭐⭐ |
|
||||
+----------------+-------------+-----------+-------------+
|
||||
|:data:`BILINEAR`| ⭐ | ⭐ | ⭐⭐⭐ |
|
||||
+----------------+-------------+-----------+-------------+
|
||||
|:data:`HAMMING` | ⭐⭐ | | ⭐⭐⭐ |
|
||||
+----------------+-------------+-----------+-------------+
|
||||
|:data:`BICUBIC` | ⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐ |
|
||||
+----------------+-------------+-----------+-------------+
|
||||
|:data:`LANCZOS` | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐ |
|
||||
+----------------+-------------+-----------+-------------+
|
||||
|
|
|
@ -8,7 +8,7 @@ Over 30 different file formats can be identified and read by the library.
|
|||
Write support is less extensive, but most common interchange and presentation
|
||||
formats are supported.
|
||||
|
||||
The :py:meth:`~PIL.Image.Image.open` function identifies files from their
|
||||
The :py:meth:`~PIL.Image.open` function identifies files from their
|
||||
contents, not their names, but the :py:meth:`~PIL.Image.Image.save` method
|
||||
looks at the name to determine which format to use, unless the format is given
|
||||
explicitly.
|
||||
|
@ -25,7 +25,7 @@ Pillow reads and writes Windows and OS/2 BMP files containing ``1``, ``L``, ``P`
|
|||
or ``RGB`` data. 16-colour images are read as ``P`` images. Run-length encoding
|
||||
is not supported.
|
||||
|
||||
The :py:meth:`~PIL.Image.Image.open` method sets the following
|
||||
The :py:meth:`~PIL.Image.open` method sets the following
|
||||
:py:attr:`~PIL.Image.Image.info` properties:
|
||||
|
||||
**compression**
|
||||
|
@ -74,7 +74,7 @@ are used or GIF89a is already in use.
|
|||
Note that GIF files are always read as grayscale (``L``)
|
||||
or palette mode (``P``) images.
|
||||
|
||||
The :py:meth:`~PIL.Image.Image.open` method sets the following
|
||||
The :py:meth:`~PIL.Image.open` method sets the following
|
||||
:py:attr:`~PIL.Image.Image.info` properties:
|
||||
|
||||
**background**
|
||||
|
@ -203,7 +203,7 @@ ICNS
|
|||
Pillow reads and (macOS only) writes macOS ``.icns`` files. By default, the
|
||||
largest available icon is read, though you can override this by setting the
|
||||
:py:attr:`~PIL.Image.Image.size` property before calling
|
||||
:py:meth:`~PIL.Image.Image.load`. The :py:meth:`~PIL.Image.Image.open` method
|
||||
:py:meth:`~PIL.Image.Image.load`. The :py:meth:`~PIL.Image.open` method
|
||||
sets the following :py:attr:`~PIL.Image.Image.info` property:
|
||||
|
||||
**sizes**
|
||||
|
@ -257,7 +257,7 @@ Using the :py:meth:`~PIL.Image.Image.draft` method, you can speed things up by
|
|||
converting ``RGB`` images to ``L``, and resize images to 1/2, 1/4 or 1/8 of
|
||||
their original size while loading them.
|
||||
|
||||
The :py:meth:`~PIL.Image.Image.open` method may set the following
|
||||
The :py:meth:`~PIL.Image.open` method may set the following
|
||||
:py:attr:`~PIL.Image.Image.info` properties if available:
|
||||
|
||||
**jfif**
|
||||
|
@ -697,7 +697,7 @@ Pillow also reads SPIDER stack files containing sequences of SPIDER images. The
|
|||
:py:meth:`~PIL.Image.Image.seek` and :py:meth:`~PIL.Image.Image.tell` methods are supported, and
|
||||
random access is allowed.
|
||||
|
||||
The :py:meth:`~PIL.Image.Image.open` method sets the following attributes:
|
||||
The :py:meth:`~PIL.Image.open` method sets the following attributes:
|
||||
|
||||
**format**
|
||||
Set to ``SPIDER``
|
||||
|
@ -750,7 +750,7 @@ uncompressed files.
|
|||
support for reading Packbits, LZW and JPEG compressed TIFFs
|
||||
without using libtiff.
|
||||
|
||||
The :py:meth:`~PIL.Image.Image.open` method sets the following
|
||||
The :py:meth:`~PIL.Image.open` method sets the following
|
||||
:py:attr:`~PIL.Image.Image.info` properties:
|
||||
|
||||
**compression**
|
||||
|
@ -1021,7 +1021,7 @@ FLI, FLC
|
|||
|
||||
Pillow reads Autodesk FLI and FLC animations.
|
||||
|
||||
The :py:meth:`~PIL.Image.Image.open` method sets the following
|
||||
The :py:meth:`~PIL.Image.open` method sets the following
|
||||
:py:attr:`~PIL.Image.Image.info` properties:
|
||||
|
||||
**duration**
|
||||
|
@ -1054,7 +1054,7 @@ GBR
|
|||
|
||||
The GBR decoder reads GIMP brush files, version 1 and 2.
|
||||
|
||||
The :py:meth:`~PIL.Image.Image.open` method sets the following
|
||||
The :py:meth:`~PIL.Image.open` method sets the following
|
||||
:py:attr:`~PIL.Image.Image.info` properties:
|
||||
|
||||
**comment**
|
||||
|
@ -1069,7 +1069,7 @@ GD
|
|||
Pillow reads uncompressed GD2 files. Note that you must use
|
||||
:py:func:`PIL.GdImageFile.open` to read such a file.
|
||||
|
||||
The :py:meth:`~PIL.Image.Image.open` method sets the following
|
||||
The :py:meth:`~PIL.Image.open` method sets the following
|
||||
:py:attr:`~PIL.Image.Image.info` properties:
|
||||
|
||||
**transparency**
|
||||
|
@ -1185,7 +1185,7 @@ XPM
|
|||
|
||||
Pillow reads X pixmap files (mode ``P``) with 256 colors or less.
|
||||
|
||||
The :py:meth:`~PIL.Image.Image.open` method sets the following
|
||||
The :py:meth:`~PIL.Image.open` method sets the following
|
||||
:py:attr:`~PIL.Image.Image.info` properties:
|
||||
|
||||
**transparency**
|
||||
|
|
|
@ -156,7 +156,7 @@ Many of Pillow's features require external libraries:
|
|||
* **littlecms** provides color management
|
||||
|
||||
* Pillow version 2.2.1 and below uses liblcms1, Pillow 2.3.0 and
|
||||
above uses liblcms2. Tested with **1.19** and **2.7-2.9**.
|
||||
above uses liblcms2. Tested with **1.19** and **2.7-2.11**.
|
||||
|
||||
* **libwebp** provides the WebP format.
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ to this::
|
|||
|
||||
from PIL import Image
|
||||
|
||||
The :py:mod:`_imaging` module has been moved. You can now import it like this::
|
||||
The :py:mod:`~PIL._imaging` module has been moved. You can now import it like this::
|
||||
|
||||
from PIL.Image import core as _imaging
|
||||
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
.. py:module:: PIL.ExifTags
|
||||
.. py:currentmodule:: PIL.ExifTags
|
||||
|
||||
:py:mod:`ExifTags` Module
|
||||
==========================
|
||||
:py:mod:`~PIL.ExifTags` Module
|
||||
==============================
|
||||
|
||||
The :py:mod:`ExifTags` module exposes two dictionaries which
|
||||
The :py:mod:`~PIL.ExifTags` module exposes two dictionaries which
|
||||
provide constants and clear-text names for various well-known EXIF tags.
|
||||
|
||||
.. py:class:: PIL.ExifTags.TAGS
|
||||
.. py:data:: TAGS
|
||||
:type: dict
|
||||
|
||||
The TAG dictionary maps 16-bit integer EXIF tag enumerations to
|
||||
descriptive string names. For instance:
|
||||
|
@ -16,7 +17,8 @@ provide constants and clear-text names for various well-known EXIF tags.
|
|||
>>> TAGS[0x010e]
|
||||
'ImageDescription'
|
||||
|
||||
.. py:class:: PIL.ExifTags.GPSTAGS
|
||||
.. py:data:: GPSTAGS
|
||||
:type: dict
|
||||
|
||||
The GPSTAGS dictionary maps 8-bit integer EXIF gps enumerations to
|
||||
descriptive string names. For instance:
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
.. py:module:: PIL.Image
|
||||
.. py:currentmodule:: PIL.Image
|
||||
|
||||
:py:mod:`Image` Module
|
||||
======================
|
||||
:py:mod:`~PIL.Image` Module
|
||||
===========================
|
||||
|
||||
The :py:mod:`~PIL.Image` module provides a class with the same name which is
|
||||
used to represent a PIL image. The module also provides a number of factory
|
||||
|
@ -76,9 +76,16 @@ Constructing images
|
|||
.. autofunction:: new
|
||||
.. autofunction:: fromarray
|
||||
.. autofunction:: frombytes
|
||||
.. autofunction:: fromstring
|
||||
.. autofunction:: frombuffer
|
||||
|
||||
Generating images
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. autofunction:: effect_mandelbrot
|
||||
.. autofunction:: effect_noise
|
||||
.. autofunction:: linear_gradient
|
||||
.. autofunction:: radial_gradient
|
||||
|
||||
Registering plugins
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
@ -88,12 +95,14 @@ Registering plugins
|
|||
ignore them.
|
||||
|
||||
.. autofunction:: register_open
|
||||
.. autofunction:: register_decoder
|
||||
.. autofunction:: register_mime
|
||||
.. autofunction:: register_save
|
||||
.. autofunction:: register_encoder
|
||||
.. autofunction:: register_save_all
|
||||
.. autofunction:: register_extension
|
||||
|
||||
.. autofunction:: register_extensions
|
||||
.. autofunction:: registered_extensions
|
||||
.. autofunction:: register_decoder
|
||||
.. autofunction:: register_encoder
|
||||
|
||||
The Image Class
|
||||
---------------
|
||||
|
@ -140,6 +149,8 @@ This crops the input image with the provided coordinates:
|
|||
|
||||
|
||||
.. automethod:: PIL.Image.Image.draft
|
||||
.. automethod:: PIL.Image.Image.effect_spread
|
||||
.. automethod:: PIL.Image.Image.entropy
|
||||
.. automethod:: PIL.Image.Image.filter
|
||||
|
||||
This blurs the input image using a filter from the ``ImageFilter`` module:
|
||||
|
@ -176,12 +187,14 @@ This helps to get the bounding box coordinates of the input image:
|
|||
print(im.getbbox())
|
||||
# Returns four coordinates in the format (left, upper, right, lower)
|
||||
|
||||
.. automethod:: PIL.Image.Image.getchannel
|
||||
.. automethod:: PIL.Image.Image.getcolors
|
||||
.. automethod:: PIL.Image.Image.getdata
|
||||
.. automethod:: PIL.Image.Image.getextrema
|
||||
.. automethod:: PIL.Image.Image.getexif
|
||||
.. automethod:: PIL.Image.Image.getextrema
|
||||
.. automethod:: PIL.Image.Image.getpalette
|
||||
.. automethod:: PIL.Image.Image.getpixel
|
||||
.. automethod:: PIL.Image.Image.getprojection
|
||||
.. automethod:: PIL.Image.Image.histogram
|
||||
.. automethod:: PIL.Image.Image.offset
|
||||
.. automethod:: PIL.Image.Image.paste
|
||||
|
@ -191,6 +204,8 @@ This helps to get the bounding box coordinates of the input image:
|
|||
.. automethod:: PIL.Image.Image.putpalette
|
||||
.. automethod:: PIL.Image.Image.putpixel
|
||||
.. automethod:: PIL.Image.Image.quantize
|
||||
.. automethod:: PIL.Image.Image.reduce
|
||||
.. automethod:: PIL.Image.Image.remap_palette
|
||||
.. automethod:: PIL.Image.Image.resize
|
||||
|
||||
This resizes the given image from ``(width, height)`` to ``(width/2, height/2)``:
|
||||
|
@ -205,7 +220,6 @@ This resizes the given image from ``(width, height)`` to ``(width/2, height/2)``
|
|||
(width, height) = (im.width // 2, im.height // 2)
|
||||
im_resized = im.resize((width, height))
|
||||
|
||||
.. automethod:: PIL.Image.Image.remap_palette
|
||||
.. automethod:: PIL.Image.Image.rotate
|
||||
|
||||
This rotates the input image by ``theta`` degrees counter clockwise:
|
||||
|
@ -225,7 +239,6 @@ This rotates the input image by ``theta`` degrees counter clockwise:
|
|||
.. automethod:: PIL.Image.Image.seek
|
||||
.. automethod:: PIL.Image.Image.show
|
||||
.. automethod:: PIL.Image.Image.split
|
||||
.. automethod:: PIL.Image.Image.getchannel
|
||||
.. automethod:: PIL.Image.Image.tell
|
||||
.. automethod:: PIL.Image.Image.thumbnail
|
||||
.. automethod:: PIL.Image.Image.tobitmap
|
||||
|
@ -234,7 +247,7 @@ This rotates the input image by ``theta`` degrees counter clockwise:
|
|||
.. automethod:: PIL.Image.Image.transform
|
||||
.. automethod:: PIL.Image.Image.transpose
|
||||
|
||||
This flips the input image by using the ``Image.FLIP_LEFT_RIGHT`` method.
|
||||
This flips the input image by using the :data:`FLIP_LEFT_RIGHT` method.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
@ -260,57 +273,51 @@ Attributes
|
|||
|
||||
Instances of the :py:class:`Image` class have the following attributes:
|
||||
|
||||
.. py:attribute:: filename
|
||||
.. py:attribute:: Image.filename
|
||||
:type: str
|
||||
|
||||
The filename or path of the source file. Only images created with the
|
||||
factory function ``open`` have a filename attribute. If the input is a
|
||||
file like object, the filename attribute is set to an empty string.
|
||||
|
||||
:type: :py:class:`string`
|
||||
|
||||
.. py:attribute:: format
|
||||
.. py:attribute:: Image.format
|
||||
:type: Optional[str]
|
||||
|
||||
The file format of the source file. For images created by the library
|
||||
itself (via a factory function, or by running a method on an existing
|
||||
image), this attribute is set to ``None``.
|
||||
|
||||
:type: :py:class:`string` or ``None``
|
||||
|
||||
.. py:attribute:: mode
|
||||
.. py:attribute:: Image.mode
|
||||
:type: str
|
||||
|
||||
Image mode. This is a string specifying the pixel format used by the image.
|
||||
Typical values are “1”, “L”, “RGB”, or “CMYK.” See
|
||||
:ref:`concept-modes` for a full list.
|
||||
|
||||
:type: :py:class:`string`
|
||||
|
||||
.. py:attribute:: size
|
||||
.. py:attribute:: Image.size
|
||||
:type: tuple[int]
|
||||
|
||||
Image size, in pixels. The size is given as a 2-tuple (width, height).
|
||||
|
||||
:type: ``(width, height)``
|
||||
|
||||
.. py:attribute:: width
|
||||
.. py:attribute:: Image.width
|
||||
:type: int
|
||||
|
||||
Image width, in pixels.
|
||||
|
||||
:type: :py:class:`int`
|
||||
|
||||
.. py:attribute:: height
|
||||
.. py:attribute:: Image.height
|
||||
:type: int
|
||||
|
||||
Image height, in pixels.
|
||||
|
||||
:type: :py:class:`int`
|
||||
|
||||
.. py:attribute:: palette
|
||||
.. py:attribute:: Image.palette
|
||||
:type: Optional[PIL.ImagePalette.ImagePalette]
|
||||
|
||||
Colour palette table, if any. If mode is "P" or "PA", this should be an
|
||||
instance of the :py:class:`~PIL.ImagePalette.ImagePalette` class.
|
||||
Otherwise, it should be set to ``None``.
|
||||
|
||||
:type: :py:class:`~PIL.ImagePalette.ImagePalette` or ``None``
|
||||
|
||||
.. py:attribute:: info
|
||||
.. py:attribute:: Image.info
|
||||
:type: dict
|
||||
|
||||
A dictionary holding data associated with the image. This dictionary is
|
||||
used by file handlers to pass on various non-image information read from
|
||||
|
@ -323,4 +330,133 @@ Instances of the :py:class:`Image` class have the following attributes:
|
|||
|
||||
Unless noted elsewhere, this dictionary does not affect saving files.
|
||||
|
||||
:type: :py:class:`dict`
|
||||
Constants
|
||||
---------
|
||||
|
||||
.. data:: NONE
|
||||
|
||||
Transpose methods
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
Used to specify the :meth:`Image.transpose` method to use.
|
||||
|
||||
.. data:: FLIP_LEFT_RIGHT
|
||||
.. data:: FLIP_TOP_BOTTOM
|
||||
.. data:: ROTATE_90
|
||||
.. data:: ROTATE_180
|
||||
.. data:: ROTATE_270
|
||||
.. data:: TRANSPOSE
|
||||
.. data:: TRANSVERSE
|
||||
|
||||
Transform methods
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
Used to specify the :meth:`Image.transform` method to use.
|
||||
|
||||
.. data:: AFFINE
|
||||
|
||||
Affine transform
|
||||
|
||||
.. data:: EXTENT
|
||||
|
||||
Cut out a rectangular subregion
|
||||
|
||||
.. data:: PERSPECTIVE
|
||||
|
||||
Perspective transform
|
||||
|
||||
.. data:: QUAD
|
||||
|
||||
Map a quadrilateral to a rectangle
|
||||
|
||||
.. data:: MESH
|
||||
|
||||
Map a number of source quadrilaterals in one operation
|
||||
|
||||
Resampling filters
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
See :ref:`concept-filters` for details.
|
||||
|
||||
.. data:: NEAREST
|
||||
:noindex:
|
||||
.. data:: BOX
|
||||
:noindex:
|
||||
.. data:: BILINEAR
|
||||
:noindex:
|
||||
.. data:: HAMMING
|
||||
:noindex:
|
||||
.. data:: BICUBIC
|
||||
:noindex:
|
||||
.. data:: LANCZOS
|
||||
:noindex:
|
||||
|
||||
Some filters are also available under the following names for backwards compatibility:
|
||||
|
||||
.. data:: NONE
|
||||
:noindex:
|
||||
:value: NEAREST
|
||||
.. data:: LINEAR
|
||||
:value: BILINEAR
|
||||
.. data:: CUBIC
|
||||
:value: BICUBIC
|
||||
.. data:: ANTIALIAS
|
||||
:value: LANCZOS
|
||||
|
||||
Dither modes
|
||||
^^^^^^^^^^^^
|
||||
|
||||
Used to specify the dithering method to use for the
|
||||
:meth:`~Image.convert` and :meth:`~Image.quantize` methods.
|
||||
|
||||
.. data:: NONE
|
||||
:noindex:
|
||||
|
||||
No dither
|
||||
|
||||
.. comment: (not implemented)
|
||||
.. data:: ORDERED
|
||||
.. data:: RASTERIZE
|
||||
|
||||
.. data:: FLOYDSTEINBERG
|
||||
|
||||
Floyd-Steinberg dither
|
||||
|
||||
Palettes
|
||||
^^^^^^^^
|
||||
|
||||
Used to specify the pallete to use for the :meth:`~Image.convert` method.
|
||||
|
||||
.. data:: WEB
|
||||
.. data:: ADAPTIVE
|
||||
|
||||
Quantization methods
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Used to specify the quantization method to use for the :meth:`~Image.quantize` method.
|
||||
|
||||
.. data:: MEDIANCUT
|
||||
|
||||
Median cut
|
||||
|
||||
.. data:: MAXCOVERAGE
|
||||
|
||||
Maximum coverage
|
||||
|
||||
.. data:: FASTOCTREE
|
||||
|
||||
Fast octree
|
||||
|
||||
.. data:: LIBIMAGEQUANT
|
||||
|
||||
libimagequant
|
||||
|
||||
Check support using :py:func:`PIL.features.check_feature`
|
||||
with ``feature="libimagequant"``.
|
||||
|
||||
.. comment: These are not referenced anywhere?
|
||||
Categories
|
||||
^^^^^^^^^^
|
||||
.. data:: NORMAL
|
||||
.. data:: SEQUENCE
|
||||
.. data:: CONTAINER
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
.. py:module:: PIL.ImageChops
|
||||
.. py:currentmodule:: PIL.ImageChops
|
||||
|
||||
:py:mod:`ImageChops` ("Channel Operations") Module
|
||||
==================================================
|
||||
:py:mod:`~PIL.ImageChops` ("Channel Operations") Module
|
||||
=======================================================
|
||||
|
||||
The :py:mod:`ImageChops` module contains a number of arithmetical image
|
||||
The :py:mod:`~PIL.ImageChops` module contains a number of arithmetical image
|
||||
operations, called channel operations (“chops”). These can be used for various
|
||||
purposes, including special effects, image compositions, algorithmic painting,
|
||||
and more.
|
||||
|
||||
For more pre-made operations, see :py:mod:`ImageOps`.
|
||||
For more pre-made operations, see :py:mod:`~PIL.ImageOps`.
|
||||
|
||||
At this time, most channel operations are only implemented for 8-bit images
|
||||
(e.g. “L” and “RGB”).
|
||||
|
|
|
@ -1,16 +1,37 @@
|
|||
.. py:module:: PIL.ImageCms
|
||||
.. py:currentmodule:: PIL.ImageCms
|
||||
|
||||
:py:mod:`ImageCms` Module
|
||||
=========================
|
||||
:py:mod:`~PIL.ImageCms` Module
|
||||
==============================
|
||||
|
||||
The :py:mod:`ImageCms` module provides color profile management
|
||||
The :py:mod:`~PIL.ImageCms` module provides color profile management
|
||||
support using the LittleCMS2 color management engine, based on Kevin
|
||||
Cazabon's PyCMS library.
|
||||
|
||||
.. automodule:: PIL.ImageCms
|
||||
:members:
|
||||
:noindex:
|
||||
.. autoclass:: ImageCmsTransform
|
||||
.. autoexception:: PyCMSError
|
||||
|
||||
Functions
|
||||
---------
|
||||
|
||||
.. autofunction:: applyTransform
|
||||
.. autofunction:: buildProofTransform
|
||||
.. autofunction:: buildProofTransformFromOpenProfiles
|
||||
.. autofunction:: buildTransform
|
||||
.. autofunction:: buildTransformFromOpenProfiles
|
||||
.. autofunction:: createProfile
|
||||
.. autofunction:: getDefaultIntent
|
||||
.. autofunction:: getOpenProfile
|
||||
.. autofunction:: getProfileCopyright
|
||||
.. autofunction:: getProfileDescription
|
||||
.. autofunction:: getProfileInfo
|
||||
.. autofunction:: getProfileManufacturer
|
||||
.. autofunction:: getProfileModel
|
||||
.. autofunction:: getProfileName
|
||||
.. autofunction:: get_display_profile
|
||||
.. autofunction:: isIntentSupported
|
||||
.. autofunction:: profileToProfile
|
||||
.. autofunction:: versions
|
||||
|
||||
CmsProfile
|
||||
----------
|
||||
|
@ -25,31 +46,30 @@ can be easily displayed in a chromaticity diagram, for example).
|
|||
.. py:class:: CmsProfile
|
||||
|
||||
.. py:attribute:: creation_date
|
||||
:type: Optional[datetime.datetime]
|
||||
|
||||
Date and time this profile was first created (see 7.2.1 of ICC.1:2010).
|
||||
|
||||
:type: :py:class:`datetime.datetime` or ``None``
|
||||
|
||||
.. py:attribute:: version
|
||||
:type: float
|
||||
|
||||
The version number of the ICC standard that this profile follows
|
||||
(e.g. ``2.0``).
|
||||
|
||||
:type: :py:class:`float`
|
||||
|
||||
.. py:attribute:: icc_version
|
||||
:type: int
|
||||
|
||||
Same as ``version``, but in encoded format (see 7.2.4 of ICC.1:2010).
|
||||
|
||||
.. py:attribute:: device_class
|
||||
:type: str
|
||||
|
||||
4-character string identifying the profile class. One of
|
||||
``scnr``, ``mntr``, ``prtr``, ``link``, ``spac``, ``abst``,
|
||||
``nmcl`` (see 7.2.5 of ICC.1:2010 for details).
|
||||
|
||||
:type: :py:class:`string`
|
||||
|
||||
.. py:attribute:: xcolor_space
|
||||
:type: str
|
||||
|
||||
4-character string (padded with whitespace) identifying the color
|
||||
space, e.g. ``XYZ␣``, ``RGB␣`` or ``CMYK`` (see 7.2.6 of
|
||||
|
@ -59,9 +79,8 @@ can be easily displayed in a chromaticity diagram, for example).
|
|||
interpreted (non-padded) variant of this (but can be empty on
|
||||
unknown input).
|
||||
|
||||
:type: :py:class:`string`
|
||||
|
||||
.. py:attribute:: connection_space
|
||||
:type: str
|
||||
|
||||
4-character string (padded with whitespace) identifying the color
|
||||
space on the B-side of the transform (see 7.2.7 of ICC.1:2010 for
|
||||
|
@ -70,42 +89,37 @@ can be easily displayed in a chromaticity diagram, for example).
|
|||
Note that the deprecated attribute ``pcs`` contains an interpreted
|
||||
(non-padded) variant of this (but can be empty on unknown input).
|
||||
|
||||
:type: :py:class:`string`
|
||||
|
||||
.. py:attribute:: header_flags
|
||||
:type: int
|
||||
|
||||
The encoded header flags of the profile (see 7.2.11 of ICC.1:2010
|
||||
for details).
|
||||
|
||||
:type: :py:class:`int`
|
||||
|
||||
.. py:attribute:: header_manufacturer
|
||||
:type: str
|
||||
|
||||
4-character string (padded with whitespace) identifying the device
|
||||
manufacturer, which shall match the signature contained in the
|
||||
appropriate section of the ICC signature registry found at
|
||||
www.color.org (see 7.2.12 of ICC.1:2010).
|
||||
|
||||
:type: :py:class:`string`
|
||||
|
||||
.. py:attribute:: header_model
|
||||
:type: str
|
||||
|
||||
4-character string (padded with whitespace) identifying the device
|
||||
model, which shall match the signature contained in the
|
||||
appropriate section of the ICC signature registry found at
|
||||
www.color.org (see 7.2.13 of ICC.1:2010).
|
||||
|
||||
:type: :py:class:`string`
|
||||
|
||||
.. py:attribute:: attributes
|
||||
:type: int
|
||||
|
||||
Flags used to identify attributes unique to the particular device
|
||||
setup for which the profile is applicable (see 7.2.14 of
|
||||
ICC.1:2010 for details).
|
||||
|
||||
:type: :py:class:`int`
|
||||
|
||||
.. py:attribute:: rendering_intent
|
||||
:type: int
|
||||
|
||||
The rendering intent to use when combining this profile with
|
||||
another profile (usually overridden at run-time, but provided here
|
||||
|
@ -114,84 +128,82 @@ can be easily displayed in a chromaticity diagram, for example).
|
|||
One of ``ImageCms.INTENT_ABSOLUTE_COLORIMETRIC``, ``ImageCms.INTENT_PERCEPTUAL``,
|
||||
``ImageCms.INTENT_RELATIVE_COLORIMETRIC`` and ``ImageCms.INTENT_SATURATION``.
|
||||
|
||||
:type: :py:class:`int`
|
||||
|
||||
.. py:attribute:: profile_id
|
||||
:type: bytes
|
||||
|
||||
A sequence of 16 bytes identifying the profile (via a specially
|
||||
constructed MD5 sum), or 16 binary zeroes if the profile ID has
|
||||
not been calculated (see 7.2.18 of ICC.1:2010).
|
||||
|
||||
:type: :py:class:`bytes`
|
||||
|
||||
.. py:attribute:: copyright
|
||||
:type: Optional[str]
|
||||
|
||||
The text copyright information for the profile (see 9.2.21 of ICC.1:2010).
|
||||
|
||||
:type: :py:class:`unicode` or ``None``
|
||||
|
||||
.. py:attribute:: manufacturer
|
||||
:type: Optional[str]
|
||||
|
||||
The (English) display string for the device manufacturer (see
|
||||
9.2.22 of ICC.1:2010).
|
||||
|
||||
:type: :py:class:`unicode` or ``None``
|
||||
|
||||
.. py:attribute:: model
|
||||
:type: Optional[str]
|
||||
|
||||
The (English) display string for the device model of the device
|
||||
for which this profile is created (see 9.2.23 of ICC.1:2010).
|
||||
|
||||
:type: :py:class:`unicode` or ``None``
|
||||
|
||||
.. py:attribute:: profile_description
|
||||
:type: Optional[str]
|
||||
|
||||
The (English) display string for the profile description (see
|
||||
9.2.41 of ICC.1:2010).
|
||||
|
||||
:type: :py:class:`unicode` or ``None``
|
||||
|
||||
.. py:attribute:: target
|
||||
:type: Optional[str]
|
||||
|
||||
The name of the registered characterization data set, or the
|
||||
measurement data for a characterization target (see 9.2.14 of
|
||||
ICC.1:2010).
|
||||
|
||||
:type: :py:class:`unicode` or ``None``
|
||||
|
||||
.. py:attribute:: red_colorant
|
||||
:type: Optional[tuple[tuple[float]]]
|
||||
|
||||
The first column in the matrix used in matrix/TRC transforms (see 9.2.44 of ICC.1:2010).
|
||||
|
||||
:type: ``((X, Y, Z), (x, y, Y))`` or ``None``
|
||||
The value is in the format ``((X, Y, Z), (x, y, Y))``, if available.
|
||||
|
||||
.. py:attribute:: green_colorant
|
||||
:type: Optional[tuple[tuple[float]]]
|
||||
|
||||
The second column in the matrix used in matrix/TRC transforms (see 9.2.30 of ICC.1:2010).
|
||||
|
||||
:type: ``((X, Y, Z), (x, y, Y))`` or ``None``
|
||||
The value is in the format ``((X, Y, Z), (x, y, Y))``, if available.
|
||||
|
||||
.. py:attribute:: blue_colorant
|
||||
:type: Optional[tuple[tuple[float]]]
|
||||
|
||||
The third column in the matrix used in matrix/TRC transforms (see 9.2.4 of ICC.1:2010).
|
||||
|
||||
:type: ``((X, Y, Z), (x, y, Y))`` or ``None``
|
||||
The value is in the format ``((X, Y, Z), (x, y, Y))``, if available.
|
||||
|
||||
.. py:attribute:: luminance
|
||||
:type: Optional[tuple[tuple[float]]]
|
||||
|
||||
The absolute luminance of emissive devices in candelas per square
|
||||
metre as described by the Y channel (see 9.2.32 of ICC.1:2010).
|
||||
|
||||
:type: ``((X, Y, Z), (x, y, Y))`` or ``None``
|
||||
The value is in the format ``((X, Y, Z), (x, y, Y))``, if available.
|
||||
|
||||
.. py:attribute:: chromaticity
|
||||
:type: Optional[tuple[tuple[float]]]
|
||||
|
||||
The data of the phosphor/colorant chromaticity set used (red,
|
||||
green and blue channels, see 9.2.16 of ICC.1:2010).
|
||||
|
||||
:type: ``((x, y, Y), (x, y, Y), (x, y, Y))`` or ``None``
|
||||
The value is in the format ``((x, y, Y), (x, y, Y), (x, y, Y))``, if available.
|
||||
|
||||
.. py:attribute:: chromatic_adaption
|
||||
:type: tuple[tuple[float]]
|
||||
|
||||
The chromatic adaption matrix converts a color measured using the
|
||||
actual illumination conditions and relative to the actual adopted
|
||||
|
@ -199,58 +211,52 @@ can be easily displayed in a chromaticity diagram, for example).
|
|||
complete adaptation from the actual adopted white chromaticity to
|
||||
the PCS adopted white chromaticity (see 9.2.15 of ICC.1:2010).
|
||||
|
||||
Two matrices are returned, one in (X, Y, Z) space and one in (x, y, Y) space.
|
||||
|
||||
:type: 2-tuple of 3-tuple, the first with (X, Y, Z) and the second with (x, y, Y) values
|
||||
Two 3-tuples of floats are returned in a 2-tuple,
|
||||
one in (X, Y, Z) space and one in (x, y, Y) space.
|
||||
|
||||
.. py:attribute:: colorant_table
|
||||
:type: list[str]
|
||||
|
||||
This tag identifies the colorants used in the profile by a unique
|
||||
name and set of PCSXYZ or PCSLAB values (see 9.2.19 of
|
||||
ICC.1:2010).
|
||||
|
||||
:type: list of strings
|
||||
|
||||
.. py:attribute:: colorant_table_out
|
||||
:type: list[str]
|
||||
|
||||
This tag identifies the colorants used in the profile by a unique
|
||||
name and set of PCSLAB values (for DeviceLink profiles only, see
|
||||
9.2.19 of ICC.1:2010).
|
||||
|
||||
:type: list of strings
|
||||
|
||||
.. py:attribute:: colorimetric_intent
|
||||
:type: Optional[str]
|
||||
|
||||
4-character string (padded with whitespace) identifying the image
|
||||
state of PCS colorimetry produced using the colorimetric intent
|
||||
transforms (see 9.2.20 of ICC.1:2010 for details).
|
||||
|
||||
:type: :py:class:`string` or ``None``
|
||||
|
||||
.. py:attribute:: perceptual_rendering_intent_gamut
|
||||
:type: Optional[str]
|
||||
|
||||
4-character string (padded with whitespace) identifying the (one)
|
||||
standard reference medium gamut (see 9.2.37 of ICC.1:2010 for
|
||||
details).
|
||||
|
||||
:type: :py:class:`string` or ``None``
|
||||
|
||||
.. py:attribute:: saturation_rendering_intent_gamut
|
||||
:type: Optional[str]
|
||||
|
||||
4-character string (padded with whitespace) identifying the (one)
|
||||
standard reference medium gamut (see 9.2.37 of ICC.1:2010 for
|
||||
details).
|
||||
|
||||
:type: :py:class:`string` or ``None``
|
||||
|
||||
.. py:attribute:: technology
|
||||
:type: Optional[str]
|
||||
|
||||
4-character string (padded with whitespace) identifying the device
|
||||
technology (see 9.2.47 of ICC.1:2010 for details).
|
||||
|
||||
:type: :py:class:`string` or ``None``
|
||||
|
||||
.. py:attribute:: media_black_point
|
||||
:type: Optional[tuple[tuple[float]]]
|
||||
|
||||
This tag specifies the media black point and is used for
|
||||
generating absolute colorimetry.
|
||||
|
@ -258,57 +264,57 @@ can be easily displayed in a chromaticity diagram, for example).
|
|||
This tag was available in ICC 3.2, but it is removed from
|
||||
version 4.
|
||||
|
||||
:type: ``((X, Y, Z), (x, y, Y))`` or ``None``
|
||||
The value is in the format ``((X, Y, Z), (x, y, Y))``, if available.
|
||||
|
||||
.. py:attribute:: media_white_point_temperature
|
||||
:type: Optional[float]
|
||||
|
||||
Calculates the white point temperature (see the LCMS documentation
|
||||
for more information).
|
||||
|
||||
:type: :py:class:`float` or ``None``
|
||||
|
||||
.. py:attribute:: viewing_condition
|
||||
:type: Optional[str]
|
||||
|
||||
The (English) display string for the viewing conditions (see
|
||||
9.2.48 of ICC.1:2010).
|
||||
|
||||
:type: :py:class:`unicode` or ``None``
|
||||
|
||||
.. py:attribute:: screening_description
|
||||
:type: Optional[str]
|
||||
|
||||
The (English) display string for the screening conditions.
|
||||
|
||||
This tag was available in ICC 3.2, but it is removed from
|
||||
version 4.
|
||||
|
||||
:type: :py:class:`unicode` or ``None``
|
||||
|
||||
.. py:attribute:: red_primary
|
||||
:type: Optional[tuple[tuple[float]]]
|
||||
|
||||
The XYZ-transformed of the RGB primary color red (1, 0, 0).
|
||||
|
||||
:type: ``((X, Y, Z), (x, y, Y))`` or ``None``
|
||||
The value is in the format ``((X, Y, Z), (x, y, Y))``, if available.
|
||||
|
||||
.. py:attribute:: green_primary
|
||||
:type: Optional[tuple[tuple[float]]]
|
||||
|
||||
The XYZ-transformed of the RGB primary color green (0, 1, 0).
|
||||
|
||||
:type: ``((X, Y, Z), (x, y, Y))`` or ``None``
|
||||
The value is in the format ``((X, Y, Z), (x, y, Y))``, if available.
|
||||
|
||||
.. py:attribute:: blue_primary
|
||||
:type: Optional[tuple[tuple[float]]]
|
||||
|
||||
The XYZ-transformed of the RGB primary color blue (0, 0, 1).
|
||||
|
||||
:type: ``((X, Y, Z), (x, y, Y))`` or ``None``
|
||||
The value is in the format ``((X, Y, Z), (x, y, Y))``, if available.
|
||||
|
||||
.. py:attribute:: is_matrix_shaper
|
||||
:type: bool
|
||||
|
||||
True if this profile is implemented as a matrix shaper (see
|
||||
documentation on LCMS).
|
||||
|
||||
:type: :py:class:`bool`
|
||||
|
||||
.. py:attribute:: clut
|
||||
:type: dict[tuple[bool]]
|
||||
|
||||
Returns a dictionary of all supported intents and directions for
|
||||
the CLUT model.
|
||||
|
@ -326,9 +332,8 @@ can be easily displayed in a chromaticity diagram, for example).
|
|||
The elements of the tuple are booleans. If the value is ``True``,
|
||||
that intent is supported for that direction.
|
||||
|
||||
:type: :py:class:`dict` of boolean 3-tuples
|
||||
|
||||
.. py:attribute:: intent_supported
|
||||
:type: dict[tuple[bool]]
|
||||
|
||||
Returns a dictionary of all supported intents and directions.
|
||||
|
||||
|
@ -345,53 +350,46 @@ can be easily displayed in a chromaticity diagram, for example).
|
|||
The elements of the tuple are booleans. If the value is ``True``,
|
||||
that intent is supported for that direction.
|
||||
|
||||
:type: :py:class:`dict` of boolean 3-tuples
|
||||
|
||||
.. py:attribute:: color_space
|
||||
:type: str
|
||||
|
||||
Deprecated but retained for backwards compatibility.
|
||||
Interpreted value of :py:attr:`.xcolor_space`. May be the
|
||||
empty string if value could not be decoded.
|
||||
|
||||
:type: :py:class:`string`
|
||||
|
||||
.. py:attribute:: pcs
|
||||
:type: str
|
||||
|
||||
Deprecated but retained for backwards compatibility.
|
||||
Interpreted value of :py:attr:`.connection_space`. May be
|
||||
the empty string if value could not be decoded.
|
||||
|
||||
:type: :py:class:`string`
|
||||
|
||||
.. py:attribute:: product_model
|
||||
:type: str
|
||||
|
||||
Deprecated but retained for backwards compatibility.
|
||||
ASCII-encoded value of :py:attr:`.model`.
|
||||
|
||||
:type: :py:class:`string`
|
||||
|
||||
.. py:attribute:: product_manufacturer
|
||||
:type: str
|
||||
|
||||
Deprecated but retained for backwards compatibility.
|
||||
ASCII-encoded value of :py:attr:`.manufacturer`.
|
||||
|
||||
:type: :py:class:`string`
|
||||
|
||||
.. py:attribute:: product_copyright
|
||||
:type: str
|
||||
|
||||
Deprecated but retained for backwards compatibility.
|
||||
ASCII-encoded value of :py:attr:`.copyright`.
|
||||
|
||||
:type: :py:class:`string`
|
||||
|
||||
.. py:attribute:: product_description
|
||||
:type: str
|
||||
|
||||
Deprecated but retained for backwards compatibility.
|
||||
ASCII-encoded value of :py:attr:`.profile_description`.
|
||||
|
||||
:type: :py:class:`string`
|
||||
|
||||
.. py:attribute:: product_desc
|
||||
:type: str
|
||||
|
||||
Deprecated but retained for backwards compatibility.
|
||||
ASCII-encoded value of :py:attr:`.profile_description`.
|
||||
|
@ -401,8 +399,6 @@ can be easily displayed in a chromaticity diagram, for example).
|
|||
depending on the value of the description, copyright,
|
||||
manufacturer and model fields).
|
||||
|
||||
:type: :py:class:`string`
|
||||
|
||||
There is one function defined on the class:
|
||||
|
||||
.. py:method:: is_intent_supported(intent, direction)
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
.. py:module:: PIL.ImageColor
|
||||
.. py:currentmodule:: PIL.ImageColor
|
||||
|
||||
:py:mod:`ImageColor` Module
|
||||
===========================
|
||||
:py:mod:`~PIL.ImageColor` Module
|
||||
================================
|
||||
|
||||
The :py:mod:`ImageColor` module contains color tables and converters from
|
||||
The :py:mod:`~PIL.ImageColor` module contains color tables and converters from
|
||||
CSS3-style color specifiers to RGB tuples. This module is used by
|
||||
:py:meth:`PIL.Image.new` and the :py:mod:`~PIL.ImageDraw` module, among
|
||||
others.
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
.. py:module:: PIL.ImageDraw
|
||||
.. py:currentmodule:: PIL.ImageDraw
|
||||
|
||||
:py:mod:`ImageDraw` Module
|
||||
==========================
|
||||
:py:mod:`~PIL.ImageDraw` Module
|
||||
===============================
|
||||
|
||||
The :py:mod:`ImageDraw` module provides simple 2D graphics for
|
||||
The :py:mod:`~PIL.ImageDraw` module provides simple 2D graphics for
|
||||
:py:class:`~PIL.Image.Image` objects. You can use this module to create new
|
||||
images, annotate or retouch existing images, and to generate graphics on the
|
||||
fly for web use.
|
||||
|
@ -124,7 +124,7 @@ Example: Draw Multiline Text
|
|||
Functions
|
||||
---------
|
||||
|
||||
.. py:class:: PIL.ImageDraw.Draw(im, mode=None)
|
||||
.. py:method:: Draw(im, mode=None)
|
||||
|
||||
Creates an object that can be used to draw in the given image.
|
||||
|
||||
|
@ -140,13 +140,13 @@ Functions
|
|||
Methods
|
||||
-------
|
||||
|
||||
.. py:method:: PIL.ImageDraw.ImageDraw.getfont()
|
||||
.. py:method:: ImageDraw.getfont()
|
||||
|
||||
Get the current default font.
|
||||
|
||||
:returns: An image font.
|
||||
|
||||
.. py:method:: PIL.ImageDraw.ImageDraw.arc(xy, start, end, fill=None, width=0)
|
||||
.. py:method:: ImageDraw.arc(xy, start, end, fill=None, width=0)
|
||||
|
||||
Draws an arc (a portion of a circle outline) between the start and end
|
||||
angles, inside the given bounding box.
|
||||
|
@ -162,7 +162,7 @@ Methods
|
|||
|
||||
.. versionadded:: 5.3.0
|
||||
|
||||
.. py:method:: PIL.ImageDraw.ImageDraw.bitmap(xy, bitmap, fill=None)
|
||||
.. py:method:: ImageDraw.bitmap(xy, bitmap, fill=None)
|
||||
|
||||
Draws a bitmap (mask) at the given position, using the current fill color
|
||||
for the non-zero portions. The bitmap should be a valid transparency mask
|
||||
|
@ -173,7 +173,7 @@ Methods
|
|||
To paste pixel data into an image, use the
|
||||
:py:meth:`~PIL.Image.Image.paste` method on the image itself.
|
||||
|
||||
.. py:method:: PIL.ImageDraw.ImageDraw.chord(xy, start, end, fill=None, outline=None, width=1)
|
||||
.. py:method:: ImageDraw.chord(xy, start, end, fill=None, outline=None, width=1)
|
||||
|
||||
Same as :py:meth:`~PIL.ImageDraw.ImageDraw.arc`, but connects the end points
|
||||
with a straight line.
|
||||
|
@ -187,7 +187,7 @@ Methods
|
|||
|
||||
.. versionadded:: 5.3.0
|
||||
|
||||
.. py:method:: PIL.ImageDraw.ImageDraw.ellipse(xy, fill=None, outline=None, width=1)
|
||||
.. py:method:: ImageDraw.ellipse(xy, fill=None, outline=None, width=1)
|
||||
|
||||
Draws an ellipse inside the given bounding box.
|
||||
|
||||
|
@ -200,9 +200,9 @@ Methods
|
|||
|
||||
.. versionadded:: 5.3.0
|
||||
|
||||
.. py:method:: PIL.ImageDraw.ImageDraw.line(xy, fill=None, width=0, joint=None)
|
||||
.. py:method:: ImageDraw.line(xy, fill=None, width=0, joint=None)
|
||||
|
||||
Draws a line between the coordinates in the **xy** list.
|
||||
Draws a line between the coordinates in the ``xy`` list.
|
||||
|
||||
:param xy: Sequence of either 2-tuples like ``[(x, y), (x, y), ...]`` or
|
||||
numeric values like ``[x, y, x, y, ...]``.
|
||||
|
@ -216,7 +216,7 @@ Methods
|
|||
|
||||
.. versionadded:: 5.3.0
|
||||
|
||||
.. py:method:: PIL.ImageDraw.ImageDraw.pieslice(xy, start, end, fill=None, outline=None, width=1)
|
||||
.. py:method:: ImageDraw.pieslice(xy, start, end, fill=None, outline=None, width=1)
|
||||
|
||||
Same as arc, but also draws straight lines between the end points and the
|
||||
center of the bounding box.
|
||||
|
@ -233,7 +233,7 @@ Methods
|
|||
|
||||
.. versionadded:: 5.3.0
|
||||
|
||||
.. py:method:: PIL.ImageDraw.ImageDraw.point(xy, fill=None)
|
||||
.. py:method:: ImageDraw.point(xy, fill=None)
|
||||
|
||||
Draws points (individual pixels) at the given coordinates.
|
||||
|
||||
|
@ -241,7 +241,7 @@ Methods
|
|||
numeric values like ``[x, y, x, y, ...]``.
|
||||
:param fill: Color to use for the point.
|
||||
|
||||
.. py:method:: PIL.ImageDraw.ImageDraw.polygon(xy, fill=None, outline=None)
|
||||
.. py:method:: ImageDraw.polygon(xy, fill=None, outline=None)
|
||||
|
||||
Draws a polygon.
|
||||
|
||||
|
@ -254,7 +254,7 @@ Methods
|
|||
:param outline: Color to use for the outline.
|
||||
:param fill: Color to use for the fill.
|
||||
|
||||
.. py:method:: PIL.ImageDraw.ImageDraw.rectangle(xy, fill=None, outline=None, width=1)
|
||||
.. py:method:: ImageDraw.rectangle(xy, fill=None, outline=None, width=1)
|
||||
|
||||
Draws a rectangle.
|
||||
|
||||
|
@ -267,13 +267,13 @@ Methods
|
|||
|
||||
.. versionadded:: 5.3.0
|
||||
|
||||
.. py:method:: PIL.ImageDraw.ImageDraw.shape(shape, fill=None, outline=None)
|
||||
.. py:method:: ImageDraw.shape(shape, fill=None, outline=None)
|
||||
|
||||
.. warning:: This method is experimental.
|
||||
|
||||
Draw a shape.
|
||||
|
||||
.. py:method:: PIL.ImageDraw.ImageDraw.text(xy, text, fill=None, font=None, anchor=None, spacing=4, align="left", direction=None, features=None, language=None, stroke_width=0, stroke_fill=None)
|
||||
.. py:method:: ImageDraw.text(xy, text, fill=None, font=None, anchor=None, spacing=4, align="left", direction=None, features=None, language=None, stroke_width=0, stroke_fill=None)
|
||||
|
||||
Draws the string at the given position.
|
||||
|
||||
|
@ -325,7 +325,7 @@ Methods
|
|||
|
||||
.. versionadded:: 6.2.0
|
||||
|
||||
.. py:method:: PIL.ImageDraw.ImageDraw.multiline_text(xy, text, fill=None, font=None, anchor=None, spacing=4, align="left", direction=None, features=None, language=None)
|
||||
.. py:method:: ImageDraw.multiline_text(xy, text, fill=None, font=None, anchor=None, spacing=4, align="left", direction=None, features=None, language=None)
|
||||
|
||||
Draws the string at the given position.
|
||||
|
||||
|
@ -362,7 +362,7 @@ Methods
|
|||
|
||||
.. versionadded:: 6.0.0
|
||||
|
||||
.. py:method:: PIL.ImageDraw.ImageDraw.textsize(text, font=None, spacing=4, direction=None, features=None, language=None, stroke_width=0)
|
||||
.. py:method:: ImageDraw.textsize(text, font=None, spacing=4, direction=None, features=None, language=None, stroke_width=0)
|
||||
|
||||
Return the size of the given string, in pixels.
|
||||
|
||||
|
@ -401,7 +401,7 @@ Methods
|
|||
|
||||
.. versionadded:: 6.2.0
|
||||
|
||||
.. py:method:: PIL.ImageDraw.ImageDraw.multiline_textsize(text, font=None, spacing=4, direction=None, features=None, language=None, stroke_width=0)
|
||||
.. py:method:: ImageDraw.multiline_textsize(text, font=None, spacing=4, direction=None, features=None, language=None, stroke_width=0)
|
||||
|
||||
Return the size of the given string, in pixels.
|
||||
|
||||
|
@ -439,7 +439,7 @@ Methods
|
|||
|
||||
.. versionadded:: 6.2.0
|
||||
|
||||
.. py:method:: PIL.ImageDraw.getdraw(im=None, hints=None)
|
||||
.. py:method:: getdraw(im=None, hints=None)
|
||||
|
||||
.. warning:: This method is experimental.
|
||||
|
||||
|
@ -450,7 +450,7 @@ Methods
|
|||
:param hints: An optional list of hints.
|
||||
:returns: A (drawing context, drawing resource factory) tuple.
|
||||
|
||||
.. py:method:: PIL.ImageDraw.floodfill(image, xy, value, border=None, thresh=0)
|
||||
.. py:method:: floodfill(image, xy, value, border=None, thresh=0)
|
||||
|
||||
.. warning:: This method is experimental.
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
.. py:module:: PIL.ImageEnhance
|
||||
.. py:currentmodule:: PIL.ImageEnhance
|
||||
|
||||
:py:mod:`ImageEnhance` Module
|
||||
=============================
|
||||
:py:mod:`~PIL.ImageEnhance` Module
|
||||
==================================
|
||||
|
||||
The :py:mod:`ImageEnhance` module contains a number of classes that can be used
|
||||
The :py:mod:`~PIL.ImageEnhance` module contains a number of classes that can be used
|
||||
for image enhancement.
|
||||
|
||||
Example: Vary the sharpness of an image
|
||||
|
@ -29,7 +29,8 @@ Classes
|
|||
All enhancement classes implement a common interface, containing a single
|
||||
method:
|
||||
|
||||
.. py:class:: PIL.ImageEnhance._Enhance
|
||||
.. py:class:: _Enhance
|
||||
|
||||
.. py:method:: enhance(factor)
|
||||
|
||||
Returns an enhanced image.
|
||||
|
@ -40,7 +41,7 @@ method:
|
|||
etc), and higher values more. There are no restrictions
|
||||
on this value.
|
||||
|
||||
.. py:class:: PIL.ImageEnhance.Color(image)
|
||||
.. py:class:: Color(image)
|
||||
|
||||
Adjust image color balance.
|
||||
|
||||
|
@ -49,7 +50,7 @@ method:
|
|||
factor of 0.0 gives a black and white image. A factor of 1.0 gives
|
||||
the original image.
|
||||
|
||||
.. py:class:: PIL.ImageEnhance.Contrast(image)
|
||||
.. py:class:: Contrast(image)
|
||||
|
||||
Adjust image contrast.
|
||||
|
||||
|
@ -57,7 +58,7 @@ method:
|
|||
to the contrast control on a TV set. An enhancement factor of 0.0
|
||||
gives a solid grey image. A factor of 1.0 gives the original image.
|
||||
|
||||
.. py:class:: PIL.ImageEnhance.Brightness(image)
|
||||
.. py:class:: Brightness(image)
|
||||
|
||||
Adjust image brightness.
|
||||
|
||||
|
@ -65,7 +66,7 @@ method:
|
|||
enhancement factor of 0.0 gives a black image. A factor of 1.0 gives the
|
||||
original image.
|
||||
|
||||
.. py:class:: PIL.ImageEnhance.Sharpness(image)
|
||||
.. py:class:: Sharpness(image)
|
||||
|
||||
Adjust image sharpness.
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
.. py:module:: PIL.ImageFile
|
||||
.. py:currentmodule:: PIL.ImageFile
|
||||
|
||||
:py:mod:`ImageFile` Module
|
||||
==========================
|
||||
:py:mod:`~PIL.ImageFile` Module
|
||||
===============================
|
||||
|
||||
The :py:mod:`ImageFile` module provides support functions for the image open
|
||||
The :py:mod:`~PIL.ImageFile` module provides support functions for the image open
|
||||
and save functions.
|
||||
|
||||
In addition, it provides a :py:class:`Parser` class which can be used to decode
|
||||
|
@ -34,14 +34,21 @@ Example: Parse an image
|
|||
im.save("copy.jpg")
|
||||
|
||||
|
||||
:py:class:`~PIL.ImageFile.Parser`
|
||||
---------------------------------
|
||||
Classes
|
||||
-------
|
||||
|
||||
.. autoclass:: PIL.ImageFile.Parser()
|
||||
:members:
|
||||
|
||||
:py:class:`~PIL.ImageFile.PyDecoder`
|
||||
------------------------------------
|
||||
|
||||
.. autoclass:: PIL.ImageFile.PyDecoder()
|
||||
:members:
|
||||
|
||||
.. autoclass:: PIL.ImageFile.ImageFile()
|
||||
:member-order: bysource
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
.. autoclass:: PIL.ImageFile.StubImageFile()
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
.. py:module:: PIL.ImageFilter
|
||||
.. py:currentmodule:: PIL.ImageFilter
|
||||
|
||||
:py:mod:`ImageFilter` Module
|
||||
============================
|
||||
:py:mod:`~PIL.ImageFilter` Module
|
||||
=================================
|
||||
|
||||
The :py:mod:`ImageFilter` module contains definitions for a pre-defined set of
|
||||
The :py:mod:`~PIL.ImageFilter` module contains definitions for a pre-defined set of
|
||||
filters, which can be be used with the :py:meth:`Image.filter()
|
||||
<PIL.Image.Image.filter>` method.
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
.. py:module:: PIL.ImageFont
|
||||
.. py:currentmodule:: PIL.ImageFont
|
||||
|
||||
:py:mod:`ImageFont` Module
|
||||
==========================
|
||||
:py:mod:`~PIL.ImageFont` Module
|
||||
===============================
|
||||
|
||||
The :py:mod:`ImageFont` module defines a class with the same name. Instances of
|
||||
The :py:mod:`~PIL.ImageFont` module defines a class with the same name. Instances of
|
||||
this class store bitmap fonts, and are used with the
|
||||
:py:meth:`PIL.ImageDraw.Draw.text` method.
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
.. py:module:: PIL.ImageGrab
|
||||
.. py:currentmodule:: PIL.ImageGrab
|
||||
|
||||
:py:mod:`ImageGrab` Module
|
||||
==========================
|
||||
:py:mod:`~PIL.ImageGrab` Module
|
||||
===============================
|
||||
|
||||
The :py:mod:`ImageGrab` module can be used to copy the contents of the screen
|
||||
The :py:mod:`~PIL.ImageGrab` module can be used to copy the contents of the screen
|
||||
or the clipboard to a PIL image memory.
|
||||
|
||||
.. versionadded:: 1.1.3
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
.. py:module:: PIL.ImageMath
|
||||
.. py:currentmodule:: PIL.ImageMath
|
||||
|
||||
:py:mod:`ImageMath` Module
|
||||
==========================
|
||||
:py:mod:`~PIL.ImageMath` Module
|
||||
===============================
|
||||
|
||||
The :py:mod:`ImageMath` module can be used to evaluate “image expressions”. The
|
||||
The :py:mod:`~PIL.ImageMath` module can be used to evaluate “image expressions”. The
|
||||
module provides a single :py:meth:`~PIL.ImageMath.eval` function, which takes
|
||||
an expression string and one or more images.
|
||||
|
||||
|
@ -98,20 +98,24 @@ These functions are applied to each individual pixel.
|
|||
.. py:currentmodule:: None
|
||||
|
||||
.. py:function:: abs(image)
|
||||
:noindex:
|
||||
|
||||
Absolute value.
|
||||
|
||||
.. py:function:: convert(image, mode)
|
||||
:noindex:
|
||||
|
||||
Convert image to the given mode. The mode must be given as a string
|
||||
constant.
|
||||
|
||||
.. py:function:: float(image)
|
||||
:noindex:
|
||||
|
||||
Convert image to 32-bit floating point. This is equivalent to
|
||||
convert(image, “F”).
|
||||
|
||||
.. py:function:: int(image)
|
||||
:noindex:
|
||||
|
||||
Convert image to 32-bit integer. This is equivalent to convert(image, “I”).
|
||||
|
||||
|
@ -119,9 +123,11 @@ These functions are applied to each individual pixel.
|
|||
integers if necessary to get a correct result.
|
||||
|
||||
.. py:function:: max(image1, image2)
|
||||
:noindex:
|
||||
|
||||
Maximum value.
|
||||
|
||||
.. py:function:: min(image1, image2)
|
||||
:noindex:
|
||||
|
||||
Minimum value.
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
.. py:module:: PIL.ImageMorph
|
||||
.. py:currentmodule:: PIL.ImageMorph
|
||||
|
||||
:py:mod:`ImageMorph` Module
|
||||
===========================
|
||||
:py:mod:`~PIL.ImageMorph` Module
|
||||
================================
|
||||
|
||||
The :py:mod:`ImageMorph` module provides morphology operations on images.
|
||||
The :py:mod:`~PIL.ImageMorph` module provides morphology operations on images.
|
||||
|
||||
.. automodule:: PIL.ImageMorph
|
||||
:members:
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
.. py:module:: PIL.ImageOps
|
||||
.. py:currentmodule:: PIL.ImageOps
|
||||
|
||||
:py:mod:`ImageOps` Module
|
||||
==========================
|
||||
:py:mod:`~PIL.ImageOps` Module
|
||||
==============================
|
||||
|
||||
The :py:mod:`ImageOps` module contains a number of ‘ready-made’ image
|
||||
The :py:mod:`~PIL.ImageOps` module contains a number of ‘ready-made’ image
|
||||
processing operations. This module is somewhat experimental, and most operators
|
||||
only work on L and RGB images.
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
.. py:module:: PIL.ImagePalette
|
||||
.. py:currentmodule:: PIL.ImagePalette
|
||||
|
||||
:py:mod:`ImagePalette` Module
|
||||
=============================
|
||||
:py:mod:`~PIL.ImagePalette` Module
|
||||
==================================
|
||||
|
||||
The :py:mod:`ImagePalette` module contains a class of the same name to
|
||||
The :py:mod:`~PIL.ImagePalette` module contains a class of the same name to
|
||||
represent the color palette of palette mapped images.
|
||||
|
||||
.. note::
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
.. py:module:: PIL.ImagePath
|
||||
.. py:currentmodule:: PIL.ImagePath
|
||||
|
||||
:py:mod:`ImagePath` Module
|
||||
==========================
|
||||
:py:mod:`~PIL.ImagePath` Module
|
||||
===============================
|
||||
|
||||
The :py:mod:`ImagePath` module is used to store and manipulate 2-dimensional
|
||||
The :py:mod:`~PIL.ImagePath` module is used to store and manipulate 2-dimensional
|
||||
vector data. Path objects can be passed to the methods on the
|
||||
:py:mod:`~PIL.ImageDraw` module.
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
.. py:module:: PIL.ImageQt
|
||||
.. py:currentmodule:: PIL.ImageQt
|
||||
|
||||
:py:mod:`ImageQt` Module
|
||||
========================
|
||||
:py:mod:`~PIL.ImageQt` Module
|
||||
=============================
|
||||
|
||||
The :py:mod:`ImageQt` module contains support for creating PyQt5 or PySide2 QImage
|
||||
The :py:mod:`~PIL.ImageQt` module contains support for creating PyQt5 or PySide2 QImage
|
||||
objects from PIL images.
|
||||
|
||||
.. versionadded:: 1.1.6
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
.. py:module:: PIL.ImageSequence
|
||||
.. py:currentmodule:: PIL.ImageSequence
|
||||
|
||||
:py:mod:`ImageSequence` Module
|
||||
==============================
|
||||
:py:mod:`~PIL.ImageSequence` Module
|
||||
===================================
|
||||
|
||||
The :py:mod:`ImageSequence` module contains a wrapper class that lets you
|
||||
The :py:mod:`~PIL.ImageSequence` module contains a wrapper class that lets you
|
||||
iterate over the frames of an image sequence.
|
||||
|
||||
Extracting frames from an animation
|
||||
|
|
27
docs/reference/ImageShow.rst
Normal file
27
docs/reference/ImageShow.rst
Normal file
|
@ -0,0 +1,27 @@
|
|||
.. py:module:: PIL.ImageShow
|
||||
.. py:currentmodule:: PIL.ImageShow
|
||||
|
||||
:py:mod:`~PIL.ImageShow` Module
|
||||
===============================
|
||||
|
||||
The :py:mod:`~PIL.ImageShow` Module is used to display images.
|
||||
All default viewers convert the image to be shown to PNG format.
|
||||
|
||||
.. autofunction:: PIL.ImageShow.show
|
||||
|
||||
.. autoclass:: WindowsViewer
|
||||
.. autoclass:: MacViewer
|
||||
|
||||
.. class:: UnixViewer
|
||||
|
||||
The following viewers may be registered on Unix-based systems, if the given command is found:
|
||||
|
||||
.. autoclass:: PIL.ImageShow.DisplayViewer
|
||||
.. autoclass:: PIL.ImageShow.EogViewer
|
||||
.. autoclass:: PIL.ImageShow.XVViewer
|
||||
|
||||
.. autofunction:: PIL.ImageShow.register
|
||||
.. autoclass:: PIL.ImageShow.Viewer
|
||||
:member-order: bysource
|
||||
:members:
|
||||
:undoc-members:
|
|
@ -1,13 +1,13 @@
|
|||
.. py:module:: PIL.ImageStat
|
||||
.. py:currentmodule:: PIL.ImageStat
|
||||
|
||||
:py:mod:`ImageStat` Module
|
||||
==========================
|
||||
:py:mod:`~PIL.ImageStat` Module
|
||||
===============================
|
||||
|
||||
The :py:mod:`ImageStat` module calculates global statistics for an image, or
|
||||
The :py:mod:`~PIL.ImageStat` module calculates global statistics for an image, or
|
||||
for a region of an image.
|
||||
|
||||
.. py:class:: PIL.ImageStat.Stat(image_or_list, mask=None)
|
||||
.. py:class:: Stat(image_or_list, mask=None)
|
||||
|
||||
Calculate statistics for the given image. If a mask is included,
|
||||
only the regions covered by that mask are included in the
|
||||
|
@ -22,13 +22,13 @@ for a region of an image.
|
|||
|
||||
.. note::
|
||||
|
||||
This relies on the :py:meth:`~PIL.Image.histogram` method, and
|
||||
This relies on the :py:meth:`~PIL.Image.Image.histogram` method, and
|
||||
simply returns the low and high bins used. This is correct for
|
||||
images with 8 bits per channel, but fails for other modes such as
|
||||
``I`` or ``F``. Instead, use :py:meth:`~PIL.Image.getextrema` to
|
||||
``I`` or ``F``. Instead, use :py:meth:`~PIL.Image.Image.getextrema` to
|
||||
return per-band extrema for the image. This is more correct and
|
||||
efficient because, for non-8-bit modes, the histogram method uses
|
||||
:py:meth:`~PIL.Image.getextrema` to determine the bins used.
|
||||
:py:meth:`~PIL.Image.Image.getextrema` to determine the bins used.
|
||||
|
||||
.. py:attribute:: count
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
.. py:module:: PIL.ImageTk
|
||||
.. py:currentmodule:: PIL.ImageTk
|
||||
|
||||
:py:mod:`ImageTk` Module
|
||||
========================
|
||||
:py:mod:`~PIL.ImageTk` Module
|
||||
=============================
|
||||
|
||||
The :py:mod:`ImageTk` module contains support to create and modify Tkinter
|
||||
The :py:mod:`~PIL.ImageTk` module contains support to create and modify Tkinter
|
||||
BitmapImage and PhotoImage objects from PIL images.
|
||||
|
||||
For examples, see the demo programs in the Scripts directory.
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
.. py:module:: PIL.ImageWin
|
||||
.. py:currentmodule:: PIL.ImageWin
|
||||
|
||||
:py:mod:`ImageWin` Module (Windows-only)
|
||||
========================================
|
||||
:py:mod:`~PIL.ImageWin` Module (Windows-only)
|
||||
=============================================
|
||||
|
||||
The :py:mod:`ImageWin` module contains support to create and display images on
|
||||
The :py:mod:`~PIL.ImageWin` module contains support to create and display images on
|
||||
Windows.
|
||||
|
||||
ImageWin can be used with PythonWin and other user interface toolkits that
|
||||
|
|
11
docs/reference/JpegPresets.rst
Normal file
11
docs/reference/JpegPresets.rst
Normal file
|
@ -0,0 +1,11 @@
|
|||
.. py:currentmodule:: PIL.JpegPresets
|
||||
|
||||
:py:mod:`~PIL.JpegPresets` Module
|
||||
=================================
|
||||
|
||||
.. automodule:: PIL.JpegPresets
|
||||
|
||||
.. data:: presets
|
||||
:type: dict
|
||||
|
||||
A dictionary of all supported presets.
|
|
@ -1,10 +1,10 @@
|
|||
.. py:module:: PIL.PSDraw
|
||||
.. py:currentmodule:: PIL.PSDraw
|
||||
|
||||
:py:mod:`PSDraw` Module
|
||||
=======================
|
||||
:py:mod:`~PIL.PSDraw` Module
|
||||
============================
|
||||
|
||||
The :py:mod:`PSDraw` module provides simple print support for Postscript
|
||||
The :py:mod:`~PIL.PSDraw` module provides simple print support for Postscript
|
||||
printers. You can print text, graphics and images through this module.
|
||||
|
||||
.. autoclass:: PIL.PSDraw.PSDraw
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
.. py:module:: PIL.PyAccess
|
||||
.. py:currentmodule:: PIL.PyAccess
|
||||
|
||||
:py:mod:`PyAccess` Module
|
||||
=========================
|
||||
:py:mod:`~PIL.PyAccess` Module
|
||||
==============================
|
||||
|
||||
The :py:mod:`PyAccess` module provides a CFFI/Python implementation of the :ref:`PixelAccess`. This implementation is far faster on PyPy than the PixelAccess version.
|
||||
The :py:mod:`~PIL.PyAccess` module provides a CFFI/Python implementation of the :ref:`PixelAccess`. This implementation is far faster on PyPy than the PixelAccess version.
|
||||
|
||||
.. note:: Accessing individual pixels is fairly slow. If you are
|
||||
looping over all of the pixels in an image, there is likely
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
.. py:module:: PIL.TiffTags
|
||||
.. py:currentmodule:: PIL.TiffTags
|
||||
|
||||
:py:mod:`TiffTags` Module
|
||||
=========================
|
||||
:py:mod:`~PIL.TiffTags` Module
|
||||
==============================
|
||||
|
||||
The :py:mod:`TiffTags` module exposes many of the standard TIFF
|
||||
The :py:mod:`~PIL.TiffTags` module exposes many of the standard TIFF
|
||||
metadata tag numbers, names, and type information.
|
||||
|
||||
.. method:: lookup(tag)
|
||||
|
||||
:param tag: Integer tag number
|
||||
:returns: Taginfo namedtuple, From the ``TAGS_V2`` info if possible,
|
||||
otherwise just populating the value and name from ``TAGS``.
|
||||
:returns: Taginfo namedtuple, From the :py:data:`~PIL.TiffTags.TAGS_V2` info if possible,
|
||||
otherwise just populating the value and name from :py:data:`~PIL.TiffTags.TAGS`.
|
||||
If the tag is not recognized, "unknown" is returned for the name
|
||||
|
||||
.. versionadded:: 3.1.0
|
||||
|
@ -22,7 +22,7 @@ metadata tag numbers, names, and type information.
|
|||
|
||||
:param value: Integer Tag Number
|
||||
:param name: Tag Name
|
||||
:param type: Integer type from :py:attr:`PIL.TiffTags.TYPES`
|
||||
:param type: Integer type from :py:data:`PIL.TiffTags.TYPES`
|
||||
:param length: Array length: 0 == variable, 1 == single value, n = fixed
|
||||
:param enum: Dict of name:integer value options for an enumeration
|
||||
|
||||
|
@ -33,15 +33,17 @@ metadata tag numbers, names, and type information.
|
|||
|
||||
.. versionadded:: 3.0.0
|
||||
|
||||
.. py:attribute:: PIL.TiffTags.TAGS_V2
|
||||
.. py:data:: PIL.TiffTags.TAGS_V2
|
||||
:type: dict
|
||||
|
||||
The ``TAGS_V2`` dictionary maps 16-bit integer tag numbers to
|
||||
:py:class:`PIL.TagTypes.TagInfo` tuples for metadata fields defined in the TIFF
|
||||
:py:class:`PIL.TiffTags.TagInfo` tuples for metadata fields defined in the TIFF
|
||||
spec.
|
||||
|
||||
.. versionadded:: 3.0.0
|
||||
|
||||
.. py:attribute:: PIL.TiffTags.TAGS
|
||||
.. py:data:: PIL.TiffTags.TAGS
|
||||
:type: dict
|
||||
|
||||
The ``TAGS`` dictionary maps 16-bit integer TIFF tag number to
|
||||
descriptive string names. For instance:
|
||||
|
@ -50,10 +52,11 @@ metadata tag numbers, names, and type information.
|
|||
>>> TAGS[0x010e]
|
||||
'ImageDescription'
|
||||
|
||||
This dictionary contains a superset of the tags in TAGS_V2, common
|
||||
This dictionary contains a superset of the tags in :py:data:`~PIL.TiffTags.TAGS_V2`, common
|
||||
EXIF tags, and other well known metadata tags.
|
||||
|
||||
.. py:attribute:: PIL.TiffTags.TYPES
|
||||
.. py:data:: PIL.TiffTags.TYPES
|
||||
:type: dict
|
||||
|
||||
The ``TYPES`` dictionary maps the TIFF type short integer to a
|
||||
human readable type name.
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
.. py:module:: PIL.features
|
||||
.. py:currentmodule:: PIL.features
|
||||
|
||||
:py:mod:`features` Module
|
||||
==========================
|
||||
:py:mod:`~PIL.features` Module
|
||||
==============================
|
||||
|
||||
The :py:mod:`PIL.features` module can be used to detect which Pillow features are available on your system.
|
||||
|
||||
.. autofunction:: PIL.features.pilinfo
|
||||
.. autofunction:: PIL.features.check
|
||||
.. autofunction:: PIL.features.version
|
||||
.. autofunction:: PIL.features.get_supported
|
||||
|
||||
Modules
|
||||
|
@ -16,28 +17,31 @@ Modules
|
|||
Support for the following modules can be checked:
|
||||
|
||||
* ``pil``: The Pillow core module, required for all functionality.
|
||||
* ``tkinter``: Tkinter support.
|
||||
* ``tkinter``: Tkinter support. Version number not available.
|
||||
* ``freetype2``: FreeType font support via :py:func:`PIL.ImageFont.truetype`.
|
||||
* ``littlecms2``: LittleCMS 2 support via :py:mod:`PIL.ImageCms`.
|
||||
* ``webp``: WebP image support.
|
||||
|
||||
.. autofunction:: PIL.features.check_module
|
||||
.. autofunction:: PIL.features.version_module
|
||||
.. autofunction:: PIL.features.get_supported_modules
|
||||
|
||||
Codecs
|
||||
------
|
||||
|
||||
These are only checked during Pillow compilation.
|
||||
Support for these is only checked during Pillow compilation.
|
||||
If the required library was uninstalled from the system, the ``pil`` core module may fail to load instead.
|
||||
Except for ``jpg``, the version number is checked at run-time.
|
||||
|
||||
Support for the following codecs can be checked:
|
||||
|
||||
* ``jpg``: (compile time) Libjpeg support, required for JPEG based image formats.
|
||||
* ``jpg``: (compile time) Libjpeg support, required for JPEG based image formats. Only compile time version number is available.
|
||||
* ``jpg_2000``: (compile time) OpenJPEG support, required for JPEG 2000 image formats.
|
||||
* ``zlib``: (compile time) Zlib support, required for zlib compressed formats, such as PNG.
|
||||
* ``libtiff``: (compile time) LibTIFF support, required for TIFF based image formats.
|
||||
|
||||
.. autofunction:: PIL.features.check_codec
|
||||
.. autofunction:: PIL.features.version_codec
|
||||
.. autofunction:: PIL.features.get_supported_codecs
|
||||
|
||||
Features
|
||||
|
@ -45,16 +49,18 @@ Features
|
|||
|
||||
Some of these are only checked during Pillow compilation.
|
||||
If the required library was uninstalled from the system, the relevant module may fail to load instead.
|
||||
Feature version numbers are available only where stated.
|
||||
|
||||
Support for the following features can be checked:
|
||||
|
||||
* ``libjpeg_turbo``: (compile time) Whether Pillow was compiled against the libjpeg-turbo version of libjpeg.
|
||||
* ``libjpeg_turbo``: (compile time) Whether Pillow was compiled against the libjpeg-turbo version of libjpeg. Compile-time version number is available.
|
||||
* ``transp_webp``: Support for transparency in WebP images.
|
||||
* ``webp_mux``: (compile time) Support for EXIF data in WebP images.
|
||||
* ``webp_anim``: (compile time) Support for animated WebP images.
|
||||
* ``raqm``: Raqm library, required for ``ImageFont.LAYOUT_RAQM`` in :py:func:`PIL.ImageFont.truetype`.
|
||||
* ``libimagequant``: (compile time) ImageQuant quantization support in :py:func:`PIL.Image.Image.quantize`.
|
||||
* ``raqm``: Raqm library, required for ``ImageFont.LAYOUT_RAQM`` in :py:func:`PIL.ImageFont.truetype`. Run-time version number is available for Raqm 0.7.0 or newer.
|
||||
* ``libimagequant``: (compile time) ImageQuant quantization support in :py:func:`PIL.Image.Image.quantize`. Run-time version number is available.
|
||||
* ``xcb``: (compile time) Support for X11 in :py:func:`PIL.ImageGrab.grab` via the XCB library.
|
||||
|
||||
.. autofunction:: PIL.features.check_feature
|
||||
.. autofunction:: PIL.features.version_feature
|
||||
.. autofunction:: PIL.features.get_supported_features
|
||||
|
|
|
@ -7,8 +7,8 @@ Reference
|
|||
|
||||
Image
|
||||
ImageChops
|
||||
ImageColor
|
||||
ImageCms
|
||||
ImageColor
|
||||
ImageDraw
|
||||
ImageEnhance
|
||||
ImageFile
|
||||
|
@ -22,11 +22,13 @@ Reference
|
|||
ImagePath
|
||||
ImageQt
|
||||
ImageSequence
|
||||
ImageShow
|
||||
ImageStat
|
||||
ImageTk
|
||||
ImageWin
|
||||
ExifTags
|
||||
TiffTags
|
||||
JpegPresets
|
||||
PSDraw
|
||||
PixelAccess
|
||||
PyAccess
|
||||
|
|
|
@ -7,4 +7,4 @@ Internal Reference Docs
|
|||
open_files
|
||||
limits
|
||||
block_allocator
|
||||
|
||||
internal_modules
|
||||
|
|
38
docs/reference/internal_modules.rst
Normal file
38
docs/reference/internal_modules.rst
Normal file
|
@ -0,0 +1,38 @@
|
|||
Internal Modules
|
||||
================
|
||||
|
||||
:mod:`~PIL._binary` Module
|
||||
--------------------------
|
||||
|
||||
.. automodule:: PIL._binary
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`~PIL._tkinter_finder` Module
|
||||
----------------------------------
|
||||
|
||||
.. automodule:: PIL._tkinter_finder
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`~PIL._util` Module
|
||||
------------------------
|
||||
|
||||
.. automodule:: PIL._util
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`~PIL._version` Module
|
||||
---------------------------
|
||||
|
||||
.. module:: PIL._version
|
||||
|
||||
.. data:: __version__
|
||||
:annotation:
|
||||
:type: str
|
||||
|
||||
This is the master version number for Pillow,
|
||||
all other uses reference this module.
|
|
@ -1,232 +1,232 @@
|
|||
Plugin reference
|
||||
================
|
||||
|
||||
:mod:`BmpImagePlugin` Module
|
||||
----------------------------
|
||||
:mod:`~PIL.BmpImagePlugin` Module
|
||||
---------------------------------
|
||||
|
||||
.. automodule:: PIL.BmpImagePlugin
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`BufrStubImagePlugin` Module
|
||||
---------------------------------
|
||||
:mod:`~PIL.BufrStubImagePlugin` Module
|
||||
--------------------------------------
|
||||
|
||||
.. automodule:: PIL.BufrStubImagePlugin
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`CurImagePlugin` Module
|
||||
----------------------------
|
||||
:mod:`~PIL.CurImagePlugin` Module
|
||||
---------------------------------
|
||||
|
||||
.. automodule:: PIL.CurImagePlugin
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`DcxImagePlugin` Module
|
||||
----------------------------
|
||||
:mod:`~PIL.DcxImagePlugin` Module
|
||||
---------------------------------
|
||||
|
||||
.. automodule:: PIL.DcxImagePlugin
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`EpsImagePlugin` Module
|
||||
----------------------------
|
||||
:mod:`~PIL.EpsImagePlugin` Module
|
||||
---------------------------------
|
||||
|
||||
.. automodule:: PIL.EpsImagePlugin
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`FitsStubImagePlugin` Module
|
||||
---------------------------------
|
||||
:mod:`~PIL.FitsStubImagePlugin` Module
|
||||
--------------------------------------
|
||||
|
||||
.. automodule:: PIL.FitsStubImagePlugin
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`FliImagePlugin` Module
|
||||
----------------------------
|
||||
:mod:`~PIL.FliImagePlugin` Module
|
||||
---------------------------------
|
||||
|
||||
.. automodule:: PIL.FliImagePlugin
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`FpxImagePlugin` Module
|
||||
----------------------------
|
||||
:mod:`~PIL.FpxImagePlugin` Module
|
||||
---------------------------------
|
||||
|
||||
.. automodule:: PIL.FpxImagePlugin
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`GbrImagePlugin` Module
|
||||
----------------------------
|
||||
:mod:`~PIL.GbrImagePlugin` Module
|
||||
---------------------------------
|
||||
|
||||
.. automodule:: PIL.GbrImagePlugin
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`GifImagePlugin` Module
|
||||
----------------------------
|
||||
:mod:`~PIL.GifImagePlugin` Module
|
||||
---------------------------------
|
||||
|
||||
.. automodule:: PIL.GifImagePlugin
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`GribStubImagePlugin` Module
|
||||
---------------------------------
|
||||
:mod:`~PIL.GribStubImagePlugin` Module
|
||||
--------------------------------------
|
||||
|
||||
.. automodule:: PIL.GribStubImagePlugin
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`Hdf5StubImagePlugin` Module
|
||||
---------------------------------
|
||||
:mod:`~PIL.Hdf5StubImagePlugin` Module
|
||||
--------------------------------------
|
||||
|
||||
.. automodule:: PIL.Hdf5StubImagePlugin
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`IcnsImagePlugin` Module
|
||||
-----------------------------
|
||||
:mod:`~PIL.IcnsImagePlugin` Module
|
||||
----------------------------------
|
||||
|
||||
.. automodule:: PIL.IcnsImagePlugin
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`IcoImagePlugin` Module
|
||||
----------------------------
|
||||
:mod:`~PIL.IcoImagePlugin` Module
|
||||
---------------------------------
|
||||
|
||||
.. automodule:: PIL.IcoImagePlugin
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`ImImagePlugin` Module
|
||||
---------------------------
|
||||
:mod:`~PIL.ImImagePlugin` Module
|
||||
--------------------------------
|
||||
|
||||
.. automodule:: PIL.ImImagePlugin
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`ImtImagePlugin` Module
|
||||
----------------------------
|
||||
:mod:`~PIL.ImtImagePlugin` Module
|
||||
---------------------------------
|
||||
|
||||
.. automodule:: PIL.ImtImagePlugin
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`IptcImagePlugin` Module
|
||||
-----------------------------
|
||||
:mod:`~PIL.IptcImagePlugin` Module
|
||||
----------------------------------
|
||||
|
||||
.. automodule:: PIL.IptcImagePlugin
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`JpegImagePlugin` Module
|
||||
-----------------------------
|
||||
:mod:`~PIL.JpegImagePlugin` Module
|
||||
----------------------------------
|
||||
|
||||
.. automodule:: PIL.JpegImagePlugin
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`Jpeg2KImagePlugin` Module
|
||||
-------------------------------
|
||||
:mod:`~PIL.Jpeg2KImagePlugin` Module
|
||||
------------------------------------
|
||||
|
||||
.. automodule:: PIL.Jpeg2KImagePlugin
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`McIdasImagePlugin` Module
|
||||
-------------------------------
|
||||
:mod:`~PIL.McIdasImagePlugin` Module
|
||||
------------------------------------
|
||||
|
||||
.. automodule:: PIL.McIdasImagePlugin
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`MicImagePlugin` Module
|
||||
----------------------------
|
||||
:mod:`~PIL.MicImagePlugin` Module
|
||||
---------------------------------
|
||||
|
||||
.. automodule:: PIL.MicImagePlugin
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`MpegImagePlugin` Module
|
||||
-----------------------------
|
||||
:mod:`~PIL.MpegImagePlugin` Module
|
||||
----------------------------------
|
||||
|
||||
.. automodule:: PIL.MpegImagePlugin
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`MspImagePlugin` Module
|
||||
----------------------------
|
||||
:mod:`~PIL.MspImagePlugin` Module
|
||||
---------------------------------
|
||||
|
||||
.. automodule:: PIL.MspImagePlugin
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`PalmImagePlugin` Module
|
||||
-----------------------------
|
||||
:mod:`~PIL.PalmImagePlugin` Module
|
||||
----------------------------------
|
||||
|
||||
.. automodule:: PIL.PalmImagePlugin
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`PcdImagePlugin` Module
|
||||
----------------------------
|
||||
:mod:`~PIL.PcdImagePlugin` Module
|
||||
---------------------------------
|
||||
|
||||
.. automodule:: PIL.PcdImagePlugin
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`PcxImagePlugin` Module
|
||||
----------------------------
|
||||
:mod:`~PIL.PcxImagePlugin` Module
|
||||
---------------------------------
|
||||
|
||||
.. automodule:: PIL.PcxImagePlugin
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`PdfImagePlugin` Module
|
||||
----------------------------
|
||||
:mod:`~PIL.PdfImagePlugin` Module
|
||||
---------------------------------
|
||||
|
||||
.. automodule:: PIL.PdfImagePlugin
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`PixarImagePlugin` Module
|
||||
------------------------------
|
||||
:mod:`~PIL.PixarImagePlugin` Module
|
||||
-----------------------------------
|
||||
|
||||
.. automodule:: PIL.PixarImagePlugin
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`PngImagePlugin` Module
|
||||
----------------------------
|
||||
:mod:`~PIL.PngImagePlugin` Module
|
||||
---------------------------------
|
||||
|
||||
.. automodule:: PIL.PngImagePlugin
|
||||
:members: ChunkStream, PngStream, getchunks, is_cid, putchunk
|
||||
|
@ -245,96 +245,96 @@ Plugin reference
|
|||
:show-inheritance:
|
||||
|
||||
|
||||
:mod:`PpmImagePlugin` Module
|
||||
----------------------------
|
||||
:mod:`~PIL.PpmImagePlugin` Module
|
||||
---------------------------------
|
||||
|
||||
.. automodule:: PIL.PpmImagePlugin
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`PsdImagePlugin` Module
|
||||
----------------------------
|
||||
:mod:`~PIL.PsdImagePlugin` Module
|
||||
---------------------------------
|
||||
|
||||
.. automodule:: PIL.PsdImagePlugin
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`SgiImagePlugin` Module
|
||||
----------------------------
|
||||
:mod:`~PIL.SgiImagePlugin` Module
|
||||
---------------------------------
|
||||
|
||||
.. automodule:: PIL.SgiImagePlugin
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`SpiderImagePlugin` Module
|
||||
-------------------------------
|
||||
:mod:`~PIL.SpiderImagePlugin` Module
|
||||
------------------------------------
|
||||
|
||||
.. automodule:: PIL.SpiderImagePlugin
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`SunImagePlugin` Module
|
||||
----------------------------
|
||||
:mod:`~PIL.SunImagePlugin` Module
|
||||
---------------------------------
|
||||
|
||||
.. automodule:: PIL.SunImagePlugin
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`TgaImagePlugin` Module
|
||||
----------------------------
|
||||
:mod:`~PIL.TgaImagePlugin` Module
|
||||
---------------------------------
|
||||
|
||||
.. automodule:: PIL.TgaImagePlugin
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`TiffImagePlugin` Module
|
||||
-----------------------------
|
||||
:mod:`~PIL.TiffImagePlugin` Module
|
||||
----------------------------------
|
||||
|
||||
.. automodule:: PIL.TiffImagePlugin
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`WebPImagePlugin` Module
|
||||
-----------------------------
|
||||
:mod:`~PIL.WebPImagePlugin` Module
|
||||
----------------------------------
|
||||
|
||||
.. automodule:: PIL.WebPImagePlugin
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`WmfImagePlugin` Module
|
||||
----------------------------
|
||||
:mod:`~PIL.WmfImagePlugin` Module
|
||||
---------------------------------
|
||||
|
||||
.. automodule:: PIL.WmfImagePlugin
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`XVThumbImagePlugin` Module
|
||||
--------------------------------
|
||||
:mod:`~PIL.XVThumbImagePlugin` Module
|
||||
-------------------------------------
|
||||
|
||||
.. automodule:: PIL.XVThumbImagePlugin
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`XbmImagePlugin` Module
|
||||
----------------------------
|
||||
:mod:`~PIL.XbmImagePlugin` Module
|
||||
---------------------------------
|
||||
|
||||
.. automodule:: PIL.XbmImagePlugin
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`XpmImagePlugin` Module
|
||||
----------------------------
|
||||
:mod:`~PIL.XpmImagePlugin` Module
|
||||
---------------------------------
|
||||
|
||||
.. automodule:: PIL.XpmImagePlugin
|
||||
:members:
|
||||
|
|
|
@ -29,53 +29,53 @@ Image resizing filters
|
|||
Image resizing methods :py:meth:`~PIL.Image.Image.resize` and
|
||||
:py:meth:`~PIL.Image.Image.thumbnail` take a ``resample`` argument, which tells
|
||||
which filter should be used for resampling. Possible values are:
|
||||
:py:attr:`PIL.Image.NEAREST`, :py:attr:`PIL.Image.BILINEAR`,
|
||||
:py:attr:`PIL.Image.BICUBIC` and :py:attr:`PIL.Image.ANTIALIAS`.
|
||||
:py:data:`PIL.Image.NEAREST`, :py:data:`PIL.Image.BILINEAR`,
|
||||
:py:data:`PIL.Image.BICUBIC` and :py:data:`PIL.Image.ANTIALIAS`.
|
||||
Almost all of them were changed in this version.
|
||||
|
||||
Bicubic and bilinear downscaling
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
From the beginning :py:attr:`~PIL.Image.BILINEAR` and
|
||||
:py:attr:`~PIL.Image.BICUBIC` filters were based on affine transformations
|
||||
From the beginning :py:data:`~PIL.Image.BILINEAR` and
|
||||
:py:data:`~PIL.Image.BICUBIC` filters were based on affine transformations
|
||||
and used a fixed number of pixels from the source image for every destination
|
||||
pixel (2x2 pixels for :py:attr:`~PIL.Image.BILINEAR` and 4x4 for
|
||||
:py:attr:`~PIL.Image.BICUBIC`). This gave an unsatisfactory result for
|
||||
pixel (2x2 pixels for :py:data:`~PIL.Image.BILINEAR` and 4x4 for
|
||||
:py:data:`~PIL.Image.BICUBIC`). This gave an unsatisfactory result for
|
||||
downscaling. At the same time, a high quality convolutions-based algorithm with
|
||||
flexible kernel was used for :py:attr:`~PIL.Image.ANTIALIAS` filter.
|
||||
flexible kernel was used for :py:data:`~PIL.Image.ANTIALIAS` filter.
|
||||
|
||||
Starting from Pillow 2.7.0, a high quality convolutions-based algorithm is used
|
||||
for all of these three filters.
|
||||
|
||||
If you have previously used any tricks to maintain quality when downscaling with
|
||||
:py:attr:`~PIL.Image.BILINEAR` and :py:attr:`~PIL.Image.BICUBIC` filters
|
||||
:py:data:`~PIL.Image.BILINEAR` and :py:data:`~PIL.Image.BICUBIC` filters
|
||||
(for example, reducing within several steps), they are unnecessary now.
|
||||
|
||||
Antialias renamed to Lanczos
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
A new :py:attr:`PIL.Image.LANCZOS` constant was added instead of
|
||||
:py:attr:`~PIL.Image.ANTIALIAS`.
|
||||
A new :py:data:`PIL.Image.LANCZOS` constant was added instead of
|
||||
:py:data:`~PIL.Image.ANTIALIAS`.
|
||||
|
||||
When :py:attr:`~PIL.Image.ANTIALIAS` was initially added, it was the only
|
||||
When :py:data:`~PIL.Image.ANTIALIAS` was initially added, it was the only
|
||||
high-quality filter based on convolutions. It's name was supposed to reflect
|
||||
this. Starting from Pillow 2.7.0 all resize method are based on convolutions.
|
||||
All of them are antialias from now on. And the real name of the
|
||||
:py:attr:`~PIL.Image.ANTIALIAS` filter is Lanczos filter.
|
||||
:py:data:`~PIL.Image.ANTIALIAS` filter is Lanczos filter.
|
||||
|
||||
The :py:attr:`~PIL.Image.ANTIALIAS` constant is left for backward compatibility
|
||||
and is an alias for :py:attr:`~PIL.Image.LANCZOS`.
|
||||
The :py:data:`~PIL.Image.ANTIALIAS` constant is left for backward compatibility
|
||||
and is an alias for :py:data:`~PIL.Image.LANCZOS`.
|
||||
|
||||
Lanczos upscaling quality
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The image upscaling quality with :py:attr:`~PIL.Image.LANCZOS` filter was
|
||||
almost the same as :py:attr:`~PIL.Image.BILINEAR` due to bug. This has been fixed.
|
||||
The image upscaling quality with :py:data:`~PIL.Image.LANCZOS` filter was
|
||||
almost the same as :py:data:`~PIL.Image.BILINEAR` due to bug. This has been fixed.
|
||||
|
||||
Bicubic upscaling quality
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The :py:attr:`~PIL.Image.BICUBIC` filter for affine transformations produced
|
||||
The :py:data:`~PIL.Image.BICUBIC` filter for affine transformations produced
|
||||
sharp, slightly pixelated image for upscaling. Bicubic for convolutions is
|
||||
more soft.
|
||||
|
||||
|
@ -84,42 +84,42 @@ Resize performance
|
|||
|
||||
In most cases, convolution is more a expensive algorithm for downscaling
|
||||
because it takes into account all the pixels of source image. Therefore
|
||||
:py:attr:`~PIL.Image.BILINEAR` and :py:attr:`~PIL.Image.BICUBIC` filters'
|
||||
:py:data:`~PIL.Image.BILINEAR` and :py:data:`~PIL.Image.BICUBIC` filters'
|
||||
performance can be lower than before. On the other hand the quality of
|
||||
:py:attr:`~PIL.Image.BILINEAR` and :py:attr:`~PIL.Image.BICUBIC` was close to
|
||||
:py:attr:`~PIL.Image.NEAREST`. So if such quality is suitable for your tasks
|
||||
you can switch to :py:attr:`~PIL.Image.NEAREST` filter for downscaling,
|
||||
:py:data:`~PIL.Image.BILINEAR` and :py:data:`~PIL.Image.BICUBIC` was close to
|
||||
:py:data:`~PIL.Image.NEAREST`. So if such quality is suitable for your tasks
|
||||
you can switch to :py:data:`~PIL.Image.NEAREST` filter for downscaling,
|
||||
which will give a huge improvement in performance.
|
||||
|
||||
At the same time performance of convolution resampling for downscaling has been
|
||||
improved by around a factor of two compared to the previous version.
|
||||
The upscaling performance of the :py:attr:`~PIL.Image.LANCZOS` filter has
|
||||
remained the same. For :py:attr:`~PIL.Image.BILINEAR` filter it has improved by
|
||||
1.5 times and for :py:attr:`~PIL.Image.BICUBIC` by four times.
|
||||
The upscaling performance of the :py:data:`~PIL.Image.LANCZOS` filter has
|
||||
remained the same. For :py:data:`~PIL.Image.BILINEAR` filter it has improved by
|
||||
1.5 times and for :py:data:`~PIL.Image.BICUBIC` by four times.
|
||||
|
||||
Default filter for thumbnails
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
In Pillow 2.5 the default filter for :py:meth:`~PIL.Image.Image.thumbnail` was
|
||||
changed from :py:attr:`~PIL.Image.NEAREST` to :py:attr:`~PIL.Image.ANTIALIAS`.
|
||||
changed from :py:data:`~PIL.Image.NEAREST` to :py:data:`~PIL.Image.ANTIALIAS`.
|
||||
Antialias was chosen because all the other filters gave poor quality for
|
||||
reduction. Starting from Pillow 2.7.0, :py:attr:`~PIL.Image.ANTIALIAS` has been
|
||||
replaced with :py:attr:`~PIL.Image.BICUBIC`, because it's faster and
|
||||
:py:attr:`~PIL.Image.ANTIALIAS` doesn't give any advantages after
|
||||
reduction. Starting from Pillow 2.7.0, :py:data:`~PIL.Image.ANTIALIAS` has been
|
||||
replaced with :py:data:`~PIL.Image.BICUBIC`, because it's faster and
|
||||
:py:data:`~PIL.Image.ANTIALIAS` doesn't give any advantages after
|
||||
downscaling with libjpeg, which uses supersampling internally, not convolutions.
|
||||
|
||||
Image transposition
|
||||
-------------------
|
||||
|
||||
A new method :py:attr:`PIL.Image.TRANSPOSE` has been added for the
|
||||
A new method :py:data:`PIL.Image.TRANSPOSE` has been added for the
|
||||
:py:meth:`~PIL.Image.Image.transpose` operation in addition to
|
||||
:py:attr:`~PIL.Image.FLIP_LEFT_RIGHT`, :py:attr:`~PIL.Image.FLIP_TOP_BOTTOM`,
|
||||
:py:attr:`~PIL.Image.ROTATE_90`, :py:attr:`~PIL.Image.ROTATE_180`,
|
||||
:py:attr:`~PIL.Image.ROTATE_270`. :py:attr:`~PIL.Image.TRANSPOSE` is an algebra
|
||||
:py:data:`~PIL.Image.FLIP_LEFT_RIGHT`, :py:data:`~PIL.Image.FLIP_TOP_BOTTOM`,
|
||||
:py:data:`~PIL.Image.ROTATE_90`, :py:data:`~PIL.Image.ROTATE_180`,
|
||||
:py:data:`~PIL.Image.ROTATE_270`. :py:data:`~PIL.Image.TRANSPOSE` is an algebra
|
||||
transpose, with an image reflected across its main diagonal.
|
||||
|
||||
The speed of :py:attr:`~PIL.Image.ROTATE_90`, :py:attr:`~PIL.Image.ROTATE_270`
|
||||
and :py:attr:`~PIL.Image.TRANSPOSE` has been significantly improved for large
|
||||
The speed of :py:data:`~PIL.Image.ROTATE_90`, :py:data:`~PIL.Image.ROTATE_270`
|
||||
and :py:data:`~PIL.Image.TRANSPOSE` has been significantly improved for large
|
||||
images which don't fit in the processor cache.
|
||||
|
||||
Gaussian blur and unsharp mask
|
||||
|
|
|
@ -27,7 +27,7 @@ New DecompressionBomb Warning
|
|||
|
||||
:py:meth:`PIL.Image.Image.crop` now may raise a DecompressionBomb
|
||||
warning if the crop region enlarges the image over the threshold
|
||||
specified by :py:attr:`PIL.Image.MAX_PIXELS`.
|
||||
specified by :py:data:`PIL.Image.MAX_PIXELS`.
|
||||
|
||||
Removed Deprecated Items
|
||||
========================
|
||||
|
|
|
@ -27,3 +27,32 @@ Moved from the legacy :py:class:`PIL.TiffImagePlugin.ImageFileDirectory_v1` to
|
|||
:py:class:`PIL.Image.Exif`. This means that Exif RATIONALs and SIGNED_RATIONALs
|
||||
are now read as :py:class:`PIL.TiffImagePlugin.IFDRational`, instead of as a
|
||||
tuple with a numerator and a denominator.
|
||||
|
||||
TIFF BYTE tags format
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
TIFF BYTE tags were previously read as a tuple containing a bytestring. They
|
||||
are now read as just a single bytestring.
|
||||
|
||||
Deprecations
|
||||
^^^^^^^^^^^^
|
||||
|
||||
Image.show command parameter
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The ``command`` parameter was deprecated and will be removed in a future release.
|
||||
Use a subclass of :py:class:`PIL.ImageShow.Viewer` instead.
|
||||
|
||||
Image._showxv
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
``Image._showxv`` has been deprecated. Use :py:meth:`~PIL.Image.Image.show`
|
||||
instead. If custom behaviour is required, use :py:meth:`~PIL.ImageShow.register` to add
|
||||
a custom :py:class:`~PIL.ImageShow.Viewer` class.
|
||||
|
||||
ImageFile.raise_ioerror
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
``IOError`` was merged into ``OSError`` in Python 3.3. So, ``ImageFile.raise_ioerror``
|
||||
is now deprecated and will be removed in a future release. Use
|
||||
``ImageFile.raise_oserror`` instead.
|
||||
|
|
|
@ -9,4 +9,5 @@ pyflakes
|
|||
pyroma
|
||||
pytest
|
||||
pytest-cov
|
||||
sphinx>=2.4
|
||||
sphinx-rtd-theme
|
||||
|
|
|
@ -9,5 +9,5 @@ line_length = 88
|
|||
multi_line_output = 3
|
||||
|
||||
[tool:pytest]
|
||||
addopts = -rs
|
||||
addopts = -ra --color=yes
|
||||
testpaths = Tests
|
||||
|
|
|
@ -17,13 +17,13 @@
|
|||
# See the README file for information on usage and redistribution.
|
||||
#
|
||||
|
||||
"""
|
||||
Parse X Bitmap Distribution Format (BDF)
|
||||
"""
|
||||
|
||||
|
||||
from . import FontFile, Image
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
# parse X Bitmap Distribution Format (BDF)
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
bdf_slant = {
|
||||
"R": "Roman",
|
||||
"I": "Italic",
|
||||
|
@ -78,11 +78,9 @@ def bdf_char(f):
|
|||
return id, int(props["ENCODING"]), bbox, im
|
||||
|
||||
|
||||
##
|
||||
# Font file plugin for the X11 BDF format.
|
||||
|
||||
|
||||
class BdfFontFile(FontFile.FontFile):
|
||||
"""Font file plugin for the X11 BDF format."""
|
||||
|
||||
def __init__(self, fp):
|
||||
super().__init__()
|
||||
|
||||
|
|
|
@ -282,8 +282,8 @@ class _BLPBaseDecoder(ImageFile.PyDecoder):
|
|||
self.magic = self.fd.read(4)
|
||||
self._read_blp_header()
|
||||
self._load()
|
||||
except struct.error:
|
||||
raise OSError("Truncated Blp file")
|
||||
except struct.error as e:
|
||||
raise OSError("Truncated Blp file") from e
|
||||
return 0, 0
|
||||
|
||||
def _read_palette(self):
|
||||
|
|
|
@ -263,7 +263,7 @@ class BmpImageFile(ImageFile.ImageFile):
|
|||
# read 14 bytes: magic number, filesize, reserved, header final offset
|
||||
head_data = self.fp.read(14)
|
||||
# choke if the file does not have the required magic bytes
|
||||
if head_data[0:2] != b"BM":
|
||||
if not _accept(head_data):
|
||||
raise SyntaxError("Not a BMP file")
|
||||
# read the start position of the BMP image data (u32)
|
||||
offset = i32(head_data[10:14])
|
||||
|
@ -304,8 +304,8 @@ def _dib_save(im, fp, filename):
|
|||
def _save(im, fp, filename, bitmap_header=True):
|
||||
try:
|
||||
rawmode, bits, colors = SAVE[im.mode]
|
||||
except KeyError:
|
||||
raise OSError("cannot write mode %s as BMP" % im.mode)
|
||||
except KeyError as e:
|
||||
raise OSError("cannot write mode %s as BMP" % im.mode) from e
|
||||
|
||||
info = im.encoderinfo
|
||||
|
||||
|
|
|
@ -14,14 +14,16 @@
|
|||
# See the README file for information on usage and redistribution.
|
||||
#
|
||||
|
||||
##
|
||||
# A file object that provides read access to a part of an existing
|
||||
# file (for example a TAR file).
|
||||
|
||||
import io
|
||||
|
||||
|
||||
class ContainerIO:
|
||||
"""
|
||||
A file object that provides read access to a part of an existing
|
||||
file (for example a TAR file).
|
||||
"""
|
||||
|
||||
def __init__(self, file, offset, length):
|
||||
"""
|
||||
Create file object.
|
||||
|
|
|
@ -46,7 +46,7 @@ class DcxImageFile(PcxImageFile):
|
|||
|
||||
# Header
|
||||
s = self.fp.read(4)
|
||||
if i32(s) != MAGIC:
|
||||
if not _accept(s):
|
||||
raise SyntaxError("not a DCX file")
|
||||
|
||||
# Component directory
|
||||
|
|
|
@ -231,8 +231,8 @@ class EpsImageFile(ImageFile.ImageFile):
|
|||
|
||||
try:
|
||||
m = split.match(s)
|
||||
except re.error:
|
||||
raise SyntaxError("not an EPS file")
|
||||
except re.error as e:
|
||||
raise SyntaxError("not an EPS file") from e
|
||||
|
||||
if m:
|
||||
k, v = m.group(1, 2)
|
||||
|
|
|
@ -9,13 +9,11 @@
|
|||
# See the README file for information on usage and redistribution.
|
||||
#
|
||||
|
||||
##
|
||||
# This module provides constants and clear-text names for various
|
||||
# well-known EXIF tags.
|
||||
##
|
||||
"""
|
||||
This module provides constants and clear-text names for various
|
||||
well-known EXIF tags.
|
||||
"""
|
||||
|
||||
##
|
||||
# Maps EXIF tags to tag names.
|
||||
|
||||
TAGS = {
|
||||
# possibly incomplete
|
||||
|
@ -280,9 +278,8 @@ TAGS = {
|
|||
0xC74E: "OpcodeList3",
|
||||
0xC761: "NoiseProfile",
|
||||
}
|
||||
"""Maps EXIF tags to tag names."""
|
||||
|
||||
##
|
||||
# Maps EXIF GPS tags to tag names.
|
||||
|
||||
GPSTAGS = {
|
||||
0: "GPSVersionID",
|
||||
|
@ -318,3 +315,4 @@ GPSTAGS = {
|
|||
30: "GPSDifferential",
|
||||
31: "GPSHPositioningError",
|
||||
}
|
||||
"""Maps EXIF GPS tags to tag names."""
|
||||
|
|
|
@ -42,9 +42,8 @@ class FliImageFile(ImageFile.ImageFile):
|
|||
|
||||
# HEAD
|
||||
s = self.fp.read(128)
|
||||
magic = i16(s[4:6])
|
||||
if not (
|
||||
magic in [0xAF11, 0xAF12]
|
||||
_accept(s)
|
||||
and i16(s[14:16]) in [0, 3] # flags
|
||||
and s[20:22] == b"\x00\x00" # reserved
|
||||
):
|
||||
|
@ -60,6 +59,7 @@ class FliImageFile(ImageFile.ImageFile):
|
|||
|
||||
# animation speed
|
||||
duration = i32(s[16:20])
|
||||
magic = i16(s[4:6])
|
||||
if magic == 0xAF11:
|
||||
duration = (duration * 1000) // 70
|
||||
self.info["duration"] = duration
|
||||
|
|
|
@ -23,18 +23,15 @@ WIDTH = 800
|
|||
|
||||
|
||||
def puti16(fp, values):
|
||||
# write network order (big-endian) 16-bit sequence
|
||||
"""Write network order (big-endian) 16-bit sequence"""
|
||||
for v in values:
|
||||
if v < 0:
|
||||
v += 65536
|
||||
fp.write(_binary.o16be(v))
|
||||
|
||||
|
||||
##
|
||||
# Base class for raster font file handlers.
|
||||
|
||||
|
||||
class FontFile:
|
||||
"""Base class for raster font file handlers."""
|
||||
|
||||
bitmap = None
|
||||
|
||||
|
|
|
@ -59,8 +59,8 @@ class FpxImageFile(ImageFile.ImageFile):
|
|||
|
||||
try:
|
||||
self.ole = olefile.OleFileIO(self.fp)
|
||||
except OSError:
|
||||
raise SyntaxError("not an FPX file; invalid OLE file")
|
||||
except OSError as e:
|
||||
raise SyntaxError("not an FPX file; invalid OLE file") from e
|
||||
|
||||
if self.ole.root.clsid != "56616700-C154-11CE-8553-00AA00A1F95B":
|
||||
raise SyntaxError("not an FPX file; bad root CLSID")
|
||||
|
|
|
@ -14,26 +14,30 @@
|
|||
#
|
||||
|
||||
|
||||
# NOTE: This format cannot be automatically recognized, so the
|
||||
# class is not registered for use with Image.open(). To open a
|
||||
# gd file, use the GdImageFile.open() function instead.
|
||||
"""
|
||||
.. note::
|
||||
This format cannot be automatically recognized, so the
|
||||
class is not registered for use with :py:func:`PIL.Image.open()`. To open a
|
||||
gd file, use the :py:func:`PIL.GdImageFile.open()` function instead.
|
||||
|
||||
# THE GD FORMAT IS NOT DESIGNED FOR DATA INTERCHANGE. This
|
||||
# implementation is provided for convenience and demonstrational
|
||||
# purposes only.
|
||||
.. warning::
|
||||
THE GD FORMAT IS NOT DESIGNED FOR DATA INTERCHANGE. This
|
||||
implementation is provided for convenience and demonstrational
|
||||
purposes only.
|
||||
"""
|
||||
|
||||
|
||||
from . import ImageFile, ImagePalette, UnidentifiedImageError
|
||||
from ._binary import i8, i16be as i16, i32be as i32
|
||||
|
||||
##
|
||||
# Image plugin for the GD uncompressed format. Note that this format
|
||||
# is not supported by the standard <b>Image.open</b> function. To use
|
||||
# this plugin, you have to import the <b>GdImageFile</b> module and
|
||||
# use the <b>GdImageFile.open</b> function.
|
||||
|
||||
|
||||
class GdImageFile(ImageFile.ImageFile):
|
||||
"""
|
||||
Image plugin for the GD uncompressed format. Note that this format
|
||||
is not supported by the standard :py:func:`PIL.Image.open()` function. To use
|
||||
this plugin, you have to import the :py:mod:`PIL.GdImageFile` module and
|
||||
use the :py:func:`PIL.GdImageFile.open()` function.
|
||||
"""
|
||||
|
||||
format = "GD"
|
||||
format_description = "GD uncompressed images"
|
||||
|
@ -81,5 +85,5 @@ def open(fp, mode="r"):
|
|||
|
||||
try:
|
||||
return GdImageFile(fp)
|
||||
except SyntaxError:
|
||||
raise UnidentifiedImageError("cannot identify this image file")
|
||||
except SyntaxError as e:
|
||||
raise UnidentifiedImageError("cannot identify this image file") from e
|
||||
|
|
|
@ -63,7 +63,7 @@ class GifImageFile(ImageFile.ImageFile):
|
|||
|
||||
# Screen
|
||||
s = self.fp.read(13)
|
||||
if s[:6] not in [b"GIF87a", b"GIF89a"]:
|
||||
if not _accept(s):
|
||||
raise SyntaxError("not a GIF file")
|
||||
|
||||
self.info["version"] = s[:6]
|
||||
|
@ -130,9 +130,9 @@ class GifImageFile(ImageFile.ImageFile):
|
|||
for f in range(self.__frame + 1, frame + 1):
|
||||
try:
|
||||
self._seek(f)
|
||||
except EOFError:
|
||||
except EOFError as e:
|
||||
self.seek(last_frame)
|
||||
raise EOFError("no more images in GIF file")
|
||||
raise EOFError("no more images in GIF file") from e
|
||||
|
||||
def _seek(self, frame):
|
||||
|
||||
|
|
|
@ -13,17 +13,19 @@
|
|||
# See the README file for information on usage and redistribution.
|
||||
#
|
||||
|
||||
"""
|
||||
Stuff to translate curve segments to palette values (derived from
|
||||
the corresponding code in GIMP, written by Federico Mena Quintero.
|
||||
See the GIMP distribution for more information.)
|
||||
"""
|
||||
|
||||
|
||||
from math import log, pi, sin, sqrt
|
||||
|
||||
from ._binary import o8
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
# Stuff to translate curve segments to palette values (derived from
|
||||
# the corresponding code in GIMP, written by Federico Mena Quintero.
|
||||
# See the GIMP distribution for more information.)
|
||||
#
|
||||
|
||||
EPSILON = 1e-10
|
||||
"""""" # Enable auto-doc for data member
|
||||
|
||||
|
||||
def linear(middle, pos):
|
||||
|
@ -58,6 +60,7 @@ def sphere_decreasing(middle, pos):
|
|||
|
||||
|
||||
SEGMENTS = [linear, curved, sine, sphere_increasing, sphere_decreasing]
|
||||
"""""" # Enable auto-doc for data member
|
||||
|
||||
|
||||
class GradientFile:
|
||||
|
@ -98,11 +101,9 @@ class GradientFile:
|
|||
return b"".join(palette), "RGBA"
|
||||
|
||||
|
||||
##
|
||||
# File handler for GIMP's gradient format.
|
||||
|
||||
|
||||
class GimpGradientFile(GradientFile):
|
||||
"""File handler for GIMP's gradient format."""
|
||||
|
||||
def __init__(self, fp):
|
||||
|
||||
if fp.readline()[:13] != b"GIMP Gradient":
|
||||
|
|
|
@ -18,11 +18,9 @@ import re
|
|||
|
||||
from ._binary import o8
|
||||
|
||||
##
|
||||
# File handler for GIMP's palette format.
|
||||
|
||||
|
||||
class GimpPaletteFile:
|
||||
"""File handler for GIMP's palette format."""
|
||||
|
||||
rawmode = "RGB"
|
||||
|
||||
|
|
|
@ -23,10 +23,10 @@ import subprocess
|
|||
import sys
|
||||
import tempfile
|
||||
|
||||
from PIL import Image, ImageFile, PngImagePlugin
|
||||
from PIL import Image, ImageFile, PngImagePlugin, features
|
||||
from PIL._binary import i8
|
||||
|
||||
enable_jpeg2k = hasattr(Image.core, "jp2klib_version")
|
||||
enable_jpeg2k = features.check_codec("jpg_2000")
|
||||
if enable_jpeg2k:
|
||||
from PIL import Jpeg2KImagePlugin
|
||||
|
||||
|
@ -337,6 +337,10 @@ def _save(im, fp, filename):
|
|||
|
||||
# iconutil -c icns -o {} {}
|
||||
|
||||
fp_only = not filename
|
||||
if fp_only:
|
||||
f, filename = tempfile.mkstemp(".icns")
|
||||
os.close(f)
|
||||
convert_cmd = ["iconutil", "-c", "icns", "-o", filename, iconset]
|
||||
convert_proc = subprocess.Popen(
|
||||
convert_cmd, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL
|
||||
|
@ -349,6 +353,10 @@ def _save(im, fp, filename):
|
|||
if retcode:
|
||||
raise subprocess.CalledProcessError(retcode, convert_cmd)
|
||||
|
||||
if fp_only:
|
||||
with open(filename, "rb") as f:
|
||||
fp.write(f.read())
|
||||
|
||||
|
||||
Image.register_open(IcnsImageFile.format, IcnsImageFile, lambda x: x[:4] == b"icns")
|
||||
Image.register_extension(IcnsImageFile.format, ".icns")
|
||||
|
|
|
@ -163,8 +163,8 @@ class ImImageFile(ImageFile.ImageFile):
|
|||
|
||||
try:
|
||||
m = split.match(s)
|
||||
except re.error:
|
||||
raise SyntaxError("not an IM file")
|
||||
except re.error as e:
|
||||
raise SyntaxError("not an IM file") from e
|
||||
|
||||
if m:
|
||||
|
||||
|
@ -341,8 +341,8 @@ def _save(im, fp, filename):
|
|||
|
||||
try:
|
||||
image_type, rawmode = SAVE[im.mode]
|
||||
except KeyError:
|
||||
raise ValueError("Cannot save %s images as IM" % im.mode)
|
||||
except KeyError as e:
|
||||
raise ValueError("Cannot save %s images as IM" % im.mode) from e
|
||||
|
||||
frames = im.encoderinfo.get("frames", 1)
|
||||
|
||||
|
|
139
src/PIL/Image.py
139
src/PIL/Image.py
|
@ -434,8 +434,8 @@ def _getdecoder(mode, decoder_name, args, extra=()):
|
|||
try:
|
||||
# get decoder
|
||||
decoder = getattr(core, decoder_name + "_decoder")
|
||||
except AttributeError:
|
||||
raise OSError("decoder %s not available" % decoder_name)
|
||||
except AttributeError as e:
|
||||
raise OSError("decoder %s not available" % decoder_name) from e
|
||||
return decoder(mode, *args + extra)
|
||||
|
||||
|
||||
|
@ -457,8 +457,8 @@ def _getencoder(mode, encoder_name, args, extra=()):
|
|||
try:
|
||||
# get encoder
|
||||
encoder = getattr(core, encoder_name + "_encoder")
|
||||
except AttributeError:
|
||||
raise OSError("encoder %s not available" % encoder_name)
|
||||
except AttributeError as e:
|
||||
raise OSError("encoder %s not available" % encoder_name) from e
|
||||
return encoder(mode, *args + extra)
|
||||
|
||||
|
||||
|
@ -876,7 +876,7 @@ class Image:
|
|||
The default method of converting a greyscale ("L") or "RGB"
|
||||
image into a bilevel (mode "1") image uses Floyd-Steinberg
|
||||
dither to approximate the original image luminosity levels. If
|
||||
dither is NONE, all values larger than 128 are set to 255 (white),
|
||||
dither is :data:`NONE`, all values larger than 128 are set to 255 (white),
|
||||
all other values to 0 (black). To use other thresholds, use the
|
||||
:py:meth:`~PIL.Image.Image.point` method.
|
||||
|
||||
|
@ -889,11 +889,11 @@ class Image:
|
|||
should be 4- or 12-tuple containing floating point values.
|
||||
:param dither: Dithering method, used when converting from
|
||||
mode "RGB" to "P" or from "RGB" or "L" to "1".
|
||||
Available methods are NONE or FLOYDSTEINBERG (default).
|
||||
Available methods are :data:`NONE` or :data:`FLOYDSTEINBERG` (default).
|
||||
Note that this is not used when **matrix** is supplied.
|
||||
:param palette: Palette to use when converting from mode "RGB"
|
||||
to "P". Available palettes are WEB or ADAPTIVE.
|
||||
:param colors: Number of colors to use for the ADAPTIVE palette.
|
||||
to "P". Available palettes are :data:`WEB` or :data:`ADAPTIVE`.
|
||||
:param colors: Number of colors to use for the :data:`ADAPTIVE` palette.
|
||||
Defaults to 256.
|
||||
:rtype: :py:class:`~PIL.Image.Image`
|
||||
:returns: An :py:class:`~PIL.Image.Image` object.
|
||||
|
@ -971,10 +971,10 @@ class Image:
|
|||
if isinstance(t, tuple):
|
||||
try:
|
||||
t = trns_im.palette.getcolor(t)
|
||||
except Exception:
|
||||
except Exception as e:
|
||||
raise ValueError(
|
||||
"Couldn't allocate a palette color for transparency"
|
||||
)
|
||||
) from e
|
||||
trns_im.putpixel((0, 0), t)
|
||||
|
||||
if mode in ("L", "RGB"):
|
||||
|
@ -1027,8 +1027,8 @@ class Image:
|
|||
# normalize source image and try again
|
||||
im = self.im.convert(getmodebase(self.mode))
|
||||
im = im.convert(mode, dither)
|
||||
except KeyError:
|
||||
raise ValueError("illegal conversion")
|
||||
except KeyError as e:
|
||||
raise ValueError("illegal conversion") from e
|
||||
|
||||
new_im = self._new(im)
|
||||
if delete_trns:
|
||||
|
@ -1051,10 +1051,10 @@ class Image:
|
|||
of colors.
|
||||
|
||||
:param colors: The desired number of colors, <= 256
|
||||
:param method: ``Image.MEDIANCUT=0`` (median cut),
|
||||
``Image.MAXCOVERAGE=1`` (maximum coverage),
|
||||
``Image.FASTOCTREE=2`` (fast octree),
|
||||
``Image.LIBIMAGEQUANT=3`` (libimagequant; check support using
|
||||
:param method: :data:`MEDIANCUT` (median cut),
|
||||
:data:`MAXCOVERAGE` (maximum coverage),
|
||||
:data:`FASTOCTREE` (fast octree),
|
||||
:data:`LIBIMAGEQUANT` (libimagequant; check support using
|
||||
:py:func:`PIL.features.check_feature`
|
||||
with ``feature="libimagequant"``).
|
||||
:param kmeans: Integer
|
||||
|
@ -1062,7 +1062,7 @@ class Image:
|
|||
:py:class:`PIL.Image.Image`.
|
||||
:param dither: Dithering method, used when converting from
|
||||
mode "RGB" to "P" or from "RGB" or "L" to "1".
|
||||
Available methods are NONE or FLOYDSTEINBERG (default).
|
||||
Available methods are :data:`NONE` or :data:`FLOYDSTEINBERG` (default).
|
||||
Default: 1 (legacy setting)
|
||||
:returns: A new image
|
||||
|
||||
|
@ -1625,16 +1625,16 @@ class Image:
|
|||
mode = getmodebase(self.mode) + "A"
|
||||
try:
|
||||
self.im.setmode(mode)
|
||||
except (AttributeError, ValueError):
|
||||
except (AttributeError, ValueError) as e:
|
||||
# do things the hard way
|
||||
im = self.im.convert(mode)
|
||||
if im.mode not in ("LA", "PA", "RGBA"):
|
||||
raise ValueError # sanity check
|
||||
raise ValueError from e # sanity check
|
||||
self.im = im
|
||||
self.pyaccess = None
|
||||
self.mode = self.im.mode
|
||||
except (KeyError, ValueError):
|
||||
raise ValueError("illegal image mode")
|
||||
except (KeyError, ValueError) as e:
|
||||
raise ValueError("illegal image mode") from e
|
||||
|
||||
if self.mode in ("LA", "PA"):
|
||||
band = 1
|
||||
|
@ -1842,12 +1842,12 @@ class Image:
|
|||
:param size: The requested size in pixels, as a 2-tuple:
|
||||
(width, height).
|
||||
:param resample: An optional resampling filter. This can be
|
||||
one of :py:attr:`PIL.Image.NEAREST`, :py:attr:`PIL.Image.BOX`,
|
||||
:py:attr:`PIL.Image.BILINEAR`, :py:attr:`PIL.Image.HAMMING`,
|
||||
:py:attr:`PIL.Image.BICUBIC` or :py:attr:`PIL.Image.LANCZOS`.
|
||||
Default filter is :py:attr:`PIL.Image.BICUBIC`.
|
||||
one of :py:data:`PIL.Image.NEAREST`, :py:data:`PIL.Image.BOX`,
|
||||
:py:data:`PIL.Image.BILINEAR`, :py:data:`PIL.Image.HAMMING`,
|
||||
:py:data:`PIL.Image.BICUBIC` or :py:data:`PIL.Image.LANCZOS`.
|
||||
Default filter is :py:data:`PIL.Image.BICUBIC`.
|
||||
If the image has mode "1" or "P", it is
|
||||
always set to :py:attr:`PIL.Image.NEAREST`.
|
||||
always set to :py:data:`PIL.Image.NEAREST`.
|
||||
See: :ref:`concept-filters`.
|
||||
:param box: An optional 4-tuple of floats providing
|
||||
the source image region to be scaled.
|
||||
|
@ -1977,12 +1977,12 @@ class Image:
|
|||
|
||||
:param angle: In degrees counter clockwise.
|
||||
:param resample: An optional resampling filter. This can be
|
||||
one of :py:attr:`PIL.Image.NEAREST` (use nearest neighbour),
|
||||
:py:attr:`PIL.Image.BILINEAR` (linear interpolation in a 2x2
|
||||
environment), or :py:attr:`PIL.Image.BICUBIC`
|
||||
one of :py:data:`PIL.Image.NEAREST` (use nearest neighbour),
|
||||
:py:data:`PIL.Image.BILINEAR` (linear interpolation in a 2x2
|
||||
environment), or :py:data:`PIL.Image.BICUBIC`
|
||||
(cubic spline interpolation in a 4x4 environment).
|
||||
If omitted, or if the image has mode "1" or "P", it is
|
||||
set to :py:attr:`PIL.Image.NEAREST`. See :ref:`concept-filters`.
|
||||
set to :py:data:`PIL.Image.NEAREST`. See :ref:`concept-filters`.
|
||||
:param expand: Optional expansion flag. If true, expands the output
|
||||
image to make it large enough to hold the entire rotated image.
|
||||
If false or omitted, make the output image the same size as the
|
||||
|
@ -2136,8 +2136,8 @@ class Image:
|
|||
init()
|
||||
try:
|
||||
format = EXTENSION[ext]
|
||||
except KeyError:
|
||||
raise ValueError("unknown file extension: {}".format(ext))
|
||||
except KeyError as e:
|
||||
raise ValueError("unknown file extension: {}".format(ext)) from e
|
||||
|
||||
if format.upper() not in SAVE:
|
||||
init()
|
||||
|
@ -2181,8 +2181,10 @@ class Image:
|
|||
|
||||
def show(self, title=None, command=None):
|
||||
"""
|
||||
Displays this image. This method is mainly intended for
|
||||
debugging purposes.
|
||||
Displays this image. This method is mainly intended for debugging purposes.
|
||||
|
||||
This method calls :py:func:`PIL.ImageShow.show` internally. You can use
|
||||
:py:func:`PIL.ImageShow.register` to override its default behaviour.
|
||||
|
||||
The image is first saved to a temporary file. By default, it will be in
|
||||
PNG format.
|
||||
|
@ -2194,11 +2196,16 @@ class Image:
|
|||
|
||||
On Windows, the image is opened with the standard PNG display utility.
|
||||
|
||||
:param title: Optional title to use for the image window,
|
||||
where possible.
|
||||
:param command: command used to show the image
|
||||
:param title: Optional title to use for the image window, where possible.
|
||||
"""
|
||||
|
||||
if command is not None:
|
||||
warnings.warn(
|
||||
"The command parameter is deprecated and will be removed in a future "
|
||||
"release. Use a subclass of ImageShow.Viewer instead.",
|
||||
DeprecationWarning,
|
||||
)
|
||||
|
||||
_show(self, title=title, command=command)
|
||||
|
||||
def split(self):
|
||||
|
@ -2238,8 +2245,8 @@ class Image:
|
|||
if isinstance(channel, str):
|
||||
try:
|
||||
channel = self.getbands().index(channel)
|
||||
except ValueError:
|
||||
raise ValueError('The image has no channel "{}"'.format(channel))
|
||||
except ValueError as e:
|
||||
raise ValueError('The image has no channel "{}"'.format(channel)) from e
|
||||
|
||||
return self._new(self.im.getband(channel))
|
||||
|
||||
|
@ -2267,10 +2274,10 @@ class Image:
|
|||
|
||||
:param size: Requested size.
|
||||
:param resample: Optional resampling filter. This can be one
|
||||
of :py:attr:`PIL.Image.NEAREST`, :py:attr:`PIL.Image.BILINEAR`,
|
||||
:py:attr:`PIL.Image.BICUBIC`, or :py:attr:`PIL.Image.LANCZOS`.
|
||||
If omitted, it defaults to :py:attr:`PIL.Image.BICUBIC`.
|
||||
(was :py:attr:`PIL.Image.NEAREST` prior to version 2.5.0).
|
||||
of :py:data:`PIL.Image.NEAREST`, :py:data:`PIL.Image.BILINEAR`,
|
||||
:py:data:`PIL.Image.BICUBIC`, or :py:data:`PIL.Image.LANCZOS`.
|
||||
If omitted, it defaults to :py:data:`PIL.Image.BICUBIC`.
|
||||
(was :py:data:`PIL.Image.NEAREST` prior to version 2.5.0).
|
||||
See: :ref:`concept-filters`.
|
||||
:param reducing_gap: Apply optimization by resizing the image
|
||||
in two steps. First, reducing the image by integer times
|
||||
|
@ -2334,11 +2341,11 @@ class Image:
|
|||
|
||||
:param size: The output size.
|
||||
:param method: The transformation method. This is one of
|
||||
:py:attr:`PIL.Image.EXTENT` (cut out a rectangular subregion),
|
||||
:py:attr:`PIL.Image.AFFINE` (affine transform),
|
||||
:py:attr:`PIL.Image.PERSPECTIVE` (perspective transform),
|
||||
:py:attr:`PIL.Image.QUAD` (map a quadrilateral to a rectangle), or
|
||||
:py:attr:`PIL.Image.MESH` (map a number of source quadrilaterals
|
||||
:py:data:`PIL.Image.EXTENT` (cut out a rectangular subregion),
|
||||
:py:data:`PIL.Image.AFFINE` (affine transform),
|
||||
:py:data:`PIL.Image.PERSPECTIVE` (perspective transform),
|
||||
:py:data:`PIL.Image.QUAD` (map a quadrilateral to a rectangle), or
|
||||
:py:data:`PIL.Image.MESH` (map a number of source quadrilaterals
|
||||
in one operation).
|
||||
|
||||
It may also be an :py:class:`~PIL.Image.ImageTransformHandler`
|
||||
|
@ -2358,11 +2365,11 @@ class Image:
|
|||
return method, data
|
||||
:param data: Extra data to the transformation method.
|
||||
:param resample: Optional resampling filter. It can be one of
|
||||
:py:attr:`PIL.Image.NEAREST` (use nearest neighbour),
|
||||
:py:attr:`PIL.Image.BILINEAR` (linear interpolation in a 2x2
|
||||
environment), or :py:attr:`PIL.Image.BICUBIC` (cubic spline
|
||||
:py:data:`PIL.Image.NEAREST` (use nearest neighbour),
|
||||
:py:data:`PIL.Image.BILINEAR` (linear interpolation in a 2x2
|
||||
environment), or :py:data:`PIL.Image.BICUBIC` (cubic spline
|
||||
interpolation in a 4x4 environment). If omitted, or if the image
|
||||
has mode "1" or "P", it is set to :py:attr:`PIL.Image.NEAREST`.
|
||||
has mode "1" or "P", it is set to :py:data:`PIL.Image.NEAREST`.
|
||||
See: :ref:`concept-filters`.
|
||||
:param fill: If **method** is an
|
||||
:py:class:`~PIL.Image.ImageTransformHandler` object, this is one of
|
||||
|
@ -2486,10 +2493,10 @@ class Image:
|
|||
"""
|
||||
Transpose image (flip or rotate in 90 degree steps)
|
||||
|
||||
:param method: One of :py:attr:`PIL.Image.FLIP_LEFT_RIGHT`,
|
||||
:py:attr:`PIL.Image.FLIP_TOP_BOTTOM`, :py:attr:`PIL.Image.ROTATE_90`,
|
||||
:py:attr:`PIL.Image.ROTATE_180`, :py:attr:`PIL.Image.ROTATE_270`,
|
||||
:py:attr:`PIL.Image.TRANSPOSE` or :py:attr:`PIL.Image.TRANSVERSE`.
|
||||
:param method: One of :py:data:`PIL.Image.FLIP_LEFT_RIGHT`,
|
||||
:py:data:`PIL.Image.FLIP_TOP_BOTTOM`, :py:data:`PIL.Image.ROTATE_90`,
|
||||
:py:data:`PIL.Image.ROTATE_180`, :py:data:`PIL.Image.ROTATE_270`,
|
||||
:py:data:`PIL.Image.TRANSPOSE` or :py:data:`PIL.Image.TRANSVERSE`.
|
||||
:returns: Returns a flipped or rotated copy of this image.
|
||||
"""
|
||||
|
||||
|
@ -2736,12 +2743,12 @@ def fromarray(obj, mode=None):
|
|||
if mode is None:
|
||||
try:
|
||||
typekey = (1, 1) + shape[2:], arr["typestr"]
|
||||
except KeyError:
|
||||
raise TypeError("Cannot handle this data type")
|
||||
except KeyError as e:
|
||||
raise TypeError("Cannot handle this data type") from e
|
||||
try:
|
||||
mode, rawmode = _fromarray_typemap[typekey]
|
||||
except KeyError:
|
||||
raise TypeError("Cannot handle this data type: %s, %s" % typekey)
|
||||
except KeyError as e:
|
||||
raise TypeError("Cannot handle this data type: %s, %s" % typekey) from e
|
||||
else:
|
||||
rawmode = mode
|
||||
if mode in ["1", "L", "I", "P", "F"]:
|
||||
|
@ -3139,17 +3146,25 @@ def register_encoder(name, encoder):
|
|||
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
# Simple display support. User code may override this.
|
||||
# Simple display support.
|
||||
|
||||
|
||||
def _show(image, **options):
|
||||
# override me, as necessary
|
||||
options["_internal_pillow"] = True
|
||||
_showxv(image, **options)
|
||||
|
||||
|
||||
def _showxv(image, title=None, **options):
|
||||
from . import ImageShow
|
||||
|
||||
if "_internal_pillow" in options:
|
||||
del options["_internal_pillow"]
|
||||
else:
|
||||
warnings.warn(
|
||||
"_showxv is deprecated and will be removed in a future release. "
|
||||
"Use Image.show instead.",
|
||||
DeprecationWarning,
|
||||
)
|
||||
ImageShow.show(image, title, **options)
|
||||
|
||||
|
||||
|
|
|
@ -295,11 +295,12 @@ def profileToProfile(
|
|||
``inputProfile`` to ``outputProfile``.
|
||||
|
||||
If the input or output profiles specified are not valid filenames, a
|
||||
``PyCMSError`` will be raised. If ``inPlace`` is ``True`` and
|
||||
``outputMode != im.mode``, a ``PyCMSError`` will be raised. If an error
|
||||
occurs during application of the profiles, a ``PyCMSError`` will be raised.
|
||||
:exc:`PyCMSError` will be raised. If ``inPlace`` is ``True`` and
|
||||
``outputMode != im.mode``, a :exc:`PyCMSError` will be raised.
|
||||
If an error occurs during application of the profiles,
|
||||
a :exc:`PyCMSError` will be raised.
|
||||
If ``outputMode`` is not a mode supported by the ``outputProfile`` (or by pyCMS),
|
||||
a ``PyCMSError`` will be raised.
|
||||
a :exc:`PyCMSError` will be raised.
|
||||
|
||||
This function applies an ICC transformation to im from ``inputProfile``'s
|
||||
color space to ``outputProfile``'s color space using the specified rendering
|
||||
|
@ -369,7 +370,7 @@ def profileToProfile(
|
|||
else:
|
||||
imOut = transform.apply(im)
|
||||
except (OSError, TypeError, ValueError) as v:
|
||||
raise PyCMSError(v)
|
||||
raise PyCMSError(v) from v
|
||||
|
||||
return imOut
|
||||
|
||||
|
@ -381,8 +382,8 @@ def getOpenProfile(profileFilename):
|
|||
The PyCMSProfile object can be passed back into pyCMS for use in creating
|
||||
transforms and such (as in ImageCms.buildTransformFromOpenProfiles()).
|
||||
|
||||
If ``profileFilename`` is not a valid filename for an ICC profile, a ``PyCMSError``
|
||||
will be raised.
|
||||
If ``profileFilename`` is not a valid filename for an ICC profile,
|
||||
a :exc:`PyCMSError` will be raised.
|
||||
|
||||
:param profileFilename: String, as a valid filename path to the ICC profile
|
||||
you wish to open, or a file-like object.
|
||||
|
@ -393,7 +394,7 @@ def getOpenProfile(profileFilename):
|
|||
try:
|
||||
return ImageCmsProfile(profileFilename)
|
||||
except (OSError, TypeError, ValueError) as v:
|
||||
raise PyCMSError(v)
|
||||
raise PyCMSError(v) from v
|
||||
|
||||
|
||||
def buildTransform(
|
||||
|
@ -410,11 +411,11 @@ def buildTransform(
|
|||
image.
|
||||
|
||||
If the input or output profiles specified are not valid filenames, a
|
||||
``PyCMSError`` will be raised. If an error occurs during creation of the
|
||||
transform, a ``PyCMSError`` will be raised.
|
||||
:exc:`PyCMSError` will be raised. If an error occurs during creation
|
||||
of the transform, a :exc:`PyCMSError` will be raised.
|
||||
|
||||
If ``inMode`` or ``outMode`` are not a mode supported by the ``outputProfile``
|
||||
(or by pyCMS), a ``PyCMSError`` will be raised.
|
||||
(or by pyCMS), a :exc:`PyCMSError` will be raised.
|
||||
|
||||
This function builds and returns an ICC transform from the ``inputProfile``
|
||||
to the ``outputProfile`` using the ``renderingIntent`` to determine what to do
|
||||
|
@ -474,7 +475,7 @@ def buildTransform(
|
|||
inputProfile, outputProfile, inMode, outMode, renderingIntent, flags=flags
|
||||
)
|
||||
except (OSError, TypeError, ValueError) as v:
|
||||
raise PyCMSError(v)
|
||||
raise PyCMSError(v) from v
|
||||
|
||||
|
||||
def buildProofTransform(
|
||||
|
@ -493,13 +494,13 @@ def buildProofTransform(
|
|||
obtained on the ``proofProfile`` device.
|
||||
|
||||
If the input, output, or proof profiles specified are not valid
|
||||
filenames, a ``PyCMSError`` will be raised.
|
||||
filenames, a :exc:`PyCMSError` will be raised.
|
||||
|
||||
If an error occurs during creation of the transform, a ``PyCMSError``
|
||||
will be raised.
|
||||
If an error occurs during creation of the transform,
|
||||
a :exc:`PyCMSError` will be raised.
|
||||
|
||||
If ``inMode`` or ``outMode`` are not a mode supported by the ``outputProfile``
|
||||
(or by pyCMS), a ``PyCMSError`` will be raised.
|
||||
(or by pyCMS), a :exc:`PyCMSError` will be raised.
|
||||
|
||||
This function builds and returns an ICC transform from the ``inputProfile``
|
||||
to the ``outputProfile``, but tries to simulate the result that would be
|
||||
|
@ -585,7 +586,7 @@ def buildProofTransform(
|
|||
flags,
|
||||
)
|
||||
except (OSError, TypeError, ValueError) as v:
|
||||
raise PyCMSError(v)
|
||||
raise PyCMSError(v) from v
|
||||
|
||||
|
||||
buildTransformFromOpenProfiles = buildTransform
|
||||
|
@ -596,17 +597,17 @@ def applyTransform(im, transform, inPlace=False):
|
|||
"""
|
||||
(pyCMS) Applies a transform to a given image.
|
||||
|
||||
If ``im.mode != transform.inMode``, a ``PyCMSError`` is raised.
|
||||
If ``im.mode != transform.inMode``, a :exc:`PyCMSError` is raised.
|
||||
|
||||
If ``inPlace`` is ``True`` and ``transform.inMode != transform.outMode``, a
|
||||
``PyCMSError`` is raised.
|
||||
:exc:`PyCMSError` is raised.
|
||||
|
||||
If ``im.mode``, ``transform.inMode`` or ``transform.outMode`` is not
|
||||
supported by pyCMSdll or the profiles you used for the transform, a
|
||||
``PyCMSError`` is raised.
|
||||
:exc:`PyCMSError` is raised.
|
||||
|
||||
If an error occurs while the transform is being applied, a ``PyCMSError``
|
||||
is raised.
|
||||
If an error occurs while the transform is being applied,
|
||||
a :exc:`PyCMSError` is raised.
|
||||
|
||||
This function applies a pre-calculated transform (from
|
||||
ImageCms.buildTransform() or ImageCms.buildTransformFromOpenProfiles())
|
||||
|
@ -640,7 +641,7 @@ def applyTransform(im, transform, inPlace=False):
|
|||
else:
|
||||
imOut = transform.apply(im)
|
||||
except (TypeError, ValueError) as v:
|
||||
raise PyCMSError(v)
|
||||
raise PyCMSError(v) from v
|
||||
|
||||
return imOut
|
||||
|
||||
|
@ -649,12 +650,14 @@ def createProfile(colorSpace, colorTemp=-1):
|
|||
"""
|
||||
(pyCMS) Creates a profile.
|
||||
|
||||
If colorSpace not in ``["LAB", "XYZ", "sRGB"]``, a ``PyCMSError`` is raised.
|
||||
If colorSpace not in ``["LAB", "XYZ", "sRGB"]``,
|
||||
a :exc:`PyCMSError` is raised.
|
||||
|
||||
If using LAB and ``colorTemp`` is not a positive integer, a ``PyCMSError`` is
|
||||
raised.
|
||||
If using LAB and ``colorTemp`` is not a positive integer,
|
||||
a :exc:`PyCMSError` is raised.
|
||||
|
||||
If an error occurs while creating the profile, a ``PyCMSError`` is raised.
|
||||
If an error occurs while creating the profile,
|
||||
a :exc:`PyCMSError` is raised.
|
||||
|
||||
Use this function to create common profiles on-the-fly instead of
|
||||
having to supply a profile on disk and knowing the path to it. It
|
||||
|
@ -682,15 +685,15 @@ def createProfile(colorSpace, colorTemp=-1):
|
|||
if colorSpace == "LAB":
|
||||
try:
|
||||
colorTemp = float(colorTemp)
|
||||
except (TypeError, ValueError):
|
||||
except (TypeError, ValueError) as e:
|
||||
raise PyCMSError(
|
||||
'Color temperature must be numeric, "%s" not valid' % colorTemp
|
||||
)
|
||||
) from e
|
||||
|
||||
try:
|
||||
return core.createProfile(colorSpace, colorTemp)
|
||||
except (TypeError, ValueError) as v:
|
||||
raise PyCMSError(v)
|
||||
raise PyCMSError(v) from v
|
||||
|
||||
|
||||
def getProfileName(profile):
|
||||
|
@ -699,8 +702,8 @@ def getProfileName(profile):
|
|||
(pyCMS) Gets the internal product name for the given profile.
|
||||
|
||||
If ``profile`` isn't a valid CmsProfile object or filename to a profile,
|
||||
a ``PyCMSError`` is raised If an error occurs while trying to obtain the
|
||||
name tag, a ``PyCMSError`` is raised.
|
||||
a :exc:`PyCMSError` is raised If an error occurs while trying
|
||||
to obtain the name tag, a :exc:`PyCMSError` is raised.
|
||||
|
||||
Use this function to obtain the INTERNAL name of the profile (stored
|
||||
in an ICC tag in the profile itself), usually the one used when the
|
||||
|
@ -732,7 +735,7 @@ def getProfileName(profile):
|
|||
return "{} - {}\n".format(model, manufacturer)
|
||||
|
||||
except (AttributeError, OSError, TypeError, ValueError) as v:
|
||||
raise PyCMSError(v)
|
||||
raise PyCMSError(v) from v
|
||||
|
||||
|
||||
def getProfileInfo(profile):
|
||||
|
@ -740,10 +743,10 @@ def getProfileInfo(profile):
|
|||
(pyCMS) Gets the internal product information for the given profile.
|
||||
|
||||
If ``profile`` isn't a valid CmsProfile object or filename to a profile,
|
||||
a ``PyCMSError`` is raised.
|
||||
a :exc:`PyCMSError` is raised.
|
||||
|
||||
If an error occurs while trying to obtain the info tag, a ``PyCMSError``
|
||||
is raised.
|
||||
If an error occurs while trying to obtain the info tag,
|
||||
a :exc:`PyCMSError` is raised.
|
||||
|
||||
Use this function to obtain the information stored in the profile's
|
||||
info tag. This often contains details about the profile, and how it
|
||||
|
@ -772,7 +775,7 @@ def getProfileInfo(profile):
|
|||
return "\r\n\r\n".join(arr) + "\r\n\r\n"
|
||||
|
||||
except (AttributeError, OSError, TypeError, ValueError) as v:
|
||||
raise PyCMSError(v)
|
||||
raise PyCMSError(v) from v
|
||||
|
||||
|
||||
def getProfileCopyright(profile):
|
||||
|
@ -780,10 +783,10 @@ def getProfileCopyright(profile):
|
|||
(pyCMS) Gets the copyright for the given profile.
|
||||
|
||||
If ``profile`` isn't a valid CmsProfile object or filename to a profile, a
|
||||
``PyCMSError`` is raised.
|
||||
:exc:`PyCMSError` is raised.
|
||||
|
||||
If an error occurs while trying to obtain the copyright tag, a ``PyCMSError``
|
||||
is raised.
|
||||
If an error occurs while trying to obtain the copyright tag,
|
||||
a :exc:`PyCMSError` is raised.
|
||||
|
||||
Use this function to obtain the information stored in the profile's
|
||||
copyright tag.
|
||||
|
@ -800,7 +803,7 @@ def getProfileCopyright(profile):
|
|||
profile = ImageCmsProfile(profile)
|
||||
return (profile.profile.copyright or "") + "\n"
|
||||
except (AttributeError, OSError, TypeError, ValueError) as v:
|
||||
raise PyCMSError(v)
|
||||
raise PyCMSError(v) from v
|
||||
|
||||
|
||||
def getProfileManufacturer(profile):
|
||||
|
@ -808,10 +811,10 @@ def getProfileManufacturer(profile):
|
|||
(pyCMS) Gets the manufacturer for the given profile.
|
||||
|
||||
If ``profile`` isn't a valid CmsProfile object or filename to a profile, a
|
||||
``PyCMSError`` is raised.
|
||||
:exc:`PyCMSError` is raised.
|
||||
|
||||
If an error occurs while trying to obtain the manufacturer tag, a
|
||||
``PyCMSError`` is raised.
|
||||
:exc:`PyCMSError` is raised.
|
||||
|
||||
Use this function to obtain the information stored in the profile's
|
||||
manufacturer tag.
|
||||
|
@ -828,7 +831,7 @@ def getProfileManufacturer(profile):
|
|||
profile = ImageCmsProfile(profile)
|
||||
return (profile.profile.manufacturer or "") + "\n"
|
||||
except (AttributeError, OSError, TypeError, ValueError) as v:
|
||||
raise PyCMSError(v)
|
||||
raise PyCMSError(v) from v
|
||||
|
||||
|
||||
def getProfileModel(profile):
|
||||
|
@ -836,10 +839,10 @@ def getProfileModel(profile):
|
|||
(pyCMS) Gets the model for the given profile.
|
||||
|
||||
If ``profile`` isn't a valid CmsProfile object or filename to a profile, a
|
||||
``PyCMSError`` is raised.
|
||||
:exc:`PyCMSError` is raised.
|
||||
|
||||
If an error occurs while trying to obtain the model tag, a ``PyCMSError``
|
||||
is raised.
|
||||
If an error occurs while trying to obtain the model tag,
|
||||
a :exc:`PyCMSError` is raised.
|
||||
|
||||
Use this function to obtain the information stored in the profile's
|
||||
model tag.
|
||||
|
@ -857,7 +860,7 @@ def getProfileModel(profile):
|
|||
profile = ImageCmsProfile(profile)
|
||||
return (profile.profile.model or "") + "\n"
|
||||
except (AttributeError, OSError, TypeError, ValueError) as v:
|
||||
raise PyCMSError(v)
|
||||
raise PyCMSError(v) from v
|
||||
|
||||
|
||||
def getProfileDescription(profile):
|
||||
|
@ -865,10 +868,10 @@ def getProfileDescription(profile):
|
|||
(pyCMS) Gets the description for the given profile.
|
||||
|
||||
If ``profile`` isn't a valid CmsProfile object or filename to a profile, a
|
||||
``PyCMSError`` is raised.
|
||||
:exc:`PyCMSError` is raised.
|
||||
|
||||
If an error occurs while trying to obtain the description tag, a ``PyCMSError``
|
||||
is raised.
|
||||
If an error occurs while trying to obtain the description tag,
|
||||
a :exc:`PyCMSError` is raised.
|
||||
|
||||
Use this function to obtain the information stored in the profile's
|
||||
description tag.
|
||||
|
@ -886,7 +889,7 @@ def getProfileDescription(profile):
|
|||
profile = ImageCmsProfile(profile)
|
||||
return (profile.profile.profile_description or "") + "\n"
|
||||
except (AttributeError, OSError, TypeError, ValueError) as v:
|
||||
raise PyCMSError(v)
|
||||
raise PyCMSError(v) from v
|
||||
|
||||
|
||||
def getDefaultIntent(profile):
|
||||
|
@ -894,10 +897,10 @@ def getDefaultIntent(profile):
|
|||
(pyCMS) Gets the default intent name for the given profile.
|
||||
|
||||
If ``profile`` isn't a valid CmsProfile object or filename to a profile, a
|
||||
``PyCMSError`` is raised.
|
||||
:exc:`PyCMSError` is raised.
|
||||
|
||||
If an error occurs while trying to obtain the default intent, a
|
||||
``PyCMSError`` is raised.
|
||||
:exc:`PyCMSError` is raised.
|
||||
|
||||
Use this function to determine the default (and usually best optimized)
|
||||
rendering intent for this profile. Most profiles support multiple
|
||||
|
@ -925,7 +928,7 @@ def getDefaultIntent(profile):
|
|||
profile = ImageCmsProfile(profile)
|
||||
return profile.profile.rendering_intent
|
||||
except (AttributeError, OSError, TypeError, ValueError) as v:
|
||||
raise PyCMSError(v)
|
||||
raise PyCMSError(v) from v
|
||||
|
||||
|
||||
def isIntentSupported(profile, intent, direction):
|
||||
|
@ -940,8 +943,8 @@ def isIntentSupported(profile, intent, direction):
|
|||
be used for others. Some profiles can only be used for certain
|
||||
rendering intents, so it's best to either verify this before trying
|
||||
to create a transform with them (using this function), or catch the
|
||||
potential ``PyCMSError`` that will occur if they don't support the modes
|
||||
you select.
|
||||
potential :exc:`PyCMSError` that will occur if they don't
|
||||
support the modes you select.
|
||||
|
||||
:param profile: EITHER a valid CmsProfile object, OR a string of the
|
||||
filename of an ICC profile.
|
||||
|
@ -976,7 +979,7 @@ def isIntentSupported(profile, intent, direction):
|
|||
else:
|
||||
return -1
|
||||
except (AttributeError, OSError, TypeError, ValueError) as v:
|
||||
raise PyCMSError(v)
|
||||
raise PyCMSError(v) from v
|
||||
|
||||
|
||||
def versions():
|
||||
|
|
|
@ -16,21 +16,35 @@
|
|||
# See the README file for information on usage and redistribution.
|
||||
#
|
||||
|
||||
|
||||
"""
|
||||
(Experimental) WCK-style drawing interface operations
|
||||
|
||||
.. seealso:: :py:mod:`PIL.ImageDraw`
|
||||
"""
|
||||
|
||||
|
||||
from . import Image, ImageColor, ImageDraw, ImageFont, ImagePath
|
||||
|
||||
|
||||
class Pen:
|
||||
"""Stores an outline color and width."""
|
||||
|
||||
def __init__(self, color, width=1, opacity=255):
|
||||
self.color = ImageColor.getrgb(color)
|
||||
self.width = width
|
||||
|
||||
|
||||
class Brush:
|
||||
"""Stores a fill color"""
|
||||
|
||||
def __init__(self, color, opacity=255):
|
||||
self.color = ImageColor.getrgb(color)
|
||||
|
||||
|
||||
class Font:
|
||||
"""Stores a TrueType font and color"""
|
||||
|
||||
def __init__(self, color, file, size=12):
|
||||
# FIXME: add support for bitmap fonts
|
||||
self.color = ImageColor.getrgb(color)
|
||||
|
@ -38,6 +52,10 @@ class Font:
|
|||
|
||||
|
||||
class Draw:
|
||||
"""
|
||||
(Experimental) WCK-style drawing interface
|
||||
"""
|
||||
|
||||
def __init__(self, image, size=None, color=None):
|
||||
if not hasattr(image, "im"):
|
||||
image = Image.new(image, size, color)
|
||||
|
@ -73,35 +91,89 @@ class Draw:
|
|||
getattr(self.draw, op)(xy, fill=fill, outline=outline)
|
||||
|
||||
def settransform(self, offset):
|
||||
"""Sets a transformation offset."""
|
||||
(xoffset, yoffset) = offset
|
||||
self.transform = (1, 0, xoffset, 0, 1, yoffset)
|
||||
|
||||
def arc(self, xy, start, end, *options):
|
||||
"""
|
||||
Draws an arc (a portion of a circle outline) between the start and end
|
||||
angles, inside the given bounding box.
|
||||
|
||||
.. seealso:: :py:meth:`PIL.ImageDraw.ImageDraw.arc`
|
||||
"""
|
||||
self.render("arc", xy, start, end, *options)
|
||||
|
||||
def chord(self, xy, start, end, *options):
|
||||
"""
|
||||
Same as :py:meth:`~PIL.ImageDraw2.Draw.arc`, but connects the end points
|
||||
with a straight line.
|
||||
|
||||
.. seealso:: :py:meth:`PIL.ImageDraw.ImageDraw.chord`
|
||||
"""
|
||||
self.render("chord", xy, start, end, *options)
|
||||
|
||||
def ellipse(self, xy, *options):
|
||||
"""
|
||||
Draws an ellipse inside the given bounding box.
|
||||
|
||||
.. seealso:: :py:meth:`PIL.ImageDraw.ImageDraw.ellipse`
|
||||
"""
|
||||
self.render("ellipse", xy, *options)
|
||||
|
||||
def line(self, xy, *options):
|
||||
"""
|
||||
Draws a line between the coordinates in the ``xy`` list.
|
||||
|
||||
.. seealso:: :py:meth:`PIL.ImageDraw.ImageDraw.line`
|
||||
"""
|
||||
self.render("line", xy, *options)
|
||||
|
||||
def pieslice(self, xy, start, end, *options):
|
||||
"""
|
||||
Same as arc, but also draws straight lines between the end points and the
|
||||
center of the bounding box.
|
||||
|
||||
.. seealso:: :py:meth:`PIL.ImageDraw.ImageDraw.pieslice`
|
||||
"""
|
||||
self.render("pieslice", xy, start, end, *options)
|
||||
|
||||
def polygon(self, xy, *options):
|
||||
"""
|
||||
Draws a polygon.
|
||||
|
||||
The polygon outline consists of straight lines between the given
|
||||
coordinates, plus a straight line between the last and the first
|
||||
coordinate.
|
||||
|
||||
|
||||
.. seealso:: :py:meth:`PIL.ImageDraw.ImageDraw.polygon`
|
||||
"""
|
||||
self.render("polygon", xy, *options)
|
||||
|
||||
def rectangle(self, xy, *options):
|
||||
"""
|
||||
Draws a rectangle.
|
||||
|
||||
.. seealso:: :py:meth:`PIL.ImageDraw.ImageDraw.rectangle`
|
||||
"""
|
||||
self.render("rectangle", xy, *options)
|
||||
|
||||
def text(self, xy, text, font):
|
||||
"""
|
||||
Draws the string at the given position.
|
||||
|
||||
.. seealso:: :py:meth:`PIL.ImageDraw.ImageDraw.text`
|
||||
"""
|
||||
if self.transform:
|
||||
xy = ImagePath.Path(xy)
|
||||
xy.transform(self.transform)
|
||||
self.draw.text(xy, text, font=font.font, fill=font.color)
|
||||
|
||||
def textsize(self, text, font):
|
||||
"""
|
||||
Return the size of the given string, in pixels.
|
||||
|
||||
.. seealso:: :py:meth:`PIL.ImageDraw.ImageDraw.textsize`
|
||||
"""
|
||||
return self.draw.textsize(text, font=font.font)
|
||||
|
|
|
@ -85,7 +85,7 @@ def _tilesort(t):
|
|||
|
||||
|
||||
class ImageFile(Image.Image):
|
||||
"Base class for image file format handlers."
|
||||
"""Base class for image file format handlers."""
|
||||
|
||||
def __init__(self, fp=None, filename=None):
|
||||
super().__init__()
|
||||
|
@ -122,7 +122,7 @@ class ImageFile(Image.Image):
|
|||
EOFError, # got header but not the first frame
|
||||
struct.error,
|
||||
) as v:
|
||||
raise SyntaxError(v)
|
||||
raise SyntaxError(v) from v
|
||||
|
||||
if not self.mode or self.size[0] <= 0:
|
||||
raise SyntaxError("not identified by this driver")
|
||||
|
@ -241,12 +241,12 @@ class ImageFile(Image.Image):
|
|||
while True:
|
||||
try:
|
||||
s = read(self.decodermaxblock)
|
||||
except (IndexError, struct.error):
|
||||
except (IndexError, struct.error) as e:
|
||||
# truncated png/gif
|
||||
if LOAD_TRUNCATED_IMAGES:
|
||||
break
|
||||
else:
|
||||
raise OSError("image file is truncated")
|
||||
raise OSError("image file is truncated") from e
|
||||
|
||||
if not s: # truncated jpeg
|
||||
if LOAD_TRUNCATED_IMAGES:
|
||||
|
@ -505,7 +505,7 @@ def _save(im, fp, tile, bufsize=0):
|
|||
try:
|
||||
fh = fp.fileno()
|
||||
fp.flush()
|
||||
except (AttributeError, io.UnsupportedOperation):
|
||||
except (AttributeError, io.UnsupportedOperation) as e:
|
||||
# compress to Python file-compatible object
|
||||
for e, b, o, a in tile:
|
||||
e = Image._getencoder(im.mode, e, a, im.encoderconfig)
|
||||
|
@ -522,7 +522,7 @@ def _save(im, fp, tile, bufsize=0):
|
|||
if s:
|
||||
break
|
||||
if s < 0:
|
||||
raise OSError("encoder error %d when writing image file" % s)
|
||||
raise OSError("encoder error %d when writing image file" % s) from e
|
||||
e.cleanup()
|
||||
else:
|
||||
# slight speedup: compress to real file object
|
||||
|
|
|
@ -411,10 +411,10 @@ class Color3DLUT(MultibandFilter):
|
|||
def _check_size(size):
|
||||
try:
|
||||
_, _, _ = size
|
||||
except ValueError:
|
||||
except ValueError as e:
|
||||
raise ValueError(
|
||||
"Size should be either an integer or a tuple of three integers."
|
||||
)
|
||||
) from e
|
||||
except TypeError:
|
||||
size = (size, size, size)
|
||||
size = [int(x) for x in size]
|
||||
|
|
|
@ -259,7 +259,7 @@ class FreeTypeFont:
|
|||
|
||||
:return: (width, height)
|
||||
"""
|
||||
size, offset = self.font.getsize(text, direction, features, language)
|
||||
size, offset = self.font.getsize(text, False, direction, features, language)
|
||||
return (
|
||||
size[0] + stroke_width * 2 + offset[0],
|
||||
size[1] + stroke_width * 2 + offset[1],
|
||||
|
@ -468,7 +468,9 @@ class FreeTypeFont:
|
|||
:py:mod:`PIL.Image.core` interface module, and the text offset, the
|
||||
gap between the starting coordinate and the first marking
|
||||
"""
|
||||
size, offset = self.font.getsize(text, direction, features, language)
|
||||
size, offset = self.font.getsize(
|
||||
text, mode == "1", direction, features, language
|
||||
)
|
||||
size = size[0] + stroke_width * 2, size[1] + stroke_width * 2
|
||||
im = fill("L", size, 0)
|
||||
self.font.render(
|
||||
|
@ -503,8 +505,8 @@ class FreeTypeFont:
|
|||
"""
|
||||
try:
|
||||
names = self.font.getvarnames()
|
||||
except AttributeError:
|
||||
raise NotImplementedError("FreeType 2.9.1 or greater is required")
|
||||
except AttributeError as e:
|
||||
raise NotImplementedError("FreeType 2.9.1 or greater is required") from e
|
||||
return [name.replace(b"\x00", b"") for name in names]
|
||||
|
||||
def set_variation_by_name(self, name):
|
||||
|
@ -533,8 +535,8 @@ class FreeTypeFont:
|
|||
"""
|
||||
try:
|
||||
axes = self.font.getvaraxes()
|
||||
except AttributeError:
|
||||
raise NotImplementedError("FreeType 2.9.1 or greater is required")
|
||||
except AttributeError as e:
|
||||
raise NotImplementedError("FreeType 2.9.1 or greater is required") from e
|
||||
for axis in axes:
|
||||
axis["name"] = axis["name"].replace(b"\x00", b"")
|
||||
return axes
|
||||
|
@ -546,8 +548,8 @@ class FreeTypeFont:
|
|||
"""
|
||||
try:
|
||||
self.font.setvaraxes(axes)
|
||||
except AttributeError:
|
||||
raise NotImplementedError("FreeType 2.9.1 or greater is required")
|
||||
except AttributeError as e:
|
||||
raise NotImplementedError("FreeType 2.9.1 or greater is required") from e
|
||||
|
||||
|
||||
class TransposedFont:
|
||||
|
|
|
@ -93,12 +93,28 @@ def grabclipboard():
|
|||
os.unlink(filepath)
|
||||
return im
|
||||
elif sys.platform == "win32":
|
||||
data = Image.core.grabclipboard_win32()
|
||||
fmt, data = Image.core.grabclipboard_win32()
|
||||
if fmt == "file": # CF_HDROP
|
||||
import struct
|
||||
|
||||
o = struct.unpack_from("I", data)[0]
|
||||
if data[16] != 0:
|
||||
files = data[o:].decode("utf-16le").split("\0")
|
||||
else:
|
||||
files = data[o:].decode("mbcs").split("\0")
|
||||
return files[: files.index("")]
|
||||
if isinstance(data, bytes):
|
||||
from . import BmpImagePlugin
|
||||
import io
|
||||
|
||||
return BmpImagePlugin.DibImageFile(io.BytesIO(data))
|
||||
return data
|
||||
data = io.BytesIO(data)
|
||||
if fmt == "png":
|
||||
from . import PngImagePlugin
|
||||
|
||||
return PngImagePlugin.PngImageFile(data)
|
||||
elif fmt == "DIB":
|
||||
from . import BmpImagePlugin
|
||||
|
||||
return BmpImagePlugin.DibImageFile(data)
|
||||
return None
|
||||
else:
|
||||
raise NotImplementedError("ImageGrab.grabclipboard() is macOS and Windows only")
|
||||
|
|
|
@ -57,8 +57,8 @@ class _Operand:
|
|||
im1.load()
|
||||
try:
|
||||
op = getattr(_imagingmath, op + "_" + im1.mode)
|
||||
except AttributeError:
|
||||
raise TypeError("bad operand type for '%s'" % op)
|
||||
except AttributeError as e:
|
||||
raise TypeError("bad operand type for '%s'" % op) from e
|
||||
_imagingmath.unop(op, out.im.id, im1.im.id)
|
||||
else:
|
||||
# binary operation
|
||||
|
@ -85,8 +85,8 @@ class _Operand:
|
|||
im2.load()
|
||||
try:
|
||||
op = getattr(_imagingmath, op + "_" + im1.mode)
|
||||
except AttributeError:
|
||||
raise TypeError("bad operand type for '%s'" % op)
|
||||
except AttributeError as e:
|
||||
raise TypeError("bad operand type for '%s'" % op) from e
|
||||
_imagingmath.binop(op, out.im.id, im1.im.id, im2.im.id)
|
||||
return _Operand(out)
|
||||
|
||||
|
|
|
@ -97,13 +97,13 @@ class ImagePalette:
|
|||
if isinstance(color, tuple):
|
||||
try:
|
||||
return self.colors[color]
|
||||
except KeyError:
|
||||
except KeyError as e:
|
||||
# allocate new color slot
|
||||
if isinstance(self.palette, bytes):
|
||||
self.palette = bytearray(self.palette)
|
||||
index = len(self.colors)
|
||||
if index >= 256:
|
||||
raise ValueError("cannot allocate more than 256 colors")
|
||||
raise ValueError("cannot allocate more than 256 colors") from e
|
||||
self.colors[color] = index
|
||||
self.palette[index] = color[0]
|
||||
self.palette[index + 256] = color[1]
|
||||
|
|
|
@ -38,8 +38,8 @@ class Iterator:
|
|||
try:
|
||||
self.im.seek(ix)
|
||||
return self.im
|
||||
except EOFError:
|
||||
raise IndexError # end of sequence
|
||||
except EOFError as e:
|
||||
raise IndexError from e # end of sequence
|
||||
|
||||
def __iter__(self):
|
||||
return self
|
||||
|
@ -49,8 +49,8 @@ class Iterator:
|
|||
self.im.seek(self.position)
|
||||
self.position += 1
|
||||
return self.im
|
||||
except EOFError:
|
||||
raise StopIteration
|
||||
except EOFError as e:
|
||||
raise StopIteration from e
|
||||
|
||||
|
||||
def all_frames(im, func=None):
|
||||
|
|
|
@ -24,6 +24,14 @@ _viewers = []
|
|||
|
||||
|
||||
def register(viewer, order=1):
|
||||
"""
|
||||
The :py:func:`register` function is used to register additional viewers.
|
||||
|
||||
: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.
|
||||
"""
|
||||
try:
|
||||
if issubclass(viewer, Viewer):
|
||||
viewer = viewer()
|
||||
|
@ -31,7 +39,7 @@ def register(viewer, order=1):
|
|||
pass # raised if viewer wasn't a class
|
||||
if order > 0:
|
||||
_viewers.append(viewer)
|
||||
elif order < 0:
|
||||
else:
|
||||
_viewers.insert(0, viewer)
|
||||
|
||||
|
||||
|
@ -40,9 +48,9 @@ def show(image, title=None, **options):
|
|||
Display a given image.
|
||||
|
||||
:param image: An image object.
|
||||
:param title: Optional title. Not all viewers can display the title.
|
||||
: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.
|
||||
:returns: ``True`` if a suitable viewer was found, ``False`` otherwise.
|
||||
"""
|
||||
for viewer in _viewers:
|
||||
if viewer.show(image, title=title, **options):
|
||||
|
@ -56,10 +64,15 @@ class Viewer:
|
|||
# main api
|
||||
|
||||
def show(self, image, **options):
|
||||
"""
|
||||
The main function for displaying an image.
|
||||
Converts the given image to the target format and displays it.
|
||||
"""
|
||||
|
||||
# save temporary image to disk
|
||||
if not (
|
||||
image.mode in ("1", "RGBA") or (self.format == "PNG" and image.mode == "LA")
|
||||
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:
|
||||
|
@ -70,25 +83,31 @@ class Viewer:
|
|||
# hook methods
|
||||
|
||||
format = None
|
||||
"""The format to convert the image into."""
|
||||
options = {}
|
||||
"""Additional options used to convert the image."""
|
||||
|
||||
def get_format(self, image):
|
||||
"""Return format name, or None to save as PGM/PPM"""
|
||||
"""Return format name, or ``None`` to save as PGM/PPM."""
|
||||
return self.format
|
||||
|
||||
def get_command(self, file, **options):
|
||||
"""
|
||||
Returns the command used to display the file.
|
||||
Not implemented in the base class.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def save_image(self, image):
|
||||
"""Save to temporary file, and return filename"""
|
||||
"""Save to temporary file and return filename."""
|
||||
return image._dump(format=self.get_format(image), **self.options)
|
||||
|
||||
def show_image(self, image, **options):
|
||||
"""Display given image"""
|
||||
"""Display the given image."""
|
||||
return self.show_file(self.save_image(image), **options)
|
||||
|
||||
def show_file(self, file, **options):
|
||||
"""Display given file"""
|
||||
"""Display the given file."""
|
||||
os.system(self.get_command(file, **options))
|
||||
return 1
|
||||
|
||||
|
@ -96,104 +115,116 @@ class Viewer:
|
|||
# --------------------------------------------------------------------
|
||||
|
||||
|
||||
class WindowsViewer(Viewer):
|
||||
"""The default viewer on Windows is the default system application for PNG files."""
|
||||
|
||||
format = "PNG"
|
||||
options = {"compress_level": 1}
|
||||
|
||||
def get_command(self, file, **options):
|
||||
return (
|
||||
'start "Pillow" /WAIT "%s" '
|
||||
"&& ping -n 2 127.0.0.1 >NUL "
|
||||
'&& del /f "%s"' % (file, file)
|
||||
)
|
||||
|
||||
|
||||
if sys.platform == "win32":
|
||||
|
||||
class WindowsViewer(Viewer):
|
||||
format = "PNG"
|
||||
options = {"compress_level": 1}
|
||||
|
||||
def get_command(self, file, **options):
|
||||
return (
|
||||
'start "Pillow" /WAIT "%s" '
|
||||
"&& ping -n 2 127.0.0.1 >NUL "
|
||||
'&& del /f "%s"' % (file, file)
|
||||
)
|
||||
|
||||
register(WindowsViewer)
|
||||
|
||||
elif sys.platform == "darwin":
|
||||
|
||||
class MacViewer(Viewer):
|
||||
format = "PNG"
|
||||
options = {"compress_level": 1}
|
||||
class MacViewer(Viewer):
|
||||
"""The default viewer on MacOS using ``Preview.app``."""
|
||||
|
||||
def get_command(self, file, **options):
|
||||
# on darwin open returns immediately resulting in the temp
|
||||
# file removal while app is opening
|
||||
command = "open -a Preview.app"
|
||||
command = "({} {}; sleep 20; rm -f {})&".format(
|
||||
command, quote(file), quote(file)
|
||||
format = "PNG"
|
||||
options = {"compress_level": 1}
|
||||
|
||||
def get_command(self, file, **options):
|
||||
# on darwin open returns immediately resulting in the temp
|
||||
# file removal while app is opening
|
||||
command = "open -a Preview.app"
|
||||
command = "({} {}; sleep 20; rm -f {})&".format(
|
||||
command, quote(file), quote(file)
|
||||
)
|
||||
return command
|
||||
|
||||
def show_file(self, file, **options):
|
||||
"""Display given file"""
|
||||
fd, path = tempfile.mkstemp()
|
||||
with os.fdopen(fd, "w") as f:
|
||||
f.write(file)
|
||||
with open(path, "r") as f:
|
||||
subprocess.Popen(
|
||||
["im=$(cat); open -a Preview.app $im; sleep 20; rm -f $im"],
|
||||
shell=True,
|
||||
stdin=f,
|
||||
)
|
||||
return command
|
||||
os.remove(path)
|
||||
return 1
|
||||
|
||||
def show_file(self, file, **options):
|
||||
"""Display given file"""
|
||||
fd, path = tempfile.mkstemp()
|
||||
with os.fdopen(fd, "w") as f:
|
||||
f.write(file)
|
||||
with open(path, "r") as f:
|
||||
subprocess.Popen(
|
||||
["im=$(cat); open -a Preview.app $im; sleep 20; rm -f $im"],
|
||||
shell=True,
|
||||
stdin=f,
|
||||
)
|
||||
os.remove(path)
|
||||
return 1
|
||||
|
||||
if sys.platform == "darwin":
|
||||
register(MacViewer)
|
||||
|
||||
else:
|
||||
|
||||
# unixoids
|
||||
class UnixViewer(Viewer):
|
||||
format = "PNG"
|
||||
options = {"compress_level": 1}
|
||||
|
||||
class UnixViewer(Viewer):
|
||||
format = "PNG"
|
||||
options = {"compress_level": 1}
|
||||
def get_command(self, file, **options):
|
||||
command = self.get_command_ex(file, **options)[0]
|
||||
return "({} {}; rm -f {})&".format(command, quote(file), quote(file))
|
||||
|
||||
def get_command(self, file, **options):
|
||||
def show_file(self, file, **options):
|
||||
"""Display given file"""
|
||||
fd, path = tempfile.mkstemp()
|
||||
with os.fdopen(fd, "w") as f:
|
||||
f.write(file)
|
||||
with open(path, "r") as f:
|
||||
command = self.get_command_ex(file, **options)[0]
|
||||
return "({} {}; rm -f {})&".format(command, quote(file), quote(file))
|
||||
subprocess.Popen(
|
||||
["im=$(cat);" + command + " $im; rm -f $im"], shell=True, stdin=f
|
||||
)
|
||||
os.remove(path)
|
||||
return 1
|
||||
|
||||
def show_file(self, file, **options):
|
||||
"""Display given file"""
|
||||
fd, path = tempfile.mkstemp()
|
||||
with os.fdopen(fd, "w") as f:
|
||||
f.write(file)
|
||||
with open(path, "r") as f:
|
||||
command = self.get_command_ex(file, **options)[0]
|
||||
subprocess.Popen(
|
||||
["im=$(cat);" + command + " $im; rm -f $im"], shell=True, stdin=f
|
||||
)
|
||||
os.remove(path)
|
||||
return 1
|
||||
|
||||
# implementations
|
||||
class DisplayViewer(UnixViewer):
|
||||
"""The ImageMagick ``display`` command."""
|
||||
|
||||
class DisplayViewer(UnixViewer):
|
||||
def get_command_ex(self, file, **options):
|
||||
command = executable = "display"
|
||||
return command, executable
|
||||
def get_command_ex(self, file, **options):
|
||||
command = executable = "display"
|
||||
return command, executable
|
||||
|
||||
|
||||
class EogViewer(UnixViewer):
|
||||
"""The GNOME Image Viewer ``eog`` command."""
|
||||
|
||||
def get_command_ex(self, file, **options):
|
||||
command = executable = "eog"
|
||||
return command, executable
|
||||
|
||||
|
||||
class XVViewer(UnixViewer):
|
||||
"""
|
||||
The X Viewer ``xv`` command.
|
||||
This viewer supports the ``title`` parameter.
|
||||
"""
|
||||
|
||||
def get_command_ex(self, file, title=None, **options):
|
||||
# note: xv is pretty outdated. most modern systems have
|
||||
# imagemagick's display command instead.
|
||||
command = executable = "xv"
|
||||
if title:
|
||||
command += " -name %s" % quote(title)
|
||||
return command, executable
|
||||
|
||||
|
||||
if sys.platform not in ("win32", "darwin"): # unixoids
|
||||
if shutil.which("display"):
|
||||
register(DisplayViewer)
|
||||
|
||||
class EogViewer(UnixViewer):
|
||||
def get_command_ex(self, file, **options):
|
||||
command = executable = "eog"
|
||||
return command, executable
|
||||
|
||||
if shutil.which("eog"):
|
||||
register(EogViewer)
|
||||
|
||||
class XVViewer(UnixViewer):
|
||||
def get_command_ex(self, file, title=None, **options):
|
||||
# note: xv is pretty outdated. most modern systems have
|
||||
# imagemagick's display command instead.
|
||||
command = executable = "xv"
|
||||
if title:
|
||||
command += " -name %s" % quote(title)
|
||||
return command, executable
|
||||
|
||||
if shutil.which("xv"):
|
||||
register(XVViewer)
|
||||
|
||||
|
|
|
@ -118,8 +118,8 @@ class IptcImageFile(ImageFile.ImageFile):
|
|||
# compression
|
||||
try:
|
||||
compression = COMPRESSION[self.getint((3, 120))]
|
||||
except KeyError:
|
||||
raise OSError("Unknown IPTC image compression")
|
||||
except KeyError as e:
|
||||
raise OSError("Unknown IPTC image compression") from e
|
||||
|
||||
# tile
|
||||
if tag == (8, 10):
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user