Repository navigation
Round halves up when converting crop coordinates to integers - #10243
sungbin1015 wants to merge 3 commits 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.
There was a problem hiding this comment.
I've pushed a commit to address this scenario.
There was a problem hiding this comment.
Thanks for the update. Rechecking the example above at 59cf86c, the size now matches the base, but the pixels still shift: base [10, 20, 30]; this head [20, 30, 40].
Rounding the width separately also changes some boxes without .5 coordinates. With the image above, im.crop((0.49, 0, 1.51, 1)) returns (2, 1) / [10, 20] on the base and (1, 1) / [10] on this head. Is that broader change intentional? The description currently says non-half coordinates round as before.
I checked the exact _crop methods from base 1295b5c and head 59cf86c against Pillow 13.0.0's core on Windows / Python 3.15; this wasn't a full PR build.
There was a problem hiding this comment.
Ok, I've pushed another commit that should meet your expectations now.
59cf86c to
72716a5
Compare
Merging this PR will degrade performance by 10.77%1 warning
Warning Please fix the performance issues or acknowledge them on CodSpeed. Performance Changes
Tip Investigate this regression by commenting Comparing Footnotes
|
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.