You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Converting F images to I turns large values, inf and NaN into -2147483648 #10372
Converted a float (F) image with large or non-finite values to I, for example a float TIFF or a NumPy result with inf or NaN pixels, or an I image that went through F for processing:
Values outside the I range clipped to it, the way F to L and F to I;16 clip to theirs, and the round trip to keep 2147483647:
I [[1, 70000, 2147483647, 2147483647, -2147483648, 0]]
L [[1, 255, 255, 255, 0, 0]]
2147483647
What actually happened?
Every value above the INT32 range, inf and NaN become -2147483648, the most negative value:
I [[1, 70000, -2147483648, -2147483648, -2147483648, -2147483648]]
L [[1, 255, 255, 255, 0, 0]]
-2147483648
The round trip fails because 2147483647 isn't representable as a float32 and rounds up to 2147483648.0, which is just past the INT32 range.
f2i in Convert.c casts with i = f; and no range check. Converting an out-of-range float or NaN to an integer is undefined behavior in C (-fsanitize=float-cast-overflow reports it), and the result depends on the CPU: x86 gives INT_MIN, while ARM saturates and gives INT32_MAX for large values and 0 for NaN. clip32() in Filter.c already guards the same overflow to INT_MIN.
I can open a PR that clips to the INT32 range in f2i and maps NaN to 0.
NaN mostly comes in with the data rather than from Image.new(). Image.fromarray(), Image.frombytes() and opening a float TIFF with NaN pixels all keep it, and all three convert to I as -2147483648. NaN is valid float data in those cases (it's often the nodata value in float TIFFs), so I don't think rejecting it would be right.
NaN is also only part of it. Finite values above the range and inf give -2147483648 too, including this round trip, which has no NaN in it:
NaN is valid float data in those cases (it's often the nodata value in float TIFFs)
If you have an image that demonstrates this, that would be cool, even just as an attachment here.
I don't think rejecting it would be right
Oh, I wasn't thinking about raising an error. I was thinking about setting it to zero immediately, rather than waiting until conversion.
...if you're saying that Pillow should allow F images to store NaN values, I'm not sold. Maybe NumPy or SciPy would do that, but I think Pillow is here for image processing, and while NaN might have meaning as data, I don't think it has meaning as part of an image.
Setting NaN to 0 is fine with me, and it's what the PR already does at conversion. The clip has to put NaN somewhere to avoid the undefined cast, so 0 it is. I don't have a sample file to share; NaN isn't what prompted this.
The main problem is the finite and infinite values. inf, anything above the INT32 range, and the I → F → I round trip of 2147483647 all become -2147483648, so f2i needs the clip whatever happens to NaN on load.
Activity
radarhere commentedon Oct 31, 2026
If you're concerned about
nan, then I think a more direct approach would be to address the F value?usmanmateen commentedon Oct 31, 2026
NaN mostly comes in with the data rather than from
Image.new().Image.fromarray(),Image.frombytes()and opening a float TIFF with NaN pixels all keep it, and all three convert toIas -2147483648. NaN is valid float data in those cases (it's often the nodata value in float TIFFs), so I don't think rejecting it would be right.NaN is also only part of it. Finite values above the range and
infgive -2147483648 too, including this round trip, which has no NaN in it:The PR maps NaN to 0 because that's what
FtoLandFtoI;16already give, but I'm happy to change that if you'd prefer a different value.radarhere commentedon Nov 1, 2026
If you have an image that demonstrates this, that would be cool, even just as an attachment here.
Oh, I wasn't thinking about raising an error. I was thinking about setting it to zero immediately, rather than waiting until conversion.
...if you're saying that Pillow should allow F images to store NaN values, I'm not sold. Maybe NumPy or SciPy would do that, but I think Pillow is here for image processing, and while NaN might have meaning as data, I don't think it has meaning as part of an image.
usmanmateen commentedon Nov 2, 2026
Setting NaN to 0 is fine with me, and it's what the PR already does at conversion. The clip has to put NaN somewhere to avoid the undefined cast, so 0 it is. I don't have a sample file to share; NaN isn't what prompted this.
The main problem is the finite and infinite values.
inf, anything above theINT32range, and theI→F→Iround trip of 2147483647 all become -2147483648, sof2ineeds the clip whatever happens to NaN on load.radarhere commentedon Nov 7, 2026
#10373 has been merged, and the original code here now gives
So everything but the NaN matches expectations. I'm not sure how much of a dealbreaker that is.
Does anyone have an example TIFF image with NaN or infinite pixel values?