mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-12-24 17:06:16 +03:00
Merge branch 'main' into version_bump
This commit is contained in:
commit
54fddf0181
|
@ -13,7 +13,7 @@ environment:
|
|||
- PYTHON: C:/Python311
|
||||
ARCHITECTURE: x86
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022
|
||||
- PYTHON: C:/Python37-x64
|
||||
- PYTHON: C:/Python38-x64
|
||||
ARCHITECTURE: x64
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
|
||||
|
@ -31,7 +31,7 @@ install:
|
|||
- path c:\nasm-2.15.05;C:\Program Files\gs\gs10.00.0\bin;%PATH%
|
||||
- cd c:\pillow\winbuild\
|
||||
- ps: |
|
||||
c:\python37\python.exe c:\pillow\winbuild\build_prepare.py -v --depends=C:\pillow-depends\
|
||||
c:\python38\python.exe c:\pillow\winbuild\build_prepare.py -v --depends=C:\pillow-depends\
|
||||
c:\pillow\winbuild\build\build_dep_all.cmd
|
||||
$host.SetShouldExit(0)
|
||||
- path C:\pillow\winbuild\build\bin;%PATH%
|
||||
|
|
|
@ -43,7 +43,7 @@ if [[ $(uname) != CYGWIN* ]]; then
|
|||
# PyQt6 doesn't support PyPy3
|
||||
if [[ $GHA_PYTHON_VERSION == 3.* ]]; then
|
||||
sudo apt-get -qq install libegl1 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-shape0 libxkbcommon-x11-0
|
||||
python3 -m pip install pyqt6
|
||||
python3 -m pip install pyqt6 PyQt6-Qt6!=6.5.0
|
||||
fi
|
||||
|
||||
# webp
|
||||
|
|
1
.github/workflows/test-cygwin.yml
vendored
1
.github/workflows/test-cygwin.yml
vendored
|
@ -67,7 +67,6 @@ jobs:
|
|||
python3${{ matrix.python-minor-version }}-numpy
|
||||
python3${{ matrix.python-minor-version }}-sip
|
||||
python3${{ matrix.python-minor-version }}-tkinter
|
||||
qt5-devel-tools
|
||||
wget
|
||||
xorg-server-extra
|
||||
zlib-devel
|
||||
|
|
2
.github/workflows/test-windows.yml
vendored
2
.github/workflows/test-windows.yml
vendored
|
@ -24,7 +24,7 @@ jobs:
|
|||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12-dev"]
|
||||
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12-dev"]
|
||||
architecture: ["x86", "x64"]
|
||||
include:
|
||||
# PyPy 7.3.4+ only ships 64-bit binaries for Windows
|
||||
|
|
3
.github/workflows/test.yml
vendored
3
.github/workflows/test.yml
vendored
|
@ -36,10 +36,9 @@ jobs:
|
|||
"3.10",
|
||||
"3.9",
|
||||
"3.8",
|
||||
"3.7",
|
||||
]
|
||||
include:
|
||||
- python-version: "3.7"
|
||||
- python-version: "3.9"
|
||||
PYTHONOPTIMIZE: 1
|
||||
REVERSE: "--reverse"
|
||||
- python-version: "3.8"
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
repos:
|
||||
- repo: https://github.com/psf/black
|
||||
rev: 23.1.0
|
||||
rev: 23.3.0
|
||||
hooks:
|
||||
- id: black
|
||||
args: [--target-version=py37]
|
||||
args: [--target-version=py38]
|
||||
# Only .py files, until https://github.com/psf/black/issues/402 resolved
|
||||
files: \.py$
|
||||
types: []
|
||||
|
@ -14,7 +14,7 @@ repos:
|
|||
- id: isort
|
||||
|
||||
- repo: https://github.com/PyCQA/bandit
|
||||
rev: 1.7.4
|
||||
rev: 1.7.5
|
||||
hooks:
|
||||
- id: bandit
|
||||
args: [--severity-level=high]
|
||||
|
@ -26,10 +26,10 @@ repos:
|
|||
- id: yesqa
|
||||
|
||||
- repo: https://github.com/Lucas-C/pre-commit-hooks
|
||||
rev: v1.4.2
|
||||
rev: v1.5.1
|
||||
hooks:
|
||||
- id: remove-tabs
|
||||
exclude: (Makefile$|\.bat$|\.cmake$|\.eps$|\.fits$|\.opt$)
|
||||
exclude: (Makefile$|\.bat$|\.cmake$|\.eps$|\.fits$|\.gd$|\.opt$)
|
||||
|
||||
- repo: https://github.com/PyCQA/flake8
|
||||
rev: 6.0.0
|
||||
|
@ -57,7 +57,7 @@ repos:
|
|||
- id: sphinx-lint
|
||||
|
||||
- repo: https://github.com/tox-dev/tox-ini-fmt
|
||||
rev: 0.6.1
|
||||
rev: 1.0.0
|
||||
hooks:
|
||||
- id: tox-ini-fmt
|
||||
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
version: 2
|
||||
|
||||
build:
|
||||
os: ubuntu-22.04
|
||||
tools:
|
||||
python: "3.11"
|
||||
|
||||
python:
|
||||
install:
|
||||
- method: pip
|
||||
|
|
|
@ -2,6 +2,15 @@
|
|||
Changelog (Pillow)
|
||||
==================
|
||||
|
||||
10.0.0 (unreleased)
|
||||
-------------------
|
||||
|
||||
- Remove deprecations for Pillow 10.0.0 #7059
|
||||
[hugovk, radarhere]
|
||||
|
||||
- Drop support for soon-EOL Python 3.7 #7058
|
||||
[hugovk, radarhere]
|
||||
|
||||
9.5.0 (2023-04-01)
|
||||
------------------
|
||||
|
||||
|
|
3
Makefile
3
Makefile
|
@ -78,6 +78,7 @@ debug:
|
|||
|
||||
.PHONY: release-test
|
||||
release-test:
|
||||
python3 Tests/check_release_notes.py
|
||||
python3 -m pip install -e .[tests]
|
||||
python3 selftest.py
|
||||
python3 -m pytest Tests
|
||||
|
@ -123,5 +124,5 @@ lint:
|
|||
lint-fix:
|
||||
python3 -c "import black" > /dev/null 2>&1 || python3 -m pip install black
|
||||
python3 -c "import isort" > /dev/null 2>&1 || python3 -m pip install isort
|
||||
python3 -m black --target-version py37 .
|
||||
python3 -m black --target-version py38 .
|
||||
python3 -m isort .
|
||||
|
|
6
Tests/check_release_notes.py
Normal file
6
Tests/check_release_notes.py
Normal file
|
@ -0,0 +1,6 @@
|
|||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
for rst in Path("docs/releasenotes").glob("[1-9]*.rst"):
|
||||
if "TODO" in open(rst).read():
|
||||
sys.exit(f"Error: remove TODO from {rst}")
|
|
@ -6,11 +6,6 @@ from PIL import _deprecate
|
|||
@pytest.mark.parametrize(
|
||||
"version, expected",
|
||||
[
|
||||
(
|
||||
10,
|
||||
"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 "
|
||||
|
@ -57,18 +52,18 @@ def test_old_version(deprecated, plural, expected):
|
|||
|
||||
def test_plural():
|
||||
expected = (
|
||||
r"Old things are deprecated and will be removed in Pillow 10 \(2023-07-01\)\. "
|
||||
r"Old things are deprecated and will be removed in Pillow 11 \(2024-10-15\)\. "
|
||||
r"Use new thing instead\."
|
||||
)
|
||||
with pytest.warns(DeprecationWarning, match=expected):
|
||||
_deprecate.deprecate("Old things", 10, "new thing", plural=True)
|
||||
_deprecate.deprecate("Old things", 11, "new thing", plural=True)
|
||||
|
||||
|
||||
def test_replacement_and_action():
|
||||
expected = "Use only one of 'replacement' and 'action'"
|
||||
with pytest.raises(ValueError, match=expected):
|
||||
_deprecate.deprecate(
|
||||
"Old thing", 10, replacement="new thing", action="Upgrade to new thing"
|
||||
"Old thing", 11, replacement="new thing", action="Upgrade to new thing"
|
||||
)
|
||||
|
||||
|
||||
|
@ -81,16 +76,16 @@ def test_replacement_and_action():
|
|||
)
|
||||
def test_action(action):
|
||||
expected = (
|
||||
r"Old thing is deprecated and will be removed in Pillow 10 \(2023-07-01\)\. "
|
||||
r"Old thing is deprecated and will be removed in Pillow 11 \(2024-10-15\)\. "
|
||||
r"Upgrade to new thing\."
|
||||
)
|
||||
with pytest.warns(DeprecationWarning, match=expected):
|
||||
_deprecate.deprecate("Old thing", 10, action=action)
|
||||
_deprecate.deprecate("Old thing", 11, action=action)
|
||||
|
||||
|
||||
def test_no_replacement_or_action():
|
||||
expected = (
|
||||
r"Old thing is deprecated and will be removed in Pillow 10 \(2023-07-01\)"
|
||||
r"Old thing is deprecated and will be removed in Pillow 11 \(2024-10-15\)"
|
||||
)
|
||||
with pytest.warns(DeprecationWarning, match=expected):
|
||||
_deprecate.deprecate("Old thing", 10)
|
||||
_deprecate.deprecate("Old thing", 11)
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
import warnings
|
||||
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
# Arrange: cause all warnings to always be triggered
|
||||
warnings.simplefilter("always")
|
||||
|
||||
# Act: trigger a warning with Qt5
|
||||
from PIL import ImageQt
|
||||
|
||||
|
||||
def test_deprecated():
|
||||
# Assert
|
||||
if ImageQt.qt_version in ("5", "side2"):
|
||||
assert len(w) == 1
|
||||
assert issubclass(w[0].category, DeprecationWarning)
|
||||
assert "deprecated" in str(w[0].message)
|
||||
else:
|
||||
assert len(w) == 0
|
|
@ -655,13 +655,3 @@ def test_different_modes_in_later_frames(mode, tmp_path):
|
|||
im.save(test_file, save_all=True, append_images=[Image.new(mode, (1, 1))])
|
||||
with Image.open(test_file) as reloaded:
|
||||
assert reloaded.mode == mode
|
||||
|
||||
|
||||
def test_constants_deprecation():
|
||||
for enum, prefix in {
|
||||
PngImagePlugin.Disposal: "APNG_DISPOSE_",
|
||||
PngImagePlugin.Blend: "APNG_BLEND_",
|
||||
}.items():
|
||||
for name in enum.__members__:
|
||||
with pytest.warns(DeprecationWarning):
|
||||
assert getattr(PngImagePlugin, prefix + name) == enum[name]
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import pytest
|
||||
|
||||
from PIL import BlpImagePlugin, Image
|
||||
from PIL import Image
|
||||
|
||||
from .helper import (
|
||||
assert_image_equal,
|
||||
|
@ -72,14 +72,3 @@ def test_crashes(test_file):
|
|||
with Image.open(f) as im:
|
||||
with pytest.raises(OSError):
|
||||
im.load()
|
||||
|
||||
|
||||
def test_constants_deprecation():
|
||||
for enum, prefix in {
|
||||
BlpImagePlugin.Format: "BLP_FORMAT_",
|
||||
BlpImagePlugin.Encoding: "BLP_ENCODING_",
|
||||
BlpImagePlugin.AlphaEncoding: "BLP_ALPHA_ENCODING_",
|
||||
}.items():
|
||||
for name in enum.__members__:
|
||||
with pytest.warns(DeprecationWarning):
|
||||
assert getattr(BlpImagePlugin, prefix + name) == enum[name]
|
||||
|
|
|
@ -2,7 +2,7 @@ from io import BytesIO
|
|||
|
||||
import pytest
|
||||
|
||||
from PIL import FitsImagePlugin, FitsStubImagePlugin, Image
|
||||
from PIL import FitsImagePlugin, Image
|
||||
|
||||
from .helper import assert_image_equal, hopper
|
||||
|
||||
|
@ -48,39 +48,3 @@ def test_comment():
|
|||
image_data = b"SIMPLE = T / comment string"
|
||||
with pytest.raises(OSError):
|
||||
FitsImagePlugin.FitsImageFile(BytesIO(image_data))
|
||||
|
||||
|
||||
def test_stub_deprecated():
|
||||
class Handler:
|
||||
opened = False
|
||||
loaded = False
|
||||
|
||||
def open(self, im):
|
||||
self.opened = True
|
||||
|
||||
def load(self, im):
|
||||
self.loaded = True
|
||||
im.fp.close()
|
||||
return Image.new("RGB", (1, 1))
|
||||
|
||||
handler = Handler()
|
||||
with pytest.warns(DeprecationWarning):
|
||||
FitsStubImagePlugin.register_handler(handler)
|
||||
|
||||
with Image.open(TEST_FILE) as im:
|
||||
assert im.format == "FITS"
|
||||
assert im.size == (128, 128)
|
||||
assert im.mode == "L"
|
||||
|
||||
assert handler.opened
|
||||
assert not handler.loaded
|
||||
|
||||
im.load()
|
||||
assert handler.loaded
|
||||
|
||||
FitsStubImagePlugin._handler = None
|
||||
Image.register_open(
|
||||
FitsImagePlugin.FitsImageFile.format,
|
||||
FitsImagePlugin.FitsImageFile,
|
||||
FitsImagePlugin._accept,
|
||||
)
|
||||
|
|
|
@ -21,12 +21,3 @@ def test_invalid_file():
|
|||
|
||||
with pytest.raises(SyntaxError):
|
||||
FtexImagePlugin.FtexImageFile(invalid_file)
|
||||
|
||||
|
||||
def test_constants_deprecation():
|
||||
for enum, prefix in {
|
||||
FtexImagePlugin.Format: "FORMAT_",
|
||||
}.items():
|
||||
for name in enum.__members__:
|
||||
with pytest.warns(DeprecationWarning):
|
||||
assert getattr(FtexImagePlugin, prefix + name) == enum[name]
|
||||
|
|
|
@ -636,12 +636,6 @@ class TestFileJpeg:
|
|||
assert max(im2.quantization[0]) <= 255
|
||||
assert max(im2.quantization[1]) <= 255
|
||||
|
||||
def test_convert_dict_qtables_deprecation(self):
|
||||
with pytest.warns(DeprecationWarning):
|
||||
qtable = {0: [1, 2, 3, 4]}
|
||||
qtable2 = JpegImagePlugin.convert_dict_qtables(qtable)
|
||||
assert qtable == qtable2
|
||||
|
||||
@pytest.mark.skipif(not djpeg_available(), reason="djpeg not available")
|
||||
def test_load_djpeg(self):
|
||||
with Image.open(TEST_FILE) as img:
|
||||
|
|
|
@ -82,9 +82,6 @@ def test_textsize(request, tmp_path):
|
|||
assert dy == 20
|
||||
assert dx in (0, 10)
|
||||
assert font.getlength(chr(i)) == dx
|
||||
with pytest.warns(DeprecationWarning) as log:
|
||||
assert font.getsize(chr(i)) == (dx, dy)
|
||||
assert len(log) == 1
|
||||
for i in range(len(message)):
|
||||
msg = message[: i + 1]
|
||||
assert font.getlength(msg) == len(msg) * 10
|
||||
|
|
|
@ -929,25 +929,7 @@ class TestImage:
|
|||
im.apply_transparency()
|
||||
assert im.palette.colors[(27, 35, 6, 214)] == 24
|
||||
|
||||
def test_categories_deprecation(self):
|
||||
with pytest.warns(DeprecationWarning):
|
||||
assert hopper().category == 0
|
||||
|
||||
with pytest.warns(DeprecationWarning):
|
||||
assert Image.NORMAL == 0
|
||||
with pytest.warns(DeprecationWarning):
|
||||
assert Image.SEQUENCE == 1
|
||||
with pytest.warns(DeprecationWarning):
|
||||
assert Image.CONTAINER == 2
|
||||
|
||||
def test_constants(self):
|
||||
with pytest.warns(DeprecationWarning):
|
||||
assert Image.LINEAR == Image.Resampling.BILINEAR
|
||||
with pytest.warns(DeprecationWarning):
|
||||
assert Image.CUBIC == Image.Resampling.BICUBIC
|
||||
with pytest.warns(DeprecationWarning):
|
||||
assert Image.ANTIALIAS == Image.Resampling.LANCZOS
|
||||
|
||||
for enum in (
|
||||
Image.Transpose,
|
||||
Image.Transform,
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
import pytest
|
||||
|
||||
from PIL import Image
|
||||
|
||||
from .helper import assert_image_equal, hopper
|
||||
|
||||
|
||||
|
@ -62,8 +60,3 @@ def test_f_mode():
|
|||
im = hopper("F")
|
||||
with pytest.raises(ValueError):
|
||||
im.point(None)
|
||||
|
||||
|
||||
def test_coerce_e_deprecation():
|
||||
with pytest.warns(DeprecationWarning):
|
||||
assert Image.coerce_e(2).data == 2
|
||||
|
|
|
@ -617,16 +617,6 @@ def test_auxiliary_channels_isolated():
|
|||
assert_image_equal(test_image.convert(dst_format[2]), reference_image)
|
||||
|
||||
|
||||
def test_constants_deprecation():
|
||||
for enum, prefix in {
|
||||
ImageCms.Intent: "INTENT_",
|
||||
ImageCms.Direction: "DIRECTION_",
|
||||
}.items():
|
||||
for name in enum.__members__:
|
||||
with pytest.warns(DeprecationWarning):
|
||||
assert getattr(ImageCms, prefix + name) == enum[name]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("mode", ("RGB", "RGBA", "RGBX"))
|
||||
def test_rgb_lab(mode):
|
||||
im = Image.new(mode, (1, 1))
|
||||
|
|
|
@ -1224,21 +1224,6 @@ def test_textbbox_stroke():
|
|||
assert draw.textbbox((2, 2), "ABC\nAaaa", font, stroke_width=4) == (-2, 2, 54, 50)
|
||||
|
||||
|
||||
def test_textsize_deprecation():
|
||||
im = Image.new("RGB", (W, H))
|
||||
draw = ImageDraw.Draw(im)
|
||||
|
||||
with pytest.warns(DeprecationWarning) as log:
|
||||
draw.textsize("Hello")
|
||||
assert len(log) == 1
|
||||
with pytest.warns(DeprecationWarning) as log:
|
||||
draw.textsize("Hello\nWorld")
|
||||
assert len(log) == 1
|
||||
with pytest.warns(DeprecationWarning) as log:
|
||||
draw.multiline_textsize("Hello\nWorld")
|
||||
assert len(log) == 1
|
||||
|
||||
|
||||
@skip_unless_feature("freetype2")
|
||||
def test_stroke():
|
||||
for suffix, stroke_fill in {"same": None, "different": "#0f0"}.items():
|
||||
|
|
|
@ -2,7 +2,7 @@ import os.path
|
|||
|
||||
import pytest
|
||||
|
||||
from PIL import Image, ImageDraw, ImageDraw2
|
||||
from PIL import Image, ImageDraw, ImageDraw2, features
|
||||
|
||||
from .helper import (
|
||||
assert_image_equal,
|
||||
|
@ -171,19 +171,18 @@ def test_text():
|
|||
|
||||
|
||||
@skip_unless_feature("freetype2")
|
||||
def test_textsize():
|
||||
def test_textbbox():
|
||||
# Arrange
|
||||
im = Image.new("RGB", (W, H))
|
||||
draw = ImageDraw2.Draw(im)
|
||||
font = ImageDraw2.Font("white", FONT_PATH)
|
||||
|
||||
# Act
|
||||
with pytest.warns(DeprecationWarning) as log:
|
||||
size = draw.textsize("ImageDraw2", font)
|
||||
assert len(log) == 1
|
||||
bbox = draw.textbbox((0, 0), "ImageDraw2", font)
|
||||
|
||||
# Assert
|
||||
assert size[1] == 12
|
||||
right = 72 if features.check_feature("raqm") else 70
|
||||
assert bbox == (0, 2, right, 12)
|
||||
|
||||
|
||||
@skip_unless_feature("freetype2")
|
||||
|
|
|
@ -251,27 +251,6 @@ def test_draw_align(font):
|
|||
draw.text((100, 40), line, (0, 0, 0), font=font, align="left")
|
||||
|
||||
|
||||
def test_multiline_size(font):
|
||||
im = Image.new(mode="RGB", size=(300, 100))
|
||||
draw = ImageDraw.Draw(im)
|
||||
|
||||
with pytest.warns(DeprecationWarning) as log:
|
||||
# Test that textsize() correctly connects to multiline_textsize()
|
||||
assert draw.textsize(TEST_TEXT, font=font) == draw.multiline_textsize(
|
||||
TEST_TEXT, font=font
|
||||
)
|
||||
|
||||
# Test that multiline_textsize corresponds to ImageFont.textsize()
|
||||
# for single line text
|
||||
assert font.getsize("A") == draw.multiline_textsize("A", font=font)
|
||||
|
||||
# Test that textsize() can pass on additional arguments
|
||||
# to multiline_textsize()
|
||||
draw.textsize(TEST_TEXT, font=font, spacing=4)
|
||||
draw.textsize(TEST_TEXT, font, 4)
|
||||
assert len(log) == 6
|
||||
|
||||
|
||||
def test_multiline_bbox(font):
|
||||
im = Image.new(mode="RGB", size=(300, 100))
|
||||
draw = ImageDraw.Draw(im)
|
||||
|
@ -298,12 +277,6 @@ def test_multiline_width(font):
|
|||
draw.textbbox((0, 0), "longest line", font=font)[2]
|
||||
== draw.multiline_textbbox((0, 0), "longest line\nline", font=font)[2]
|
||||
)
|
||||
with pytest.warns(DeprecationWarning) as log:
|
||||
assert (
|
||||
draw.textsize("longest line", font=font)[0]
|
||||
== draw.multiline_textsize("longest line\nline", font=font)[0]
|
||||
)
|
||||
assert len(log) == 2
|
||||
|
||||
|
||||
def test_multiline_spacing(font):
|
||||
|
@ -326,29 +299,23 @@ def test_rotated_transposed_font(font, orientation):
|
|||
|
||||
# Original font
|
||||
draw.font = font
|
||||
with pytest.warns(DeprecationWarning) as log:
|
||||
box_size_a = draw.textsize(word)
|
||||
assert box_size_a == font.getsize(word)
|
||||
assert len(log) == 2
|
||||
bbox_a = draw.textbbox((10, 10), word)
|
||||
|
||||
# Rotated font
|
||||
draw.font = transposed_font
|
||||
with pytest.warns(DeprecationWarning) as log:
|
||||
box_size_b = draw.textsize(word)
|
||||
assert box_size_b == transposed_font.getsize(word)
|
||||
assert len(log) == 2
|
||||
bbox_b = draw.textbbox((20, 20), word)
|
||||
|
||||
# Check (w,h) of box a is (h,w) of box b
|
||||
assert box_size_a[0] == box_size_b[1]
|
||||
assert box_size_a[1] == box_size_b[0]
|
||||
# Check (w, h) of box a is (h, w) of box b
|
||||
assert (
|
||||
bbox_a[2] - bbox_a[0],
|
||||
bbox_a[3] - bbox_a[1],
|
||||
) == (
|
||||
bbox_b[3] - bbox_b[1],
|
||||
bbox_b[2] - bbox_b[0],
|
||||
)
|
||||
|
||||
# Check bbox b is (20, 20, 20 + h, 20 + w)
|
||||
assert bbox_b[0] == 20
|
||||
assert bbox_b[1] == 20
|
||||
assert bbox_b[2] == 20 + bbox_a[3] - bbox_a[1]
|
||||
assert bbox_b[3] == 20 + bbox_a[2] - bbox_a[0]
|
||||
# Check top left co-ordinates are correct
|
||||
assert bbox_b[:2] == (20, 20)
|
||||
|
||||
# text length is undefined for vertical text
|
||||
with pytest.raises(ValueError):
|
||||
|
@ -373,28 +340,25 @@ def test_unrotated_transposed_font(font, orientation):
|
|||
|
||||
# Original font
|
||||
draw.font = font
|
||||
with pytest.warns(DeprecationWarning) as log:
|
||||
box_size_a = draw.textsize(word)
|
||||
assert len(log) == 1
|
||||
bbox_a = draw.textbbox((10, 10), word)
|
||||
length_a = draw.textlength(word)
|
||||
|
||||
# Rotated font
|
||||
draw.font = transposed_font
|
||||
with pytest.warns(DeprecationWarning) as log:
|
||||
box_size_b = draw.textsize(word)
|
||||
assert len(log) == 1
|
||||
bbox_b = draw.textbbox((20, 20), word)
|
||||
length_b = draw.textlength(word)
|
||||
|
||||
# Check boxes a and b are same size
|
||||
assert box_size_a == box_size_b
|
||||
assert (
|
||||
bbox_a[2] - bbox_a[0],
|
||||
bbox_a[3] - bbox_a[1],
|
||||
) == (
|
||||
bbox_b[2] - bbox_b[0],
|
||||
bbox_b[3] - bbox_b[1],
|
||||
)
|
||||
|
||||
# Check bbox b is (20, 20, 20 + w, 20 + h)
|
||||
assert bbox_b[0] == 20
|
||||
assert bbox_b[1] == 20
|
||||
assert bbox_b[2] == 20 + bbox_a[2] - bbox_a[0]
|
||||
assert bbox_b[3] == 20 + bbox_a[3] - bbox_a[1]
|
||||
# Check top left co-ordinates are correct
|
||||
assert bbox_b[:2] == (20, 20)
|
||||
|
||||
assert length_a == length_b
|
||||
|
||||
|
@ -447,19 +411,6 @@ def test_free_type_font_get_metrics(font):
|
|||
assert (ascent, descent) == (16, 4)
|
||||
|
||||
|
||||
def test_free_type_font_get_offset(font):
|
||||
# Arrange
|
||||
text = "offset this"
|
||||
|
||||
# Act
|
||||
with pytest.warns(DeprecationWarning) as log:
|
||||
offset = font.getoffset(text)
|
||||
|
||||
# Assert
|
||||
assert len(log) == 1
|
||||
assert offset == (0, 3)
|
||||
|
||||
|
||||
def test_free_type_font_get_mask(font):
|
||||
# Arrange
|
||||
text = "mask this"
|
||||
|
@ -618,19 +569,6 @@ def test_imagefont_getters(font):
|
|||
assert font.getlength("M") == 12
|
||||
assert font.getlength("y") == 12
|
||||
assert font.getlength("a") == 12
|
||||
with pytest.warns(DeprecationWarning) as log:
|
||||
assert font.getsize("A") == (12, 16)
|
||||
assert font.getsize("AB") == (24, 16)
|
||||
assert font.getsize("M") == (12, 16)
|
||||
assert font.getsize("y") == (12, 20)
|
||||
assert font.getsize("a") == (12, 16)
|
||||
assert font.getsize_multiline("A") == (12, 16)
|
||||
assert font.getsize_multiline("AB") == (24, 16)
|
||||
assert font.getsize_multiline("a") == (12, 16)
|
||||
assert font.getsize_multiline("ABC\n") == (36, 36)
|
||||
assert font.getsize_multiline("ABC\nA") == (36, 36)
|
||||
assert font.getsize_multiline("ABC\nAaaa") == (48, 36)
|
||||
assert len(log) == 11
|
||||
|
||||
|
||||
@pytest.mark.parametrize("stroke_width", (0, 2))
|
||||
|
@ -641,16 +579,6 @@ def test_getsize_stroke(font, stroke_width):
|
|||
12 + stroke_width,
|
||||
16 + stroke_width,
|
||||
)
|
||||
with pytest.warns(DeprecationWarning) as log:
|
||||
assert font.getsize("A", stroke_width=stroke_width) == (
|
||||
12 + stroke_width * 2,
|
||||
16 + stroke_width * 2,
|
||||
)
|
||||
assert font.getsize_multiline("ABC\nAaaa", stroke_width=stroke_width) == (
|
||||
48 + stroke_width * 2,
|
||||
36 + stroke_width * 4,
|
||||
)
|
||||
assert len(log) == 2
|
||||
|
||||
|
||||
def test_complex_font_settings():
|
||||
|
@ -781,11 +709,8 @@ def test_textbbox_non_freetypefont():
|
|||
im = Image.new("RGB", (200, 200))
|
||||
d = ImageDraw.Draw(im)
|
||||
default_font = ImageFont.load_default()
|
||||
with pytest.warns(DeprecationWarning) as log:
|
||||
width, height = d.textsize("test", font=default_font)
|
||||
assert len(log) == 1
|
||||
assert d.textlength("test", font=default_font) == width
|
||||
assert d.textbbox((0, 0), "test", font=default_font) == (0, 0, width, height)
|
||||
assert d.textlength("test", font=default_font) == 24
|
||||
assert d.textbbox((0, 0), "test", font=default_font) == (0, 0, 24, 11)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
|
@ -1083,14 +1008,6 @@ def test_woff2(layout_engine):
|
|||
assert_image_similar_tofile(im, "Tests/images/test_woff2.png", 5)
|
||||
|
||||
|
||||
def test_fill_deprecation(font):
|
||||
with pytest.warns(DeprecationWarning):
|
||||
font.getmask2("Hello world", fill=Image.core.fill)
|
||||
with pytest.warns(DeprecationWarning):
|
||||
with pytest.raises(TypeError):
|
||||
font.getmask2("Hello world", fill=None)
|
||||
|
||||
|
||||
def test_render_mono_size():
|
||||
# issue 4177
|
||||
|
||||
|
@ -1130,12 +1047,3 @@ def test_raqm_missing_warning(monkeypatch):
|
|||
"Raqm layout was requested, but Raqm is not available. "
|
||||
"Falling back to basic layout."
|
||||
)
|
||||
|
||||
|
||||
def test_constants_deprecation():
|
||||
for enum, prefix in {
|
||||
ImageFont.Layout: "LAYOUT_",
|
||||
}.items():
|
||||
for name in enum.__members__:
|
||||
with pytest.warns(DeprecationWarning):
|
||||
assert getattr(ImageFont, prefix + name) == enum[name]
|
||||
|
|
|
@ -9,10 +9,6 @@ def test_sanity():
|
|||
palette = ImagePalette.ImagePalette("RGB", list(range(256)) * 3)
|
||||
assert len(palette.colors) == 256
|
||||
|
||||
with pytest.warns(DeprecationWarning):
|
||||
with pytest.raises(ValueError):
|
||||
ImagePalette.ImagePalette("RGB", list(range(256)) * 3, 10)
|
||||
|
||||
|
||||
def test_reload():
|
||||
with Image.open("Tests/images/hopper.gif") as im:
|
||||
|
|
|
@ -2,13 +2,10 @@ import warnings
|
|||
|
||||
import pytest
|
||||
|
||||
from PIL import ImageQt
|
||||
|
||||
from .helper import assert_image_similar, hopper
|
||||
|
||||
with warnings.catch_warnings() as w:
|
||||
warnings.simplefilter("ignore", category=DeprecationWarning)
|
||||
from PIL import ImageQt
|
||||
|
||||
|
||||
pytestmark = pytest.mark.skipif(
|
||||
not ImageQt.qt_is_installed, reason="Qt bindings are not installed"
|
||||
)
|
||||
|
@ -26,10 +23,6 @@ def test_rgb():
|
|||
from PyQt6.QtGui import qRgb
|
||||
elif ImageQt.qt_version == "side6":
|
||||
from PySide6.QtGui import qRgb
|
||||
elif ImageQt.qt_version == "5":
|
||||
from PyQt5.QtGui import qRgb
|
||||
elif ImageQt.qt_version == "side2":
|
||||
from PySide2.QtGui import qRgb
|
||||
|
||||
assert qRgb(0, 0, 0) == qRgba(0, 0, 0, 255)
|
||||
|
||||
|
|
|
@ -89,20 +89,3 @@ def test_ipythonviewer():
|
|||
|
||||
im = hopper()
|
||||
assert test_viewer.show(im) == 1
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
not on_ci() or is_win32(),
|
||||
reason="Only run on CIs; hangs on Windows CIs",
|
||||
)
|
||||
@pytest.mark.parametrize("viewer", ImageShow._viewers)
|
||||
def test_file_deprecated(tmp_path, viewer):
|
||||
f = str(tmp_path / "temp.jpg")
|
||||
hopper().save(f)
|
||||
with pytest.warns(DeprecationWarning):
|
||||
try:
|
||||
viewer.show_file(file=f)
|
||||
except NotImplementedError:
|
||||
pass
|
||||
with pytest.raises(TypeError):
|
||||
viewer.show_file()
|
||||
|
|
|
@ -89,13 +89,6 @@ def test_photoimage_blank(mode):
|
|||
assert_image_equal(reloaded.convert(mode), im)
|
||||
|
||||
|
||||
def test_box_deprecation():
|
||||
im = hopper()
|
||||
im_tk = ImageTk.PhotoImage(im)
|
||||
with pytest.warns(DeprecationWarning):
|
||||
im_tk.paste(im, (0, 0, 128, 128))
|
||||
|
||||
|
||||
def test_bitmapimage():
|
||||
im = hopper("1")
|
||||
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
import warnings
|
||||
|
||||
import pytest
|
||||
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter("ignore", category=DeprecationWarning)
|
||||
from PIL import ImageQt
|
||||
from PIL import ImageQt
|
||||
|
||||
from .helper import assert_image_equal_tofile, assert_image_similar, hopper
|
||||
|
||||
|
@ -19,14 +15,6 @@ if ImageQt.qt_is_installed:
|
|||
from PySide6.QtCore import QPoint
|
||||
from PySide6.QtGui import QImage, QPainter, QRegion
|
||||
from PySide6.QtWidgets import QApplication, QHBoxLayout, QLabel, QWidget
|
||||
elif ImageQt.qt_version == "5":
|
||||
from PyQt5.QtCore import QPoint
|
||||
from PyQt5.QtGui import QImage, QPainter, QRegion
|
||||
from PyQt5.QtWidgets import QApplication, QHBoxLayout, QLabel, QWidget
|
||||
elif ImageQt.qt_version == "side2":
|
||||
from PySide2.QtCore import QPoint
|
||||
from PySide2.QtGui import QImage, QPainter, QRegion
|
||||
from PySide2.QtWidgets import QApplication, QHBoxLayout, QLabel, QWidget
|
||||
|
||||
class Example(QWidget):
|
||||
def __init__(self):
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
import warnings
|
||||
|
||||
import pytest
|
||||
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter("ignore", category=DeprecationWarning)
|
||||
from PIL import ImageQt
|
||||
from PIL import ImageQt
|
||||
|
||||
from .helper import assert_image_equal, assert_image_equal_tofile, hopper
|
||||
|
||||
|
@ -32,7 +28,7 @@ def test_sanity(mode, tmp_path):
|
|||
assert_image_equal(rt, src)
|
||||
|
||||
if mode == "1":
|
||||
# BW appears to not save correctly on QT5
|
||||
# BW appears to not save correctly on Qt
|
||||
# kicks out errors on console:
|
||||
# libpng warning: Invalid color type/bit depth combination
|
||||
# in IHDR
|
||||
|
|
|
@ -12,22 +12,38 @@ Deprecated features
|
|||
Below are features which are considered deprecated. Where appropriate,
|
||||
a ``DeprecationWarning`` is issued.
|
||||
|
||||
PSFile
|
||||
~~~~~~
|
||||
|
||||
.. deprecated:: 9.5.0
|
||||
|
||||
The :py:class:`~PIL.EpsImagePlugin.PSFile` class has been deprecated and will
|
||||
be removed in Pillow 11 (2024-10-15). This class was only made as a helper to
|
||||
be used internally, so there is no replacement. If you need this functionality
|
||||
though, it is a very short class that can easily be recreated in your own code.
|
||||
|
||||
Removed features
|
||||
----------------
|
||||
|
||||
Deprecated features are only removed in major releases after an appropriate
|
||||
period of deprecation has passed.
|
||||
|
||||
Tk/Tcl 8.4
|
||||
~~~~~~~~~~
|
||||
|
||||
.. deprecated:: 8.2.0
|
||||
.. versionremoved:: 10.0.0
|
||||
|
||||
Support for Tk/Tcl 8.4 is deprecated and will be removed in Pillow 10.0.0 (2023-07-01),
|
||||
when Tk/Tcl 8.5 will be the minimum supported.
|
||||
Support for Tk/Tcl 8.4 was removed in Pillow 10.0.0 (2023-07-01).
|
||||
|
||||
Categories
|
||||
~~~~~~~~~~
|
||||
|
||||
.. deprecated:: 8.2.0
|
||||
.. versionremoved:: 10.0.0
|
||||
|
||||
``im.category`` is deprecated and will be removed in Pillow 10.0.0 (2023-07-01),
|
||||
along with the related ``Image.NORMAL``, ``Image.SEQUENCE`` and
|
||||
``Image.CONTAINER`` attributes.
|
||||
``im.category`` was removed along with the related ``Image.NORMAL``,
|
||||
``Image.SEQUENCE`` and ``Image.CONTAINER`` attributes.
|
||||
|
||||
To determine if an image has multiple frames or not,
|
||||
``getattr(im, "is_animated", False)`` can be used instead.
|
||||
|
@ -36,43 +52,40 @@ JpegImagePlugin.convert_dict_qtables
|
|||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. deprecated:: 8.3.0
|
||||
.. versionremoved:: 10.0.0
|
||||
|
||||
JPEG ``quantization`` is now automatically converted, but still returned as a
|
||||
dictionary. The :py:attr:`~PIL.JpegImagePlugin.convert_dict_qtables` method no longer
|
||||
performs any operations on the data given to it, has been deprecated and will be
|
||||
removed in Pillow 10.0.0 (2023-07-01).
|
||||
Since deprecation in Pillow 8.3.0, the ``convert_dict_qtables`` method no longer
|
||||
performed any operations on the data given to it, and has been removed.
|
||||
|
||||
ImagePalette size parameter
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. deprecated:: 8.4.0
|
||||
|
||||
The ``size`` parameter will be removed in Pillow 10.0.0 (2023-07-01).
|
||||
.. versionremoved:: 10.0.0
|
||||
|
||||
Before Pillow 8.3.0, ``ImagePalette`` required palette data of particular lengths by
|
||||
default, and the size parameter could be used to override that. Pillow 8.3.0 removed
|
||||
the default required length, also removing the need for the size parameter.
|
||||
default, and the ``size`` parameter could be used to override that. Pillow 8.3.0
|
||||
removed the default required length, also removing the need for the ``size`` parameter.
|
||||
|
||||
ImageShow.Viewer.show_file file argument
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. deprecated:: 9.1.0
|
||||
.. versionremoved:: 10.0.0
|
||||
|
||||
The ``file`` argument in :py:meth:`~PIL.ImageShow.Viewer.show_file()` has been
|
||||
deprecated and will be removed in Pillow 10.0.0 (2023-07-01). It has been replaced by
|
||||
``path``.
|
||||
removed and replaced by ``path``.
|
||||
|
||||
In effect, ``viewer.show_file("test.jpg")`` will continue to work unchanged.
|
||||
``viewer.show_file(file="test.jpg")`` will raise a deprecation warning, and suggest
|
||||
``viewer.show_file(path="test.jpg")`` instead.
|
||||
|
||||
Constants
|
||||
~~~~~~~~~
|
||||
|
||||
.. deprecated:: 9.1.0
|
||||
.. versionremoved:: 10.0.0
|
||||
|
||||
A number of constants have been deprecated and will be removed in Pillow 10.0.0
|
||||
(2023-07-01). Instead, ``enum.IntEnum`` classes have been added.
|
||||
A number of constants have been removed.
|
||||
Instead, ``enum.IntEnum`` classes have been added.
|
||||
|
||||
.. note::
|
||||
|
||||
|
@ -81,7 +94,7 @@ A number of constants have been deprecated and will be removed in Pillow 10.0.0
|
|||
See :ref:`restored-image-constants`
|
||||
|
||||
===================================================== ============================================================
|
||||
Deprecated Use instead
|
||||
Removed Use instead
|
||||
===================================================== ============================================================
|
||||
``Image.LINEAR`` ``Image.BILINEAR`` or ``Image.Resampling.BILINEAR``
|
||||
``Image.CUBIC`` ``Image.BICUBIC`` or ``Image.Resampling.BICUBIC``
|
||||
|
@ -115,67 +128,29 @@ FitsStubImagePlugin
|
|||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. deprecated:: 9.1.0
|
||||
.. versionremoved:: 10.0.0
|
||||
|
||||
The stub image plugin ``FitsStubImagePlugin`` has been deprecated and will be removed in
|
||||
Pillow 10.0.0 (2023-07-01). FITS images can be read without a handler through
|
||||
:mod:`~PIL.FitsImagePlugin` instead.
|
||||
|
||||
FreeTypeFont.getmask2 fill parameter
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. deprecated:: 9.2.0
|
||||
|
||||
The undocumented ``fill`` parameter of :py:meth:`.FreeTypeFont.getmask2` has been
|
||||
deprecated and will be removed in Pillow 10 (2023-07-01).
|
||||
|
||||
PhotoImage.paste box parameter
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. deprecated:: 9.2.0
|
||||
|
||||
The ``box`` parameter is unused. It will be removed in Pillow 10.0.0 (2023-07-01).
|
||||
|
||||
PyQt5 and PySide2
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. deprecated:: 9.2.0
|
||||
|
||||
`Qt 5 reached end-of-life <https://www.qt.io/blog/qt-5.15-released>`_ on 2020-12-08 for
|
||||
open-source users (and will reach EOL on 2023-12-08 for commercial licence holders).
|
||||
|
||||
Support for PyQt5 and PySide2 has been deprecated from ``ImageQt`` and will be removed
|
||||
in Pillow 10 (2023-07-01). Upgrade to
|
||||
`PyQt6 <https://www.riverbankcomputing.com/static/Docs/PyQt6/>`_ or
|
||||
`PySide6 <https://doc.qt.io/qtforpython/>`_ instead.
|
||||
|
||||
Image.coerce_e
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
.. deprecated:: 9.2.0
|
||||
|
||||
This undocumented method has been deprecated and will be removed in Pillow 10
|
||||
(2023-07-01).
|
||||
|
||||
.. _Font size and offset methods:
|
||||
The stub image plugin ``FitsStubImagePlugin`` has been removed.
|
||||
FITS images can be read without a handler through :mod:`~PIL.FitsImagePlugin` instead.
|
||||
|
||||
Font size and offset methods
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. deprecated:: 9.2.0
|
||||
.. versionremoved:: 10.0.0
|
||||
|
||||
Several functions for computing the size and offset of rendered text
|
||||
have been deprecated and will be removed in Pillow 10 (2023-07-01):
|
||||
Several functions for computing the size and offset of rendered text have been removed:
|
||||
|
||||
=========================================================================== =============================================================================================================
|
||||
Deprecated Use instead
|
||||
=========================================================================== =============================================================================================================
|
||||
:py:meth:`.FreeTypeFont.getsize` and :py:meth:`.FreeTypeFont.getoffset` :py:meth:`.FreeTypeFont.getbbox` and :py:meth:`.FreeTypeFont.getlength`
|
||||
:py:meth:`.FreeTypeFont.getsize_multiline` :py:meth:`.ImageDraw.multiline_textbbox`
|
||||
:py:meth:`.ImageFont.getsize` :py:meth:`.ImageFont.getbbox` and :py:meth:`.ImageFont.getlength`
|
||||
:py:meth:`.TransposedFont.getsize` :py:meth:`.TransposedFont.getbbox` and :py:meth:`.TransposedFont.getlength`
|
||||
:py:meth:`.ImageDraw.textsize` and :py:meth:`.ImageDraw.multiline_textsize` :py:meth:`.ImageDraw.textbbox`, :py:meth:`.ImageDraw.textlength` and :py:meth:`.ImageDraw.multiline_textbbox`
|
||||
:py:meth:`.ImageDraw2.Draw.textsize` :py:meth:`.ImageDraw2.Draw.textbbox` and :py:meth:`.ImageDraw2.Draw.textlength`
|
||||
=========================================================================== =============================================================================================================
|
||||
=============================================================== =============================================================================================================
|
||||
Removed Use instead
|
||||
=============================================================== =============================================================================================================
|
||||
``FreeTypeFont.getsize()`` and ``FreeTypeFont.getoffset()`` :py:meth:`.FreeTypeFont.getbbox` and :py:meth:`.FreeTypeFont.getlength`
|
||||
``FreeTypeFont.getsize_multiline()`` :py:meth:`.ImageDraw.multiline_textbbox`
|
||||
``ImageFont.getsize()`` :py:meth:`.ImageFont.getbbox` and :py:meth:`.ImageFont.getlength`
|
||||
``TransposedFont.getsize()`` :py:meth:`.TransposedFont.getbbox` and :py:meth:`.TransposedFont.getlength`
|
||||
``ImageDraw.textsize()`` and ``ImageDraw.multiline_textsize()`` :py:meth:`.ImageDraw.textbbox`, :py:meth:`.ImageDraw.textlength` and :py:meth:`.ImageDraw.multiline_textbbox`
|
||||
``ImageDraw2.Draw.textsize()`` :py:meth:`.ImageDraw2.Draw.textbbox` and :py:meth:`.ImageDraw2.Draw.textlength`
|
||||
=============================================================== =============================================================================================================
|
||||
|
||||
Previous code::
|
||||
|
||||
|
@ -207,21 +182,43 @@ Use instead::
|
|||
left, top, right, bottom = draw.multiline_textbbox((0, 0), "Hello\nworld")
|
||||
width, height = right - left, bottom - top
|
||||
|
||||
PSFile
|
||||
~~~~~~
|
||||
FreeTypeFont.getmask2 fill parameter
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. deprecated:: 9.5.0
|
||||
.. deprecated:: 9.2.0
|
||||
.. versionremoved:: 10.0.0
|
||||
|
||||
The :py:class:`~PIL.EpsImagePlugin.PSFile` class has been deprecated and will
|
||||
be removed in Pillow 11 (2024-10-15). This class was only made as a helper to
|
||||
be used internally, so there is no replacement. If you need this functionality
|
||||
though, it is a very short class that can easily be recreated in your own code.
|
||||
The undocumented ``fill`` parameter of :py:meth:`.FreeTypeFont.getmask2` has been
|
||||
removed.
|
||||
|
||||
Removed features
|
||||
----------------
|
||||
PhotoImage.paste box parameter
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Deprecated features are only removed in major releases after an appropriate
|
||||
period of deprecation has passed.
|
||||
.. deprecated:: 9.2.0
|
||||
.. versionremoved:: 10.0.0
|
||||
|
||||
The ``box`` parameter was unused and has been removed.
|
||||
|
||||
PyQt5 and PySide2
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. deprecated:: 9.2.0
|
||||
.. versionremoved:: 10.0.0
|
||||
|
||||
`Qt 5 reached end-of-life <https://www.qt.io/blog/qt-5.15-released>`_ on 2020-12-08 for
|
||||
open-source users (and will reach EOL on 2023-12-08 for commercial licence holders).
|
||||
|
||||
Support for PyQt5 and PySide2 has been removed from ``ImageQt``. Upgrade to
|
||||
`PyQt6 <https://www.riverbankcomputing.com/static/Docs/PyQt6/>`_ or
|
||||
`PySide6 <https://doc.qt.io/qtforpython/>`_ instead.
|
||||
|
||||
Image.coerce_e
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
.. deprecated:: 9.2.0
|
||||
.. versionremoved:: 10.0.0
|
||||
|
||||
This undocumented method has been removed.
|
||||
|
||||
PILLOW_VERSION constant
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
|
|
@ -434,7 +434,7 @@ These platforms are built and tested for every change.
|
|||
+==================================+============================+=====================+
|
||||
| Alpine | 3.9 | x86-64 |
|
||||
+----------------------------------+----------------------------+---------------------+
|
||||
| Amazon Linux 2 | 3.7 | x86-64 |
|
||||
| Amazon Linux 2 | 3.9 | x86-64 |
|
||||
+----------------------------------+----------------------------+---------------------+
|
||||
| Amazon Linux 2023 | 3.9 | x86-64 |
|
||||
+----------------------------------+----------------------------+---------------------+
|
||||
|
@ -454,22 +454,22 @@ These platforms are built and tested for every change.
|
|||
+----------------------------------+----------------------------+---------------------+
|
||||
| Gentoo | 3.9 | x86-64 |
|
||||
+----------------------------------+----------------------------+---------------------+
|
||||
| macOS 12 Monterey | 3.7, 3.8, 3.9, 3.10, 3.11, | x86-64 |
|
||||
| macOS 12 Monterey | 3.8, 3.9, 3.10, 3.11, | x86-64 |
|
||||
| | 3.12, PyPy3 | |
|
||||
+----------------------------------+----------------------------+---------------------+
|
||||
| Ubuntu Linux 18.04 LTS (Bionic) | 3.9 | x86-64 |
|
||||
+----------------------------------+----------------------------+---------------------+
|
||||
| Ubuntu Linux 20.04 LTS (Focal) | 3.8 | x86-64 |
|
||||
+----------------------------------+----------------------------+---------------------+
|
||||
| Ubuntu Linux 22.04 LTS (Jammy) | 3.7, 3.8, 3.9, 3.10, 3.11, | x86-64 |
|
||||
| Ubuntu Linux 22.04 LTS (Jammy) | 3.8, 3.9, 3.10, 3.11, | x86-64 |
|
||||
| | 3.12, PyPy3 | |
|
||||
| +----------------------------+---------------------+
|
||||
| | 3.10 | arm64v8, ppc64le, |
|
||||
| | | s390x |
|
||||
+----------------------------------+----------------------------+---------------------+
|
||||
| Windows Server 2016 | 3.7 | x86-64 |
|
||||
| Windows Server 2016 | 3.8 | x86-64 |
|
||||
+----------------------------------+----------------------------+---------------------+
|
||||
| Windows Server 2022 | 3.7, 3.8, 3.9, 3.10, 3.11, | x86, x86-64 |
|
||||
| Windows Server 2022 | 3.8, 3.9, 3.10, 3.11, | x86, x86-64 |
|
||||
| | 3.12, PyPy3 | |
|
||||
| +----------------------------+---------------------+
|
||||
| | 3.9 (MinGW) | x86, x86-64 |
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
Python,3.11,3.10,3.9,3.8,3.7,3.6,3.5
|
||||
Pillow >= 9.3,Yes,Yes,Yes,Yes,Yes,,
|
||||
Pillow >= 10,Yes,Yes,Yes,Yes,,,
|
||||
Pillow 9.3 - 9.5,Yes,Yes,Yes,Yes,Yes,,
|
||||
Pillow 9.0 - 9.2,,Yes,Yes,Yes,Yes,,
|
||||
Pillow 8.3.2 - 8.4,,Yes,Yes,Yes,Yes,Yes,
|
||||
Pillow 8.0 - 8.3.1,,,Yes,Yes,Yes,Yes,
|
||||
|
|
|
|
@ -412,18 +412,6 @@ See :ref:`concept-filters` for details.
|
|||
:undoc-members:
|
||||
:noindex:
|
||||
|
||||
Some deprecated filters are also available under the following names:
|
||||
|
||||
.. data:: NONE
|
||||
:noindex:
|
||||
:value: Resampling.NEAREST
|
||||
.. data:: LINEAR
|
||||
:value: Resampling.BILINEAR
|
||||
.. data:: CUBIC
|
||||
:value: Resampling.BICUBIC
|
||||
.. data:: ANTIALIAS
|
||||
:value: Resampling.LANCZOS
|
||||
|
||||
Dither modes
|
||||
^^^^^^^^^^^^
|
||||
|
||||
|
|
|
@ -474,116 +474,6 @@ Methods
|
|||
|
||||
.. versionadded:: 8.0.0
|
||||
|
||||
.. py:method:: ImageDraw.textsize(text, font=None, spacing=4, direction=None, features=None, language=None, stroke_width=0)
|
||||
|
||||
.. deprecated:: 9.2.0
|
||||
|
||||
See :ref:`deprecations <Font size and offset methods>` for more information.
|
||||
|
||||
Use :py:meth:`textlength()` to measure the offset of following text with
|
||||
1/64 pixel precision.
|
||||
Use :py:meth:`textbbox()` to get the exact bounding box based on an anchor.
|
||||
|
||||
Return the size of the given string, in pixels.
|
||||
|
||||
.. note:: For historical reasons this function measures text height from
|
||||
the ascender line instead of the top, see :ref:`text-anchors`.
|
||||
If you wish to measure text height from the top, it is recommended
|
||||
to use :meth:`textbbox` with ``anchor='lt'`` instead.
|
||||
|
||||
:param text: Text to be measured. If it contains any newline characters,
|
||||
the text is passed on to :py:meth:`~PIL.ImageDraw.ImageDraw.multiline_textsize`.
|
||||
:param font: An :py:class:`~PIL.ImageFont.ImageFont` instance.
|
||||
:param spacing: If the text is passed on to
|
||||
:py:meth:`~PIL.ImageDraw.ImageDraw.multiline_textsize`,
|
||||
the number of pixels between lines.
|
||||
:param direction: Direction of the text. It can be ``"rtl"`` (right to
|
||||
left), ``"ltr"`` (left to right) or ``"ttb"`` (top to bottom).
|
||||
Requires libraqm.
|
||||
|
||||
.. versionadded:: 4.2.0
|
||||
:param features: A list of OpenType font features to be used during text
|
||||
layout. This is usually used to turn on optional
|
||||
font features that are not enabled by default,
|
||||
for example ``"dlig"`` or ``"ss01"``, but can be also
|
||||
used to turn off default font features, for
|
||||
example ``"-liga"`` to disable ligatures or ``"-kern"``
|
||||
to disable kerning. To get all supported
|
||||
features, see `OpenType docs`_.
|
||||
Requires libraqm.
|
||||
|
||||
.. versionadded:: 4.2.0
|
||||
:param language: Language of the text. Different languages may use
|
||||
different glyph shapes or ligatures. This parameter tells
|
||||
the font which language the text is in, and to apply the
|
||||
correct substitutions as appropriate, if available.
|
||||
It should be a `BCP 47 language code`_.
|
||||
Requires libraqm.
|
||||
|
||||
.. versionadded:: 6.0.0
|
||||
|
||||
:param stroke_width: The width of the text stroke.
|
||||
|
||||
.. versionadded:: 6.2.0
|
||||
|
||||
:return: (width, height)
|
||||
|
||||
.. py:method:: ImageDraw.multiline_textsize(text, font=None, spacing=4, direction=None, features=None, language=None, stroke_width=0)
|
||||
|
||||
.. deprecated:: 9.2.0
|
||||
|
||||
See :ref:`deprecations <Font size and offset methods>` for more information.
|
||||
|
||||
Use :py:meth:`.multiline_textbbox` instead.
|
||||
|
||||
Return the size of the given string, in pixels.
|
||||
|
||||
Use :py:meth:`textlength()` to measure the offset of following text with
|
||||
1/64 pixel precision.
|
||||
Use :py:meth:`textbbox()` to get the exact bounding box based on an anchor.
|
||||
|
||||
.. note:: For historical reasons this function measures text height as the
|
||||
distance between the top ascender line and bottom descender line,
|
||||
not the top and bottom of the text, see :ref:`text-anchors`.
|
||||
If you wish to measure text height from the top to the bottom of text,
|
||||
it is recommended to use :meth:`multiline_textbbox` instead.
|
||||
|
||||
:param text: Text to be measured.
|
||||
:param font: An :py:class:`~PIL.ImageFont.ImageFont` instance.
|
||||
:param spacing: The number of pixels between lines.
|
||||
:param direction: Direction of the text. It can be ``"rtl"`` (right to
|
||||
left), ``"ltr"`` (left to right) or ``"ttb"`` (top to bottom).
|
||||
Requires libraqm.
|
||||
|
||||
.. versionadded:: 4.2.0
|
||||
|
||||
:param features: A list of OpenType font features to be used during text
|
||||
layout. This is usually used to turn on optional
|
||||
font features that are not enabled by default,
|
||||
for example ``"dlig"`` or ``"ss01"``, but can be also
|
||||
used to turn off default font features, for
|
||||
example ``"-liga"`` to disable ligatures or ``"-kern"``
|
||||
to disable kerning. To get all supported
|
||||
features, see `OpenType docs`_.
|
||||
Requires libraqm.
|
||||
|
||||
.. versionadded:: 4.2.0
|
||||
|
||||
:param language: Language of the text. Different languages may use
|
||||
different glyph shapes or ligatures. This parameter tells
|
||||
the font which language the text is in, and to apply the
|
||||
correct substitutions as appropriate, if available.
|
||||
It should be a `BCP 47 language code`_.
|
||||
Requires libraqm.
|
||||
|
||||
.. versionadded:: 6.0.0
|
||||
|
||||
:param stroke_width: The width of the text stroke.
|
||||
|
||||
.. versionadded:: 6.2.0
|
||||
|
||||
:return: (width, height)
|
||||
|
||||
.. py:method:: ImageDraw.textlength(text, font=None, direction=None, features=None, language=None, embedded_color=False)
|
||||
|
||||
Returns length (in pixels with 1/64 precision) of given text when rendered
|
||||
|
|
|
@ -29,6 +29,8 @@ Classes
|
|||
All enhancement classes implement a common interface, containing a single
|
||||
method:
|
||||
|
||||
.. _enhancement-factor:
|
||||
|
||||
.. py:class:: _Enhance
|
||||
|
||||
.. py:method:: enhance(factor)
|
||||
|
@ -45,31 +47,35 @@ method:
|
|||
|
||||
Adjust image color balance.
|
||||
|
||||
This class can be used to adjust the colour balance of an image, in
|
||||
a manner similar to the controls on a colour TV set. An enhancement
|
||||
factor of 0.0 gives a black and white image. A factor of 1.0 gives
|
||||
the original image.
|
||||
This class can be used to adjust the colour balance of an image, in a
|
||||
manner similar to the controls on a colour TV set. An
|
||||
:ref:`enhancement factor <enhancement-factor>` of 0.0 gives a black and
|
||||
white image. A factor of 1.0 gives the original image.
|
||||
|
||||
.. py:class:: Contrast(image)
|
||||
|
||||
Adjust image contrast.
|
||||
|
||||
This class can be used to control the contrast of an image, similar
|
||||
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.
|
||||
This class can be used to control the contrast of an image, similar to the
|
||||
contrast control on a TV set. An
|
||||
:ref:`enhancement factor <enhancement-factor>` of 0.0 gives a solid grey
|
||||
image, a factor of 1.0 gives the original image, and greater values
|
||||
increase the contrast of the image.
|
||||
|
||||
.. py:class:: Brightness(image)
|
||||
|
||||
Adjust image brightness.
|
||||
|
||||
This class can be used to control the brightness of an image. An
|
||||
enhancement factor of 0.0 gives a black image. A factor of 1.0 gives the
|
||||
original image.
|
||||
This class can be used to control the brightness of an image. An
|
||||
:ref:`enhancement factor <enhancement-factor>` of 0.0 gives a black image,
|
||||
a factor of 1.0 gives the original image, and greater values increase the
|
||||
brightness of the image.
|
||||
|
||||
.. py:class:: Sharpness(image)
|
||||
|
||||
Adjust image sharpness.
|
||||
|
||||
This class can be used to adjust the sharpness of an image. An
|
||||
enhancement factor of 0.0 gives a blurred image, a factor of 1.0 gives the
|
||||
original image, and a factor of 2.0 gives a sharpened image.
|
||||
:ref:`enhancement factor <enhancement-factor>` of 0.0 gives a blurred
|
||||
image, a factor of 1.0 gives the original image, and a factor of 2.0 gives
|
||||
a sharpened image.
|
||||
|
|
|
@ -4,16 +4,8 @@
|
|||
:py:mod:`~PIL.ImageQt` Module
|
||||
=============================
|
||||
|
||||
The :py:mod:`~PIL.ImageQt` module contains support for creating PyQt6, PySide6, PyQt5
|
||||
or PySide2 QImage objects from PIL images.
|
||||
|
||||
`Qt 5 reached end-of-life <https://www.qt.io/blog/qt-5.15-released>`_ on 2020-12-08 for
|
||||
open-source users (and will reach EOL on 2023-12-08 for commercial licence holders).
|
||||
|
||||
Support for PyQt5 and PySide2 has been deprecated from ``ImageQt`` and will be removed
|
||||
in Pillow 10 (2023-07-01). Upgrade to
|
||||
`PyQt6 <https://www.riverbankcomputing.com/static/Docs/PyQt6/>`_ or
|
||||
`PySide6 <https://doc.qt.io/qtforpython/>`_ instead.
|
||||
The :py:mod:`~PIL.ImageQt` module contains support for creating PyQt6 or PySide6
|
||||
QImage objects from PIL images.
|
||||
|
||||
.. versionadded:: 1.1.6
|
||||
|
||||
|
@ -22,7 +14,7 @@ in Pillow 10 (2023-07-01). Upgrade to
|
|||
Creates an :py:class:`~PIL.ImageQt.ImageQt` object from a PIL
|
||||
:py:class:`~PIL.Image.Image` object. This class is a subclass of
|
||||
QtGui.QImage, which means that you can pass the resulting objects directly
|
||||
to PyQt6/PySide6/PyQt5/PySide2 API functions and methods.
|
||||
to PyQt6/PySide6 API functions and methods.
|
||||
|
||||
This operation is currently supported for mode 1, L, P, RGB, and RGBA
|
||||
images. To handle other modes, you need to convert the image first.
|
||||
|
|
165
docs/releasenotes/10.0.0.rst
Normal file
165
docs/releasenotes/10.0.0.rst
Normal file
|
@ -0,0 +1,165 @@
|
|||
10.0.0
|
||||
------
|
||||
|
||||
Backwards Incompatible Changes
|
||||
==============================
|
||||
|
||||
Categories
|
||||
^^^^^^^^^^
|
||||
|
||||
``im.category`` has been removed, along with the related ``Image.NORMAL``,
|
||||
``Image.SEQUENCE`` and ``Image.CONTAINER`` attributes.
|
||||
|
||||
To determine if an image has multiple frames or not,
|
||||
``getattr(im, "is_animated", False)`` can be used instead.
|
||||
|
||||
Tk/Tcl 8.4
|
||||
^^^^^^^^^^
|
||||
|
||||
Support for Tk/Tcl 8.4 has been removed.
|
||||
|
||||
JpegImagePlugin.convert_dict_qtables
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Since deprecation in Pillow 8.3.0, the ``convert_dict_qtables`` method no longer
|
||||
performed any operations on the data given to it, and has been removed.
|
||||
|
||||
ImagePalette size parameter
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Before Pillow 8.3.0, ``ImagePalette`` required palette data of particular lengths by
|
||||
default, and the ``size`` parameter could be used to override that. Pillow 8.3.0
|
||||
removed the default required length, also removing the need for the ``size`` parameter.
|
||||
|
||||
ImageShow.Viewer.show_file file argument
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The ``file`` argument in :py:meth:`~PIL.ImageShow.Viewer.show_file()` has been
|
||||
removed and replaced by ``path``.
|
||||
|
||||
In effect, ``viewer.show_file("test.jpg")`` will continue to work unchanged.
|
||||
|
||||
Constants
|
||||
^^^^^^^^^
|
||||
|
||||
A number of constants have been removed.
|
||||
Instead, ``enum.IntEnum`` classes have been added.
|
||||
|
||||
===================================================== ============================================================
|
||||
Removed Use instead
|
||||
===================================================== ============================================================
|
||||
``Image.LINEAR`` ``Image.BILINEAR`` or ``Image.Resampling.BILINEAR``
|
||||
``Image.CUBIC`` ``Image.BICUBIC`` or ``Image.Resampling.BICUBIC``
|
||||
``Image.ANTIALIAS`` ``Image.LANCZOS`` or ``Image.Resampling.LANCZOS``
|
||||
``ImageCms.INTENT_PERCEPTUAL`` ``ImageCms.Intent.PERCEPTUAL``
|
||||
``ImageCms.INTENT_RELATIVE_COLORMETRIC`` ``ImageCms.Intent.RELATIVE_COLORMETRIC``
|
||||
``ImageCms.INTENT_SATURATION`` ``ImageCms.Intent.SATURATION``
|
||||
``ImageCms.INTENT_ABSOLUTE_COLORIMETRIC`` ``ImageCms.Intent.ABSOLUTE_COLORIMETRIC``
|
||||
``ImageCms.DIRECTION_INPUT`` ``ImageCms.Direction.INPUT``
|
||||
``ImageCms.DIRECTION_OUTPUT`` ``ImageCms.Direction.OUTPUT``
|
||||
``ImageCms.DIRECTION_PROOF`` ``ImageCms.Direction.PROOF``
|
||||
``ImageFont.LAYOUT_BASIC`` ``ImageFont.Layout.BASIC``
|
||||
``ImageFont.LAYOUT_RAQM`` ``ImageFont.Layout.RAQM``
|
||||
``BlpImagePlugin.BLP_FORMAT_JPEG`` ``BlpImagePlugin.Format.JPEG``
|
||||
``BlpImagePlugin.BLP_ENCODING_UNCOMPRESSED`` ``BlpImagePlugin.Encoding.UNCOMPRESSED``
|
||||
``BlpImagePlugin.BLP_ENCODING_DXT`` ``BlpImagePlugin.Encoding.DXT``
|
||||
``BlpImagePlugin.BLP_ENCODING_UNCOMPRESSED_RAW_RGBA`` ``BlpImagePlugin.Encoding.UNCOMPRESSED_RAW_RGBA``
|
||||
``BlpImagePlugin.BLP_ALPHA_ENCODING_DXT1`` ``BlpImagePlugin.AlphaEncoding.DXT1``
|
||||
``BlpImagePlugin.BLP_ALPHA_ENCODING_DXT3`` ``BlpImagePlugin.AlphaEncoding.DXT3``
|
||||
``BlpImagePlugin.BLP_ALPHA_ENCODING_DXT5`` ``BlpImagePlugin.AlphaEncoding.DXT5``
|
||||
``FtexImagePlugin.FORMAT_DXT1`` ``FtexImagePlugin.Format.DXT1``
|
||||
``FtexImagePlugin.FORMAT_UNCOMPRESSED`` ``FtexImagePlugin.Format.UNCOMPRESSED``
|
||||
``PngImagePlugin.APNG_DISPOSE_OP_NONE`` ``PngImagePlugin.Disposal.OP_NONE``
|
||||
``PngImagePlugin.APNG_DISPOSE_OP_BACKGROUND`` ``PngImagePlugin.Disposal.OP_BACKGROUND``
|
||||
``PngImagePlugin.APNG_DISPOSE_OP_PREVIOUS`` ``PngImagePlugin.Disposal.OP_PREVIOUS``
|
||||
``PngImagePlugin.APNG_BLEND_OP_SOURCE`` ``PngImagePlugin.Blend.OP_SOURCE``
|
||||
``PngImagePlugin.APNG_BLEND_OP_OVER`` ``PngImagePlugin.Blend.OP_OVER``
|
||||
===================================================== ============================================================
|
||||
|
||||
FitsStubImagePlugin
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The stub image plugin ``FitsStubImagePlugin`` has been removed.
|
||||
FITS images can be read without a handler through :mod:`~PIL.FitsImagePlugin` instead.
|
||||
|
||||
Font size and offset methods
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Several functions for computing the size and offset of rendered text have been removed:
|
||||
|
||||
=============================================================== =============================================================================================================
|
||||
Removed Use instead
|
||||
=============================================================== =============================================================================================================
|
||||
``FreeTypeFont.getsize()`` and ``FreeTypeFont.getoffset()`` :py:meth:`.FreeTypeFont.getbbox` and :py:meth:`.FreeTypeFont.getlength`
|
||||
``FreeTypeFont.getsize_multiline()`` :py:meth:`.ImageDraw.multiline_textbbox`
|
||||
``ImageFont.getsize()`` :py:meth:`.ImageFont.getbbox` and :py:meth:`.ImageFont.getlength`
|
||||
``TransposedFont.getsize()`` :py:meth:`.TransposedFont.getbbox` and :py:meth:`.TransposedFont.getlength`
|
||||
``ImageDraw.textsize()`` and ``ImageDraw.multiline_textsize()`` :py:meth:`.ImageDraw.textbbox`, :py:meth:`.ImageDraw.textlength` and :py:meth:`.ImageDraw.multiline_textbbox`
|
||||
``ImageDraw2.Draw.textsize()`` :py:meth:`.ImageDraw2.Draw.textbbox` and :py:meth:`.ImageDraw2.Draw.textlength`
|
||||
=============================================================== =============================================================================================================
|
||||
|
||||
FreeTypeFont.getmask2 fill parameter
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The undocumented ``fill`` parameter of :py:meth:`.FreeTypeFont.getmask2` has been
|
||||
removed.
|
||||
|
||||
PhotoImage.paste box parameter
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The ``box`` parameter was unused and has been removed.
|
||||
|
||||
PyQt5 and PySide2
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
`Qt 5 reached end-of-life <https://www.qt.io/blog/qt-5.15-released>`_ on 2020-12-08 for
|
||||
open-source users (and will reach EOL on 2023-12-08 for commercial licence holders).
|
||||
|
||||
Support for PyQt5 and PySide2 has been removed from ``ImageQt``. Upgrade to
|
||||
`PyQt6 <https://www.riverbankcomputing.com/static/Docs/PyQt6/>`_ or
|
||||
`PySide6 <https://doc.qt.io/qtforpython/>`_ instead.
|
||||
|
||||
Image.coerce_e
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
This undocumented method has been removed.
|
||||
|
||||
Deprecations
|
||||
============
|
||||
|
||||
TODO
|
||||
^^^^
|
||||
|
||||
TODO
|
||||
|
||||
API Changes
|
||||
===========
|
||||
|
||||
TODO
|
||||
^^^^
|
||||
|
||||
TODO
|
||||
|
||||
API Additions
|
||||
=============
|
||||
|
||||
TODO
|
||||
^^^^
|
||||
|
||||
TODO
|
||||
|
||||
Security
|
||||
========
|
||||
|
||||
TODO
|
||||
^^^^
|
||||
|
||||
TODO
|
||||
|
||||
Other Changes
|
||||
=============
|
||||
|
||||
TODO
|
||||
^^^^
|
||||
|
||||
TODO
|
|
@ -8,7 +8,7 @@ JpegImagePlugin.convert_dict_qtables
|
|||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
JPEG ``quantization`` is now automatically converted, but still returned as a
|
||||
dictionary. The :py:attr:`~PIL.JpegImagePlugin.convert_dict_qtables` method no longer
|
||||
dictionary. The ``convert_dict_qtables`` method no longer
|
||||
performs any operations on the data given to it, has been deprecated and will be
|
||||
removed in Pillow 10.0.0 (2023-07-01).
|
||||
|
||||
|
|
|
@ -48,16 +48,16 @@ Font size and offset methods
|
|||
Several functions for computing the size and offset of rendered text
|
||||
have been deprecated and will be removed in Pillow 10 (2023-07-01):
|
||||
|
||||
=========================================================================== =============================================================================================================
|
||||
Deprecated Use instead
|
||||
=========================================================================== =============================================================================================================
|
||||
:py:meth:`.FreeTypeFont.getsize` and :py:meth:`.FreeTypeFont.getoffset` :py:meth:`.FreeTypeFont.getbbox` and :py:meth:`.FreeTypeFont.getlength`
|
||||
:py:meth:`.FreeTypeFont.getsize_multiline` :py:meth:`.ImageDraw.multiline_textbbox`
|
||||
:py:meth:`.ImageFont.getsize` :py:meth:`.ImageFont.getbbox` and :py:meth:`.ImageFont.getlength`
|
||||
:py:meth:`.TransposedFont.getsize` :py:meth:`.TransposedFont.getbbox` and :py:meth:`.TransposedFont.getlength`
|
||||
:py:meth:`.ImageDraw.textsize` and :py:meth:`.ImageDraw.multiline_textsize` :py:meth:`.ImageDraw.textbbox`, :py:meth:`.ImageDraw.textlength` and :py:meth:`.ImageDraw.multiline_textbbox`
|
||||
:py:meth:`.ImageDraw2.Draw.textsize` :py:meth:`.ImageDraw2.Draw.textbbox` and :py:meth:`.ImageDraw2.Draw.textlength`
|
||||
=========================================================================== =============================================================================================================
|
||||
=============================================================== =============================================================================================================
|
||||
Deprecated Use instead
|
||||
=============================================================== =============================================================================================================
|
||||
``FreeTypeFont.getsize()`` and ``FreeTypeFont.getoffset()`` :py:meth:`.FreeTypeFont.getbbox` and :py:meth:`.FreeTypeFont.getlength`
|
||||
``FreeTypeFont.getsize_multiline()`` :py:meth:`.ImageDraw.multiline_textbbox`
|
||||
``ImageFont.getsize()`` :py:meth:`.ImageFont.getbbox` and :py:meth:`.ImageFont.getlength`
|
||||
``TransposedFont.getsize()`` :py:meth:`.TransposedFont.getbbox` and :py:meth:`.TransposedFont.getlength`
|
||||
``ImageDraw.textsize()`` and ``ImageDraw.multiline_textsize()`` :py:meth:`.ImageDraw.textbbox`, :py:meth:`.ImageDraw.textlength` and :py:meth:`.ImageDraw.multiline_textbbox`
|
||||
``ImageDraw2.Draw.textsize()`` :py:meth:`.ImageDraw2.Draw.textbbox` and :py:meth:`.ImageDraw2.Draw.textlength`
|
||||
=============================================================== =============================================================================================================
|
||||
|
||||
Previous code::
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ expected to be backported to earlier versions.
|
|||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
10.0.0
|
||||
9.5.0
|
||||
9.4.0
|
||||
9.3.0
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
x.y.z
|
||||
-----
|
||||
xx.y.z
|
||||
------
|
||||
|
||||
Backwards Incompatible Changes
|
||||
==============================
|
||||
|
|
|
@ -12,7 +12,6 @@ classifiers =
|
|||
License :: OSI Approved :: Historical Permission Notice and Disclaimer (HPND)
|
||||
Programming Language :: Python :: 3
|
||||
Programming Language :: Python :: 3 :: Only
|
||||
Programming Language :: Python :: 3.7
|
||||
Programming Language :: Python :: 3.8
|
||||
Programming Language :: Python :: 3.9
|
||||
Programming Language :: Python :: 3.10
|
||||
|
@ -36,7 +35,7 @@ project_urls =
|
|||
|
||||
[options]
|
||||
packages = PIL
|
||||
python_requires = >=3.7
|
||||
python_requires = >=3.8
|
||||
include_package_data = True
|
||||
package_dir =
|
||||
= src
|
||||
|
|
4
setup.py
4
setup.py
|
@ -681,10 +681,6 @@ class pil_build_ext(build_ext):
|
|||
# Add the directory to the include path so we can include
|
||||
# <openjpeg.h> rather than having to cope with the versioned
|
||||
# include path
|
||||
# FIXME (melvyn-sopacua):
|
||||
# At this point it's possible that best_path is already in
|
||||
# self.compiler.include_dirs. Should investigate how that is
|
||||
# possible.
|
||||
_add_directory(self.compiler.include_dirs, best_path, 0)
|
||||
feature.jpeg2000 = "openjp2"
|
||||
feature.openjpeg_version = ".".join(str(x) for x in best_version)
|
||||
|
|
|
@ -35,7 +35,6 @@ from enum import IntEnum
|
|||
from io import BytesIO
|
||||
|
||||
from . import Image, ImageFile
|
||||
from ._deprecate import deprecate
|
||||
|
||||
|
||||
class Format(IntEnum):
|
||||
|
@ -54,21 +53,6 @@ class AlphaEncoding(IntEnum):
|
|||
DXT5 = 7
|
||||
|
||||
|
||||
def __getattr__(name):
|
||||
for enum, prefix in {
|
||||
Format: "BLP_FORMAT_",
|
||||
Encoding: "BLP_ENCODING_",
|
||||
AlphaEncoding: "BLP_ALPHA_ENCODING_",
|
||||
}.items():
|
||||
if name.startswith(prefix):
|
||||
name = name[len(prefix) :]
|
||||
if name in enum.__members__:
|
||||
deprecate(f"{prefix}{name}", 10, f"{enum.__name__}.{name}")
|
||||
return enum[name]
|
||||
msg = f"module '{__name__}' has no attribute '{name}'"
|
||||
raise AttributeError(msg)
|
||||
|
||||
|
||||
def unpack_565(i):
|
||||
return ((i >> 11) & 0x1F) << 3, ((i >> 5) & 0x3F) << 2, (i & 0x1F) << 3
|
||||
|
||||
|
|
|
@ -1,76 +0,0 @@
|
|||
#
|
||||
# The Python Imaging Library
|
||||
# $Id$
|
||||
#
|
||||
# FITS stub adapter
|
||||
#
|
||||
# Copyright (c) 1998-2003 by Fredrik Lundh
|
||||
#
|
||||
# See the README file for information on usage and redistribution.
|
||||
#
|
||||
|
||||
from . import FitsImagePlugin, Image, ImageFile
|
||||
from ._deprecate import deprecate
|
||||
|
||||
_handler = None
|
||||
|
||||
|
||||
def register_handler(handler):
|
||||
"""
|
||||
Install application-specific FITS image handler.
|
||||
|
||||
:param handler: Handler object.
|
||||
"""
|
||||
global _handler
|
||||
_handler = handler
|
||||
|
||||
deprecate(
|
||||
"FitsStubImagePlugin",
|
||||
10,
|
||||
action="FITS images can now be read without "
|
||||
"a handler through FitsImagePlugin instead",
|
||||
)
|
||||
|
||||
# Override FitsImagePlugin with this handler
|
||||
# for backwards compatibility
|
||||
try:
|
||||
Image.ID.remove(FITSStubImageFile.format)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
Image.register_open(
|
||||
FITSStubImageFile.format, FITSStubImageFile, FitsImagePlugin._accept
|
||||
)
|
||||
|
||||
|
||||
class FITSStubImageFile(ImageFile.StubImageFile):
|
||||
format = FitsImagePlugin.FitsImageFile.format
|
||||
format_description = FitsImagePlugin.FitsImageFile.format_description
|
||||
|
||||
def _open(self):
|
||||
offset = self.fp.tell()
|
||||
|
||||
im = FitsImagePlugin.FitsImageFile(self.fp)
|
||||
self._size = im.size
|
||||
self.mode = im.mode
|
||||
self.tile = []
|
||||
|
||||
self.fp.seek(offset)
|
||||
|
||||
loader = self._load()
|
||||
if loader:
|
||||
loader.open(self)
|
||||
|
||||
def _load(self):
|
||||
return _handler
|
||||
|
||||
|
||||
def _save(im, fp, filename):
|
||||
msg = "FITS save handler not installed"
|
||||
raise OSError(msg)
|
||||
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
# Registry
|
||||
|
||||
Image.register_save(FITSStubImageFile.format, _save)
|
|
@ -56,7 +56,6 @@ from enum import IntEnum
|
|||
from io import BytesIO
|
||||
|
||||
from . import Image, ImageFile
|
||||
from ._deprecate import deprecate
|
||||
|
||||
MAGIC = b"FTEX"
|
||||
|
||||
|
@ -66,17 +65,6 @@ class Format(IntEnum):
|
|||
UNCOMPRESSED = 1
|
||||
|
||||
|
||||
def __getattr__(name):
|
||||
for enum, prefix in {Format: "FORMAT_"}.items():
|
||||
if name.startswith(prefix):
|
||||
name = name[len(prefix) :]
|
||||
if name in enum.__members__:
|
||||
deprecate(f"{prefix}{name}", 10, f"{enum.__name__}.{name}")
|
||||
return enum[name]
|
||||
msg = f"module '{__name__}' has no attribute '{name}'"
|
||||
raise AttributeError(msg)
|
||||
|
||||
|
||||
class FtexImageFile(ImageFile.ImageFile):
|
||||
format = "FTEX"
|
||||
format_description = "Texture File Format (IW2:EOC)"
|
||||
|
|
|
@ -56,29 +56,8 @@ from . import (
|
|||
_plugins,
|
||||
)
|
||||
from ._binary import i32le, o32be, o32le
|
||||
from ._deprecate import deprecate
|
||||
from ._util import DeferredError, is_path
|
||||
|
||||
|
||||
def __getattr__(name):
|
||||
categories = {"NORMAL": 0, "SEQUENCE": 1, "CONTAINER": 2}
|
||||
if name in categories:
|
||||
deprecate("Image categories", 10, "is_animated", plural=True)
|
||||
return categories[name]
|
||||
old_resampling = {
|
||||
"LINEAR": "BILINEAR",
|
||||
"CUBIC": "BICUBIC",
|
||||
"ANTIALIAS": "LANCZOS",
|
||||
}
|
||||
if name in old_resampling:
|
||||
deprecate(
|
||||
name, 10, f"{old_resampling[name]} or Resampling.{old_resampling[name]}"
|
||||
)
|
||||
return Resampling[old_resampling[name]]
|
||||
msg = f"module '{__name__}' has no attribute '{name}'"
|
||||
raise AttributeError(msg)
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
|
@ -441,26 +420,18 @@ def _getencoder(mode, encoder_name, args, extra=()):
|
|||
# Simple expression analyzer
|
||||
|
||||
|
||||
def coerce_e(value):
|
||||
deprecate("coerce_e", 10)
|
||||
return value if isinstance(value, _E) else _E(1, value)
|
||||
|
||||
|
||||
# _E(scale, offset) represents the affine transformation scale * x + offset.
|
||||
# The "data" field is named for compatibility with the old implementation,
|
||||
# and should be renamed once coerce_e is removed.
|
||||
class _E:
|
||||
def __init__(self, scale, data):
|
||||
def __init__(self, scale, offset):
|
||||
self.scale = scale
|
||||
self.data = data
|
||||
self.offset = offset
|
||||
|
||||
def __neg__(self):
|
||||
return _E(-self.scale, -self.data)
|
||||
return _E(-self.scale, -self.offset)
|
||||
|
||||
def __add__(self, other):
|
||||
if isinstance(other, _E):
|
||||
return _E(self.scale + other.scale, self.data + other.data)
|
||||
return _E(self.scale, self.data + other)
|
||||
return _E(self.scale + other.scale, self.offset + other.offset)
|
||||
return _E(self.scale, self.offset + other)
|
||||
|
||||
__radd__ = __add__
|
||||
|
||||
|
@ -473,19 +444,19 @@ class _E:
|
|||
def __mul__(self, other):
|
||||
if isinstance(other, _E):
|
||||
return NotImplemented
|
||||
return _E(self.scale * other, self.data * other)
|
||||
return _E(self.scale * other, self.offset * other)
|
||||
|
||||
__rmul__ = __mul__
|
||||
|
||||
def __truediv__(self, other):
|
||||
if isinstance(other, _E):
|
||||
return NotImplemented
|
||||
return _E(self.scale / other, self.data / other)
|
||||
return _E(self.scale / other, self.offset / other)
|
||||
|
||||
|
||||
def _getscaleoffset(expr):
|
||||
a = expr(_E(1, 0))
|
||||
return (a.scale, a.data) if isinstance(a, _E) else (0, a)
|
||||
return (a.scale, a.offset) if isinstance(a, _E) else (0, a)
|
||||
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
|
@ -516,17 +487,10 @@ class Image:
|
|||
self._size = (0, 0)
|
||||
self.palette = None
|
||||
self.info = {}
|
||||
self._category = 0
|
||||
self.readonly = 0
|
||||
self.pyaccess = None
|
||||
self._exif = None
|
||||
|
||||
def __getattr__(self, name):
|
||||
if name == "category":
|
||||
deprecate("Image categories", 10, "is_animated", plural=True)
|
||||
return self._category
|
||||
raise AttributeError(name)
|
||||
|
||||
@property
|
||||
def width(self):
|
||||
return self.size[0]
|
||||
|
@ -639,7 +603,6 @@ class Image:
|
|||
and self.mode == other.mode
|
||||
and self.size == other.size
|
||||
and self.info == other.info
|
||||
and self._category == other._category
|
||||
and self.getpalette() == other.getpalette()
|
||||
and self.tobytes() == other.tobytes()
|
||||
)
|
||||
|
|
|
@ -20,8 +20,6 @@ from enum import IntEnum
|
|||
|
||||
from PIL import Image
|
||||
|
||||
from ._deprecate import deprecate
|
||||
|
||||
try:
|
||||
from PIL import _imagingcms
|
||||
except ImportError as ex:
|
||||
|
@ -117,17 +115,6 @@ class Direction(IntEnum):
|
|||
PROOF = 2
|
||||
|
||||
|
||||
def __getattr__(name):
|
||||
for enum, prefix in {Intent: "INTENT_", Direction: "DIRECTION_"}.items():
|
||||
if name.startswith(prefix):
|
||||
name = name[len(prefix) :]
|
||||
if name in enum.__members__:
|
||||
deprecate(f"{prefix}{name}", 10, f"{enum.__name__}.{name}")
|
||||
return enum[name]
|
||||
msg = f"module '{__name__}' has no attribute '{name}'"
|
||||
raise AttributeError(msg)
|
||||
|
||||
|
||||
#
|
||||
# flags
|
||||
|
||||
|
|
|
@ -32,10 +32,8 @@
|
|||
|
||||
import math
|
||||
import numbers
|
||||
import warnings
|
||||
|
||||
from . import Image, ImageColor
|
||||
from ._deprecate import deprecate
|
||||
|
||||
"""
|
||||
A simple 2D drawing interface for PIL images.
|
||||
|
@ -433,17 +431,11 @@ class ImageDraw:
|
|||
return text.split(split_character)
|
||||
|
||||
def _multiline_spacing(self, font, spacing, stroke_width):
|
||||
# this can be replaced with self.textbbox(...)[3] when textsize is removed
|
||||
with warnings.catch_warnings():
|
||||
warnings.filterwarnings("ignore", category=DeprecationWarning)
|
||||
return (
|
||||
self.textsize(
|
||||
"A",
|
||||
font=font,
|
||||
stroke_width=stroke_width,
|
||||
)[1]
|
||||
+ spacing
|
||||
)
|
||||
return (
|
||||
self.textbbox((0, 0), "A", font, stroke_width=stroke_width)[3]
|
||||
+ stroke_width
|
||||
+ spacing
|
||||
)
|
||||
|
||||
def text(
|
||||
self,
|
||||
|
@ -645,72 +637,6 @@ class ImageDraw:
|
|||
)
|
||||
top += line_spacing
|
||||
|
||||
def textsize(
|
||||
self,
|
||||
text,
|
||||
font=None,
|
||||
spacing=4,
|
||||
direction=None,
|
||||
features=None,
|
||||
language=None,
|
||||
stroke_width=0,
|
||||
):
|
||||
"""Get the size of a given string, in pixels."""
|
||||
deprecate("textsize", 10, "textbbox or textlength")
|
||||
if self._multiline_check(text):
|
||||
with warnings.catch_warnings():
|
||||
warnings.filterwarnings("ignore", category=DeprecationWarning)
|
||||
return self.multiline_textsize(
|
||||
text,
|
||||
font,
|
||||
spacing,
|
||||
direction,
|
||||
features,
|
||||
language,
|
||||
stroke_width,
|
||||
)
|
||||
|
||||
if font is None:
|
||||
font = self.getfont()
|
||||
with warnings.catch_warnings():
|
||||
warnings.filterwarnings("ignore", category=DeprecationWarning)
|
||||
return font.getsize(
|
||||
text,
|
||||
direction,
|
||||
features,
|
||||
language,
|
||||
stroke_width,
|
||||
)
|
||||
|
||||
def multiline_textsize(
|
||||
self,
|
||||
text,
|
||||
font=None,
|
||||
spacing=4,
|
||||
direction=None,
|
||||
features=None,
|
||||
language=None,
|
||||
stroke_width=0,
|
||||
):
|
||||
deprecate("multiline_textsize", 10, "multiline_textbbox")
|
||||
max_width = 0
|
||||
lines = self._multiline_split(text)
|
||||
line_spacing = self._multiline_spacing(font, spacing, stroke_width)
|
||||
with warnings.catch_warnings():
|
||||
warnings.filterwarnings("ignore", category=DeprecationWarning)
|
||||
for line in lines:
|
||||
line_width, line_height = self.textsize(
|
||||
line,
|
||||
font,
|
||||
spacing,
|
||||
direction,
|
||||
features,
|
||||
language,
|
||||
stroke_width,
|
||||
)
|
||||
max_width = max(max_width, line_width)
|
||||
return max_width, len(lines) * line_spacing - spacing
|
||||
|
||||
def textlength(
|
||||
self,
|
||||
text,
|
||||
|
@ -731,22 +657,7 @@ class ImageDraw:
|
|||
if font is None:
|
||||
font = self.getfont()
|
||||
mode = "RGBA" if embedded_color else self.fontmode
|
||||
try:
|
||||
return font.getlength(text, mode, direction, features, language)
|
||||
except AttributeError:
|
||||
deprecate("textlength support for fonts without getlength", 10)
|
||||
with warnings.catch_warnings():
|
||||
warnings.filterwarnings("ignore", category=DeprecationWarning)
|
||||
size = self.textsize(
|
||||
text,
|
||||
font,
|
||||
direction=direction,
|
||||
features=features,
|
||||
language=language,
|
||||
)
|
||||
if direction == "ttb":
|
||||
return size[1]
|
||||
return size[0]
|
||||
return font.getlength(text, mode, direction, features, language)
|
||||
|
||||
def textbbox(
|
||||
self,
|
||||
|
|
|
@ -24,10 +24,7 @@
|
|||
"""
|
||||
|
||||
|
||||
import warnings
|
||||
|
||||
from . import Image, ImageColor, ImageDraw, ImageFont, ImagePath
|
||||
from ._deprecate import deprecate
|
||||
|
||||
|
||||
class Pen:
|
||||
|
@ -173,19 +170,6 @@ class Draw:
|
|||
xy.transform(self.transform)
|
||||
self.draw.text(xy, text, font=font.font, fill=font.color)
|
||||
|
||||
def textsize(self, text, font):
|
||||
"""
|
||||
.. deprecated:: 9.2.0
|
||||
|
||||
Return the size of the given string, in pixels.
|
||||
|
||||
.. seealso:: :py:meth:`PIL.ImageDraw.ImageDraw.textsize`
|
||||
"""
|
||||
deprecate("textsize", 10, "textbbox or textlength")
|
||||
with warnings.catch_warnings():
|
||||
warnings.filterwarnings("ignore", category=DeprecationWarning)
|
||||
return self.draw.textsize(text, font=font.font)
|
||||
|
||||
def textbbox(self, xy, text, font):
|
||||
"""
|
||||
Returns bounding box (in pixels) of given text.
|
||||
|
|
|
@ -34,7 +34,6 @@ from enum import IntEnum
|
|||
from io import BytesIO
|
||||
|
||||
from . import Image
|
||||
from ._deprecate import deprecate
|
||||
from ._util import is_directory, is_path
|
||||
|
||||
|
||||
|
@ -43,17 +42,6 @@ class Layout(IntEnum):
|
|||
RAQM = 1
|
||||
|
||||
|
||||
def __getattr__(name):
|
||||
for enum, prefix in {Layout: "LAYOUT_"}.items():
|
||||
if name.startswith(prefix):
|
||||
name = name[len(prefix) :]
|
||||
if name in enum.__members__:
|
||||
deprecate(f"{prefix}{name}", 10, f"{enum.__name__}.{name}")
|
||||
return enum[name]
|
||||
msg = f"module '{__name__}' has no attribute '{name}'"
|
||||
raise AttributeError(msg)
|
||||
|
||||
|
||||
try:
|
||||
from . import _imagingft as core
|
||||
except ImportError as ex:
|
||||
|
@ -62,9 +50,6 @@ except ImportError as ex:
|
|||
core = DeferredError(ex)
|
||||
|
||||
|
||||
_UNSPECIFIED = object()
|
||||
|
||||
|
||||
# FIXME: add support for pilfont2 format (see FontFile.py)
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
|
@ -134,23 +119,6 @@ class ImageFont:
|
|||
|
||||
self.font = Image.core.font(image.im, data)
|
||||
|
||||
def getsize(self, text, *args, **kwargs):
|
||||
"""
|
||||
.. deprecated:: 9.2.0
|
||||
|
||||
Use :py:meth:`.getbbox` or :py:meth:`.getlength` instead.
|
||||
|
||||
See :ref:`deprecations <Font size and offset methods>` for more information.
|
||||
|
||||
Returns width and height (in pixels) of given text.
|
||||
|
||||
:param text: Text to measure.
|
||||
|
||||
:return: (width, height)
|
||||
"""
|
||||
deprecate("getsize", 10, "getbbox or getlength")
|
||||
return self.font.getsize(text)
|
||||
|
||||
def getmask(self, text, mode="", *args, **kwargs):
|
||||
"""
|
||||
Create a bitmap for the text.
|
||||
|
@ -412,165 +380,6 @@ class FreeTypeFont:
|
|||
width, height = size[0] + 2 * stroke_width, size[1] + 2 * stroke_width
|
||||
return left, top, left + width, top + height
|
||||
|
||||
def getsize(
|
||||
self,
|
||||
text,
|
||||
direction=None,
|
||||
features=None,
|
||||
language=None,
|
||||
stroke_width=0,
|
||||
):
|
||||
"""
|
||||
.. deprecated:: 9.2.0
|
||||
|
||||
Use :py:meth:`getlength()` to measure the offset of following text with
|
||||
1/64 pixel precision.
|
||||
Use :py:meth:`getbbox()` to get the exact bounding box based on an anchor.
|
||||
|
||||
See :ref:`deprecations <Font size and offset methods>` for more information.
|
||||
|
||||
Returns width and height (in pixels) of given text if rendered in font with
|
||||
provided direction, features, and language.
|
||||
|
||||
.. note:: For historical reasons this function measures text height from
|
||||
the ascender line instead of the top, see :ref:`text-anchors`.
|
||||
If you wish to measure text height from the top, it is recommended
|
||||
to use the bottom value of :meth:`getbbox` with ``anchor='lt'`` instead.
|
||||
|
||||
:param text: Text to measure.
|
||||
|
||||
:param direction: Direction of the text. It can be 'rtl' (right to
|
||||
left), 'ltr' (left to right) or 'ttb' (top to bottom).
|
||||
Requires libraqm.
|
||||
|
||||
.. versionadded:: 4.2.0
|
||||
|
||||
:param features: A list of OpenType font features to be used during text
|
||||
layout. This is usually used to turn on optional
|
||||
font features that are not enabled by default,
|
||||
for example 'dlig' or 'ss01', but can be also
|
||||
used to turn off default font features for
|
||||
example '-liga' to disable ligatures or '-kern'
|
||||
to disable kerning. To get all supported
|
||||
features, see
|
||||
https://learn.microsoft.com/en-us/typography/opentype/spec/featurelist
|
||||
Requires libraqm.
|
||||
|
||||
.. versionadded:: 4.2.0
|
||||
|
||||
:param language: Language of the text. Different languages may use
|
||||
different glyph shapes or ligatures. This parameter tells
|
||||
the font which language the text is in, and to apply the
|
||||
correct substitutions as appropriate, if available.
|
||||
It should be a `BCP 47 language code
|
||||
<https://www.w3.org/International/articles/language-tags/>`_
|
||||
Requires libraqm.
|
||||
|
||||
.. versionadded:: 6.0.0
|
||||
|
||||
:param stroke_width: The width of the text stroke.
|
||||
|
||||
.. versionadded:: 6.2.0
|
||||
|
||||
:return: (width, height)
|
||||
"""
|
||||
deprecate("getsize", 10, "getbbox or getlength")
|
||||
# vertical offset is added for historical reasons
|
||||
# see https://github.com/python-pillow/Pillow/pull/4910#discussion_r486682929
|
||||
size, offset = self.font.getsize(text, "L", direction, features, language)
|
||||
return (
|
||||
size[0] + stroke_width * 2,
|
||||
size[1] + stroke_width * 2 + offset[1],
|
||||
)
|
||||
|
||||
def getsize_multiline(
|
||||
self,
|
||||
text,
|
||||
direction=None,
|
||||
spacing=4,
|
||||
features=None,
|
||||
language=None,
|
||||
stroke_width=0,
|
||||
):
|
||||
"""
|
||||
.. deprecated:: 9.2.0
|
||||
|
||||
Use :py:meth:`.ImageDraw.multiline_textbbox` instead.
|
||||
|
||||
See :ref:`deprecations <Font size and offset methods>` for more information.
|
||||
|
||||
Returns width and height (in pixels) of given text if rendered in font
|
||||
with provided direction, features, and language, while respecting
|
||||
newline characters.
|
||||
|
||||
:param text: Text to measure.
|
||||
|
||||
:param direction: Direction of the text. It can be 'rtl' (right to
|
||||
left), 'ltr' (left to right) or 'ttb' (top to bottom).
|
||||
Requires libraqm.
|
||||
|
||||
:param spacing: The vertical gap between lines, defaulting to 4 pixels.
|
||||
|
||||
:param features: A list of OpenType font features to be used during text
|
||||
layout. This is usually used to turn on optional
|
||||
font features that are not enabled by default,
|
||||
for example 'dlig' or 'ss01', but can be also
|
||||
used to turn off default font features for
|
||||
example '-liga' to disable ligatures or '-kern'
|
||||
to disable kerning. To get all supported
|
||||
features, see
|
||||
https://learn.microsoft.com/en-us/typography/opentype/spec/featurelist
|
||||
Requires libraqm.
|
||||
|
||||
:param language: Language of the text. Different languages may use
|
||||
different glyph shapes or ligatures. This parameter tells
|
||||
the font which language the text is in, and to apply the
|
||||
correct substitutions as appropriate, if available.
|
||||
It should be a `BCP 47 language code
|
||||
<https://www.w3.org/International/articles/language-tags/>`_
|
||||
Requires libraqm.
|
||||
|
||||
.. versionadded:: 6.0.0
|
||||
|
||||
:param stroke_width: The width of the text stroke.
|
||||
|
||||
.. versionadded:: 6.2.0
|
||||
|
||||
:return: (width, height)
|
||||
"""
|
||||
deprecate("getsize_multiline", 10, "ImageDraw.multiline_textbbox")
|
||||
max_width = 0
|
||||
lines = self._multiline_split(text)
|
||||
with warnings.catch_warnings():
|
||||
warnings.filterwarnings("ignore", category=DeprecationWarning)
|
||||
line_spacing = self.getsize("A", stroke_width=stroke_width)[1] + spacing
|
||||
for line in lines:
|
||||
line_width, line_height = self.getsize(
|
||||
line, direction, features, language, stroke_width
|
||||
)
|
||||
max_width = max(max_width, line_width)
|
||||
|
||||
return max_width, len(lines) * line_spacing - spacing
|
||||
|
||||
def getoffset(self, text):
|
||||
"""
|
||||
.. deprecated:: 9.2.0
|
||||
|
||||
Use :py:meth:`.getbbox` instead.
|
||||
|
||||
See :ref:`deprecations <Font size and offset methods>` for more information.
|
||||
|
||||
Returns the offset of given text. This is the gap between the
|
||||
starting coordinate and the first marking. Note that this gap is
|
||||
included in the result of :py:func:`~PIL.ImageFont.FreeTypeFont.getsize`.
|
||||
|
||||
:param text: Text to measure.
|
||||
|
||||
:return: A tuple of the x and y offset
|
||||
"""
|
||||
deprecate("getoffset", 10, "getbbox")
|
||||
return self.font.getsize(text)[1]
|
||||
|
||||
def getmask(
|
||||
self,
|
||||
text,
|
||||
|
@ -665,7 +474,6 @@ class FreeTypeFont:
|
|||
self,
|
||||
text,
|
||||
mode="",
|
||||
fill=_UNSPECIFIED,
|
||||
direction=None,
|
||||
features=None,
|
||||
language=None,
|
||||
|
@ -691,12 +499,6 @@ class FreeTypeFont:
|
|||
|
||||
.. versionadded:: 1.1.5
|
||||
|
||||
:param fill: Optional fill function. By default, an internal Pillow function
|
||||
will be used.
|
||||
|
||||
Deprecated. This parameter will be removed in Pillow 10
|
||||
(2023-07-01).
|
||||
|
||||
:param direction: Direction of the text. It can be 'rtl' (right to
|
||||
left), 'ltr' (left to right) or 'ttb' (top to bottom).
|
||||
Requires libraqm.
|
||||
|
@ -749,10 +551,6 @@ class FreeTypeFont:
|
|||
:py:mod:`PIL.Image.core` interface module, and the text offset, the
|
||||
gap between the starting coordinate and the first marking
|
||||
"""
|
||||
if fill is _UNSPECIFIED:
|
||||
fill = Image.core.fill
|
||||
else:
|
||||
deprecate("fill", 10)
|
||||
size, offset = self.font.getsize(
|
||||
text, mode, direction, features, language, anchor
|
||||
)
|
||||
|
@ -761,7 +559,7 @@ class FreeTypeFont:
|
|||
size = tuple(math.ceil(size[i] + stroke_width * 2 + start[i]) for i in range(2))
|
||||
offset = offset[0] - stroke_width, offset[1] - stroke_width
|
||||
Image._decompression_bomb_check(size)
|
||||
im = fill("RGBA" if mode == "RGBA" else "L", size, 0)
|
||||
im = Image.core.fill("RGBA" if mode == "RGBA" else "L", size, 0)
|
||||
if min(size):
|
||||
self.font.render(
|
||||
text,
|
||||
|
@ -876,22 +674,6 @@ class TransposedFont:
|
|||
self.font = font
|
||||
self.orientation = orientation # any 'transpose' argument, or None
|
||||
|
||||
def getsize(self, text, *args, **kwargs):
|
||||
"""
|
||||
.. deprecated:: 9.2.0
|
||||
|
||||
Use :py:meth:`.getbbox` or :py:meth:`.getlength` instead.
|
||||
|
||||
See :ref:`deprecations <Font size and offset methods>` for more information.
|
||||
"""
|
||||
deprecate("getsize", 10, "getbbox or getlength")
|
||||
with warnings.catch_warnings():
|
||||
warnings.filterwarnings("ignore", category=DeprecationWarning)
|
||||
w, h = self.font.getsize(text)
|
||||
if self.orientation in (Image.Transpose.ROTATE_90, Image.Transpose.ROTATE_270):
|
||||
return h, w
|
||||
return w, h
|
||||
|
||||
def getmask(self, text, mode="", *args, **kwargs):
|
||||
im = self.font.getmask(text, mode, *args, **kwargs)
|
||||
if self.orientation is not None:
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
import array
|
||||
|
||||
from . import GimpGradientFile, GimpPaletteFile, ImageColor, PaletteFile
|
||||
from ._deprecate import deprecate
|
||||
|
||||
|
||||
class ImagePalette:
|
||||
|
@ -34,16 +33,11 @@ class ImagePalette:
|
|||
Defaults to an empty palette.
|
||||
"""
|
||||
|
||||
def __init__(self, mode="RGB", palette=None, size=0):
|
||||
def __init__(self, mode="RGB", palette=None):
|
||||
self.mode = mode
|
||||
self.rawmode = None # if set, palette contains raw data
|
||||
self.palette = palette or bytearray()
|
||||
self.dirty = None
|
||||
if size != 0:
|
||||
deprecate("The size parameter", 10, None)
|
||||
if size != len(self.palette):
|
||||
msg = "wrong palette size"
|
||||
raise ValueError(msg)
|
||||
|
||||
@property
|
||||
def palette(self):
|
||||
|
|
|
@ -20,14 +20,11 @@ import sys
|
|||
from io import BytesIO
|
||||
|
||||
from . import Image
|
||||
from ._deprecate import deprecate
|
||||
from ._util import is_path
|
||||
|
||||
qt_versions = [
|
||||
["6", "PyQt6"],
|
||||
["side6", "PySide6"],
|
||||
["5", "PyQt5"],
|
||||
["side2", "PySide2"],
|
||||
]
|
||||
|
||||
# If a version has already been imported, attempt it first
|
||||
|
@ -40,16 +37,6 @@ for qt_version, qt_module in qt_versions:
|
|||
elif qt_module == "PySide6":
|
||||
from PySide6.QtCore import QBuffer, QIODevice
|
||||
from PySide6.QtGui import QImage, QPixmap, qRgba
|
||||
elif qt_module == "PyQt5":
|
||||
from PyQt5.QtCore import QBuffer, QIODevice
|
||||
from PyQt5.QtGui import QImage, QPixmap, qRgba
|
||||
|
||||
deprecate("Support for PyQt5", 10, "PyQt6 or PySide6")
|
||||
elif qt_module == "PySide2":
|
||||
from PySide2.QtCore import QBuffer, QIODevice
|
||||
from PySide2.QtGui import QImage, QPixmap, qRgba
|
||||
|
||||
deprecate("Support for PySide2", 10, "PyQt6 or PySide6")
|
||||
except (ImportError, RuntimeError):
|
||||
continue
|
||||
qt_is_installed = True
|
||||
|
|
|
@ -19,8 +19,6 @@ from shlex import quote
|
|||
|
||||
from PIL import Image
|
||||
|
||||
from ._deprecate import deprecate
|
||||
|
||||
_viewers = []
|
||||
|
||||
|
||||
|
@ -111,21 +109,10 @@ class Viewer:
|
|||
"""Display the given image."""
|
||||
return self.show_file(self.save_image(image), **options)
|
||||
|
||||
def show_file(self, path=None, **options):
|
||||
def show_file(self, path, **options):
|
||||
"""
|
||||
Display given file.
|
||||
|
||||
Before Pillow 9.1.0, the first argument was ``file``. This is now deprecated,
|
||||
and will be removed in Pillow 10.0.0 (2023-07-01). ``path`` should be used
|
||||
instead.
|
||||
"""
|
||||
if path is None:
|
||||
if "file" in options:
|
||||
deprecate("The 'file' argument", 10, "'path'")
|
||||
path = options.pop("file")
|
||||
else:
|
||||
msg = "Missing required argument: 'path'"
|
||||
raise TypeError(msg)
|
||||
os.system(self.get_command(path, **options)) # nosec
|
||||
return 1
|
||||
|
||||
|
@ -164,21 +151,10 @@ class MacViewer(Viewer):
|
|||
command = f"({command} {quote(file)}; sleep 20; rm -f {quote(file)})&"
|
||||
return command
|
||||
|
||||
def show_file(self, path=None, **options):
|
||||
def show_file(self, path, **options):
|
||||
"""
|
||||
Display given file.
|
||||
|
||||
Before Pillow 9.1.0, the first argument was ``file``. This is now deprecated,
|
||||
and will be removed in Pillow 10.0.0 (2023-07-01). ``path`` should be used
|
||||
instead.
|
||||
"""
|
||||
if path is None:
|
||||
if "file" in options:
|
||||
deprecate("The 'file' argument", 10, "'path'")
|
||||
path = options.pop("file")
|
||||
else:
|
||||
msg = "Missing required argument: 'path'"
|
||||
raise TypeError(msg)
|
||||
subprocess.call(["open", "-a", "Preview.app", path])
|
||||
executable = sys.executable or shutil.which("python3")
|
||||
if executable:
|
||||
|
@ -215,21 +191,10 @@ class XDGViewer(UnixViewer):
|
|||
command = executable = "xdg-open"
|
||||
return command, executable
|
||||
|
||||
def show_file(self, path=None, **options):
|
||||
def show_file(self, path, **options):
|
||||
"""
|
||||
Display given file.
|
||||
|
||||
Before Pillow 9.1.0, the first argument was ``file``. This is now deprecated,
|
||||
and will be removed in Pillow 10.0.0 (2023-07-01). ``path`` should be used
|
||||
instead.
|
||||
"""
|
||||
if path is None:
|
||||
if "file" in options:
|
||||
deprecate("The 'file' argument", 10, "'path'")
|
||||
path = options.pop("file")
|
||||
else:
|
||||
msg = "Missing required argument: 'path'"
|
||||
raise TypeError(msg)
|
||||
subprocess.Popen(["xdg-open", path])
|
||||
return 1
|
||||
|
||||
|
@ -246,20 +211,10 @@ class DisplayViewer(UnixViewer):
|
|||
command += f" -title {quote(title)}"
|
||||
return command, executable
|
||||
|
||||
def show_file(self, path=None, **options):
|
||||
def show_file(self, path, **options):
|
||||
"""
|
||||
Display given file.
|
||||
|
||||
Before Pillow 9.1.0, the first argument was ``file``. This is now deprecated,
|
||||
and ``path`` should be used instead.
|
||||
"""
|
||||
if path is None:
|
||||
if "file" in options:
|
||||
deprecate("The 'file' argument", 10, "'path'")
|
||||
path = options.pop("file")
|
||||
else:
|
||||
msg = "Missing required argument: 'path'"
|
||||
raise TypeError(msg)
|
||||
args = ["display"]
|
||||
title = options.get("title")
|
||||
if title:
|
||||
|
@ -278,20 +233,10 @@ class GmDisplayViewer(UnixViewer):
|
|||
command = "gm display"
|
||||
return command, executable
|
||||
|
||||
def show_file(self, path=None, **options):
|
||||
def show_file(self, path, **options):
|
||||
"""
|
||||
Display given file.
|
||||
|
||||
Before Pillow 9.1.0, the first argument was ``file``. This is now deprecated,
|
||||
and ``path`` should be used instead.
|
||||
"""
|
||||
if path is None:
|
||||
if "file" in options:
|
||||
deprecate("The 'file' argument", 10, "'path'")
|
||||
path = options.pop("file")
|
||||
else:
|
||||
msg = "Missing required argument: 'path'"
|
||||
raise TypeError(msg)
|
||||
subprocess.Popen(["gm", "display", path])
|
||||
return 1
|
||||
|
||||
|
@ -304,20 +249,10 @@ class EogViewer(UnixViewer):
|
|||
command = "eog -n"
|
||||
return command, executable
|
||||
|
||||
def show_file(self, path=None, **options):
|
||||
def show_file(self, path, **options):
|
||||
"""
|
||||
Display given file.
|
||||
|
||||
Before Pillow 9.1.0, the first argument was ``file``. This is now deprecated,
|
||||
and ``path`` should be used instead.
|
||||
"""
|
||||
if path is None:
|
||||
if "file" in options:
|
||||
deprecate("The 'file' argument", 10, "'path'")
|
||||
path = options.pop("file")
|
||||
else:
|
||||
msg = "Missing required argument: 'path'"
|
||||
raise TypeError(msg)
|
||||
subprocess.Popen(["eog", "-n", path])
|
||||
return 1
|
||||
|
||||
|
@ -336,20 +271,10 @@ class XVViewer(UnixViewer):
|
|||
command += f" -name {quote(title)}"
|
||||
return command, executable
|
||||
|
||||
def show_file(self, path=None, **options):
|
||||
def show_file(self, path, **options):
|
||||
"""
|
||||
Display given file.
|
||||
|
||||
Before Pillow 9.1.0, the first argument was ``file``. This is now deprecated,
|
||||
and ``path`` should be used instead.
|
||||
"""
|
||||
if path is None:
|
||||
if "file" in options:
|
||||
deprecate("The 'file' argument", 10, "'path'")
|
||||
path = options.pop("file")
|
||||
else:
|
||||
msg = "Missing required argument: 'path'"
|
||||
raise TypeError(msg)
|
||||
args = ["xv"]
|
||||
title = options.get("title")
|
||||
if title:
|
||||
|
|
|
@ -29,7 +29,6 @@ import tkinter
|
|||
from io import BytesIO
|
||||
|
||||
from . import Image
|
||||
from ._deprecate import deprecate
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
# Check for Tkinter interface hooks
|
||||
|
@ -162,7 +161,7 @@ class PhotoImage:
|
|||
"""
|
||||
return self.__size[1]
|
||||
|
||||
def paste(self, im, box=None):
|
||||
def paste(self, im):
|
||||
"""
|
||||
Paste a PIL image into the photo image. Note that this can
|
||||
be very slow if the photo image is displayed.
|
||||
|
@ -170,13 +169,7 @@ class PhotoImage:
|
|||
:param im: A PIL image. The size must match the target region. If the
|
||||
mode does not match, the image is converted to the mode of
|
||||
the bitmap image.
|
||||
:param box: Deprecated. This parameter will be removed in Pillow 10
|
||||
(2023-07-01).
|
||||
"""
|
||||
|
||||
if box is not None:
|
||||
deprecate("The box parameter", 10, None)
|
||||
|
||||
# convert to blittable
|
||||
im.load()
|
||||
image = im.im
|
||||
|
|
|
@ -46,7 +46,6 @@ from ._binary import i16be as i16
|
|||
from ._binary import i32be as i32
|
||||
from ._binary import o8
|
||||
from ._binary import o16be as o16
|
||||
from ._deprecate import deprecate
|
||||
from .JpegPresets import presets
|
||||
|
||||
#
|
||||
|
@ -612,11 +611,6 @@ samplings = {
|
|||
# fmt: on
|
||||
|
||||
|
||||
def convert_dict_qtables(qtables):
|
||||
deprecate("convert_dict_qtables", 10, action="Conversion is no longer needed")
|
||||
return qtables
|
||||
|
||||
|
||||
def get_sampling(im):
|
||||
# There's no subsampling when images have only 1 layer
|
||||
# (grayscale images) or when they are CMYK (4 layers),
|
||||
|
|
|
@ -66,9 +66,6 @@ class MicImageFile(TiffImagePlugin.TiffImageFile):
|
|||
self._n_frames = len(self.images)
|
||||
self.is_animated = self._n_frames > 1
|
||||
|
||||
if len(self.images) > 1:
|
||||
self._category = Image.CONTAINER
|
||||
|
||||
self.seek(0)
|
||||
|
||||
def seek(self, frame):
|
||||
|
|
|
@ -45,7 +45,6 @@ from ._binary import i32be as i32
|
|||
from ._binary import o8
|
||||
from ._binary import o16be as o16
|
||||
from ._binary import o32be as o32
|
||||
from ._deprecate import deprecate
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
@ -131,17 +130,6 @@ class Blend(IntEnum):
|
|||
"""
|
||||
|
||||
|
||||
def __getattr__(name):
|
||||
for enum, prefix in {Disposal: "APNG_DISPOSE_", Blend: "APNG_BLEND_"}.items():
|
||||
if name.startswith(prefix):
|
||||
name = name[len(prefix) :]
|
||||
if name in enum.__members__:
|
||||
deprecate(f"{prefix}{name}", 10, f"{enum.__name__}.{name}")
|
||||
return enum[name]
|
||||
msg = f"module '{__name__}' has no attribute '{name}'"
|
||||
raise AttributeError(msg)
|
||||
|
||||
|
||||
def _safe_zlib_decompress(s):
|
||||
dobj = zlib.decompressobj()
|
||||
plaintext = dobj.decompress(s, MAX_TEXT_CHUNK)
|
||||
|
|
|
@ -31,7 +31,6 @@ _plugins = [
|
|||
"DdsImagePlugin",
|
||||
"EpsImagePlugin",
|
||||
"FitsImagePlugin",
|
||||
"FitsStubImagePlugin",
|
||||
"FliImagePlugin",
|
||||
"FpxImagePlugin",
|
||||
"FtexImagePlugin",
|
||||
|
|
|
@ -45,8 +45,6 @@ def deprecate(
|
|||
elif when <= int(__version__.split(".")[0]):
|
||||
msg = f"{deprecated} {is_} deprecated and should be removed."
|
||||
raise RuntimeError(msg)
|
||||
elif when == 10:
|
||||
removed = "Pillow 10 (2023-07-01)"
|
||||
elif when == 11:
|
||||
removed = "Pillow 11 (2024-10-15)"
|
||||
else:
|
||||
|
|
|
@ -4,8 +4,6 @@ import sys
|
|||
import tkinter
|
||||
from tkinter import _tkinter as tk
|
||||
|
||||
from ._deprecate import deprecate
|
||||
|
||||
try:
|
||||
if hasattr(sys, "pypy_find_executable"):
|
||||
TKINTER_LIB = tk.tklib_cffi.__file__
|
||||
|
@ -17,7 +15,3 @@ except AttributeError:
|
|||
TKINTER_LIB = None
|
||||
|
||||
tk_version = str(tkinter.TkVersion)
|
||||
if tk_version == "8.4":
|
||||
deprecate(
|
||||
"Support for Tk/Tcl 8.4", 10, action="Please upgrade to Tk/Tcl 8.5 or newer"
|
||||
)
|
||||
|
|
|
@ -119,17 +119,7 @@ typedef struct Tk_PhotoImageBlock {
|
|||
} Tk_PhotoImageBlock;
|
||||
|
||||
/* Typedefs derived from function signatures in Tk header */
|
||||
/* Tk_PhotoPutBlock for Tk <= 8.4 */
|
||||
typedef void (*Tk_PhotoPutBlock_84_t)(
|
||||
Tk_PhotoHandle handle,
|
||||
Tk_PhotoImageBlock *blockPtr,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height,
|
||||
int compRule);
|
||||
/* Tk_PhotoPutBlock for Tk >= 8.5 */
|
||||
typedef int (*Tk_PhotoPutBlock_85_t)(
|
||||
typedef int (*Tk_PhotoPutBlock_t)(
|
||||
Tcl_Interp *interp,
|
||||
Tk_PhotoHandle handle,
|
||||
Tk_PhotoImageBlock *blockPtr,
|
||||
|
@ -138,8 +128,6 @@ typedef int (*Tk_PhotoPutBlock_85_t)(
|
|||
int width,
|
||||
int height,
|
||||
int compRule);
|
||||
/* Tk_PhotoSetSize for Tk <= 8.4 */
|
||||
typedef void (*Tk_PhotoSetSize_84_t)(Tk_PhotoHandle handle, int width, int height);
|
||||
/* Tk_FindPhoto */
|
||||
typedef Tk_PhotoHandle (*Tk_FindPhoto_t)(Tcl_Interp *interp, const char *imageName);
|
||||
/* Tk_PhotoGetImage */
|
||||
|
|
|
@ -48,14 +48,11 @@
|
|||
* Global vars for Tcl / Tk functions. We load these symbols from the tkinter
|
||||
* extension module or loaded Tcl / Tk libraries at run-time.
|
||||
*/
|
||||
static int TK_LT_85 = 0;
|
||||
static Tcl_CreateCommand_t TCL_CREATE_COMMAND;
|
||||
static Tcl_AppendResult_t TCL_APPEND_RESULT;
|
||||
static Tk_FindPhoto_t TK_FIND_PHOTO;
|
||||
static Tk_PhotoGetImage_t TK_PHOTO_GET_IMAGE;
|
||||
static Tk_PhotoPutBlock_84_t TK_PHOTO_PUT_BLOCK_84;
|
||||
static Tk_PhotoSetSize_84_t TK_PHOTO_SET_SIZE_84;
|
||||
static Tk_PhotoPutBlock_85_t TK_PHOTO_PUT_BLOCK_85;
|
||||
static Tk_PhotoPutBlock_t TK_PHOTO_PUT_BLOCK;
|
||||
|
||||
static Imaging
|
||||
ImagingFind(const char *name) {
|
||||
|
@ -130,26 +127,15 @@ PyImagingPhotoPut(
|
|||
block.pitch = im->linesize;
|
||||
block.pixelPtr = (unsigned char *)im->block;
|
||||
|
||||
if (TK_LT_85) { /* Tk 8.4 */
|
||||
TK_PHOTO_PUT_BLOCK_84(
|
||||
photo, &block, 0, 0, block.width, block.height, TK_PHOTO_COMPOSITE_SET);
|
||||
if (strcmp(im->mode, "RGBA") == 0) {
|
||||
/* Tk workaround: we need apply ToggleComplexAlphaIfNeeded */
|
||||
/* (fixed in Tk 8.5a3) */
|
||||
TK_PHOTO_SET_SIZE_84(photo, block.width, block.height);
|
||||
}
|
||||
} else {
|
||||
/* Tk >=8.5 */
|
||||
TK_PHOTO_PUT_BLOCK_85(
|
||||
interp,
|
||||
photo,
|
||||
&block,
|
||||
0,
|
||||
0,
|
||||
block.width,
|
||||
block.height,
|
||||
TK_PHOTO_COMPOSITE_SET);
|
||||
}
|
||||
TK_PHOTO_PUT_BLOCK(
|
||||
interp,
|
||||
photo,
|
||||
&block,
|
||||
0,
|
||||
0,
|
||||
block.width,
|
||||
block.height,
|
||||
TK_PHOTO_COMPOSITE_SET);
|
||||
|
||||
return TCL_OK;
|
||||
}
|
||||
|
@ -290,16 +276,7 @@ get_tk(HMODULE hMod) {
|
|||
if ((TK_FIND_PHOTO = (Tk_FindPhoto_t)_dfunc(hMod, "Tk_FindPhoto")) == NULL) {
|
||||
return -1;
|
||||
};
|
||||
TK_LT_85 = GetProcAddress(hMod, "Tk_PhotoPutBlock_Panic") == NULL;
|
||||
/* Tk_PhotoPutBlock_Panic defined as of 8.5.0 */
|
||||
if (TK_LT_85) {
|
||||
TK_PHOTO_PUT_BLOCK_84 = (Tk_PhotoPutBlock_84_t)func;
|
||||
return ((TK_PHOTO_SET_SIZE_84 =
|
||||
(Tk_PhotoSetSize_84_t)_dfunc(hMod, "Tk_PhotoSetSize")) == NULL)
|
||||
? -1
|
||||
: 1;
|
||||
}
|
||||
TK_PHOTO_PUT_BLOCK_85 = (Tk_PhotoPutBlock_85_t)func;
|
||||
TK_PHOTO_PUT_BLOCK = (Tk_PhotoPutBlock_t)func;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -422,18 +399,9 @@ _func_loader(void *lib) {
|
|||
if ((TK_FIND_PHOTO = (Tk_FindPhoto_t)_dfunc(lib, "Tk_FindPhoto")) == NULL) {
|
||||
return 1;
|
||||
}
|
||||
/* Tk_PhotoPutBlock_Panic defined as of 8.5.0 */
|
||||
TK_LT_85 = (dlsym(lib, "Tk_PhotoPutBlock_Panic") == NULL);
|
||||
if (TK_LT_85) {
|
||||
return (
|
||||
((TK_PHOTO_PUT_BLOCK_84 =
|
||||
(Tk_PhotoPutBlock_84_t)_dfunc(lib, "Tk_PhotoPutBlock")) == NULL) ||
|
||||
((TK_PHOTO_SET_SIZE_84 =
|
||||
(Tk_PhotoSetSize_84_t)_dfunc(lib, "Tk_PhotoSetSize")) == NULL));
|
||||
}
|
||||
return (
|
||||
(TK_PHOTO_PUT_BLOCK_85 =
|
||||
(Tk_PhotoPutBlock_85_t)_dfunc(lib, "Tk_PhotoPutBlock")) == NULL);
|
||||
(TK_PHOTO_PUT_BLOCK =
|
||||
(Tk_PhotoPutBlock_t)_dfunc(lib, "Tk_PhotoPutBlock")) == NULL);
|
||||
}
|
||||
|
||||
int
|
||||
|
|
11
tox.ini
11
tox.ini
|
@ -1,8 +1,8 @@
|
|||
[tox]
|
||||
minversion = 1.9
|
||||
envlist =
|
||||
lint
|
||||
py{py3, 311, 310, 39, 38, 37}
|
||||
minversion = 1.9
|
||||
py{py3, 311, 310, 39, 38}
|
||||
|
||||
[testenv]
|
||||
deps =
|
||||
|
@ -15,15 +15,16 @@ commands =
|
|||
{envpython} -m pip install --global-option="build_ext" --global-option="--inplace" .
|
||||
{envpython} selftest.py
|
||||
{envpython} -m pytest -W always {posargs}
|
||||
allowlist_externals = make
|
||||
allowlist_externals =
|
||||
make
|
||||
|
||||
[testenv:lint]
|
||||
passenv =
|
||||
PRE_COMMIT_COLOR
|
||||
skip_install = true
|
||||
deps =
|
||||
check-manifest
|
||||
pre-commit
|
||||
passenv =
|
||||
PRE_COMMIT_COLOR
|
||||
commands =
|
||||
pre-commit run --all-files --show-diff-on-failure
|
||||
check-manifest
|
||||
|
|
|
@ -18,7 +18,7 @@ The following is a simplified version of the script used on AppVeyor:
|
|||
```
|
||||
set PYTHON=C:\Python38\bin
|
||||
cd /D C:\Pillow\winbuild
|
||||
C:\Python37\bin\python.exe build_prepare.py -v --depends=C:\pillow-depends
|
||||
C:\Python39\bin\python.exe build_prepare.py -v --depends=C:\pillow-depends
|
||||
build\build_dep_all.cmd
|
||||
build\build_pillow.cmd install
|
||||
cd ..
|
||||
|
|
|
@ -112,7 +112,7 @@ The following is a simplified version of the script used on AppVeyor::
|
|||
|
||||
set PYTHON=C:\Python38\bin
|
||||
cd /D C:\Pillow\winbuild
|
||||
C:\Python37\bin\python.exe build_prepare.py -v --depends C:\pillow-depends
|
||||
C:\Python39\bin\python.exe build_prepare.py -v --depends C:\pillow-depends
|
||||
build\build_dep_all.cmd
|
||||
build\build_pillow.cmd install
|
||||
cd ..
|
||||
|
|
Loading…
Reference in New Issue
Block a user