Skip to content

Commit e59ec21

Browse files
committed
Fix getbbox for I;16 modes
1 parent 5cf86bc commit e59ec21

2 files changed

Lines changed: 65 additions & 57 deletions

File tree

Tests/test_image_getbbox.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ def check(im: Image.Image, fill_color: int | tuple[int, ...]) -> None:
2525
im.paste(fill_color, (-10, -10, 110, 110))
2626
assert im.getbbox() == (0, 0, 100, 100)
2727

28-
# 8-bit mode
29-
im = Image.new("L", (100, 100), 0)
30-
check(im, 255)
28+
for mode in ("1", "L", "I", "P", "I;16", "I;16L", "I;16B"):
29+
im = Image.new(mode, (100, 100), 0)
30+
check(im, 255)
3131

3232
# 32-bit mode
3333
im = Image.new("RGB", (100, 100), 0)
@@ -44,7 +44,9 @@ def check(im: Image.Image, fill_color: int | tuple[int, ...]) -> None:
4444
check(im, (255, 255))
4545

4646

47-
@pytest.mark.parametrize("mode", ("L", "RGB", "RGBA", "I", "F"))
47+
@pytest.mark.parametrize(
48+
"mode", ("L", "RGB", "RGBA", "I", "F", "I;16", "I;16L", "I;16B")
49+
)
4850
@pytest.mark.parametrize(
4951
"box",
5052
(

src/libImaging/GetBBox.c

Lines changed: 59 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -30,62 +30,68 @@ ImagingGetBBox(Imaging im, int bbox[4], int alpha_only) {
3030
bbox[1] = -1;
3131
bbox[2] = bbox[3] = 0;
3232

33-
#define GETBBOX(image, mask, type) \
34-
/* first stage: looking for any pixels from top */ \
35-
for (int y = 0; y < ysize; y++) { \
36-
has_data = 0; \
37-
const type *restrict row = im->image[y]; \
38-
for (int x = 0; x < xsize; x++) { \
39-
if (row[x] & mask) { \
40-
has_data = 1; \
41-
bbox[0] = x; \
42-
bbox[1] = y; \
43-
break; \
44-
} \
45-
} \
46-
if (has_data) { \
47-
break; \
48-
} \
49-
} \
50-
/* Check that we have a box */ \
51-
if (bbox[1] < 0) { \
52-
return 0; /* no data */ \
53-
} \
54-
/* second stage: looking for any pixels from bottom */ \
55-
for (int y = ysize - 1; y >= bbox[1]; y--) { \
56-
has_data = 0; \
57-
const type *restrict row = im->image[y]; \
58-
for (int x = 0; x < xsize; x++) { \
59-
if (row[x] & mask) { \
60-
has_data = 1; \
61-
bbox[0] = x < bbox[0] ? x : bbox[0]; \
62-
bbox[3] = y + 1; \
63-
break; \
64-
} \
65-
} \
66-
if (has_data) { \
67-
break; \
68-
} \
69-
} \
70-
/* third stage: looking for left and right boundaries */ \
71-
for (int y = bbox[1]; y < bbox[3]; y++) { \
72-
const type *restrict row = im->image[y]; \
73-
for (int x = 0; x < bbox[0]; x++) { \
74-
if (row[x] & mask) { \
75-
bbox[0] = x; \
76-
break; \
77-
} \
78-
} \
79-
for (int x = xsize - 1; x >= bbox[2]; x--) { \
80-
if (row[x] & mask) { \
81-
bbox[2] = x + 1; \
82-
break; \
83-
} \
84-
} \
33+
#define GETBBOX(image, mask, type) \
34+
/* first stage: looking for any pixels from top */ \
35+
for (int y = 0; y < ysize; y++) { \
36+
has_data = 0; \
37+
const type *restrict row = (const type *)im->image[y]; \
38+
for (int x = 0; x < xsize; x++) { \
39+
if (row[x] & mask) { \
40+
has_data = 1; \
41+
bbox[0] = x; \
42+
bbox[1] = y; \
43+
break; \
44+
} \
45+
} \
46+
if (has_data) { \
47+
break; \
48+
} \
49+
} \
50+
/* Check that we have a box */ \
51+
if (bbox[1] < 0) { \
52+
return 0; /* no data */ \
53+
} \
54+
/* second stage: looking for any pixels from bottom */ \
55+
for (int y = ysize - 1; y >= bbox[1]; y--) { \
56+
has_data = 0; \
57+
const type *restrict row = (const type *)im->image[y]; \
58+
for (int x = 0; x < xsize; x++) { \
59+
if (row[x] & mask) { \
60+
has_data = 1; \
61+
bbox[0] = x < bbox[0] ? x : bbox[0]; \
62+
bbox[3] = y + 1; \
63+
break; \
64+
} \
65+
} \
66+
if (has_data) { \
67+
break; \
68+
} \
69+
} \
70+
/* third stage: looking for left and right boundaries */ \
71+
for (int y = bbox[1]; y < bbox[3]; y++) { \
72+
const type *restrict row = (const type *)im->image[y]; \
73+
for (int x = 0; x < bbox[0]; x++) { \
74+
if (row[x] & mask) { \
75+
bbox[0] = x; \
76+
break; \
77+
} \
78+
} \
79+
for (int x = xsize - 1; x >= bbox[2]; x--) { \
80+
if (row[x] & mask) { \
81+
bbox[2] = x + 1; \
82+
break; \
83+
} \
84+
} \
8585
}
8686

8787
if (im->image8) {
88-
GETBBOX(image8, 0xff, UINT8);
88+
if (isModeI16(im->mode)) {
89+
// In I16 modes, image8 is two-byte pixels, so scan as UINT16.
90+
// Since we're looking for zeroes, endianness testing is independent.
91+
GETBBOX(image8, 0xffff, UINT16);
92+
} else {
93+
GETBBOX(image8, 0xff, UINT8);
94+
}
8995
} else {
9096
INT32 mask = 0xffffffff;
9197
if (im->bands == 3) {

0 commit comments

Comments
 (0)