Skip to content

Commit a94578c

Browse files
authored
Speed up Image.getchannel(), Image.merge(), Image.putalpha() and Image.split() (#9675)
1 parent 53e02c4 commit a94578c

1 file changed

Lines changed: 69 additions & 51 deletions

File tree

src/libImaging/Bands.c

Lines changed: 69 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -47,16 +47,19 @@ ImagingGetBand(Imaging imIn, int band) {
4747
}
4848

4949
/* Extract band from image */
50-
for (y = 0; y < imIn->ysize; y++) {
51-
UINT8 *in = (UINT8 *)imIn->image[y] + band;
52-
UINT8 *out = imOut->image8[y];
50+
// restrict safe: imIn is read-only, imOut is a fresh allocation.
51+
int xsize = imIn->xsize;
52+
int ysize = imIn->ysize;
53+
for (y = 0; y < ysize; y++) {
54+
UINT8 *restrict in = (UINT8 *)imIn->image[y] + band;
55+
UINT8 *restrict out = imOut->image8[y];
5356
x = 0;
54-
for (; x < imIn->xsize - 3; x += 4) {
57+
for (; x < xsize - 3; x += 4) {
5558
UINT32 v = MAKE_UINT32(in[0], in[4], in[8], in[12]);
5659
memcpy(out + x, &v, sizeof(v));
5760
in += 16;
5861
}
59-
for (; x < imIn->xsize; x++) {
62+
for (; x < xsize; x++) {
6063
out[x] = *in;
6164
in += 4;
6265
}
@@ -92,33 +95,37 @@ ImagingSplit(Imaging imIn, Imaging bands[4]) {
9295
}
9396

9497
/* Extract bands from image */
98+
// restrict safe: imIn is read-only and each band is a distinct fresh
99+
// allocation, so none of in/out0..out3 alias each other.
100+
int xsize = imIn->xsize;
101+
int ysize = imIn->ysize;
95102
if (imIn->bands == 2) {
96-
for (y = 0; y < imIn->ysize; y++) {
97-
UINT8 *in = (UINT8 *)imIn->image[y];
98-
UINT8 *out0 = bands[0]->image8[y];
99-
UINT8 *out1 = bands[1]->image8[y];
103+
for (y = 0; y < ysize; y++) {
104+
UINT8 *restrict in = (UINT8 *)imIn->image[y];
105+
UINT8 *restrict out0 = bands[0]->image8[y];
106+
UINT8 *restrict out1 = bands[1]->image8[y];
100107
x = 0;
101-
for (; x < imIn->xsize - 3; x += 4) {
108+
for (; x < xsize - 3; x += 4) {
102109
UINT32 v = MAKE_UINT32(in[0], in[4], in[8], in[12]);
103110
memcpy(out0 + x, &v, sizeof(v));
104111
v = MAKE_UINT32(in[0 + 3], in[4 + 3], in[8 + 3], in[12 + 3]);
105112
memcpy(out1 + x, &v, sizeof(v));
106113
in += 16;
107114
}
108-
for (; x < imIn->xsize; x++) {
115+
for (; x < xsize; x++) {
109116
out0[x] = in[0];
110117
out1[x] = in[3];
111118
in += 4;
112119
}
113120
}
114121
} else if (imIn->bands == 3) {
115-
for (y = 0; y < imIn->ysize; y++) {
116-
UINT8 *in = (UINT8 *)imIn->image[y];
117-
UINT8 *out0 = bands[0]->image8[y];
118-
UINT8 *out1 = bands[1]->image8[y];
119-
UINT8 *out2 = bands[2]->image8[y];
122+
for (y = 0; y < ysize; y++) {
123+
UINT8 *restrict in = (UINT8 *)imIn->image[y];
124+
UINT8 *restrict out0 = bands[0]->image8[y];
125+
UINT8 *restrict out1 = bands[1]->image8[y];
126+
UINT8 *restrict out2 = bands[2]->image8[y];
120127
x = 0;
121-
for (; x < imIn->xsize - 3; x += 4) {
128+
for (; x < xsize - 3; x += 4) {
122129
UINT32 v = MAKE_UINT32(in[0], in[4], in[8], in[12]);
123130
memcpy(out0 + x, &v, sizeof(v));
124131
v = MAKE_UINT32(in[0 + 1], in[4 + 1], in[8 + 1], in[12 + 1]);
@@ -127,22 +134,22 @@ ImagingSplit(Imaging imIn, Imaging bands[4]) {
127134
memcpy(out2 + x, &v, sizeof(v));
128135
in += 16;
129136
}
130-
for (; x < imIn->xsize; x++) {
137+
for (; x < xsize; x++) {
131138
out0[x] = in[0];
132139
out1[x] = in[1];
133140
out2[x] = in[2];
134141
in += 4;
135142
}
136143
}
137144
} else {
138-
for (y = 0; y < imIn->ysize; y++) {
139-
UINT8 *in = (UINT8 *)imIn->image[y];
140-
UINT8 *out0 = bands[0]->image8[y];
141-
UINT8 *out1 = bands[1]->image8[y];
142-
UINT8 *out2 = bands[2]->image8[y];
143-
UINT8 *out3 = bands[3]->image8[y];
145+
for (y = 0; y < ysize; y++) {
146+
UINT8 *restrict in = (UINT8 *)imIn->image[y];
147+
UINT8 *restrict out0 = bands[0]->image8[y];
148+
UINT8 *restrict out1 = bands[1]->image8[y];
149+
UINT8 *restrict out2 = bands[2]->image8[y];
150+
UINT8 *restrict out3 = bands[3]->image8[y];
144151
x = 0;
145-
for (; x < imIn->xsize - 3; x += 4) {
152+
for (; x < xsize - 3; x += 4) {
146153
UINT32 v = MAKE_UINT32(in[0], in[4], in[8], in[12]);
147154
memcpy(out0 + x, &v, sizeof(v));
148155
v = MAKE_UINT32(in[0 + 1], in[4 + 1], in[8 + 1], in[12 + 1]);
@@ -153,7 +160,7 @@ ImagingSplit(Imaging imIn, Imaging bands[4]) {
153160
memcpy(out3 + x, &v, sizeof(v));
154161
in += 16;
155162
}
156-
for (; x < imIn->xsize; x++) {
163+
for (; x < xsize; x++) {
157164
out0[x] = in[0];
158165
out1[x] = in[1];
159166
out2[x] = in[2];
@@ -195,10 +202,15 @@ ImagingPutBand(Imaging imOut, Imaging imIn, int band) {
195202
}
196203

197204
/* Insert band into image */
198-
for (y = 0; y < imIn->ysize; y++) {
199-
UINT8 *in = imIn->image8[y];
200-
UINT8 *out = (UINT8 *)imOut->image[y] + band;
201-
for (x = 0; x < imIn->xsize; x++) {
205+
// restrict safe: imIn is single-band (bands verified 1),
206+
// imOut must be multi-band or we would have shortcut out above,
207+
// so they're distinct images with disparate buffers.
208+
int xsize = imIn->xsize;
209+
int ysize = imIn->ysize;
210+
for (y = 0; y < ysize; y++) {
211+
UINT8 *restrict in = imIn->image8[y];
212+
UINT8 *restrict out = (UINT8 *)imOut->image[y] + band;
213+
for (x = 0; x < xsize; x++) {
202214
*out = in[x];
203215
out += 4;
204216
}
@@ -228,9 +240,11 @@ ImagingFillBand(Imaging imOut, int band, int color) {
228240
color = CLIP8(color);
229241

230242
/* Insert color into image */
231-
for (y = 0; y < imOut->ysize; y++) {
232-
UINT8 *out = (UINT8 *)imOut->image[y] + band;
233-
for (x = 0; x < imOut->xsize; x++) {
243+
int xsize = imOut->xsize;
244+
int ysize = imOut->ysize;
245+
for (y = 0; y < ysize; y++) {
246+
UINT8 *restrict out = (UINT8 *)imOut->image[y] + band;
247+
for (x = 0; x < xsize; x++) {
234248
*out = (UINT8)color;
235249
out += 4;
236250
}
@@ -279,33 +293,37 @@ ImagingMerge(const ModeID mode, Imaging bands[4]) {
279293
return ImagingCopy2(imOut, firstBand);
280294
}
281295

296+
// restrict safe: the input bands are read-only and imOut is a fresh
297+
// allocation, so none of in0..in3/out alias each other.
298+
int xsize = imOut->xsize;
299+
int ysize = imOut->ysize;
282300
if (imOut->bands == 2) {
283-
for (y = 0; y < imOut->ysize; y++) {
284-
UINT8 *in0 = bands[0]->image8[y];
285-
UINT8 *in1 = bands[1]->image8[y];
286-
UINT32 *out = (UINT32 *)imOut->image32[y];
287-
for (x = 0; x < imOut->xsize; x++) {
301+
for (y = 0; y < ysize; y++) {
302+
UINT8 *restrict in0 = bands[0]->image8[y];
303+
UINT8 *restrict in1 = bands[1]->image8[y];
304+
UINT32 *restrict out = (UINT32 *)imOut->image32[y];
305+
for (x = 0; x < xsize; x++) {
288306
out[x] = MAKE_UINT32(in0[x], 0, 0, in1[x]);
289307
}
290308
}
291309
} else if (imOut->bands == 3) {
292-
for (y = 0; y < imOut->ysize; y++) {
293-
UINT8 *in0 = bands[0]->image8[y];
294-
UINT8 *in1 = bands[1]->image8[y];
295-
UINT8 *in2 = bands[2]->image8[y];
296-
UINT32 *out = (UINT32 *)imOut->image32[y];
297-
for (x = 0; x < imOut->xsize; x++) {
310+
for (y = 0; y < ysize; y++) {
311+
UINT8 *restrict in0 = bands[0]->image8[y];
312+
UINT8 *restrict in1 = bands[1]->image8[y];
313+
UINT8 *restrict in2 = bands[2]->image8[y];
314+
UINT32 *restrict out = (UINT32 *)imOut->image32[y];
315+
for (x = 0; x < xsize; x++) {
298316
out[x] = MAKE_UINT32(in0[x], in1[x], in2[x], 0);
299317
}
300318
}
301319
} else if (imOut->bands == 4) {
302-
for (y = 0; y < imOut->ysize; y++) {
303-
UINT8 *in0 = bands[0]->image8[y];
304-
UINT8 *in1 = bands[1]->image8[y];
305-
UINT8 *in2 = bands[2]->image8[y];
306-
UINT8 *in3 = bands[3]->image8[y];
307-
UINT32 *out = (UINT32 *)imOut->image32[y];
308-
for (x = 0; x < imOut->xsize; x++) {
320+
for (y = 0; y < ysize; y++) {
321+
UINT8 *restrict in0 = bands[0]->image8[y];
322+
UINT8 *restrict in1 = bands[1]->image8[y];
323+
UINT8 *restrict in2 = bands[2]->image8[y];
324+
UINT8 *restrict in3 = bands[3]->image8[y];
325+
UINT32 *restrict out = (UINT32 *)imOut->image32[y];
326+
for (x = 0; x < xsize; x++) {
309327
out[x] = MAKE_UINT32(in0[x], in1[x], in2[x], in3[x]);
310328
}
311329
}

0 commit comments

Comments
 (0)