Repository: python-pillow/Pillow

Issue:
rounded_rectangle raises an "y1 should be > y0" even when coordinates are correctly ordered
### What did you do?

I recently updated one of my programs from 9.4 to 9.5 and got this new ValueError when drawing rounded rectangles on an image.

After some trials and error, I think the bug only happens when the rectangle height equals `1 + 2*radius`. I'm not 200% confident about that, but that's all I got so far.

The exact lines causing the error are https://github.com/python-pillow/Pillow/blob/2a274a476088c610451370b9b78e7c63b7b31da3/src/PIL/ImageDraw.py#L378-L383

### What did you expect to happen?

Well, PIL should be able to correctly calculate positions and draw my rounded corners.

### What actually happened?

```
Traceback (most recent call last):
  File "/.../test.py", line 17, in <module>
    main()
  File "/.../test.py", line 14, in main
    draw.rounded_rectangle(coordinates, radius=3, fill=(0, 0, 0))
  File "/.../env/lib/python3.9/site-packages/PIL/ImageDraw.py", line 385, in rounded_rectangle
    self.draw.draw_rectangle(left, fill, 1)
ValueError: y1 must be greater than or equal to y0
```

### What are your OS, Python and Pillow versions?

* OS: macOS 13.3.1
* Python: 3.9.16
* Pillow: 9.5.0

```python
from PIL import Image, ImageDraw

def main():
    # get a 1021x340 image
    img = Image.new('RGB', (20, 20), color=(255, 255, 255))
    # draw a rounded rectangle on it
    draw = ImageDraw.Draw(img)
    coordinates = (
        (5, 0),
        (15, 7)
    )
    # here's the bug:
    # on ImageDraw.py line 383, y1 from "left" will be 1px less than y0
    draw.rounded_rectangle(coordinates, radius=3, fill=(0, 0, 0))

if __name__ == '__main__':
    main()

```



Discussion:

Resolving patch:
diff --git a/src/PIL/ImageDraw.py b/src/PIL/ImageDraw.py
--- a/src/PIL/ImageDraw.py
+++ b/src/PIL/ImageDraw.py
@@ -314,11 +314,11 @@ def rounded_rectangle(
 
         full_x, full_y = False, False
         if all(corners):
-            full_x = d >= x1 - x0
+            full_x = d >= x1 - x0 - 1
             if full_x:
                 # The two left and two right corners are joined
                 d = x1 - x0
-            full_y = d >= y1 - y0
+            full_y = d >= y1 - y0 - 1
             if full_y:
                 # The two top and two bottom corners are joined
                 d = y1 - y0


Test patch:
diff --git a/Tests/images/imagedraw_rounded_rectangle_x_odd.png b/Tests/images/imagedraw_rounded_rectangle_x_odd.png
new file mode 100644
Binary files /dev/null and b/Tests/images/imagedraw_rounded_rectangle_x_odd.png differ
diff --git a/Tests/images/imagedraw_rounded_rectangle_y_odd.png b/Tests/images/imagedraw_rounded_rectangle_y_odd.png
new file mode 100644
Binary files /dev/null and b/Tests/images/imagedraw_rounded_rectangle_y_odd.png differ
diff --git a/Tests/test_imagedraw.py b/Tests/test_imagedraw.py
--- a/Tests/test_imagedraw.py
+++ b/Tests/test_imagedraw.py
@@ -839,7 +839,9 @@ def test_rounded_rectangle_zero_radius(bbox):
     "xy, suffix",
     [
         ((20, 10, 80, 90), "x"),
+        ((20, 10, 81, 90), "x_odd"),
         ((10, 20, 90, 80), "y"),
+        ((10, 20, 90, 81), "y_odd"),
         ((20, 20, 80, 80), "both"),
     ],
 )