mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-01-26 01:04:29 +03:00
Support more affine expression forms in Image.point
In modes I and F, Image.point only supported affine expressions of the forms (lambda x:) x * a, x + a, and x * a + b. Expressions like 1 - x had to be written x * -1 + 1. This rewrite, though still limited to affine transformations, supports far more expression forms, including 1 - x, (2 * x + 1) / 3, etc.
This commit is contained in:
parent
9d988dab6a
commit
4e12ccc63e
|
@ -18,10 +18,18 @@ def test_sanity():
|
|||
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)
|
||||
with pytest.raises(TypeError):
|
||||
im.point(lambda x: x - 1)
|
||||
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 // 2)
|
||||
|
||||
|
||||
def test_16bit_lut():
|
||||
|
|
|
@ -431,45 +431,44 @@ def _getencoder(mode, encoder_name, args, extra=()):
|
|||
# Simple expression analyzer
|
||||
|
||||
|
||||
def coerce_e(value):
|
||||
return value if isinstance(value, _E) else _E(value)
|
||||
# _Affine(m, b) represents the polynomial m x + b
|
||||
class _Affine:
|
||||
def __init__(self, m, b):
|
||||
self.m = m
|
||||
self.b = b
|
||||
|
||||
|
||||
class _E:
|
||||
def __init__(self, data):
|
||||
self.data = data
|
||||
def __neg__(self):
|
||||
return _Affine(-self.m, -self.b)
|
||||
|
||||
def __add__(self, other):
|
||||
return _E((self.data, "__add__", coerce_e(other).data))
|
||||
if isinstance(other, _Affine):
|
||||
return _Affine(self.m + other.m, self.b + other.b)
|
||||
return _Affine(self.m, self.b + 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, _Affine):
|
||||
return NotImplemented
|
||||
return _Affine(self.m * other, self.b * other)
|
||||
|
||||
__rmul__ = __mul__
|
||||
|
||||
def __truediv__(self, other):
|
||||
if isinstance(other, _Affine):
|
||||
return NotImplemented
|
||||
return _Affine(self.m / other, self.b / 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(_Affine(1.0, 0.0))
|
||||
return (a.m, a.b) if isinstance(a, _Affine) else (0.0, a)
|
||||
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
|
|
Loading…
Reference in New Issue
Block a user