mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-01-13 10:46:16 +03:00
Merge branch 'main' into eps_plugin_perf
This commit is contained in:
commit
35463e8ca3
28
.github/workflows/test-cygwin.yml
vendored
28
.github/workflows/test-cygwin.yml
vendored
|
@ -34,18 +34,34 @@ jobs:
|
|||
with:
|
||||
platform: x86_64
|
||||
packages: >
|
||||
ImageMagick gcc-g++ ghostscript jpeg libfreetype-devel
|
||||
libimagequant-devel libjpeg-devel liblapack-devel
|
||||
liblcms2-devel libopenjp2-devel libraqm-devel
|
||||
libtiff-devel libwebp-devel libxcb-devel libxcb-xinerama0
|
||||
make netpbm perl
|
||||
gcc-g++
|
||||
ghostscript
|
||||
ImageMagick
|
||||
jpeg
|
||||
libfreetype-devel
|
||||
libimagequant-devel
|
||||
libjpeg-devel
|
||||
liblapack-devel
|
||||
liblcms2-devel
|
||||
libopenjp2-devel
|
||||
libraqm-devel
|
||||
libtiff-devel
|
||||
libwebp-devel
|
||||
libxcb-devel
|
||||
libxcb-xinerama0
|
||||
make
|
||||
netpbm
|
||||
perl
|
||||
python3${{ matrix.python-minor-version }}-cffi
|
||||
python3${{ matrix.python-minor-version }}-cython
|
||||
python3${{ matrix.python-minor-version }}-devel
|
||||
python3${{ matrix.python-minor-version }}-numpy
|
||||
python3${{ matrix.python-minor-version }}-sip
|
||||
python3${{ matrix.python-minor-version }}-tkinter
|
||||
qt5-devel-tools subversion xorg-server-extra zlib-devel
|
||||
qt5-devel-tools
|
||||
subversion
|
||||
xorg-server-extra
|
||||
zlib-devel
|
||||
|
||||
- name: Add Lapack to PATH
|
||||
uses: egor-tensin/cleanup-path@v3
|
||||
|
|
10
.github/workflows/test-mingw.yml
vendored
10
.github/workflows/test-mingw.yml
vendored
|
@ -45,11 +45,6 @@ jobs:
|
|||
- name: Install dependencies
|
||||
run: |
|
||||
pacman -S --noconfirm \
|
||||
${{ matrix.package }}-python3-cffi \
|
||||
${{ matrix.package }}-python3-numpy \
|
||||
${{ matrix.package }}-python3-olefile \
|
||||
${{ matrix.package }}-python3-pip \
|
||||
${{ matrix.package }}-python3-setuptools \
|
||||
${{ matrix.package }}-freetype \
|
||||
${{ matrix.package }}-gcc \
|
||||
${{ matrix.package }}-ghostscript \
|
||||
|
@ -60,6 +55,11 @@ jobs:
|
|||
${{ matrix.package }}-libtiff \
|
||||
${{ matrix.package }}-libwebp \
|
||||
${{ matrix.package }}-openjpeg2 \
|
||||
${{ matrix.package }}-python3-cffi \
|
||||
${{ matrix.package }}-python3-numpy \
|
||||
${{ matrix.package }}-python3-olefile \
|
||||
${{ matrix.package }}-python3-pip \
|
||||
${{ matrix.package }}-python3-setuptools \
|
||||
subversion
|
||||
|
||||
if [ ${{ matrix.package }} == "mingw-w64-x86_64" ]; then
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
repos:
|
||||
- repo: https://github.com/psf/black
|
||||
rev: 22.12.0
|
||||
rev: 23.1.0
|
||||
hooks:
|
||||
- id: black
|
||||
args: [--target-version=py37]
|
||||
|
@ -9,7 +9,7 @@ repos:
|
|||
types: []
|
||||
|
||||
- repo: https://github.com/PyCQA/isort
|
||||
rev: 5.11.4
|
||||
rev: 5.12.0
|
||||
hooks:
|
||||
- id: isort
|
||||
|
||||
|
@ -26,7 +26,7 @@ repos:
|
|||
- id: yesqa
|
||||
|
||||
- repo: https://github.com/Lucas-C/pre-commit-hooks
|
||||
rev: v1.3.1
|
||||
rev: v1.4.2
|
||||
hooks:
|
||||
- id: remove-tabs
|
||||
exclude: (Makefile$|\.bat$|\.cmake$|\.eps$|\.fits$|\.opt$)
|
||||
|
@ -39,7 +39,7 @@ repos:
|
|||
[flake8-2020, flake8-errmsg, flake8-implicit-str-concat]
|
||||
|
||||
- repo: https://github.com/pre-commit/pygrep-hooks
|
||||
rev: v1.9.0
|
||||
rev: v1.10.0
|
||||
hooks:
|
||||
- id: python-check-blanket-noqa
|
||||
- id: rst-backticks
|
||||
|
@ -57,7 +57,7 @@ repos:
|
|||
- id: sphinx-lint
|
||||
|
||||
- repo: https://github.com/tox-dev/tox-ini-fmt
|
||||
rev: 0.5.2
|
||||
rev: 0.6.1
|
||||
hooks:
|
||||
- id: tox-ini-fmt
|
||||
|
||||
|
|
18
CHANGES.rst
18
CHANGES.rst
|
@ -5,6 +5,24 @@ Changelog (Pillow)
|
|||
9.5.0 (unreleased)
|
||||
------------------
|
||||
|
||||
- Handle more than one directory returned by pkg-config #6896
|
||||
[sebastic, radarhere]
|
||||
|
||||
- Do not retry past formats when loading all formats for the first time #6902
|
||||
[radarhere]
|
||||
|
||||
- Do not retry specified formats if they failed when opening #6893
|
||||
[radarhere]
|
||||
|
||||
- Do not unintentionally load TIFF format at first #6892
|
||||
[radarhere]
|
||||
|
||||
- Stop reading when EPS line becomes too long #6897
|
||||
[radarhere]
|
||||
|
||||
- Allow writing IFDRational to BYTE tag #6890
|
||||
[radarhere]
|
||||
|
||||
- Raise ValueError for BoxBlur filter with negative radius #6874
|
||||
[hugovk, radarhere]
|
||||
|
||||
|
|
2
LICENSE
2
LICENSE
|
@ -5,7 +5,7 @@ The Python Imaging Library (PIL) is
|
|||
|
||||
Pillow is the friendly PIL fork. It is
|
||||
|
||||
Copyright © 2010-2023 by Alex Clark and contributors
|
||||
Copyright © 2010-2023 by Jeffrey A. Clark (Alex) and contributors.
|
||||
|
||||
Like PIL, Pillow is licensed under the open source HPND License:
|
||||
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
|
||||
## Python Imaging Library (Fork)
|
||||
|
||||
Pillow is the friendly PIL fork by [Alex Clark and
|
||||
Contributors](https://github.com/python-pillow/Pillow/graphs/contributors).
|
||||
Pillow is the friendly PIL fork by [Jeffrey A. Clark (Alex) and
|
||||
contributors](https://github.com/python-pillow/Pillow/graphs/contributors).
|
||||
PIL is the Python Imaging Library by Fredrik Lundh and Contributors.
|
||||
As of 2019, Pillow development is
|
||||
[supported by Tidelift](https://tidelift.com/subscription/pkg/pypi-pillow?utm_source=pypi-pillow&utm_medium=readme&utm_campaign=enterprise).
|
||||
|
|
|
@ -4,7 +4,6 @@ TEST_FILE = "Tests/images/fli_overflow.fli"
|
|||
|
||||
|
||||
def test_fli_overflow():
|
||||
|
||||
# this should not crash with a malloc error or access violation
|
||||
with Image.open(TEST_FILE) as im:
|
||||
im.load()
|
||||
|
|
|
@ -23,7 +23,6 @@ def test_ignore_dos_text():
|
|||
|
||||
|
||||
def test_dos_text():
|
||||
|
||||
try:
|
||||
im = Image.open(TEST_FILE)
|
||||
im.load()
|
||||
|
|
|
@ -18,7 +18,6 @@ def test_bad():
|
|||
"""These shouldn't crash/dos, but they shouldn't return anything
|
||||
either"""
|
||||
for f in get_files("b"):
|
||||
|
||||
# Assert that there is no unclosed file warning
|
||||
with warnings.catch_warnings():
|
||||
try:
|
||||
|
|
|
@ -11,6 +11,11 @@ from PIL import _deprecate
|
|||
"Old thing is deprecated and will be removed in Pillow 10 "
|
||||
r"\(2023-07-01\)\. Use new thing instead\.",
|
||||
),
|
||||
(
|
||||
11,
|
||||
"Old thing is deprecated and will be removed in Pillow 11 "
|
||||
r"\(2024-10-15\)\. Use new thing instead\.",
|
||||
),
|
||||
(
|
||||
None,
|
||||
r"Old thing is deprecated and will be removed in a future version\. "
|
||||
|
|
|
@ -141,7 +141,6 @@ def test_rgba_bitfields():
|
|||
# This test image has been manually hexedited
|
||||
# to change the bitfield compression in the header from XBGR to RGBA
|
||||
with Image.open("Tests/images/rgb32bf-rgba.bmp") as im:
|
||||
|
||||
# So before the comparing the image, swap the channels
|
||||
b, g, r = im.split()[1:]
|
||||
im = Image.merge("RGB", (r, g, b))
|
||||
|
|
|
@ -10,7 +10,6 @@ TEST_FILE = "Tests/images/gfs.t06z.rassda.tm00.bufr_d"
|
|||
def test_open():
|
||||
# Act
|
||||
with Image.open(TEST_FILE) as im:
|
||||
|
||||
# Assert
|
||||
assert im.format == "BUFR"
|
||||
|
||||
|
@ -31,7 +30,6 @@ def test_invalid_file():
|
|||
def test_load():
|
||||
# Arrange
|
||||
with Image.open(TEST_FILE) as im:
|
||||
|
||||
# Act / Assert: stub cannot load without an implemented handler
|
||||
with pytest.raises(OSError):
|
||||
im.load()
|
||||
|
|
|
@ -15,7 +15,6 @@ def test_sanity():
|
|||
|
||||
# Act
|
||||
with Image.open(TEST_FILE) as im:
|
||||
|
||||
# Assert
|
||||
assert im.size == (128, 128)
|
||||
assert isinstance(im, DcxImagePlugin.DcxImageFile)
|
||||
|
@ -54,7 +53,6 @@ def test_invalid_file():
|
|||
def test_tell():
|
||||
# Arrange
|
||||
with Image.open(TEST_FILE) as im:
|
||||
|
||||
# Act
|
||||
frame = im.tell()
|
||||
|
||||
|
|
|
@ -12,7 +12,6 @@ TEST_FILE = "Tests/images/hopper.fits"
|
|||
def test_open():
|
||||
# Act
|
||||
with Image.open(TEST_FILE) as im:
|
||||
|
||||
# Assert
|
||||
assert im.format == "FITS"
|
||||
assert im.size == (128, 128)
|
||||
|
|
|
@ -64,7 +64,6 @@ def test_context_manager():
|
|||
def test_tell():
|
||||
# Arrange
|
||||
with Image.open(static_test_file) as im:
|
||||
|
||||
# Act
|
||||
frame = im.tell()
|
||||
|
||||
|
@ -110,7 +109,6 @@ def test_eoferror():
|
|||
|
||||
def test_seek_tell():
|
||||
with Image.open(animated_test_file) as im:
|
||||
|
||||
layer_number = im.tell()
|
||||
assert layer_number == 0
|
||||
|
||||
|
|
|
@ -209,7 +209,7 @@ def test_optimize_if_palette_can_be_reduced_by_half():
|
|||
im = im.resize((591, 443))
|
||||
im_rgb = im.convert("RGB")
|
||||
|
||||
for (optimize, colors) in ((False, 256), (True, 8)):
|
||||
for optimize, colors in ((False, 256), (True, 8)):
|
||||
out = BytesIO()
|
||||
im_rgb.save(out, "GIF", optimize=optimize)
|
||||
with Image.open(out) as reloaded:
|
||||
|
@ -221,7 +221,6 @@ def test_roundtrip(tmp_path):
|
|||
im = hopper()
|
||||
im.save(out)
|
||||
with Image.open(out) as reread:
|
||||
|
||||
assert_image_similar(reread.convert("RGB"), im, 50)
|
||||
|
||||
|
||||
|
@ -232,7 +231,6 @@ def test_roundtrip2(tmp_path):
|
|||
im2 = im.copy()
|
||||
im2.save(out)
|
||||
with Image.open(out) as reread:
|
||||
|
||||
assert_image_similar(reread.convert("RGB"), hopper(), 50)
|
||||
|
||||
|
||||
|
@ -242,7 +240,6 @@ def test_roundtrip_save_all(tmp_path):
|
|||
im = hopper()
|
||||
im.save(out, save_all=True)
|
||||
with Image.open(out) as reread:
|
||||
|
||||
assert_image_similar(reread.convert("RGB"), im, 50)
|
||||
|
||||
# Multiframe image
|
||||
|
@ -284,13 +281,11 @@ def test_headers_saving_for_animated_gifs(tmp_path):
|
|||
important_headers = ["background", "version", "duration", "loop"]
|
||||
# Multiframe image
|
||||
with Image.open("Tests/images/dispose_bgnd.gif") as im:
|
||||
|
||||
info = im.info.copy()
|
||||
|
||||
out = str(tmp_path / "temp.gif")
|
||||
im.save(out, save_all=True)
|
||||
with Image.open(out) as reread:
|
||||
|
||||
for header in important_headers:
|
||||
assert info[header] == reread.info[header]
|
||||
|
||||
|
@ -308,7 +303,6 @@ def test_palette_handling(tmp_path):
|
|||
im2.save(f, optimize=True)
|
||||
|
||||
with Image.open(f) as reloaded:
|
||||
|
||||
assert_image_similar(im, reloaded.convert("RGB"), 10)
|
||||
|
||||
|
||||
|
@ -324,7 +318,6 @@ def test_palette_434(tmp_path):
|
|||
|
||||
orig = "Tests/images/test.colors.gif"
|
||||
with Image.open(orig) as im:
|
||||
|
||||
with roundtrip(im) as reloaded:
|
||||
assert_image_similar(im, reloaded, 1)
|
||||
with roundtrip(im, optimize=True) as reloaded:
|
||||
|
@ -575,7 +568,6 @@ def test_save_dispose(tmp_path):
|
|||
)
|
||||
|
||||
with Image.open(out) as img:
|
||||
|
||||
for i in range(2):
|
||||
img.seek(img.tell() + 1)
|
||||
assert img.disposal_method == i + 1
|
||||
|
@ -773,7 +765,6 @@ def test_multiple_duration(tmp_path):
|
|||
out, save_all=True, append_images=im_list[1:], duration=duration_list
|
||||
)
|
||||
with Image.open(out) as reread:
|
||||
|
||||
for duration in duration_list:
|
||||
assert reread.info["duration"] == duration
|
||||
try:
|
||||
|
@ -786,7 +777,6 @@ def test_multiple_duration(tmp_path):
|
|||
out, save_all=True, append_images=im_list[1:], duration=tuple(duration_list)
|
||||
)
|
||||
with Image.open(out) as reread:
|
||||
|
||||
for duration in duration_list:
|
||||
assert reread.info["duration"] == duration
|
||||
try:
|
||||
|
@ -844,7 +834,6 @@ def test_identical_frames(tmp_path):
|
|||
out, save_all=True, append_images=im_list[1:], duration=duration_list
|
||||
)
|
||||
with Image.open(out) as reread:
|
||||
|
||||
# Assert that the first three frames were combined
|
||||
assert reread.n_frames == 2
|
||||
|
||||
|
|
|
@ -10,7 +10,6 @@ TEST_FILE = "Tests/images/WAlaska.wind.7days.grb"
|
|||
def test_open():
|
||||
# Act
|
||||
with Image.open(TEST_FILE) as im:
|
||||
|
||||
# Assert
|
||||
assert im.format == "GRIB"
|
||||
|
||||
|
@ -31,7 +30,6 @@ def test_invalid_file():
|
|||
def test_load():
|
||||
# Arrange
|
||||
with Image.open(TEST_FILE) as im:
|
||||
|
||||
# Act / Assert: stub cannot load without an implemented handler
|
||||
with pytest.raises(OSError):
|
||||
im.load()
|
||||
|
|
|
@ -8,7 +8,6 @@ TEST_FILE = "Tests/images/hdf5.h5"
|
|||
def test_open():
|
||||
# Act
|
||||
with Image.open(TEST_FILE) as im:
|
||||
|
||||
# Assert
|
||||
assert im.format == "HDF5"
|
||||
|
||||
|
@ -29,7 +28,6 @@ def test_invalid_file():
|
|||
def test_load():
|
||||
# Arrange
|
||||
with Image.open(TEST_FILE) as im:
|
||||
|
||||
# Act / Assert: stub cannot load without an implemented handler
|
||||
with pytest.raises(OSError):
|
||||
im.load()
|
||||
|
|
|
@ -16,7 +16,6 @@ def test_sanity():
|
|||
# Loading this icon by default should result in the largest size
|
||||
# (512x512@2x) being loaded
|
||||
with Image.open(TEST_FILE) as im:
|
||||
|
||||
# Assert that there is no unclosed file warning
|
||||
with warnings.catch_warnings():
|
||||
im.load()
|
||||
|
|
|
@ -175,7 +175,6 @@ def test_save_256x256(tmp_path):
|
|||
# Act
|
||||
im.save(outfile)
|
||||
with Image.open(outfile) as im_saved:
|
||||
|
||||
# Assert
|
||||
assert im_saved.size == (256, 256)
|
||||
|
||||
|
|
|
@ -51,7 +51,6 @@ def test_context_manager():
|
|||
def test_tell():
|
||||
# Arrange
|
||||
with Image.open(TEST_IM) as im:
|
||||
|
||||
# Act
|
||||
frame = im.tell()
|
||||
|
||||
|
|
|
@ -11,7 +11,6 @@ TEST_FILE = "Tests/images/iptc.jpg"
|
|||
def test_getiptcinfo_jpg_none():
|
||||
# Arrange
|
||||
with hopper() as im:
|
||||
|
||||
# Act
|
||||
iptc = IptcImagePlugin.getiptcinfo(im)
|
||||
|
||||
|
@ -22,7 +21,6 @@ def test_getiptcinfo_jpg_none():
|
|||
def test_getiptcinfo_jpg_found():
|
||||
# Arrange
|
||||
with Image.open(TEST_FILE) as im:
|
||||
|
||||
# Act
|
||||
iptc = IptcImagePlugin.getiptcinfo(im)
|
||||
|
||||
|
@ -35,7 +33,6 @@ def test_getiptcinfo_jpg_found():
|
|||
def test_getiptcinfo_tiff_none():
|
||||
# Arrange
|
||||
with Image.open("Tests/images/hopper.tif") as im:
|
||||
|
||||
# Act
|
||||
iptc = IptcImagePlugin.getiptcinfo(im)
|
||||
|
||||
|
|
|
@ -57,7 +57,6 @@ class TestFileJpeg:
|
|||
return Image.frombytes(mode, size, os.urandom(size[0] * size[1] * len(mode)))
|
||||
|
||||
def test_sanity(self):
|
||||
|
||||
# internal version number
|
||||
assert re.search(r"\d+\.\d+$", features.version_codec("jpg"))
|
||||
|
||||
|
@ -368,7 +367,6 @@ class TestFileJpeg:
|
|||
|
||||
def test_exif_gps_typeerror(self):
|
||||
with Image.open("Tests/images/exif_gps_typeerror.jpg") as im:
|
||||
|
||||
# Should not raise a TypeError
|
||||
im._getexif()
|
||||
|
||||
|
@ -682,7 +680,6 @@ class TestFileJpeg:
|
|||
# Shouldn't raise error
|
||||
fn = "Tests/images/sugarshack_bad_mpo_header.jpg"
|
||||
with pytest.warns(UserWarning, Image.open, fn) as im:
|
||||
|
||||
# Assert
|
||||
assert im.format == "JPEG"
|
||||
|
||||
|
@ -704,7 +701,6 @@ class TestFileJpeg:
|
|||
# Arrange
|
||||
outfile = str(tmp_path / "temp.tif")
|
||||
with Image.open("Tests/images/hopper.tif") as im:
|
||||
|
||||
# Act
|
||||
im.save(outfile, "JPEG", dpi=im.info["dpi"])
|
||||
|
||||
|
@ -731,7 +727,6 @@ class TestFileJpeg:
|
|||
# This Photoshop CC 2017 image has DPI in EXIF not metadata
|
||||
# EXIF XResolution is (2000000, 10000)
|
||||
with Image.open("Tests/images/photoshop-200dpi.jpg") as im:
|
||||
|
||||
# Act / Assert
|
||||
assert im.info.get("dpi") == (200, 200)
|
||||
|
||||
|
@ -740,7 +735,6 @@ class TestFileJpeg:
|
|||
# This image has DPI in EXIF not metadata
|
||||
# EXIF XResolution is 72
|
||||
with Image.open("Tests/images/exif-72dpi-int.jpg") as im:
|
||||
|
||||
# Act / Assert
|
||||
assert im.info.get("dpi") == (72, 72)
|
||||
|
||||
|
@ -749,7 +743,6 @@ class TestFileJpeg:
|
|||
# This is photoshop-200dpi.jpg with EXIF resolution unit set to cm:
|
||||
# exiftool -exif:ResolutionUnit=cm photoshop-200dpi.jpg
|
||||
with Image.open("Tests/images/exif-200dpcm.jpg") as im:
|
||||
|
||||
# Act / Assert
|
||||
assert im.info.get("dpi") == (508, 508)
|
||||
|
||||
|
@ -758,7 +751,6 @@ class TestFileJpeg:
|
|||
# This is photoshop-200dpi.jpg with EXIF resolution set to 0/0:
|
||||
# exiftool -XResolution=0/0 -YResolution=0/0 photoshop-200dpi.jpg
|
||||
with Image.open("Tests/images/exif-dpi-zerodivision.jpg") as im:
|
||||
|
||||
# Act / Assert
|
||||
# This should return the default, and not raise a ZeroDivisionError
|
||||
assert im.info.get("dpi") == (72, 72)
|
||||
|
@ -767,7 +759,6 @@ class TestFileJpeg:
|
|||
# Arrange
|
||||
# 0x011A tag in this exif contains string '300300\x02'
|
||||
with Image.open("Tests/images/broken_exif_dpi.jpg") as im:
|
||||
|
||||
# Act / Assert
|
||||
# This should return the default
|
||||
assert im.info.get("dpi") == (72, 72)
|
||||
|
@ -777,7 +768,6 @@ class TestFileJpeg:
|
|||
# This is photoshop-200dpi.jpg with resolution removed from EXIF:
|
||||
# exiftool "-*resolution*"= photoshop-200dpi.jpg
|
||||
with Image.open("Tests/images/no-dpi-in-exif.jpg") as im:
|
||||
|
||||
# Act / Assert
|
||||
# "When the image resolution is unknown, 72 [dpi] is designated."
|
||||
# https://exiv2.org/tags.html
|
||||
|
@ -787,7 +777,6 @@ class TestFileJpeg:
|
|||
# This is no-dpi-in-exif with the tiff header of the exif block
|
||||
# hexedited from MM * to FF FF FF FF
|
||||
with Image.open("Tests/images/invalid-exif.jpg") as im:
|
||||
|
||||
# This should return the default, and not a SyntaxError or
|
||||
# OSError for unidentified image.
|
||||
assert im.info.get("dpi") == (72, 72)
|
||||
|
@ -810,7 +799,6 @@ class TestFileJpeg:
|
|||
def test_invalid_exif_x_resolution(self):
|
||||
# When no x or y resolution is defined in EXIF
|
||||
with Image.open("Tests/images/invalid-exif-without-x-resolution.jpg") as im:
|
||||
|
||||
# This should return the default, and not a ValueError or
|
||||
# OSError for an unidentified image.
|
||||
assert im.info.get("dpi") == (72, 72)
|
||||
|
@ -820,7 +808,6 @@ class TestFileJpeg:
|
|||
# This image has been manually hexedited to have an IFD offset of 10,
|
||||
# in contrast to normal 8
|
||||
with Image.open("Tests/images/exif-ifd-offset.jpg") as im:
|
||||
|
||||
# Act / Assert
|
||||
assert im._getexif()[306] == "2017:03:13 23:03:09"
|
||||
|
||||
|
|
|
@ -270,7 +270,6 @@ def test_rgba():
|
|||
# Arrange
|
||||
with Image.open("Tests/images/rgb_trns_ycbc.j2k") as j2k:
|
||||
with Image.open("Tests/images/rgb_trns_ycbc.jp2") as jp2:
|
||||
|
||||
# Act
|
||||
j2k.load()
|
||||
jp2.load()
|
||||
|
|
|
@ -645,7 +645,6 @@ class TestFileLibTiff(LibTiffTestCase):
|
|||
pilim = hopper()
|
||||
|
||||
def save_bytesio(compression=None):
|
||||
|
||||
buffer_io = io.BytesIO()
|
||||
pilim.save(buffer_io, format="tiff", compression=compression)
|
||||
buffer_io.seek(0)
|
||||
|
@ -740,7 +739,6 @@ class TestFileLibTiff(LibTiffTestCase):
|
|||
|
||||
def test_multipage_compression(self):
|
||||
with Image.open("Tests/images/compression.tif") as im:
|
||||
|
||||
im.seek(0)
|
||||
assert im._compression == "tiff_ccitt"
|
||||
assert im.size == (10, 10)
|
||||
|
|
|
@ -44,7 +44,6 @@ def test_open_windows_v1():
|
|||
# Arrange
|
||||
# Act
|
||||
with Image.open(TEST_FILE) as im:
|
||||
|
||||
# Assert
|
||||
assert_image_equal(im, hopper("1"))
|
||||
assert isinstance(im, MspImagePlugin.MspImageFile)
|
||||
|
@ -59,7 +58,6 @@ def _assert_file_image_equal(source_path, target_path):
|
|||
not os.path.exists(EXTRA_DIR), reason="Extra image files not installed"
|
||||
)
|
||||
def test_open_windows_v2():
|
||||
|
||||
files = (
|
||||
os.path.join(EXTRA_DIR, f)
|
||||
for f in os.listdir(EXTRA_DIR)
|
||||
|
|
|
@ -89,7 +89,6 @@ def test_save_all(tmp_path):
|
|||
|
||||
# Multiframe image
|
||||
with Image.open("Tests/images/dispose_bgnd.gif") as im:
|
||||
|
||||
outfile = str(tmp_path / "temp.pdf")
|
||||
im.save(outfile, save_all=True)
|
||||
|
||||
|
@ -123,7 +122,6 @@ def test_save_all(tmp_path):
|
|||
def test_multiframe_normal_save(tmp_path):
|
||||
# Test saving a multiframe image without save_all
|
||||
with Image.open("Tests/images/dispose_bgnd.gif") as im:
|
||||
|
||||
outfile = str(tmp_path / "temp.pdf")
|
||||
im.save(outfile)
|
||||
|
||||
|
|
|
@ -78,7 +78,6 @@ class TestFilePng:
|
|||
return chunks
|
||||
|
||||
def test_sanity(self, tmp_path):
|
||||
|
||||
# internal version number
|
||||
assert re.search(r"\d+\.\d+\.\d+(\.\d+)?$", features.version_codec("zlib"))
|
||||
|
||||
|
@ -156,7 +155,6 @@ class TestFilePng:
|
|||
assert im.info == {"spam": "egg"}
|
||||
|
||||
def test_bad_itxt(self):
|
||||
|
||||
im = load(HEAD + chunk(b"iTXt") + TAIL)
|
||||
assert im.info == {}
|
||||
|
||||
|
@ -201,7 +199,6 @@ class TestFilePng:
|
|||
assert im.info["spam"].tkey == "Spam"
|
||||
|
||||
def test_interlace(self):
|
||||
|
||||
test_file = "Tests/images/pil123p.png"
|
||||
with Image.open(test_file) as im:
|
||||
assert_image(im, "P", (162, 150))
|
||||
|
@ -495,7 +492,6 @@ class TestFilePng:
|
|||
# Check reading images with null tRNS value, issue #1239
|
||||
test_file = "Tests/images/tRNS_null_1x1.png"
|
||||
with Image.open(test_file) as im:
|
||||
|
||||
assert im.info["transparency"] == 0
|
||||
|
||||
def test_save_icc_profile(self):
|
||||
|
|
|
@ -77,7 +77,6 @@ def test_eoferror():
|
|||
|
||||
def test_seek_tell():
|
||||
with Image.open(test_file) as im:
|
||||
|
||||
layer_number = im.tell()
|
||||
assert layer_number == 1
|
||||
|
||||
|
@ -95,7 +94,6 @@ def test_seek_tell():
|
|||
|
||||
def test_seek_eoferror():
|
||||
with Image.open(test_file) as im:
|
||||
|
||||
with pytest.raises(EOFError):
|
||||
im.seek(-1)
|
||||
|
||||
|
|
|
@ -79,7 +79,6 @@ def test_is_spider_image():
|
|||
def test_tell():
|
||||
# Arrange
|
||||
with Image.open(TEST_FILE) as im:
|
||||
|
||||
# Act
|
||||
index = im.tell()
|
||||
|
||||
|
|
|
@ -16,7 +16,6 @@ def test_sanity():
|
|||
|
||||
# Act
|
||||
with Image.open(test_file) as im:
|
||||
|
||||
# Assert
|
||||
assert im.size == (128, 128)
|
||||
|
||||
|
|
|
@ -10,18 +10,21 @@ from .helper import is_pypy
|
|||
TEST_TAR_FILE = "Tests/images/hopper.tar"
|
||||
|
||||
|
||||
def test_sanity():
|
||||
for codec, test_path, format in [
|
||||
["zlib", "hopper.png", "PNG"],
|
||||
["jpg", "hopper.jpg", "JPEG"],
|
||||
]:
|
||||
if features.check(codec):
|
||||
with TarIO.TarIO(TEST_TAR_FILE, test_path) as tar:
|
||||
with Image.open(tar) as im:
|
||||
im.load()
|
||||
assert im.mode == "RGB"
|
||||
assert im.size == (128, 128)
|
||||
assert im.format == format
|
||||
@pytest.mark.parametrize(
|
||||
"codec, test_path, format",
|
||||
(
|
||||
("zlib", "hopper.png", "PNG"),
|
||||
("jpg", "hopper.jpg", "JPEG"),
|
||||
),
|
||||
)
|
||||
def test_sanity(codec, test_path, format):
|
||||
if features.check(codec):
|
||||
with TarIO.TarIO(TEST_TAR_FILE, test_path) as tar:
|
||||
with Image.open(tar) as im:
|
||||
im.load()
|
||||
assert im.mode == "RGB"
|
||||
assert im.size == (128, 128)
|
||||
assert im.format == format
|
||||
|
||||
|
||||
@pytest.mark.skipif(is_pypy(), reason="Requires CPython")
|
||||
|
|
|
@ -78,7 +78,6 @@ def test_id_field():
|
|||
|
||||
# Act
|
||||
with Image.open(test_file) as im:
|
||||
|
||||
# Assert
|
||||
assert im.size == (100, 100)
|
||||
|
||||
|
@ -89,7 +88,6 @@ def test_id_field_rle():
|
|||
|
||||
# Act
|
||||
with Image.open(test_file) as im:
|
||||
|
||||
# Assert
|
||||
assert im.size == (199, 199)
|
||||
|
||||
|
@ -171,7 +169,6 @@ def test_save_id_section(tmp_path):
|
|||
|
||||
test_file = "Tests/images/tga_id_field.tga"
|
||||
with Image.open(test_file) as im:
|
||||
|
||||
# Save with no id section
|
||||
im.save(out, id_section="")
|
||||
with Image.open(out) as test_im:
|
||||
|
|
|
@ -25,7 +25,6 @@ except ImportError:
|
|||
|
||||
class TestFileTiff:
|
||||
def test_sanity(self, tmp_path):
|
||||
|
||||
filename = str(tmp_path / "temp.tif")
|
||||
|
||||
hopper("RGB").save(filename)
|
||||
|
@ -157,7 +156,6 @@ class TestFileTiff:
|
|||
def test_xyres_tiff(self):
|
||||
filename = "Tests/images/pil168.tif"
|
||||
with Image.open(filename) as im:
|
||||
|
||||
# legacy api
|
||||
assert isinstance(im.tag[X_RESOLUTION][0], tuple)
|
||||
assert isinstance(im.tag[Y_RESOLUTION][0], tuple)
|
||||
|
@ -171,7 +169,6 @@ class TestFileTiff:
|
|||
def test_xyres_fallback_tiff(self):
|
||||
filename = "Tests/images/compression.tif"
|
||||
with Image.open(filename) as im:
|
||||
|
||||
# v2 api
|
||||
assert isinstance(im.tag_v2[X_RESOLUTION], TiffImagePlugin.IFDRational)
|
||||
assert isinstance(im.tag_v2[Y_RESOLUTION], TiffImagePlugin.IFDRational)
|
||||
|
@ -186,7 +183,6 @@ class TestFileTiff:
|
|||
def test_int_resolution(self):
|
||||
filename = "Tests/images/pil168.tif"
|
||||
with Image.open(filename) as im:
|
||||
|
||||
# Try to read a file where X,Y_RESOLUTION are ints
|
||||
im.tag_v2[X_RESOLUTION] = 71
|
||||
im.tag_v2[Y_RESOLUTION] = 71
|
||||
|
@ -381,7 +377,6 @@ class TestFileTiff:
|
|||
def test___str__(self):
|
||||
filename = "Tests/images/pil136.tiff"
|
||||
with Image.open(filename) as im:
|
||||
|
||||
# Act
|
||||
ret = str(im.ifd)
|
||||
|
||||
|
@ -392,7 +387,6 @@ class TestFileTiff:
|
|||
# Arrange
|
||||
filename = "Tests/images/pil136.tiff"
|
||||
with Image.open(filename) as im:
|
||||
|
||||
# v2 interface
|
||||
v2_tags = {
|
||||
256: 55,
|
||||
|
@ -630,7 +624,6 @@ class TestFileTiff:
|
|||
filename = str(tmp_path / "temp.tif")
|
||||
hopper("RGB").save(filename, **kwargs)
|
||||
with Image.open(filename) as im:
|
||||
|
||||
# legacy interface
|
||||
assert im.tag[X_RESOLUTION][0][0] == 72
|
||||
assert im.tag[Y_RESOLUTION][0][0] == 36
|
||||
|
|
|
@ -54,7 +54,6 @@ def test_rt_metadata(tmp_path):
|
|||
img.save(f, tiffinfo=info)
|
||||
|
||||
with Image.open(f) as loaded:
|
||||
|
||||
assert loaded.tag[ImageJMetaDataByteCounts] == (len(bin_data),)
|
||||
assert loaded.tag_v2[ImageJMetaDataByteCounts] == (len(bin_data),)
|
||||
|
||||
|
@ -74,14 +73,12 @@ def test_rt_metadata(tmp_path):
|
|||
info[ImageJMetaDataByteCounts] = (8, len(bin_data) - 8)
|
||||
img.save(f, tiffinfo=info)
|
||||
with Image.open(f) as loaded:
|
||||
|
||||
assert loaded.tag[ImageJMetaDataByteCounts] == (8, len(bin_data) - 8)
|
||||
assert loaded.tag_v2[ImageJMetaDataByteCounts] == (8, len(bin_data) - 8)
|
||||
|
||||
|
||||
def test_read_metadata():
|
||||
with Image.open("Tests/images/hopper_g4.tif") as img:
|
||||
|
||||
assert {
|
||||
"YResolution": IFDRational(4294967295, 113653537),
|
||||
"PlanarConfiguration": 1,
|
||||
|
@ -202,14 +199,15 @@ def test_writing_other_types_to_ascii(value, expected, tmp_path):
|
|||
assert reloaded.tag_v2[271] == expected
|
||||
|
||||
|
||||
def test_writing_int_to_bytes(tmp_path):
|
||||
@pytest.mark.parametrize("value", (1, IFDRational(1)))
|
||||
def test_writing_other_types_to_bytes(value, tmp_path):
|
||||
im = hopper()
|
||||
info = TiffImagePlugin.ImageFileDirectory_v2()
|
||||
|
||||
tag = TiffTags.TAGS_V2[700]
|
||||
assert tag.type == TiffTags.BYTE
|
||||
|
||||
info[700] = 1
|
||||
info[700] = value
|
||||
|
||||
out = str(tmp_path / "temp.tiff")
|
||||
im.save(out, tiffinfo=info)
|
||||
|
|
|
@ -18,10 +18,8 @@ except ImportError:
|
|||
|
||||
|
||||
def test_read_exif_metadata():
|
||||
|
||||
file_path = "Tests/images/flower.webp"
|
||||
with Image.open(file_path) as image:
|
||||
|
||||
assert image.format == "WEBP"
|
||||
exif_data = image.info.get("exif", None)
|
||||
assert exif_data
|
||||
|
@ -64,10 +62,8 @@ def test_write_exif_metadata():
|
|||
|
||||
|
||||
def test_read_icc_profile():
|
||||
|
||||
file_path = "Tests/images/flower2.webp"
|
||||
with Image.open(file_path) as image:
|
||||
|
||||
assert image.format == "WEBP"
|
||||
assert image.info.get("icc_profile", None)
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@ from .helper import assert_image_similar_tofile, hopper
|
|||
|
||||
|
||||
def test_load_raw():
|
||||
|
||||
# Test basic EMF open and rendering
|
||||
with Image.open("Tests/images/drawing.emf") as im:
|
||||
if hasattr(Image.core, "drawwmf"):
|
||||
|
|
|
@ -44,7 +44,6 @@ def test_open():
|
|||
|
||||
# Act
|
||||
with Image.open(filename) as im:
|
||||
|
||||
# Assert
|
||||
assert im.mode == "1"
|
||||
assert im.size == (128, 128)
|
||||
|
@ -57,7 +56,6 @@ def test_open_filename_with_underscore():
|
|||
|
||||
# Act
|
||||
with Image.open(filename) as im:
|
||||
|
||||
# Assert
|
||||
assert im.mode == "1"
|
||||
assert im.size == (128, 128)
|
||||
|
|
|
@ -10,7 +10,6 @@ TEST_FILE = "Tests/images/hopper.p7"
|
|||
def test_open():
|
||||
# Act
|
||||
with Image.open(TEST_FILE) as im:
|
||||
|
||||
# Assert
|
||||
assert im.format == "XVThumb"
|
||||
|
||||
|
|
|
@ -69,7 +69,6 @@ class TestImage:
|
|||
assert issubclass(UnidentifiedImageError, OSError)
|
||||
|
||||
def test_sanity(self):
|
||||
|
||||
im = Image.new("L", (100, 100))
|
||||
assert repr(im)[:45] == "<PIL.Image.Image image mode=L size=100x100 at"
|
||||
assert im.mode == "L"
|
||||
|
@ -398,6 +397,17 @@ class TestImage:
|
|||
with pytest.raises(ValueError):
|
||||
source.alpha_composite(over, (0, 0), (0, -1))
|
||||
|
||||
def test_register_open_duplicates(self):
|
||||
# Arrange
|
||||
factory, accept = Image.OPEN["JPEG"]
|
||||
id_length = len(Image.ID)
|
||||
|
||||
# Act
|
||||
Image.register_open("JPEG", factory, accept)
|
||||
|
||||
# Assert
|
||||
assert len(Image.ID) == id_length
|
||||
|
||||
def test_registered_extensions_uninitialized(self):
|
||||
# Arrange
|
||||
Image._initialized = 0
|
||||
|
@ -996,7 +1006,6 @@ def mock_encode(*args):
|
|||
|
||||
class TestRegistry:
|
||||
def test_encode_registry(self):
|
||||
|
||||
Image.register_encoder("MOCK", mock_encode)
|
||||
assert "MOCK" in Image.ENCODERS
|
||||
|
||||
|
|
|
@ -45,7 +45,6 @@ def test_unsupported_conversion():
|
|||
|
||||
|
||||
def test_default():
|
||||
|
||||
im = hopper("P")
|
||||
assert im.mode == "P"
|
||||
converted_im = im.convert()
|
||||
|
|
|
@ -86,7 +86,6 @@ def test_crop_crash():
|
|||
|
||||
|
||||
def test_crop_zero():
|
||||
|
||||
im = Image.new("RGB", (0, 0), "white")
|
||||
|
||||
cropped = im.crop((0, 0, 0, 0))
|
||||
|
|
|
@ -4,7 +4,6 @@ from .helper import hopper
|
|||
|
||||
|
||||
def test_sanity():
|
||||
|
||||
bbox = hopper().getbbox()
|
||||
assert isinstance(bbox, tuple)
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@ from .helper import hopper
|
|||
|
||||
|
||||
def test_sanity():
|
||||
|
||||
with hopper() as im:
|
||||
im.mode
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ def test_resample():
|
|||
# >>> im.save('Tests/images/hopper_45.png')
|
||||
|
||||
with Image.open("Tests/images/hopper_45.png") as target:
|
||||
for (resample, epsilon) in (
|
||||
for resample, epsilon in (
|
||||
(Image.Resampling.NEAREST, 10),
|
||||
(Image.Resampling.BILINEAR, 5),
|
||||
(Image.Resampling.BICUBIC, 0),
|
||||
|
|
|
@ -4,7 +4,6 @@ from .helper import assert_image_equal, fromstring, hopper
|
|||
|
||||
|
||||
def test_sanity():
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
hopper().tobitmap()
|
||||
|
||||
|
|
|
@ -50,7 +50,6 @@ def test_add():
|
|||
# Arrange
|
||||
with Image.open("Tests/images/imagedraw_ellipse_RGB.png") as im1:
|
||||
with Image.open("Tests/images/imagedraw_floodfill_RGB.png") as im2:
|
||||
|
||||
# Act
|
||||
new = ImageChops.add(im1, im2)
|
||||
|
||||
|
@ -63,7 +62,6 @@ def test_add_scale_offset():
|
|||
# Arrange
|
||||
with Image.open("Tests/images/imagedraw_ellipse_RGB.png") as im1:
|
||||
with Image.open("Tests/images/imagedraw_floodfill_RGB.png") as im2:
|
||||
|
||||
# Act
|
||||
new = ImageChops.add(im1, im2, scale=2.5, offset=100)
|
||||
|
||||
|
@ -87,7 +85,6 @@ def test_add_modulo():
|
|||
# Arrange
|
||||
with Image.open("Tests/images/imagedraw_ellipse_RGB.png") as im1:
|
||||
with Image.open("Tests/images/imagedraw_floodfill_RGB.png") as im2:
|
||||
|
||||
# Act
|
||||
new = ImageChops.add_modulo(im1, im2)
|
||||
|
||||
|
@ -111,7 +108,6 @@ def test_blend():
|
|||
# Arrange
|
||||
with Image.open("Tests/images/imagedraw_ellipse_RGB.png") as im1:
|
||||
with Image.open("Tests/images/imagedraw_floodfill_RGB.png") as im2:
|
||||
|
||||
# Act
|
||||
new = ImageChops.blend(im1, im2, 0.5)
|
||||
|
||||
|
@ -137,7 +133,6 @@ def test_darker_image():
|
|||
# Arrange
|
||||
with Image.open("Tests/images/imagedraw_chord_RGB.png") as im1:
|
||||
with Image.open("Tests/images/imagedraw_outline_chord_RGB.png") as im2:
|
||||
|
||||
# Act
|
||||
new = ImageChops.darker(im1, im2)
|
||||
|
||||
|
@ -149,7 +144,6 @@ def test_darker_pixel():
|
|||
# Arrange
|
||||
im1 = hopper()
|
||||
with Image.open("Tests/images/imagedraw_chord_RGB.png") as im2:
|
||||
|
||||
# Act
|
||||
new = ImageChops.darker(im1, im2)
|
||||
|
||||
|
@ -161,7 +155,6 @@ def test_difference():
|
|||
# Arrange
|
||||
with Image.open("Tests/images/imagedraw_arc_end_le_start.png") as im1:
|
||||
with Image.open("Tests/images/imagedraw_arc_no_loops.png") as im2:
|
||||
|
||||
# Act
|
||||
new = ImageChops.difference(im1, im2)
|
||||
|
||||
|
@ -173,7 +166,6 @@ def test_difference_pixel():
|
|||
# Arrange
|
||||
im1 = hopper()
|
||||
with Image.open("Tests/images/imagedraw_polygon_kite_RGB.png") as im2:
|
||||
|
||||
# Act
|
||||
new = ImageChops.difference(im1, im2)
|
||||
|
||||
|
@ -195,7 +187,6 @@ def test_duplicate():
|
|||
def test_invert():
|
||||
# Arrange
|
||||
with Image.open("Tests/images/imagedraw_floodfill_RGB.png") as im:
|
||||
|
||||
# Act
|
||||
new = ImageChops.invert(im)
|
||||
|
||||
|
@ -209,7 +200,6 @@ def test_lighter_image():
|
|||
# Arrange
|
||||
with Image.open("Tests/images/imagedraw_chord_RGB.png") as im1:
|
||||
with Image.open("Tests/images/imagedraw_outline_chord_RGB.png") as im2:
|
||||
|
||||
# Act
|
||||
new = ImageChops.lighter(im1, im2)
|
||||
|
||||
|
@ -221,7 +211,6 @@ def test_lighter_pixel():
|
|||
# Arrange
|
||||
im1 = hopper()
|
||||
with Image.open("Tests/images/imagedraw_chord_RGB.png") as im2:
|
||||
|
||||
# Act
|
||||
new = ImageChops.lighter(im1, im2)
|
||||
|
||||
|
@ -275,7 +264,6 @@ def test_offset():
|
|||
xoffset = 45
|
||||
yoffset = 20
|
||||
with Image.open("Tests/images/imagedraw_ellipse_RGB.png") as im:
|
||||
|
||||
# Act
|
||||
new = ImageChops.offset(im, xoffset, yoffset)
|
||||
|
||||
|
@ -292,7 +280,6 @@ def test_screen():
|
|||
# Arrange
|
||||
with Image.open("Tests/images/imagedraw_ellipse_RGB.png") as im1:
|
||||
with Image.open("Tests/images/imagedraw_floodfill_RGB.png") as im2:
|
||||
|
||||
# Act
|
||||
new = ImageChops.screen(im1, im2)
|
||||
|
||||
|
@ -305,7 +292,6 @@ def test_subtract():
|
|||
# Arrange
|
||||
with Image.open("Tests/images/imagedraw_chord_RGB.png") as im1:
|
||||
with Image.open("Tests/images/imagedraw_outline_chord_RGB.png") as im2:
|
||||
|
||||
# Act
|
||||
new = ImageChops.subtract(im1, im2)
|
||||
|
||||
|
@ -319,7 +305,6 @@ def test_subtract_scale_offset():
|
|||
# Arrange
|
||||
with Image.open("Tests/images/imagedraw_chord_RGB.png") as im1:
|
||||
with Image.open("Tests/images/imagedraw_outline_chord_RGB.png") as im2:
|
||||
|
||||
# Act
|
||||
new = ImageChops.subtract(im1, im2, scale=2.5, offset=100)
|
||||
|
||||
|
@ -332,7 +317,6 @@ def test_subtract_clip():
|
|||
# Arrange
|
||||
im1 = hopper()
|
||||
with Image.open("Tests/images/imagedraw_chord_RGB.png") as im2:
|
||||
|
||||
# Act
|
||||
new = ImageChops.subtract(im1, im2)
|
||||
|
||||
|
@ -344,7 +328,6 @@ def test_subtract_modulo():
|
|||
# Arrange
|
||||
with Image.open("Tests/images/imagedraw_chord_RGB.png") as im1:
|
||||
with Image.open("Tests/images/imagedraw_outline_chord_RGB.png") as im2:
|
||||
|
||||
# Act
|
||||
new = ImageChops.subtract_modulo(im1, im2)
|
||||
|
||||
|
@ -358,7 +341,6 @@ def test_subtract_modulo_no_clip():
|
|||
# Arrange
|
||||
im1 = hopper()
|
||||
with Image.open("Tests/images/imagedraw_chord_RGB.png") as im2:
|
||||
|
||||
# Act
|
||||
new = ImageChops.subtract_modulo(im1, im2)
|
||||
|
||||
|
@ -370,7 +352,6 @@ def test_soft_light():
|
|||
# Arrange
|
||||
with Image.open("Tests/images/hopper.png") as im1:
|
||||
with Image.open("Tests/images/hopper-XYZ.png") as im2:
|
||||
|
||||
# Act
|
||||
new = ImageChops.soft_light(im1, im2)
|
||||
|
||||
|
@ -383,7 +364,6 @@ def test_hard_light():
|
|||
# Arrange
|
||||
with Image.open("Tests/images/hopper.png") as im1:
|
||||
with Image.open("Tests/images/hopper-XYZ.png") as im2:
|
||||
|
||||
# Act
|
||||
new = ImageChops.hard_light(im1, im2)
|
||||
|
||||
|
@ -396,7 +376,6 @@ def test_overlay():
|
|||
# Arrange
|
||||
with Image.open("Tests/images/hopper.png") as im1:
|
||||
with Image.open("Tests/images/hopper-XYZ.png") as im2:
|
||||
|
||||
# Act
|
||||
new = ImageChops.overlay(im1, im2)
|
||||
|
||||
|
|
|
@ -52,7 +52,6 @@ def test_sanity():
|
|||
|
||||
def test_valueerror():
|
||||
with Image.open("Tests/images/chi.gif") as im:
|
||||
|
||||
draw = ImageDraw.Draw(im)
|
||||
draw.line((0, 0), fill=(0, 0, 0))
|
||||
|
||||
|
|
|
@ -30,7 +30,6 @@ SAFEBLOCK = ImageFile.SAFEBLOCK
|
|||
class TestImageFile:
|
||||
def test_parser(self):
|
||||
def roundtrip(format):
|
||||
|
||||
im = hopper("L").resize((1000, 1000), Image.Resampling.NEAREST)
|
||||
if format in ("MSP", "XBM"):
|
||||
im = im.convert("1")
|
||||
|
|
|
@ -21,7 +21,6 @@ deformer = Deformer()
|
|||
|
||||
|
||||
def test_sanity():
|
||||
|
||||
ImageOps.autocontrast(hopper("L"))
|
||||
ImageOps.autocontrast(hopper("RGB"))
|
||||
|
||||
|
@ -419,7 +418,6 @@ def test_autocontrast_cutoff():
|
|||
def test_autocontrast_mask_toy_input():
|
||||
# Test the mask argument of autocontrast
|
||||
with Image.open("Tests/images/bw_gradient.png") as img:
|
||||
|
||||
rect_mask = Image.new("L", img.size, 0)
|
||||
draw = ImageDraw.Draw(rect_mask)
|
||||
x0 = img.size[0] // 4
|
||||
|
@ -439,7 +437,6 @@ def test_autocontrast_mask_toy_input():
|
|||
def test_autocontrast_mask_real_input():
|
||||
# Test the autocontrast with a rectangular mask
|
||||
with Image.open("Tests/images/iptc.jpg") as img:
|
||||
|
||||
rect_mask = Image.new("L", img.size, 0)
|
||||
draw = ImageDraw.Draw(rect_mask)
|
||||
x0, y0 = img.size[0] // 2, img.size[1] // 2
|
||||
|
|
|
@ -6,7 +6,6 @@ from .helper import assert_image_equal, assert_image_equal_tofile
|
|||
|
||||
|
||||
def test_sanity():
|
||||
|
||||
palette = ImagePalette.ImagePalette("RGB", list(range(256)) * 3)
|
||||
assert len(palette.colors) == 256
|
||||
|
||||
|
@ -23,7 +22,6 @@ def test_reload():
|
|||
|
||||
|
||||
def test_getcolor():
|
||||
|
||||
palette = ImagePalette.ImagePalette()
|
||||
assert len(palette.palette) == 0
|
||||
assert len(palette.colors) == 0
|
||||
|
@ -84,7 +82,6 @@ def test_getcolor_not_special(index, palette):
|
|||
|
||||
|
||||
def test_file(tmp_path):
|
||||
|
||||
palette = ImagePalette.ImagePalette("RGB", list(range(256)) * 3)
|
||||
|
||||
f = str(tmp_path / "temp.lut")
|
||||
|
|
|
@ -8,7 +8,6 @@ from PIL import Image, ImagePath
|
|||
|
||||
|
||||
def test_path():
|
||||
|
||||
p = ImagePath.Path(list(range(10)))
|
||||
|
||||
# sequence interface
|
||||
|
|
|
@ -6,7 +6,6 @@ from .helper import assert_image_equal, hopper, skip_unless_feature
|
|||
|
||||
|
||||
def test_sanity(tmp_path):
|
||||
|
||||
test_file = str(tmp_path / "temp.im")
|
||||
|
||||
im = hopper("RGB")
|
||||
|
|
|
@ -6,7 +6,6 @@ from .helper import hopper
|
|||
|
||||
|
||||
def test_sanity():
|
||||
|
||||
im = hopper()
|
||||
|
||||
st = ImageStat.Stat(im)
|
||||
|
@ -31,7 +30,6 @@ def test_sanity():
|
|||
|
||||
|
||||
def test_hopper():
|
||||
|
||||
im = hopper()
|
||||
|
||||
st = ImageStat.Stat(im)
|
||||
|
@ -45,7 +43,6 @@ def test_hopper():
|
|||
|
||||
|
||||
def test_constant():
|
||||
|
||||
im = Image.new("L", (128, 128), 128)
|
||||
|
||||
st = ImageStat.Stat(im)
|
||||
|
|
|
@ -4,7 +4,6 @@ from PIL import Image
|
|||
|
||||
|
||||
def test_setmode():
|
||||
|
||||
im = Image.new("L", (1, 1), 255)
|
||||
im.im.setmode("1")
|
||||
assert im.im.getpixel((0, 0)) == 255
|
||||
|
|
|
@ -42,7 +42,6 @@ def test_basic(tmp_path, mode):
|
|||
im_in.save(filename)
|
||||
|
||||
with Image.open(filename) as im_out:
|
||||
|
||||
verify(im_in)
|
||||
verify(im_out)
|
||||
|
||||
|
@ -87,7 +86,6 @@ def test_tobytes():
|
|||
|
||||
|
||||
def test_convert():
|
||||
|
||||
im = original.copy()
|
||||
|
||||
verify(im.convert("I;16"))
|
||||
|
|
|
@ -235,7 +235,6 @@ def test_no_resource_warning_for_numpy_array():
|
|||
|
||||
test_file = "Tests/images/hopper.png"
|
||||
with Image.open(test_file) as im:
|
||||
|
||||
# Act/Assert
|
||||
with warnings.catch_warnings():
|
||||
array(im)
|
||||
|
|
|
@ -89,7 +89,6 @@ def test_pickle_la_mode_with_palette(tmp_path):
|
|||
def test_pickle_tell():
|
||||
# Arrange
|
||||
with Image.open("Tests/images/hopper.webp") as image:
|
||||
|
||||
# Act: roundtrip
|
||||
unpickled_image = pickle.loads(pickle.dumps(image))
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ with warnings.catch_warnings():
|
|||
warnings.simplefilter("ignore", category=DeprecationWarning)
|
||||
from PIL import ImageQt
|
||||
|
||||
from .helper import assert_image_equal, assert_image_equal_tofile, hopper
|
||||
from .helper import assert_image_equal_tofile, assert_image_similar, hopper
|
||||
|
||||
if ImageQt.qt_is_installed:
|
||||
from PIL.ImageQt import QPixmap
|
||||
|
@ -48,7 +48,7 @@ if ImageQt.qt_is_installed:
|
|||
def roundtrip(expected):
|
||||
result = ImageQt.fromqpixmap(ImageQt.toqpixmap(expected))
|
||||
# Qt saves all pixmaps as rgb
|
||||
assert_image_equal(result, expected.convert("RGB"))
|
||||
assert_image_similar(result, expected.convert("RGB"), 0.3)
|
||||
|
||||
|
||||
@pytest.mark.skipif(not ImageQt.qt_is_installed, reason="Qt bindings are not installed")
|
||||
|
|
|
@ -7,7 +7,6 @@ from .helper import hopper
|
|||
|
||||
|
||||
def _test_equal(num, denom, target):
|
||||
|
||||
t = IFDRational(num, denom)
|
||||
|
||||
assert target == t
|
||||
|
@ -15,7 +14,6 @@ def _test_equal(num, denom, target):
|
|||
|
||||
|
||||
def test_sanity():
|
||||
|
||||
_test_equal(1, 1, 1)
|
||||
_test_equal(1, 1, Fraction(1, 1))
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@ test_file = "Tests/images/hopper.webp"
|
|||
|
||||
@skip_unless_feature("webp")
|
||||
class TestWebPLeaks(PillowLeakTestCase):
|
||||
|
||||
mem_limit = 3 * 1024 # kb
|
||||
iterations = 100
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#!/bin/bash
|
||||
# install libimagequant
|
||||
|
||||
archive=libimagequant-4.0.4
|
||||
archive=libimagequant-4.1.0
|
||||
|
||||
./download-and-extract.sh $archive https://raw.githubusercontent.com/python-pillow/pillow-depends/main/$archive.tar.gz
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#!/bin/bash
|
||||
# install webp
|
||||
|
||||
archive=libwebp-1.2.4
|
||||
archive=libwebp-1.3.0
|
||||
|
||||
./download-and-extract.sh $archive https://raw.githubusercontent.com/python-pillow/pillow-depends/main/$archive.tar.gz
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ The Python Imaging Library (PIL) is
|
|||
|
||||
Pillow is the friendly PIL fork. It is
|
||||
|
||||
Copyright © 2010-2023 by Alex Clark and contributors
|
||||
Copyright © 2010-2023 by Jeffrey A. Clark (Alex) and contributors
|
||||
|
||||
Like PIL, Pillow is licensed under the open source PIL
|
||||
Software License:
|
||||
|
|
10
docs/conf.py
10
docs/conf.py
|
@ -52,8 +52,10 @@ master_doc = "index"
|
|||
|
||||
# General information about the project.
|
||||
project = "Pillow (PIL Fork)"
|
||||
copyright = "1995-2011 Fredrik Lundh, 2010-2023 Alex Clark and Contributors"
|
||||
author = "Fredrik Lundh, Alex Clark and Contributors"
|
||||
copyright = (
|
||||
"1995-2011 Fredrik Lundh, 2010-2023 Jeffrey A. Clark (Alex) and contributors"
|
||||
)
|
||||
author = "Fredrik Lundh, Jeffrey A. Clark (Alex), contributors"
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
|
@ -243,7 +245,7 @@ latex_documents = [
|
|||
master_doc,
|
||||
"PillowPILFork.tex",
|
||||
"Pillow (PIL Fork) Documentation",
|
||||
"Alex Clark",
|
||||
"Jeffrey A. Clark (Alex)",
|
||||
"manual",
|
||||
)
|
||||
]
|
||||
|
@ -293,7 +295,7 @@ texinfo_documents = [
|
|||
"Pillow (PIL Fork) Documentation",
|
||||
author,
|
||||
"PillowPILFork",
|
||||
"Pillow is the friendly PIL fork by Alex Clark and Contributors.",
|
||||
"Pillow is the friendly PIL fork by Jeffrey A. Clark (Alex) and contributors.",
|
||||
"Miscellaneous",
|
||||
)
|
||||
]
|
||||
|
|
|
@ -31,7 +31,7 @@ INT32 and a 32-bit floating point pixel has the range of FLOAT32. The current re
|
|||
supports the following standard modes:
|
||||
|
||||
* ``1`` (1-bit pixels, black and white, stored with one pixel per byte)
|
||||
* ``L`` (8-bit pixels, black and white)
|
||||
* ``L`` (8-bit pixels, grayscale)
|
||||
* ``P`` (8-bit pixels, mapped to any other mode using a color palette)
|
||||
* ``RGB`` (3x8-bit pixels, true color)
|
||||
* ``RGBA`` (4x8-bit pixels, true color with transparency mask)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
Pillow
|
||||
======
|
||||
|
||||
Pillow is the friendly PIL fork by `Alex Clark and Contributors <https://github.com/python-pillow/Pillow/graphs/contributors>`_. PIL is the Python Imaging Library by Fredrik Lundh and Contributors.
|
||||
Pillow is the friendly PIL fork by `Jeffrey A. Clark (Alex) and contributors <https://github.com/python-pillow/Pillow/graphs/contributors>`_. PIL is the Python Imaging Library by Fredrik Lundh and contributors.
|
||||
|
||||
Pillow for enterprise is available via the Tidelift Subscription. `Learn more <https://tidelift.com/subscription/pkg/pypi-pillow?utm_source=pypi-pillow&utm_medium=docs&utm_campaign=enterprise>`_.
|
||||
|
||||
|
|
|
@ -169,7 +169,7 @@ Many of Pillow's features require external libraries:
|
|||
|
||||
* **libimagequant** provides improved color quantization
|
||||
|
||||
* Pillow has been tested with libimagequant **2.6-4.0.4**
|
||||
* Pillow has been tested with libimagequant **2.6-4.1**
|
||||
* Libimagequant is licensed GPLv3, which is more restrictive than
|
||||
the Pillow license, therefore we will not be distributing binaries
|
||||
with libimagequant support enabled.
|
||||
|
|
|
@ -4,8 +4,8 @@ description = Python Imaging Library (Fork)
|
|||
long_description = file: README.md
|
||||
long_description_content_type = text/markdown
|
||||
url = https://python-pillow.org
|
||||
author = Alex Clark (PIL Fork Author)
|
||||
author_email = aclark@python-pillow.org
|
||||
author = Jeffrey A. Clark (Alex)
|
||||
author_email = aclark@aclark.net
|
||||
license = HPND
|
||||
classifiers =
|
||||
Development Status :: 6 - Mature
|
||||
|
|
28
setup.py
28
setup.py
|
@ -263,18 +263,18 @@ def _pkg_config(name):
|
|||
if not DEBUG:
|
||||
command_libs.append("--silence-errors")
|
||||
command_cflags.append("--silence-errors")
|
||||
libs = (
|
||||
libs = re.split(
|
||||
r"(^|\s+)-L",
|
||||
subprocess.check_output(command_libs, stderr=stderr)
|
||||
.decode("utf8")
|
||||
.strip()
|
||||
.replace("-L", "")
|
||||
)
|
||||
cflags = (
|
||||
subprocess.check_output(command_cflags)
|
||||
.strip(),
|
||||
)[::2][1:]
|
||||
cflags = re.split(
|
||||
r"(^|\s+)-I",
|
||||
subprocess.check_output(command_cflags, stderr=stderr)
|
||||
.decode("utf8")
|
||||
.strip()
|
||||
.replace("-I", "")
|
||||
)
|
||||
.strip(),
|
||||
)[::2][1:]
|
||||
return libs, cflags
|
||||
except Exception:
|
||||
pass
|
||||
|
@ -430,7 +430,6 @@ class pil_build_ext(build_ext):
|
|||
return sdk_path
|
||||
|
||||
def build_extensions(self):
|
||||
|
||||
library_dirs = []
|
||||
include_dirs = []
|
||||
|
||||
|
@ -473,8 +472,12 @@ class pil_build_ext(build_ext):
|
|||
else:
|
||||
lib_root = include_root = root
|
||||
|
||||
_add_directory(library_dirs, lib_root)
|
||||
_add_directory(include_dirs, include_root)
|
||||
if lib_root is not None:
|
||||
for lib_dir in lib_root:
|
||||
_add_directory(library_dirs, lib_dir)
|
||||
if include_root is not None:
|
||||
for include_dir in include_root:
|
||||
_add_directory(include_dirs, include_dir)
|
||||
|
||||
# respect CFLAGS/CPPFLAGS/LDFLAGS
|
||||
for k in ("CFLAGS", "CPPFLAGS", "LDFLAGS"):
|
||||
|
@ -913,7 +916,6 @@ class pil_build_ext(build_ext):
|
|||
self.summary_report(feature)
|
||||
|
||||
def summary_report(self, feature):
|
||||
|
||||
print("-" * 68)
|
||||
print("PIL SETUP SUMMARY")
|
||||
print("-" * 68)
|
||||
|
|
|
@ -223,7 +223,6 @@ class BmpImageFile(ImageFile.ImageFile):
|
|||
|
||||
# --------------- Once the header is processed, process the palette/LUT
|
||||
if self.mode == "P": # Paletted for 1, 4 and 8 bit images
|
||||
|
||||
# ---------------------------------------------------- 1-bit images
|
||||
if not (0 < file_info["colors"] <= 65536):
|
||||
msg = f"Unsupported BMP Palette size ({file_info['colors']})"
|
||||
|
@ -360,7 +359,6 @@ class BmpRleDecoder(ImageFile.PyDecoder):
|
|||
# Image plugin for the DIB format (BMP alias)
|
||||
# =============================================================================
|
||||
class DibImageFile(BmpImageFile):
|
||||
|
||||
format = "DIB"
|
||||
format_description = "Windows Bitmap"
|
||||
|
||||
|
|
|
@ -33,12 +33,10 @@ def _accept(prefix):
|
|||
|
||||
|
||||
class BufrStubImageFile(ImageFile.StubImageFile):
|
||||
|
||||
format = "BUFR"
|
||||
format_description = "BUFR"
|
||||
|
||||
def _open(self):
|
||||
|
||||
offset = self.fp.tell()
|
||||
|
||||
if not _accept(self.fp.read(4)):
|
||||
|
|
|
@ -32,12 +32,10 @@ def _accept(prefix):
|
|||
|
||||
|
||||
class CurImageFile(BmpImagePlugin.BmpImageFile):
|
||||
|
||||
format = "CUR"
|
||||
format_description = "Windows Cursor"
|
||||
|
||||
def _open(self):
|
||||
|
||||
offset = self.fp.tell()
|
||||
|
||||
# check magic
|
||||
|
|
|
@ -37,13 +37,11 @@ def _accept(prefix):
|
|||
|
||||
|
||||
class DcxImageFile(PcxImageFile):
|
||||
|
||||
format = "DCX"
|
||||
format_description = "Intel DCX"
|
||||
_close_exclusive_fp_after_loading = False
|
||||
|
||||
def _open(self):
|
||||
|
||||
# Header
|
||||
s = self.fp.read(4)
|
||||
if not _accept(s):
|
||||
|
|
|
@ -19,7 +19,6 @@ def _accept(prefix):
|
|||
|
||||
|
||||
class FitsImageFile(ImageFile.ImageFile):
|
||||
|
||||
format = "FITS"
|
||||
format_description = "FITS"
|
||||
|
||||
|
|
|
@ -44,7 +44,6 @@ def register_handler(handler):
|
|||
|
||||
|
||||
class FITSStubImageFile(ImageFile.StubImageFile):
|
||||
|
||||
format = FitsImagePlugin.FitsImageFile.format
|
||||
format_description = FitsImagePlugin.FitsImageFile.format_description
|
||||
|
||||
|
|
|
@ -40,13 +40,11 @@ def _accept(prefix):
|
|||
|
||||
|
||||
class FliImageFile(ImageFile.ImageFile):
|
||||
|
||||
format = "FLI"
|
||||
format_description = "Autodesk FLI/FLC Animation"
|
||||
_close_exclusive_fp_after_loading = False
|
||||
|
||||
def _open(self):
|
||||
|
||||
# HEAD
|
||||
s = self.fp.read(128)
|
||||
if not (_accept(s) and s[20:22] == b"\x00\x00"):
|
||||
|
|
|
@ -36,7 +36,6 @@ class FontFile:
|
|||
bitmap = None
|
||||
|
||||
def __init__(self):
|
||||
|
||||
self.info = {}
|
||||
self.glyph = [None] * 256
|
||||
|
||||
|
|
|
@ -48,7 +48,6 @@ def _accept(prefix):
|
|||
|
||||
|
||||
class FpxImageFile(ImageFile.ImageFile):
|
||||
|
||||
format = "FPX"
|
||||
format_description = "FlashPix"
|
||||
|
||||
|
@ -157,7 +156,6 @@ class FpxImageFile(ImageFile.ImageFile):
|
|||
self.tile = []
|
||||
|
||||
for i in range(0, len(s), length):
|
||||
|
||||
x1 = min(xsize, x + xtile)
|
||||
y1 = min(ysize, y + ytile)
|
||||
|
||||
|
@ -174,7 +172,6 @@ class FpxImageFile(ImageFile.ImageFile):
|
|||
)
|
||||
|
||||
elif compression == 1:
|
||||
|
||||
# FIXME: the fill decoder is not implemented
|
||||
self.tile.append(
|
||||
(
|
||||
|
@ -186,7 +183,6 @@ class FpxImageFile(ImageFile.ImageFile):
|
|||
)
|
||||
|
||||
elif compression == 2:
|
||||
|
||||
internal_color_conversion = s[14]
|
||||
jpeg_tables = s[15]
|
||||
rawmode = self.rawmode
|
||||
|
@ -234,7 +230,6 @@ class FpxImageFile(ImageFile.ImageFile):
|
|||
self.fp = None
|
||||
|
||||
def load(self):
|
||||
|
||||
if not self.fp:
|
||||
self.fp = self.ole.openstream(self.stream[:2] + ["Subimage 0000 Data"])
|
||||
|
||||
|
|
|
@ -37,7 +37,6 @@ def _accept(prefix):
|
|||
|
||||
|
||||
class GbrImageFile(ImageFile.ImageFile):
|
||||
|
||||
format = "GBR"
|
||||
format_description = "GIMP brush file"
|
||||
|
||||
|
|
|
@ -44,7 +44,6 @@ class GdImageFile(ImageFile.ImageFile):
|
|||
format_description = "GD uncompressed images"
|
||||
|
||||
def _open(self):
|
||||
|
||||
# Header
|
||||
s = self.fp.read(1037)
|
||||
|
||||
|
|
|
@ -61,7 +61,6 @@ def _accept(prefix):
|
|||
|
||||
|
||||
class GifImageFile(ImageFile.ImageFile):
|
||||
|
||||
format = "GIF"
|
||||
format_description = "Compuserve GIF"
|
||||
_close_exclusive_fp_after_loading = False
|
||||
|
@ -81,7 +80,6 @@ class GifImageFile(ImageFile.ImageFile):
|
|||
return False
|
||||
|
||||
def _open(self):
|
||||
|
||||
# Screen
|
||||
s = self.fp.read(13)
|
||||
if not _accept(s):
|
||||
|
@ -157,7 +155,6 @@ class GifImageFile(ImageFile.ImageFile):
|
|||
raise EOFError(msg) from e
|
||||
|
||||
def _seek(self, frame, update_image=True):
|
||||
|
||||
if frame == 0:
|
||||
# rewind
|
||||
self.__offset = 0
|
||||
|
@ -195,7 +192,6 @@ class GifImageFile(ImageFile.ImageFile):
|
|||
interlace = None
|
||||
frame_dispose_extent = None
|
||||
while True:
|
||||
|
||||
if not s:
|
||||
s = self.fp.read(1)
|
||||
if not s or s == b";":
|
||||
|
@ -579,7 +575,6 @@ def _getbbox(base_im, im_frame):
|
|||
|
||||
|
||||
def _write_multiple_frames(im, fp, palette):
|
||||
|
||||
duration = im.encoderinfo.get("duration")
|
||||
disposal = im.encoderinfo.get("disposal", im.info.get("disposal"))
|
||||
|
||||
|
@ -752,7 +747,6 @@ def _write_local_header(fp, im, offset, flags):
|
|||
|
||||
|
||||
def _save_netpbm(im, fp, filename):
|
||||
|
||||
# Unused by default.
|
||||
# To use, uncomment the register_save call at the end of the file.
|
||||
#
|
||||
|
|
|
@ -64,18 +64,15 @@ SEGMENTS = [linear, curved, sine, sphere_increasing, sphere_decreasing]
|
|||
|
||||
|
||||
class GradientFile:
|
||||
|
||||
gradient = None
|
||||
|
||||
def getpalette(self, entries=256):
|
||||
|
||||
palette = []
|
||||
|
||||
ix = 0
|
||||
x0, x1, xm, rgb0, rgb1, segment = self.gradient[ix]
|
||||
|
||||
for i in range(entries):
|
||||
|
||||
x = i / (entries - 1)
|
||||
|
||||
while x1 < x:
|
||||
|
@ -105,7 +102,6 @@ class GimpGradientFile(GradientFile):
|
|||
"""File handler for GIMP's gradient format."""
|
||||
|
||||
def __init__(self, fp):
|
||||
|
||||
if fp.readline()[:13] != b"GIMP Gradient":
|
||||
msg = "not a GIMP gradient file"
|
||||
raise SyntaxError(msg)
|
||||
|
@ -121,7 +117,6 @@ class GimpGradientFile(GradientFile):
|
|||
gradient = []
|
||||
|
||||
for i in range(count):
|
||||
|
||||
s = fp.readline().split()
|
||||
w = [float(x) for x in s[:11]]
|
||||
|
||||
|
|
|
@ -25,7 +25,6 @@ class GimpPaletteFile:
|
|||
rawmode = "RGB"
|
||||
|
||||
def __init__(self, fp):
|
||||
|
||||
self.palette = [o8(i) * 3 for i in range(256)]
|
||||
|
||||
if fp.readline()[:12] != b"GIMP Palette":
|
||||
|
@ -33,7 +32,6 @@ class GimpPaletteFile:
|
|||
raise SyntaxError(msg)
|
||||
|
||||
for i in range(256):
|
||||
|
||||
s = fp.readline()
|
||||
if not s:
|
||||
break
|
||||
|
@ -55,5 +53,4 @@ class GimpPaletteFile:
|
|||
self.palette = b"".join(self.palette)
|
||||
|
||||
def getpalette(self):
|
||||
|
||||
return self.palette, self.rawmode
|
||||
|
|
|
@ -33,12 +33,10 @@ def _accept(prefix):
|
|||
|
||||
|
||||
class GribStubImageFile(ImageFile.StubImageFile):
|
||||
|
||||
format = "GRIB"
|
||||
format_description = "GRIB"
|
||||
|
||||
def _open(self):
|
||||
|
||||
offset = self.fp.tell()
|
||||
|
||||
if not _accept(self.fp.read(8)):
|
||||
|
|
|
@ -33,12 +33,10 @@ def _accept(prefix):
|
|||
|
||||
|
||||
class HDF5StubImageFile(ImageFile.StubImageFile):
|
||||
|
||||
format = "HDF5"
|
||||
format_description = "HDF5"
|
||||
|
||||
def _open(self):
|
||||
|
||||
offset = self.fp.tell()
|
||||
|
||||
if not _accept(self.fp.read(8)):
|
||||
|
|
|
@ -135,7 +135,6 @@ def read_png_or_jpeg2000(fobj, start_length, size):
|
|||
|
||||
|
||||
class IcnsFile:
|
||||
|
||||
SIZES = {
|
||||
(512, 512, 2): [(b"ic10", read_png_or_jpeg2000)],
|
||||
(512, 512, 1): [(b"ic09", read_png_or_jpeg2000)],
|
||||
|
@ -189,7 +188,7 @@ class IcnsFile:
|
|||
def itersizes(self):
|
||||
sizes = []
|
||||
for size, fmts in self.SIZES.items():
|
||||
for (fmt, reader) in fmts:
|
||||
for fmt, reader in fmts:
|
||||
if fmt in self.dct:
|
||||
sizes.append(size)
|
||||
break
|
||||
|
|
|
@ -185,7 +185,7 @@ class IcoFile:
|
|||
return {(h["width"], h["height"]) for h in self.entry}
|
||||
|
||||
def getentryindex(self, size, bpp=False):
|
||||
for (i, h) in enumerate(self.entry):
|
||||
for i, h in enumerate(self.entry):
|
||||
if size == h["dim"] and (bpp is False or bpp == h["color_depth"]):
|
||||
return i
|
||||
return 0
|
||||
|
|
|
@ -115,13 +115,11 @@ def number(s):
|
|||
|
||||
|
||||
class ImImageFile(ImageFile.ImageFile):
|
||||
|
||||
format = "IM"
|
||||
format_description = "IFUNC Image Memory"
|
||||
_close_exclusive_fp_after_loading = False
|
||||
|
||||
def _open(self):
|
||||
|
||||
# Quick rejection: if there's not an LF among the first
|
||||
# 100 bytes, this is (probably) not a text header.
|
||||
|
||||
|
@ -140,7 +138,6 @@ class ImImageFile(ImageFile.ImageFile):
|
|||
self.rawmode = "L"
|
||||
|
||||
while True:
|
||||
|
||||
s = self.fp.read(1)
|
||||
|
||||
# Some versions of IFUNC uses \n\r instead of \r\n...
|
||||
|
@ -169,7 +166,6 @@ class ImImageFile(ImageFile.ImageFile):
|
|||
raise SyntaxError(msg) from e
|
||||
|
||||
if m:
|
||||
|
||||
k, v = m.group(1, 2)
|
||||
|
||||
# Don't know if this is the correct encoding,
|
||||
|
@ -200,7 +196,6 @@ class ImImageFile(ImageFile.ImageFile):
|
|||
n += 1
|
||||
|
||||
else:
|
||||
|
||||
msg = "Syntax error in IM header: " + s.decode("ascii", "replace")
|
||||
raise SyntaxError(msg)
|
||||
|
||||
|
@ -252,7 +247,6 @@ class ImImageFile(ImageFile.ImageFile):
|
|||
self._fp = self.fp # FIXME: hack
|
||||
|
||||
if self.rawmode[:2] == "F;":
|
||||
|
||||
# ifunc95 formats
|
||||
try:
|
||||
# use bit decoder (if necessary)
|
||||
|
@ -332,7 +326,6 @@ SAVE = {
|
|||
|
||||
|
||||
def _save(im, fp, filename):
|
||||
|
||||
try:
|
||||
image_type, rawmode = SAVE[im.mode]
|
||||
except KeyError as e:
|
||||
|
|
|
@ -153,6 +153,7 @@ def isImageType(t):
|
|||
#
|
||||
# Constants
|
||||
|
||||
|
||||
# transpose
|
||||
class Transpose(IntEnum):
|
||||
FLIP_LEFT_RIGHT = 0
|
||||
|
@ -391,7 +392,6 @@ def init():
|
|||
|
||||
|
||||
def _getdecoder(mode, decoder_name, args, extra=()):
|
||||
|
||||
# tweak arguments
|
||||
if args is None:
|
||||
args = ()
|
||||
|
@ -415,7 +415,6 @@ def _getdecoder(mode, decoder_name, args, extra=()):
|
|||
|
||||
|
||||
def _getencoder(mode, encoder_name, args, extra=()):
|
||||
|
||||
# tweak arguments
|
||||
if args is None:
|
||||
args = ()
|
||||
|
@ -3267,9 +3266,15 @@ def open(fp, mode="r", formats=None):
|
|||
|
||||
im = _open_core(fp, filename, prefix, formats)
|
||||
|
||||
if im is None:
|
||||
if im is None and formats is ID:
|
||||
checked_formats = formats.copy()
|
||||
if init():
|
||||
im = _open_core(fp, filename, prefix, formats)
|
||||
im = _open_core(
|
||||
fp,
|
||||
filename,
|
||||
prefix,
|
||||
tuple(format for format in formats if format not in checked_formats),
|
||||
)
|
||||
|
||||
if im:
|
||||
im._exclusive_fp = exclusive_fp
|
||||
|
@ -3400,7 +3405,8 @@ def register_open(id, factory, accept=None):
|
|||
reject images having another format.
|
||||
"""
|
||||
id = id.upper()
|
||||
ID.append(id)
|
||||
if id not in ID:
|
||||
ID.append(id)
|
||||
OPEN[id] = factory, accept
|
||||
|
||||
|
||||
|
|
|
@ -928,8 +928,8 @@ def floodfill(image, xy, value, border=None, thresh=0):
|
|||
full_edge = set()
|
||||
while edge:
|
||||
new_edge = set()
|
||||
for (x, y) in edge: # 4 adjacent method
|
||||
for (s, t) in ((x + 1, y), (x - 1, y), (x, y + 1), (x, y - 1)):
|
||||
for x, y in edge: # 4 adjacent method
|
||||
for s, t in ((x + 1, y), (x - 1, y), (x, y + 1), (x, y - 1)):
|
||||
# If already processed, or if a coordinate is negative, skip
|
||||
if (s, t) in full_edge or s < 0 or t < 0:
|
||||
continue
|
||||
|
|
|
@ -395,7 +395,6 @@ class Parser:
|
|||
|
||||
# parse what we have
|
||||
if self.decoder:
|
||||
|
||||
if self.offset > 0:
|
||||
# skip header
|
||||
skip = min(len(self.data), self.offset)
|
||||
|
@ -420,14 +419,12 @@ class Parser:
|
|||
self.data = self.data[n:]
|
||||
|
||||
elif self.image:
|
||||
|
||||
# if we end up here with no decoder, this file cannot
|
||||
# be incrementally parsed. wait until we've gotten all
|
||||
# available data
|
||||
pass
|
||||
|
||||
else:
|
||||
|
||||
# attempt to open this file
|
||||
try:
|
||||
with io.BytesIO(self.data) as fp:
|
||||
|
|
|
@ -90,7 +90,6 @@ class ImageFont:
|
|||
"""PIL font wrapper"""
|
||||
|
||||
def _load_pilfont(self, filename):
|
||||
|
||||
with open(filename, "rb") as fp:
|
||||
image = None
|
||||
for ext in (".png", ".gif", ".pbm"):
|
||||
|
@ -116,7 +115,6 @@ class ImageFont:
|
|||
image.close()
|
||||
|
||||
def _load_pilfont_data(self, file, image):
|
||||
|
||||
# read PILfont header
|
||||
if file.readline() != b"PILfont\n":
|
||||
msg = "Not a PILfont file"
|
||||
|
|
|
@ -205,7 +205,6 @@ def colorize(image, black, white, mid=None, blackpoint=0, whitepoint=255, midpoi
|
|||
|
||||
# Create the mapping (2-color)
|
||||
if mid is None:
|
||||
|
||||
range_map = range(0, whitepoint - blackpoint)
|
||||
|
||||
for i in range_map:
|
||||
|
@ -215,7 +214,6 @@ def colorize(image, black, white, mid=None, blackpoint=0, whitepoint=255, midpoi
|
|||
|
||||
# Create the mapping (3-color)
|
||||
else:
|
||||
|
||||
range_map1 = range(0, midpoint - blackpoint)
|
||||
range_map2 = range(0, whitepoint - midpoint)
|
||||
|
||||
|
|
|
@ -248,11 +248,9 @@ def wedge(mode="RGB"):
|
|||
|
||||
|
||||
def load(filename):
|
||||
|
||||
# FIXME: supports GIMP gradients only
|
||||
|
||||
with open(filename, "rb") as fp:
|
||||
|
||||
for paletteHandler in [
|
||||
GimpPaletteFile.GimpPaletteFile,
|
||||
GimpGradientFile.GimpGradientFile,
|
||||
|
|
|
@ -390,7 +390,6 @@ else:
|
|||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
print("Syntax: python3 ImageShow.py imagefile [title]")
|
||||
sys.exit()
|
||||
|
|
|
@ -97,7 +97,6 @@ class PhotoImage:
|
|||
"""
|
||||
|
||||
def __init__(self, image=None, size=None, **kw):
|
||||
|
||||
# Tk compatibility: file or data
|
||||
if image is None:
|
||||
image = _get_image_from_kw(kw)
|
||||
|
@ -209,7 +208,6 @@ class BitmapImage:
|
|||
"""
|
||||
|
||||
def __init__(self, image=None, **kw):
|
||||
|
||||
# Tk compatibility: file or data
|
||||
if image is None:
|
||||
image = _get_image_from_kw(kw)
|
||||
|
|
|
@ -30,12 +30,10 @@ field = re.compile(rb"([a-z]*) ([^ \r\n]*)")
|
|||
|
||||
|
||||
class ImtImageFile(ImageFile.ImageFile):
|
||||
|
||||
format = "IMT"
|
||||
format_description = "IM Tools"
|
||||
|
||||
def _open(self):
|
||||
|
||||
# Quick rejection: if there's not a LF among the first
|
||||
# 100 bytes, this is (probably) not a text header.
|
||||
|
||||
|
@ -47,7 +45,6 @@ class ImtImageFile(ImageFile.ImageFile):
|
|||
xsize = ysize = 0
|
||||
|
||||
while True:
|
||||
|
||||
if buffer:
|
||||
s = buffer[:1]
|
||||
buffer = buffer[1:]
|
||||
|
@ -57,7 +54,6 @@ class ImtImageFile(ImageFile.ImageFile):
|
|||
break
|
||||
|
||||
if s == b"\x0C":
|
||||
|
||||
# image data begins
|
||||
self.tile = [
|
||||
(
|
||||
|
@ -71,7 +67,6 @@ class ImtImageFile(ImageFile.ImageFile):
|
|||
break
|
||||
|
||||
else:
|
||||
|
||||
# read key/value pair
|
||||
if b"\n" not in buffer:
|
||||
buffer += self.fp.read(100)
|
||||
|
|
|
@ -48,7 +48,6 @@ def dump(c):
|
|||
|
||||
|
||||
class IptcImageFile(ImageFile.ImageFile):
|
||||
|
||||
format = "IPTC"
|
||||
format_description = "IPTC/NAA"
|
||||
|
||||
|
@ -84,7 +83,6 @@ class IptcImageFile(ImageFile.ImageFile):
|
|||
return tag, size
|
||||
|
||||
def _open(self):
|
||||
|
||||
# load descriptive fields
|
||||
while True:
|
||||
offset = self.fp.tell()
|
||||
|
@ -134,7 +132,6 @@ class IptcImageFile(ImageFile.ImageFile):
|
|||
]
|
||||
|
||||
def load(self):
|
||||
|
||||
if len(self.tile) != 1 or self.tile[0][0] != "iptc":
|
||||
return ImageFile.ImageFile.load(self)
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ import sys
|
|||
import tempfile
|
||||
import warnings
|
||||
|
||||
from . import Image, ImageFile, TiffImagePlugin
|
||||
from . import Image, ImageFile
|
||||
from ._binary import i16be as i16
|
||||
from ._binary import i32be as i32
|
||||
from ._binary import o8
|
||||
|
@ -344,12 +344,10 @@ def _accept(prefix):
|
|||
|
||||
|
||||
class JpegImageFile(ImageFile.ImageFile):
|
||||
|
||||
format = "JPEG"
|
||||
format_description = "JPEG (ISO 10918)"
|
||||
|
||||
def _open(self):
|
||||
|
||||
s = self.fp.read(3)
|
||||
|
||||
if not _accept(s):
|
||||
|
@ -370,7 +368,6 @@ class JpegImageFile(ImageFile.ImageFile):
|
|||
self.icclist = []
|
||||
|
||||
while True:
|
||||
|
||||
i = s[0]
|
||||
if i == 0xFF:
|
||||
s = s + self.fp.read(1)
|
||||
|
@ -418,7 +415,6 @@ class JpegImageFile(ImageFile.ImageFile):
|
|||
return s
|
||||
|
||||
def draft(self, mode, size):
|
||||
|
||||
if len(self.tile) != 1:
|
||||
return
|
||||
|
||||
|
@ -455,7 +451,6 @@ class JpegImageFile(ImageFile.ImageFile):
|
|||
return self.mode, box
|
||||
|
||||
def load_djpeg(self):
|
||||
|
||||
# ALTERNATIVE: handle JPEGs via the IJG command line utilities
|
||||
|
||||
f, path = tempfile.mkstemp()
|
||||
|
@ -524,6 +519,8 @@ def _getmp(self):
|
|||
head = file_contents.read(8)
|
||||
endianness = ">" if head[:4] == b"\x4d\x4d\x00\x2a" else "<"
|
||||
# process dictionary
|
||||
from . import TiffImagePlugin
|
||||
|
||||
try:
|
||||
info = TiffImagePlugin.ImageFileDirectory_v2(head)
|
||||
file_contents.seek(info.next)
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user