diff --git a/Tests/test_tiff_ifdrational.py b/Tests/test_tiff_ifdrational.py index c16cd506e65..b38c418dd58 100644 --- a/Tests/test_tiff_ifdrational.py +++ b/Tests/test_tiff_ifdrational.py @@ -54,6 +54,16 @@ def test_float() -> None: assert math.isnan(float(IFDRational(0, 0))) +def test_arithmetic_between_rationals() -> None: + a = IFDRational(1, 2) + b = IFDRational(1, 3) + + assert a + b == Fraction(5, 6) + assert a - b == Fraction(1, 6) + assert a * b == Fraction(1, 6) + assert a / b == Fraction(3, 2) + + def test_ranges() -> None: for num in range(1, 10): for denom in range(1, 10): diff --git a/src/PIL/TiffImagePlugin.py b/src/PIL/TiffImagePlugin.py index df0173f2475..5a9cf6b850d 100644 --- a/src/PIL/TiffImagePlugin.py +++ b/src/PIL/TiffImagePlugin.py @@ -337,7 +337,10 @@ def _delegate(op: str) -> Any: def delegate( self: IFDRational, *args: tuple[float, ...] ) -> bool | float | Fraction: - return getattr(self._val, op)(*args) + func = getattr(self._val, op) + if len(args) == 1 and isinstance(args[0], IFDRational): + return func(args[0]._val) + return func(*args) return delegate @@ -700,7 +703,12 @@ def _setitem(self, tag: int, value: Any, legacy_api: bool) -> None: self.tagtype[tag] = TiffTags.UNDEFINED if all(isinstance(v, IFDRational) for v in values): for v in values: - if v < IFDRational(0): + value = ( + v.numerator + if isinstance(v, IFDRational) and v.denominator == 0 + else v + ) + if value < IFDRational(0): self.tagtype[tag] = TiffTags.SIGNED_RATIONAL break else: