Skip to content

Commit 7b163cc

Browse files
authored
Use mask in C when drawing wide polygon lines (#8984)
1 parent 05636dc commit 7b163cc

File tree

4 files changed

+116
-52
lines changed

4 files changed

+116
-52
lines changed

src/PIL/ImageDraw.py

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -365,22 +365,10 @@ def polygon(
365365
# use the fill as a mask
366366
mask = Image.new("1", self.im.size)
367367
mask_ink = self._getink(1)[0]
368-
369-
fill_im = mask.copy()
370-
draw = Draw(fill_im)
368+
draw = Draw(mask)
371369
draw.draw.draw_polygon(xy, mask_ink, 1)
372370

373-
ink_im = mask.copy()
374-
draw = Draw(ink_im)
375-
width = width * 2 - 1
376-
draw.draw.draw_polygon(xy, mask_ink, 0, width)
377-
378-
mask.paste(ink_im, mask=fill_im)
379-
380-
im = Image.new(self.mode, self.im.size)
381-
draw = Draw(im)
382-
draw.draw.draw_polygon(xy, ink, 0, width)
383-
self.im.paste(im.im, (0, 0) + im.size, mask.im)
371+
self.draw.draw_polygon(xy, ink, 0, width * 2 - 1, mask.im)
384372

385373
def regular_polygon(
386374
self,

src/_imaging.c

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3220,7 +3220,8 @@ _draw_lines(ImagingDrawObject *self, PyObject *args) {
32203220
(int)p[3],
32213221
&ink,
32223222
width,
3223-
self->blend
3223+
self->blend,
3224+
NULL
32243225
) < 0) {
32253226
free(xy);
32263227
return NULL;
@@ -3358,7 +3359,10 @@ _draw_polygon(ImagingDrawObject *self, PyObject *args) {
33583359
int ink;
33593360
int fill = 0;
33603361
int width = 0;
3361-
if (!PyArg_ParseTuple(args, "Oi|ii", &data, &ink, &fill, &width)) {
3362+
ImagingObject *maskp = NULL;
3363+
if (!PyArg_ParseTuple(
3364+
args, "Oi|iiO!", &data, &ink, &fill, &width, &Imaging_Type, &maskp
3365+
)) {
33623366
return NULL;
33633367
}
33643368

@@ -3388,8 +3392,16 @@ _draw_polygon(ImagingDrawObject *self, PyObject *args) {
33883392

33893393
free(xy);
33903394

3391-
if (ImagingDrawPolygon(self->image->image, n, ixy, &ink, fill, width, self->blend) <
3392-
0) {
3395+
if (ImagingDrawPolygon(
3396+
self->image->image,
3397+
n,
3398+
ixy,
3399+
&ink,
3400+
fill,
3401+
width,
3402+
self->blend,
3403+
maskp ? maskp->image : NULL
3404+
) < 0) {
33933405
free(ixy);
33943406
return NULL;
33953407
}

src/libImaging/Draw.c

Lines changed: 81 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ typedef struct {
6363
} Edge;
6464

6565
/* Type used in "polygon*" functions */
66-
typedef void (*hline_handler)(Imaging, int, int, int, int);
66+
typedef void (*hline_handler)(Imaging, int, int, int, int, Imaging);
6767

6868
static inline void
6969
point8(Imaging im, int x, int y, int ink) {
@@ -103,7 +103,7 @@ point32rgba(Imaging im, int x, int y, int ink) {
103103
}
104104

105105
static inline void
106-
hline8(Imaging im, int x0, int y0, int x1, int ink) {
106+
hline8(Imaging im, int x0, int y0, int x1, int ink, Imaging mask) {
107107
int pixelwidth;
108108

109109
if (y0 >= 0 && y0 < im->ysize) {
@@ -119,15 +119,30 @@ hline8(Imaging im, int x0, int y0, int x1, int ink) {
119119
}
120120
if (x0 <= x1) {
121121
pixelwidth = strncmp(im->mode, "I;16", 4) == 0 ? 2 : 1;
122-
memset(
123-
im->image8[y0] + x0 * pixelwidth, (UINT8)ink, (x1 - x0 + 1) * pixelwidth
124-
);
122+
if (mask == NULL) {
123+
memset(
124+
im->image8[y0] + x0 * pixelwidth,
125+
(UINT8)ink,
126+
(x1 - x0 + 1) * pixelwidth
127+
);
128+
} else {
129+
UINT8 *p = im->image8[y0];
130+
while (x0 <= x1) {
131+
if (mask->image8[y0][x0]) {
132+
p[x0 * pixelwidth] = ink;
133+
if (pixelwidth == 2) {
134+
p[x0 * pixelwidth + 1] = ink;
135+
}
136+
}
137+
x0++;
138+
}
139+
}
125140
}
126141
}
127142
}
128143

129144
static inline void
130-
hline32(Imaging im, int x0, int y0, int x1, int ink) {
145+
hline32(Imaging im, int x0, int y0, int x1, int ink, Imaging mask) {
131146
INT32 *p;
132147

133148
if (y0 >= 0 && y0 < im->ysize) {
@@ -143,13 +158,16 @@ hline32(Imaging im, int x0, int y0, int x1, int ink) {
143158
}
144159
p = im->image32[y0];
145160
while (x0 <= x1) {
146-
p[x0++] = ink;
161+
if (mask == NULL || mask->image8[y0][x0]) {
162+
p[x0] = ink;
163+
}
164+
x0++;
147165
}
148166
}
149167
}
150168

151169
static inline void
152-
hline32rgba(Imaging im, int x0, int y0, int x1, int ink) {
170+
hline32rgba(Imaging im, int x0, int y0, int x1, int ink, Imaging mask) {
153171
unsigned int tmp;
154172

155173
if (y0 >= 0 && y0 < im->ysize) {
@@ -167,9 +185,11 @@ hline32rgba(Imaging im, int x0, int y0, int x1, int ink) {
167185
UINT8 *out = (UINT8 *)im->image[y0] + x0 * 4;
168186
UINT8 *in = (UINT8 *)&ink;
169187
while (x0 <= x1) {
170-
out[0] = BLEND(in[3], out[0], in[0], tmp);
171-
out[1] = BLEND(in[3], out[1], in[1], tmp);
172-
out[2] = BLEND(in[3], out[2], in[2], tmp);
188+
if (mask == NULL || mask->image8[y0][x0]) {
189+
out[0] = BLEND(in[3], out[0], in[0], tmp);
190+
out[1] = BLEND(in[3], out[1], in[1], tmp);
191+
out[2] = BLEND(in[3], out[2], in[2], tmp);
192+
}
173193
x0++;
174194
out += 4;
175195
}
@@ -407,7 +427,14 @@ x_cmp(const void *x0, const void *x1) {
407427

408428
static void
409429
draw_horizontal_lines(
410-
Imaging im, int n, Edge *e, int ink, int *x_pos, int y, hline_handler hline
430+
Imaging im,
431+
int n,
432+
Edge *e,
433+
int ink,
434+
int *x_pos,
435+
int y,
436+
hline_handler hline,
437+
Imaging mask
411438
) {
412439
int i;
413440
for (i = 0; i < n; i++) {
@@ -429,7 +456,7 @@ draw_horizontal_lines(
429456
}
430457
}
431458

432-
(*hline)(im, xmin, e[i].ymin, xmax, ink);
459+
(*hline)(im, xmin, e[i].ymin, xmax, ink, mask);
433460
*x_pos = xmax + 1;
434461
}
435462
}
@@ -439,7 +466,9 @@ draw_horizontal_lines(
439466
* Filled polygon draw function using scan line algorithm.
440467
*/
441468
static inline int
442-
polygon_generic(Imaging im, int n, Edge *e, int ink, int eofill, hline_handler hline) {
469+
polygon_generic(
470+
Imaging im, int n, Edge *e, int ink, int eofill, hline_handler hline, Imaging mask
471+
) {
443472
Edge **edge_table;
444473
float *xx;
445474
int edge_count = 0;
@@ -469,7 +498,7 @@ polygon_generic(Imaging im, int n, Edge *e, int ink, int eofill, hline_handler h
469498
}
470499
if (e[i].ymin == e[i].ymax) {
471500
if (hasAlpha != 1) {
472-
(*hline)(im, e[i].xmin, e[i].ymin, e[i].xmax, ink);
501+
(*hline)(im, e[i].xmin, e[i].ymin, e[i].xmax, ink, mask);
473502
}
474503
continue;
475504
}
@@ -557,7 +586,7 @@ polygon_generic(Imaging im, int n, Edge *e, int ink, int eofill, hline_handler h
557586
// Line would be before the current position
558587
continue;
559588
}
560-
draw_horizontal_lines(im, n, e, ink, &x_pos, ymin, hline);
589+
draw_horizontal_lines(im, n, e, ink, &x_pos, ymin, hline, mask);
561590
if (x_end < x_pos) {
562591
// Line would be before the current position
563592
continue;
@@ -573,13 +602,13 @@ polygon_generic(Imaging im, int n, Edge *e, int ink, int eofill, hline_handler h
573602
continue;
574603
}
575604
}
576-
(*hline)(im, x_start, ymin, x_end, ink);
605+
(*hline)(im, x_start, ymin, x_end, ink, mask);
577606
x_pos = x_end + 1;
578607
}
579-
draw_horizontal_lines(im, n, e, ink, &x_pos, ymin, hline);
608+
draw_horizontal_lines(im, n, e, ink, &x_pos, ymin, hline, mask);
580609
} else {
581610
for (i = 1; i < j; i += 2) {
582-
(*hline)(im, ROUND_UP(xx[i - 1]), ymin, ROUND_DOWN(xx[i]), ink);
611+
(*hline)(im, ROUND_UP(xx[i - 1]), ymin, ROUND_DOWN(xx[i]), ink, mask);
583612
}
584613
}
585614
}
@@ -623,7 +652,7 @@ add_edge(Edge *e, int x0, int y0, int x1, int y1) {
623652

624653
typedef struct {
625654
void (*point)(Imaging im, int x, int y, int ink);
626-
void (*hline)(Imaging im, int x0, int y0, int x1, int ink);
655+
void (*hline)(Imaging im, int x0, int y0, int x1, int ink, Imaging mask);
627656
void (*line)(Imaging im, int x0, int y0, int x1, int y1, int ink);
628657
} DRAW;
629658

@@ -674,7 +703,15 @@ ImagingDrawLine(Imaging im, int x0, int y0, int x1, int y1, const void *ink_, in
674703

675704
int
676705
ImagingDrawWideLine(
677-
Imaging im, int x0, int y0, int x1, int y1, const void *ink_, int width, int op
706+
Imaging im,
707+
int x0,
708+
int y0,
709+
int x1,
710+
int y1,
711+
const void *ink_,
712+
int width,
713+
int op,
714+
Imaging mask
678715
) {
679716
DRAW *draw;
680717
INT32 ink;
@@ -714,7 +751,7 @@ ImagingDrawWideLine(
714751
add_edge(e + 2, vertices[2][0], vertices[2][1], vertices[3][0], vertices[3][1]);
715752
add_edge(e + 3, vertices[3][0], vertices[3][1], vertices[0][0], vertices[0][1]);
716753

717-
polygon_generic(im, 4, e, ink, 0, draw->hline);
754+
polygon_generic(im, 4, e, ink, 0, draw->hline, mask);
718755
}
719756
return 0;
720757
}
@@ -757,7 +794,7 @@ ImagingDrawRectangle(
757794
}
758795

759796
for (y = y0; y <= y1; y++) {
760-
draw->hline(im, x0, y, x1, ink);
797+
draw->hline(im, x0, y, x1, ink, NULL);
761798
}
762799

763800
} else {
@@ -766,8 +803,8 @@ ImagingDrawRectangle(
766803
width = 1;
767804
}
768805
for (i = 0; i < width; i++) {
769-
draw->hline(im, x0, y0 + i, x1, ink);
770-
draw->hline(im, x0, y1 - i, x1, ink);
806+
draw->hline(im, x0, y0 + i, x1, ink, NULL);
807+
draw->hline(im, x0, y1 - i, x1, ink, NULL);
771808
draw->line(im, x1 - i, y0 + width, x1 - i, y1 - width + 1, ink);
772809
draw->line(im, x0 + i, y0 + width, x0 + i, y1 - width + 1, ink);
773810
}
@@ -778,7 +815,14 @@ ImagingDrawRectangle(
778815

779816
int
780817
ImagingDrawPolygon(
781-
Imaging im, int count, int *xy, const void *ink_, int fill, int width, int op
818+
Imaging im,
819+
int count,
820+
int *xy,
821+
const void *ink_,
822+
int fill,
823+
int width,
824+
int op,
825+
Imaging mask
782826
) {
783827
int i, n, x0, y0, x1, y1;
784828
DRAW *draw;
@@ -822,7 +866,7 @@ ImagingDrawPolygon(
822866
if (xy[i * 2] != xy[0] || xy[i * 2 + 1] != xy[1]) {
823867
add_edge(&e[n++], xy[i * 2], xy[i * 2 + 1], xy[0], xy[1]);
824868
}
825-
polygon_generic(im, n, e, ink, 0, draw->hline);
869+
polygon_generic(im, n, e, ink, 0, draw->hline, mask);
826870
free(e);
827871

828872
} else {
@@ -844,11 +888,12 @@ ImagingDrawPolygon(
844888
xy[i * 2 + 3],
845889
ink_,
846890
width,
847-
op
891+
op,
892+
mask
848893
);
849894
}
850895
ImagingDrawWideLine(
851-
im, xy[i * 2], xy[i * 2 + 1], xy[0], xy[1], ink_, width, op
896+
im, xy[i * 2], xy[i * 2 + 1], xy[0], xy[1], ink_, width, op, mask
852897
);
853898
}
854899
}
@@ -1519,7 +1564,9 @@ ellipseNew(
15191564
ellipse_init(&st, a, b, width);
15201565
int32_t X0, Y, X1;
15211566
while (ellipse_next(&st, &X0, &Y, &X1) != -1) {
1522-
draw->hline(im, x0 + (X0 + a) / 2, y0 + (Y + b) / 2, x0 + (X1 + a) / 2, ink);
1567+
draw->hline(
1568+
im, x0 + (X0 + a) / 2, y0 + (Y + b) / 2, x0 + (X1 + a) / 2, ink, NULL
1569+
);
15231570
}
15241571
return 0;
15251572
}
@@ -1554,7 +1601,9 @@ clipEllipseNew(
15541601
int32_t X0, Y, X1;
15551602
int next_code;
15561603
while ((next_code = clip_ellipse_next(&st, &X0, &Y, &X1)) >= 0) {
1557-
draw->hline(im, x0 + (X0 + a) / 2, y0 + (Y + b) / 2, x0 + (X1 + a) / 2, ink);
1604+
draw->hline(
1605+
im, x0 + (X0 + a) / 2, y0 + (Y + b) / 2, x0 + (X1 + a) / 2, ink, NULL
1606+
);
15581607
}
15591608
clip_ellipse_free(&st);
15601609
return next_code == -1 ? 0 : -1;
@@ -1972,7 +2021,7 @@ ImagingDrawOutline(
19722021

19732022
DRAWINIT();
19742023

1975-
polygon_generic(im, outline->count, outline->edges, ink, 0, draw->hline);
2024+
polygon_generic(im, outline->count, outline->edges, ink, 0, draw->hline, NULL);
19762025

19772026
return 0;
19782027
}

src/libImaging/Imaging.h

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -510,7 +510,15 @@ extern int
510510
ImagingDrawLine(Imaging im, int x0, int y0, int x1, int y1, const void *ink, int op);
511511
extern int
512512
ImagingDrawWideLine(
513-
Imaging im, int x0, int y0, int x1, int y1, const void *ink, int width, int op
513+
Imaging im,
514+
int x0,
515+
int y0,
516+
int x1,
517+
int y1,
518+
const void *ink,
519+
int width,
520+
int op,
521+
Imaging mask
514522
);
515523
extern int
516524
ImagingDrawPieslice(
@@ -530,7 +538,14 @@ extern int
530538
ImagingDrawPoint(Imaging im, int x, int y, const void *ink, int op);
531539
extern int
532540
ImagingDrawPolygon(
533-
Imaging im, int points, int *xy, const void *ink, int fill, int width, int op
541+
Imaging im,
542+
int points,
543+
int *xy,
544+
const void *ink,
545+
int fill,
546+
int width,
547+
int op,
548+
Imaging mask
534549
);
535550
extern int
536551
ImagingDrawRectangle(

0 commit comments

Comments
 (0)