Converting F images to I turns large values, inf and NaN into -2147483648

オープン 初心者向け
#10,372 コメント 4 件 リアクション 0 件 担当者 0 名 GitHub で見る

メンテナーはふだん 1 日以内に返信

@usmanmateen がすでに取り組んでいます。

2026年10月31日 から。

  • #10373 @usmanmateen による — オープン

評価

難易度
2/5
見積もり時間
1〜3時間
初心者へのやさしさ
72/100
issue の種類
バグ
明瞭さ
明確に書かれている
活発さ
活発
技術スタック
c, python
領域
backend

調査の方向性

バグは、範囲チェックのないキャスト i = f; で、場所は f2i 関数(src/libImaging/Convert.c)です。clip32()(src/libImaging/Filter.c)に既存の範囲ガードがあるので、それに倣ってください。issue の Python スニペットで再現し、F から I への結果を確認してください。INT32 の範囲を超える値は 2147483647 にクリップされ、-inf は -2147483648 にクリップされ、NaN は 0 になり、ラウンドトリップで 2147483647 が返れば完了です。

索引モデルが issue の本文から書いたものです。

説明

Conversion
What did you do?

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:

import numpy as np
from PIL import Image

im = Image.fromarray(np.array([[1.5, 70000, 3e9, np.inf, -np.inf, np.nan]], np.float32), "F")
print("I", np.asarray(im.convert("I")).tolist())
print("L", np.asarray(im.convert("L")).tolist())

print(Image.new("I", (1, 1), 2**31 - 1).convert("F").convert("I").getpixel((0, 0)))
What did you expect to happen?

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.

What are your OS, Python and Pillow versions?
  • OS: Ubuntu 26.04 (WSL2), x86-64
  • Python: 3.12.13
  • Pillow: 13.0.0
主要言語
Python
スター
14k
フォーク
2.6k
平均マージ
1日 4時間
マージ済み PR(30日)
182

環境構築

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

python-pillow/Pillow のほかの issue

python-pillow/Pillow の issue をすべて見る

似ている issue

Python の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。