mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-07-10 16:22:22 +03:00
Merge pull request #6254 from benrg/affine-transform
Support more affine expression forms in im.point()
This commit is contained in:
commit
80782bba9b
|
@ -1,5 +1,7 @@
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
from PIL import Image
|
||||||
|
|
||||||
from .helper import assert_image_equal, hopper
|
from .helper import assert_image_equal, hopper
|
||||||
|
|
||||||
|
|
||||||
|
@ -17,11 +19,24 @@ def test_sanity():
|
||||||
im.point(list(range(256)))
|
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)
|
||||||
|
im.point(lambda x: x - 1)
|
||||||
im.point(lambda x: x * 1 + 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):
|
with pytest.raises(TypeError):
|
||||||
im.point(lambda x: x - 1)
|
im.point(lambda x: x * x)
|
||||||
with pytest.raises(TypeError):
|
with pytest.raises(TypeError):
|
||||||
im.point(lambda x: x / 1)
|
im.point(lambda x: x / x)
|
||||||
|
with pytest.raises(TypeError):
|
||||||
|
im.point(lambda x: 1 / x)
|
||||||
|
with pytest.raises(TypeError):
|
||||||
|
im.point(lambda x: x // 2)
|
||||||
|
|
||||||
|
|
||||||
def test_16bit_lut():
|
def test_16bit_lut():
|
||||||
|
@ -47,3 +62,8 @@ def test_f_mode():
|
||||||
im = hopper("F")
|
im = hopper("F")
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
im.point(None)
|
im.point(None)
|
||||||
|
|
||||||
|
|
||||||
|
def test_coerce_e_deprecation():
|
||||||
|
with pytest.warns(DeprecationWarning):
|
||||||
|
assert Image.coerce_e(2).data == 2
|
||||||
|
|
|
@ -170,6 +170,14 @@ in Pillow 10 (2023-07-01). Upgrade to
|
||||||
`PyQt6 <https://www.riverbankcomputing.com/static/Docs/PyQt6/>`_ or
|
`PyQt6 <https://www.riverbankcomputing.com/static/Docs/PyQt6/>`_ or
|
||||||
`PySide6 <https://doc.qt.io/qtforpython/>`_ instead.
|
`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).
|
||||||
|
|
||||||
Removed features
|
Removed features
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,14 @@ FreeTypeFont.getmask2 fill parameter
|
||||||
The undocumented ``fill`` parameter of :py:meth:`.FreeTypeFont.getmask2`
|
The undocumented ``fill`` parameter of :py:meth:`.FreeTypeFont.getmask2`
|
||||||
has been deprecated and will be removed in Pillow 10 (2023-07-01).
|
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
|
API Changes
|
||||||
===========
|
===========
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,6 @@ import builtins
|
||||||
import io
|
import io
|
||||||
import logging
|
import logging
|
||||||
import math
|
import math
|
||||||
import numbers
|
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import struct
|
import struct
|
||||||
|
@ -432,44 +431,50 @@ def _getencoder(mode, encoder_name, args, extra=()):
|
||||||
|
|
||||||
|
|
||||||
def coerce_e(value):
|
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:
|
class _E:
|
||||||
def __init__(self, data):
|
def __init__(self, scale, data):
|
||||||
|
self.scale = scale
|
||||||
self.data = data
|
self.data = data
|
||||||
|
|
||||||
|
def __neg__(self):
|
||||||
|
return _E(-self.scale, -self.data)
|
||||||
|
|
||||||
def __add__(self, other):
|
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):
|
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):
|
def _getscaleoffset(expr):
|
||||||
stub = ["stub"]
|
a = expr(_E(1, 0))
|
||||||
data = expr(_E(stub)).data
|
return (a.scale, a.data) if isinstance(a, _E) else (0, a)
|
||||||
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")
|
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
|
|
Loading…
Reference in New Issue
Block a user