Skip to content

Commit d07694f

Browse files
committed
Speed up ImagingGetBBox by doing vectorisable work upfront
1 parent 3af9116 commit d07694f

1 file changed

Lines changed: 45 additions & 20 deletions

File tree

src/libImaging/GetBBox.c

Lines changed: 45 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ ImagingGetBBox(Imaging im, int bbox[4], int alpha_only) {
2323
/* Get the bounding box for any non-zero data in the image.*/
2424

2525
int xsize = im->xsize, ysize = im->ysize;
26-
int has_data;
2726

2827
/* Initialize bounding box to max values */
2928
bbox[0] = xsize;
@@ -33,61 +32,87 @@ ImagingGetBBox(Imaging im, int bbox[4], int alpha_only) {
3332
#define GETBBOX(image, mask, type) \
3433
/* first stage: looking for any pixels from top */ \
3534
for (int y = 0; y < ysize; y++) { \
36-
has_data = 0; \
3735
const type *restrict row = (const type *)im->image[y]; \
36+
/* vectorisable OR-reduce of the row */ \
37+
type acc = 0; \
38+
for (int x = 0; x < xsize; x++) { \
39+
acc |= row[x] & mask; \
40+
} \
41+
if (!acc) { \
42+
continue; \
43+
} \
3844
for (int x = 0; x < xsize; x++) { \
3945
if (row[x] & mask) { \
40-
has_data = 1; \
4146
bbox[0] = x; \
4247
bbox[1] = y; \
4348
break; \
4449
} \
4550
} \
46-
if (has_data) { \
47-
break; \
48-
} \
51+
break; \
4952
} \
5053
/* Check that we have a box */ \
5154
if (bbox[1] < 0) { \
5255
return 0; /* no data */ \
5356
} \
5457
/* second stage: looking for any pixels from bottom */ \
5558
for (int y = ysize - 1; y >= bbox[1]; y--) { \
56-
has_data = 0; \
5759
const type *restrict row = (const type *)im->image[y]; \
60+
/* vectorisable OR-reduce of the row */ \
61+
type acc = 0; \
62+
for (int x = 0; x < xsize; x++) { \
63+
acc |= row[x] & mask; \
64+
} \
65+
if (!acc) { \
66+
continue; \
67+
} \
5868
for (int x = 0; x < xsize; x++) { \
5969
if (row[x] & mask) { \
60-
has_data = 1; \
6170
bbox[0] = x < bbox[0] ? x : bbox[0]; \
6271
bbox[3] = y + 1; \
6372
break; \
6473
} \
6574
} \
66-
if (has_data) { \
67-
break; \
68-
} \
75+
break; \
6976
} \
7077
/* third stage: looking for left and right boundaries */ \
7178
for (int y = bbox[1]; y < bbox[3]; y++) { \
7279
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; \
80+
if (bbox[0] > 0) { \
81+
/* vectorisable OR-reduce of the left margin */ \
82+
type acc = 0; \
83+
for (int x = 0; x < bbox[0]; x++) { \
84+
acc |= row[x] & mask; \
85+
} \
86+
if (acc) { \
87+
for (int x = 0; x < bbox[0]; x++) { \
88+
if (row[x] & mask) { \
89+
bbox[0] = x; \
90+
break; \
91+
} \
92+
} \
7793
} \
7894
} \
79-
for (int x = xsize - 1; x >= bbox[2]; x--) { \
80-
if (row[x] & mask) { \
81-
bbox[2] = x + 1; \
82-
break; \
95+
if (bbox[2] < xsize) { \
96+
/* vectorisable OR-reduce of the right margin */ \
97+
type acc = 0; \
98+
for (int x = bbox[2]; x < xsize; x++) { \
99+
acc |= row[x] & mask; \
100+
} \
101+
if (acc) { \
102+
for (int x = xsize - 1; x >= bbox[2]; x--) { \
103+
if (row[x] & mask) { \
104+
bbox[2] = x + 1; \
105+
break; \
106+
} \
107+
} \
83108
} \
84109
} \
85110
}
86111

87112
if (im->image8) {
88113
if (isModeI16(im->mode)) {
89114
// In I16 modes, image8 is two-byte pixels, so scan as UINT16.
90-
// Since we're looking for zeroes, endianness testing is independent.
115+
// Since we're looking for zeroes, endianness doesn't matter.
91116
GETBBOX(image8, 0xffff, UINT16);
92117
} else {
93118
GETBBOX(image8, 0xff, UINT8);

0 commit comments

Comments
 (0)