Browse Source

Images : une image uniforme à très grandes valeurs ne fait plus planter

- Une image en flottants dont toutes les mesures sont égales, au-delà
  d'environ 1e16 en valeur absolue, levait ZeroDivisionError dans
  _to_8_bits : « low - 1, high + 1 » ne change plus un si grand flottant,
  l'écart restait nul. Le membre recevait « erreur inattendue », et une
  telle image dans un message cité faisait échouer toute la réponse au
  lieu d'être ignorée.
- L'écart ajouté est maintenant proportionnel à la valeur (au moins 1) :
  gris moyen comme avant pour les petites valeurs, et aussi pour les
  grandes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Johnounet 1 ngày trước cách đây
mục cha
commit
213c0be48d
2 tập tin đã thay đổi với 10 bổ sung và 4 xóa
  1. 3 1
      bot/images.py
  2. 7 3
      tests/test_attachments_prep.py

+ 3 - 1
bot/images.py

@@ -150,7 +150,9 @@ def _to_8_bits(img: Image.Image) -> Image.Image:
         elif low >= 0 and high <= 65535 and img.mode != "F":  # flottants : mètres, degrés…, pas 16 bits
             low, high = 0, 65535
         elif high == low:  # image uniforme hors de ces plages : gris moyen, pas noir
-            low, high = low - 1, high + 1
+            # Écart proportionnel à la valeur : ajouter 1 à un très grand flottant ne le change plus.
+            margin = max(1.0, abs(low))
+            low, high = low - margin, high + margin
     img = img.convert("F")
     scale = 255 / (high - low)
     result = img.point(lambda v: (v - low) * scale + 0.5).convert("L")  # + 0.5 : arrondi, pas troncature

+ 7 - 3
tests/test_attachments_prep.py

@@ -133,10 +133,14 @@ class PrepareImageTest(unittest.TestCase):
 
     def test_uniform_out_of_range_grey(self):
         # Image uniforme hors des plages connues : rien à voir, mais un gris moyen plutôt qu'un noir de trou.
-        for img in (Image.new("I", (200, 100), 100000), Image.new("F", (200, 100), -5.0)):
-            with self.subTest(mode=img.mode):
+        # Aussi pour de très grandes valeurs, où ajouter 1 ne change plus rien.
+        with_holes = Image.new("F", (200, 100), 1e19)
+        with_holes.paste(float("nan"), (0, 0, 100, 100))
+        for img in (Image.new("I", (200, 100), 100000), Image.new("F", (200, 100), -5.0),
+                    Image.new("F", (200, 100), 1e19), Image.new("F", (200, 100), -1e19), with_holes):
+            with self.subTest(mode=img.mode, value=img.getpixel((199, 0))):
                 result = opened(prepare_image(encode(img, "TIFF")).data)
-                self.assertEqual(result.convert("L").getpixel((0, 0)), 128)
+                self.assertEqual(result.convert("L").getpixel((199, 0)), 128)
 
     def test_transparency_kept(self):
         result = prepare_image(encode(Image.new("RGBA", (3000, 100), (255, 0, 0, 0)), "PNG"))