Merge remote-tracking branch 'upstream/master' into ellipse

This commit is contained in:
Stanislau Tsitsianok 2020-06-29 23:31:25 +03:00
commit 7dedb1402f
No known key found for this signature in database
GPG Key ID: 349CB26B2ED6E0C0
140 changed files with 2023 additions and 1117 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)
------------------

View File

@ -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)

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 557 B

BIN
Tests/images/text_mono.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -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():

View File

@ -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)

View File

@ -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

View File

@ -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")

View File

@ -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()

View File

@ -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:

View File

@ -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)

View File

@ -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")

View File

@ -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():

View File

@ -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):
"""

View File

@ -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

View File

@ -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),

View File

@ -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)

View File

@ -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 (

View File

@ -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)

View File

@ -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)

View File

@ -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")

View File

@ -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")

View File

@ -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

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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` | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐ |
+----------------+-------------+-----------+-------------+

View File

@ -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**

View File

@ -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.

View File

@ -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

View File

@ -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:

View File

@ -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

View File

@ -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”).

View File

@ -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)

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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:

View File

@ -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.

View File

@ -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.

View File

@ -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

View File

@ -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.

View File

@ -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:

View File

@ -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.

View File

@ -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::

View File

@ -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.

View File

@ -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

View File

@ -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

View 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:

View File

@ -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

View File

@ -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.

View File

@ -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

View 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.

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -7,4 +7,4 @@ Internal Reference Docs
open_files
limits
block_allocator
internal_modules

View 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.

View File

@ -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:

View File

@ -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

View File

@ -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
========================

View File

@ -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.

View File

@ -9,4 +9,5 @@ pyflakes
pyroma
pytest
pytest-cov
sphinx>=2.4
sphinx-rtd-theme

View File

@ -9,5 +9,5 @@ line_length = 88
multi_line_output = 3
[tool:pytest]
addopts = -rs
addopts = -ra --color=yes
testpaths = Tests

View File

@ -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__()

View File

@ -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):

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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)

View File

@ -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."""

View File

@ -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

View File

@ -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

View File

@ -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")

View File

@ -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

View File

@ -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):

View File

@ -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":

View File

@ -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"

View File

@ -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")

View File

@ -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)

View File

@ -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)

View File

@ -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():

View File

@ -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)

View File

@ -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

View File

@ -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]

View File

@ -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:

View File

@ -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")

View File

@ -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)

View File

@ -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]

View File

@ -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):

View File

@ -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)

View File

@ -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