Repository navigation
Round halves up when converting crop coordinates to integers - #10243
sungbin1015 wants to merge 1 commit into
Conversation
Muguett-DBY
left a comment
There was a problem hiding this comment.
I checked the exact base and PR _crop implementations against the Pillow 13.0.0 core. The intended half-coordinate cases work, but a float just below a half can now lose a pixel; the inline comment has a small reproduction.
This was a targeted crop check, rather than a full build of the PR. The installed 13.0.0 wheel also passed the 59 upstream self-tests.
| """ | ||
|
|
||
| x0, y0, x1, y1 = map(int, map(round, box)) | ||
| x0, y0, x1, y1 = (math.floor(v + 0.5) for v in box) |
There was a problem hiding this comment.
Could we keep non-tie coordinates rounding as before? math.nextafter(0.5, 0.0) is below 0.5, but adding 0.5 rounds the intermediate value to exactly 1.0:
v = math.nextafter(0.5, 0.0)
im = Image.new("L", (4, 1))
im.putdata([10, 20, 30, 40])
out = im.crop((v, 0, 3, 1))
print(out.size, list(out.get_flattened_data()))Base: (3, 1) [10, 20, 30]; this change: (2, 1) [20, 30].
Computing n = math.floor(v) first, then using n + (v - n >= 0.5), avoids that intermediate rounding. I checked that alternative against exact-ratio rounding for 288 cases across all four box edges and L/RGB/RGBA; it also preserves the intended half-up behavior. A regression case just below 0.5 would catch this.
Follows on from #10242.
Changes proposed in this pull request:
test_crop_float_half_crop()usesround(), which since Python 3 sends halves to the nearest even integer. So the same box can come out a pixel larger or smaller depending on where it is:With
math.floor(v + 0.5)these are(31, 1),(31, 1)and(1, 1). Coordinates that aren't exactly .5 round as before, sotest_crop_floatfrom #1745 is unchanged. #10229 is close in spirit, but it changes how ImageDraw truncates negative coordinates in C and doesn't touchcrop().The full test suite and pre-commit pass locally.