diff --git a/Tests/test_image_point.py b/Tests/test_image_point.py index 428ad116b3d..157ecb120f0 100644 --- a/Tests/test_image_point.py +++ b/Tests/test_image_point.py @@ -1,5 +1,7 @@ import pytest +from PIL import Image + from .helper import assert_image_equal, hopper @@ -17,11 +19,24 @@ def test_sanity(): im.point(list(range(256))) im.point(lambda x: x * 1) im.point(lambda x: x + 1) + im.point(lambda x: x - 1) im.point(lambda x: x * 1 + 1) + im.point(lambda x: 0.1 + 0.2 * x) + im.point(lambda x: -x) + im.point(lambda x: x - 0.5) + im.point(lambda x: 1 - x / 2) + im.point(lambda x: (2 + x) / 3) + im.point(lambda x: 0.5) + im.point(lambda x: x / 1) + im.point(lambda x: x + x) + with pytest.raises(TypeError): + im.point(lambda x: x * x) + with pytest.raises(TypeError): + im.point(lambda x: x / x) with pytest.raises(TypeError): - im.point(lambda x: x - 1) + im.point(lambda x: 1 / x) with pytest.raises(TypeError): - im.point(lambda x: x / 1) + im.point(lambda x: x // 2) def test_16bit_lut(): @@ -47,3 +62,8 @@ 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 diff --git a/docs/deprecations.rst b/docs/deprecations.rst index ad030acd071..8c5b8a748d7 100644 --- a/docs/deprecations.rst +++ b/docs/deprecations.rst @@ -170,6 +170,14 @@ in Pillow 10 (2023-07-01). Upgrade to `PyQt6 `_ or `PySide6 `_ instead. +Image.coerce_e +~~~~~~~~~~~~~~ + +.. deprecated:: 9.2.0 + +This undocumented method has been deprecated and will be removed in Pillow 10 +(2023-07-01). + Removed features ---------------- diff --git a/docs/releasenotes/9.2.0.rst b/docs/releasenotes/9.2.0.rst index c38944b10e9..db051d1881f 100644 --- a/docs/releasenotes/9.2.0.rst +++ b/docs/releasenotes/9.2.0.rst @@ -31,6 +31,14 @@ FreeTypeFont.getmask2 fill parameter The undocumented ``fill`` parameter of :py:meth:`.FreeTypeFont.getmask2` has been deprecated and will be removed in Pillow 10 (2023-07-01). +Image.coerce_e +~~~~~~~~~~~~~~ + +.. deprecated:: 9.2.0 + +This undocumented method has been deprecated and will be removed in Pillow 10 +(2023-07-01). + API Changes =========== diff --git a/src/PIL/Image.py b/src/PIL/Image.py index fead48b29d9..4ac4fda26b5 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -29,7 +29,6 @@ import io import logging import math -import numbers import os import re import struct @@ -432,44 +431,50 @@ def _getencoder(mode, encoder_name, args, extra=()): def coerce_e(value): - return value if isinstance(value, _E) else _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, data): + def __init__(self, scale, data): + self.scale = scale self.data = data + def __neg__(self): + return _E(-self.scale, -self.data) + def __add__(self, other): - return _E((self.data, "__add__", coerce_e(other).data)) + if isinstance(other, _E): + return _E(self.scale + other.scale, self.data + other.data) + return _E(self.scale, self.data + other) + + __radd__ = __add__ + + def __sub__(self, other): + return self + -other + + def __rsub__(self, other): + return other + -self def __mul__(self, other): - return _E((self.data, "__mul__", coerce_e(other).data)) + if isinstance(other, _E): + return NotImplemented + return _E(self.scale * other, self.data * other) + + __rmul__ = __mul__ + + def __truediv__(self, other): + if isinstance(other, _E): + return NotImplemented + return _E(self.scale / other, self.data / other) def _getscaleoffset(expr): - stub = ["stub"] - data = expr(_E(stub)).data - try: - (a, b, c) = data # simplified syntax - if a is stub and b == "__mul__" and isinstance(c, numbers.Number): - return c, 0.0 - if a is stub and b == "__add__" and isinstance(c, numbers.Number): - return 1.0, c - except TypeError: - pass - try: - ((a, b, c), d, e) = data # full syntax - if ( - a is stub - and b == "__mul__" - and isinstance(c, numbers.Number) - and d == "__add__" - and isinstance(e, numbers.Number) - ): - return c, e - except TypeError: - pass - raise ValueError("illegal expression") + a = expr(_E(1, 0)) + return (a.scale, a.data) if isinstance(a, _E) else (0, a) # --------------------------------------------------------------------