-
-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Allow for IFDRational with negative numerator and zero denominator #8970
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
epou
commented
May 23, 2025
The proposed solution is functionally correct, but it requires developers to manually check the numerator and denominator each time. This introduces potential for inconsistency or error, especially if this behaviour needs to be checked on other parts of the code in the future.
It seems the underlying issue, is that the code assumes IFDRational instances behave like floats and are directly comparable. That expectation is natural and intuitive, and likely why the bug slipped in when the previous change was committed. This made me think that it'd make more sense to align the behavior of IFDRational more closely with float semantics. A more mathematically consistent handling of division-by-zero cases would be:
- Positive numerator / zero denominator →
math.inf
- Negative numerator / zero denominator →
-math.inf
- Zero numerator / zero denominator → 0 (or we could keep using
float('nan')
)
If we go this route, and implement __float__
as I did in the other pull request (https://github.com/python-pillow/Pillow/pull/8966/files#diff-6ad43f85f1a075181d4d8cfcd97ae27bba1eccf5c3db5a3457160f98218eba6eR405-R407), the comparisons v < 0
made for setting the tag type would behave correctly. This change would also make IFDRational instances more intuitive to work with and directly comparable using standard float logic.
Does this approach make sense to you? I’d be happy to open a PR implementing the -inf/inf logic so you can review it in context.
4c43e94
to
abf295f
Compare
abf295f
to
c8c6ff9
Compare
Ok, my next suggestion is v < IFDRational(0)
. I've updated this PR.
I don't object to your idea, but Pillow tends to value backwards compatibility. The nan
value is also explicitly described in the docstring.
Pillow/src/PIL/TiffImagePlugin.py
Lines 335 to 343 in 7e4d8e2
So there might be a preference to leave that as it is.
I have to imagine that it is rare for IFDRationals with zero denominators to be checked for their sign, simply because it's taken this long for an issue to be raised about it. And since you discovered this problem from Pillow's internal use of the class, I have to imagine that external checks are rarer still.
So, feel free to create a pull request with your suggestion, and see what others think. If you haven't thought of it already, another possibility would be changing IFDRational
's __lt__
and __gt__
.
epou
commented
May 26, 2025
I understand your point about backward compatibility and the existing docstring documentation for nan
.
I’ve gone ahead and opened a new PR implementing the math.inf / -math.inf logic for zero denominators, as said before: #8978. Would be great if you could take a look when you have a chance.
Uh oh!
There was an error while loading. Please reload this page.
Resolves #8965. Alternative to #8966 and #8978
A user has found an image where the ExposureBiasValue signed rational TIFF tag has a negative numerator but a zero denominator.
When this is passed to our IFDRational, it is considered
nan
,Pillow/src/PIL/TiffImagePlugin.py
Lines 374 to 375 in 3c71559
which means it is not less than zero.
This means that it isn't detected as something to write as a signed rational.
Pillow/src/PIL/TiffImagePlugin.py
Lines 690 to 692 in 3c71559
This PR suggests replacing
v < 0
with(float(v.numerator) < 0) != (float(v.denominator) < 0)