mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-07-10 08:12:33 +03:00
Use mask in C when drawing wide polygon lines (#8984)
This commit is contained in:
parent
05636dca17
commit
7b163cc35d
|
@ -365,22 +365,10 @@ class ImageDraw:
|
|||
# use the fill as a mask
|
||||
mask = Image.new("1", self.im.size)
|
||||
mask_ink = self._getink(1)[0]
|
||||
|
||||
fill_im = mask.copy()
|
||||
draw = Draw(fill_im)
|
||||
draw = Draw(mask)
|
||||
draw.draw.draw_polygon(xy, mask_ink, 1)
|
||||
|
||||
ink_im = mask.copy()
|
||||
draw = Draw(ink_im)
|
||||
width = width * 2 - 1
|
||||
draw.draw.draw_polygon(xy, mask_ink, 0, width)
|
||||
|
||||
mask.paste(ink_im, mask=fill_im)
|
||||
|
||||
im = Image.new(self.mode, self.im.size)
|
||||
draw = Draw(im)
|
||||
draw.draw.draw_polygon(xy, ink, 0, width)
|
||||
self.im.paste(im.im, (0, 0) + im.size, mask.im)
|
||||
self.draw.draw_polygon(xy, ink, 0, width * 2 - 1, mask.im)
|
||||
|
||||
def regular_polygon(
|
||||
self,
|
||||
|
|
|
@ -3220,7 +3220,8 @@ _draw_lines(ImagingDrawObject *self, PyObject *args) {
|
|||
(int)p[3],
|
||||
&ink,
|
||||
width,
|
||||
self->blend
|
||||
self->blend,
|
||||
NULL
|
||||
) < 0) {
|
||||
free(xy);
|
||||
return NULL;
|
||||
|
@ -3358,7 +3359,10 @@ _draw_polygon(ImagingDrawObject *self, PyObject *args) {
|
|||
int ink;
|
||||
int fill = 0;
|
||||
int width = 0;
|
||||
if (!PyArg_ParseTuple(args, "Oi|ii", &data, &ink, &fill, &width)) {
|
||||
ImagingObject *maskp = NULL;
|
||||
if (!PyArg_ParseTuple(
|
||||
args, "Oi|iiO!", &data, &ink, &fill, &width, &Imaging_Type, &maskp
|
||||
)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -3388,8 +3392,16 @@ _draw_polygon(ImagingDrawObject *self, PyObject *args) {
|
|||
|
||||
free(xy);
|
||||
|
||||
if (ImagingDrawPolygon(self->image->image, n, ixy, &ink, fill, width, self->blend) <
|
||||
0) {
|
||||
if (ImagingDrawPolygon(
|
||||
self->image->image,
|
||||
n,
|
||||
ixy,
|
||||
&ink,
|
||||
fill,
|
||||
width,
|
||||
self->blend,
|
||||
maskp ? maskp->image : NULL
|
||||
) < 0) {
|
||||
free(ixy);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -63,7 +63,7 @@ typedef struct {
|
|||
} Edge;
|
||||
|
||||
/* Type used in "polygon*" functions */
|
||||
typedef void (*hline_handler)(Imaging, int, int, int, int);
|
||||
typedef void (*hline_handler)(Imaging, int, int, int, int, Imaging);
|
||||
|
||||
static inline void
|
||||
point8(Imaging im, int x, int y, int ink) {
|
||||
|
@ -103,7 +103,7 @@ point32rgba(Imaging im, int x, int y, int ink) {
|
|||
}
|
||||
|
||||
static inline void
|
||||
hline8(Imaging im, int x0, int y0, int x1, int ink) {
|
||||
hline8(Imaging im, int x0, int y0, int x1, int ink, Imaging mask) {
|
||||
int pixelwidth;
|
||||
|
||||
if (y0 >= 0 && y0 < im->ysize) {
|
||||
|
@ -119,15 +119,30 @@ hline8(Imaging im, int x0, int y0, int x1, int ink) {
|
|||
}
|
||||
if (x0 <= x1) {
|
||||
pixelwidth = strncmp(im->mode, "I;16", 4) == 0 ? 2 : 1;
|
||||
memset(
|
||||
im->image8[y0] + x0 * pixelwidth, (UINT8)ink, (x1 - x0 + 1) * pixelwidth
|
||||
);
|
||||
if (mask == NULL) {
|
||||
memset(
|
||||
im->image8[y0] + x0 * pixelwidth,
|
||||
(UINT8)ink,
|
||||
(x1 - x0 + 1) * pixelwidth
|
||||
);
|
||||
} else {
|
||||
UINT8 *p = im->image8[y0];
|
||||
while (x0 <= x1) {
|
||||
if (mask->image8[y0][x0]) {
|
||||
p[x0 * pixelwidth] = ink;
|
||||
if (pixelwidth == 2) {
|
||||
p[x0 * pixelwidth + 1] = ink;
|
||||
}
|
||||
}
|
||||
x0++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
hline32(Imaging im, int x0, int y0, int x1, int ink) {
|
||||
hline32(Imaging im, int x0, int y0, int x1, int ink, Imaging mask) {
|
||||
INT32 *p;
|
||||
|
||||
if (y0 >= 0 && y0 < im->ysize) {
|
||||
|
@ -143,13 +158,16 @@ hline32(Imaging im, int x0, int y0, int x1, int ink) {
|
|||
}
|
||||
p = im->image32[y0];
|
||||
while (x0 <= x1) {
|
||||
p[x0++] = ink;
|
||||
if (mask == NULL || mask->image8[y0][x0]) {
|
||||
p[x0] = ink;
|
||||
}
|
||||
x0++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
hline32rgba(Imaging im, int x0, int y0, int x1, int ink) {
|
||||
hline32rgba(Imaging im, int x0, int y0, int x1, int ink, Imaging mask) {
|
||||
unsigned int tmp;
|
||||
|
||||
if (y0 >= 0 && y0 < im->ysize) {
|
||||
|
@ -167,9 +185,11 @@ hline32rgba(Imaging im, int x0, int y0, int x1, int ink) {
|
|||
UINT8 *out = (UINT8 *)im->image[y0] + x0 * 4;
|
||||
UINT8 *in = (UINT8 *)&ink;
|
||||
while (x0 <= x1) {
|
||||
out[0] = BLEND(in[3], out[0], in[0], tmp);
|
||||
out[1] = BLEND(in[3], out[1], in[1], tmp);
|
||||
out[2] = BLEND(in[3], out[2], in[2], tmp);
|
||||
if (mask == NULL || mask->image8[y0][x0]) {
|
||||
out[0] = BLEND(in[3], out[0], in[0], tmp);
|
||||
out[1] = BLEND(in[3], out[1], in[1], tmp);
|
||||
out[2] = BLEND(in[3], out[2], in[2], tmp);
|
||||
}
|
||||
x0++;
|
||||
out += 4;
|
||||
}
|
||||
|
@ -407,7 +427,14 @@ x_cmp(const void *x0, const void *x1) {
|
|||
|
||||
static void
|
||||
draw_horizontal_lines(
|
||||
Imaging im, int n, Edge *e, int ink, int *x_pos, int y, hline_handler hline
|
||||
Imaging im,
|
||||
int n,
|
||||
Edge *e,
|
||||
int ink,
|
||||
int *x_pos,
|
||||
int y,
|
||||
hline_handler hline,
|
||||
Imaging mask
|
||||
) {
|
||||
int i;
|
||||
for (i = 0; i < n; i++) {
|
||||
|
@ -429,7 +456,7 @@ draw_horizontal_lines(
|
|||
}
|
||||
}
|
||||
|
||||
(*hline)(im, xmin, e[i].ymin, xmax, ink);
|
||||
(*hline)(im, xmin, e[i].ymin, xmax, ink, mask);
|
||||
*x_pos = xmax + 1;
|
||||
}
|
||||
}
|
||||
|
@ -439,7 +466,9 @@ draw_horizontal_lines(
|
|||
* Filled polygon draw function using scan line algorithm.
|
||||
*/
|
||||
static inline int
|
||||
polygon_generic(Imaging im, int n, Edge *e, int ink, int eofill, hline_handler hline) {
|
||||
polygon_generic(
|
||||
Imaging im, int n, Edge *e, int ink, int eofill, hline_handler hline, Imaging mask
|
||||
) {
|
||||
Edge **edge_table;
|
||||
float *xx;
|
||||
int edge_count = 0;
|
||||
|
@ -469,7 +498,7 @@ polygon_generic(Imaging im, int n, Edge *e, int ink, int eofill, hline_handler h
|
|||
}
|
||||
if (e[i].ymin == e[i].ymax) {
|
||||
if (hasAlpha != 1) {
|
||||
(*hline)(im, e[i].xmin, e[i].ymin, e[i].xmax, ink);
|
||||
(*hline)(im, e[i].xmin, e[i].ymin, e[i].xmax, ink, mask);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
@ -557,7 +586,7 @@ polygon_generic(Imaging im, int n, Edge *e, int ink, int eofill, hline_handler h
|
|||
// Line would be before the current position
|
||||
continue;
|
||||
}
|
||||
draw_horizontal_lines(im, n, e, ink, &x_pos, ymin, hline);
|
||||
draw_horizontal_lines(im, n, e, ink, &x_pos, ymin, hline, mask);
|
||||
if (x_end < x_pos) {
|
||||
// Line would be before the current position
|
||||
continue;
|
||||
|
@ -573,13 +602,13 @@ polygon_generic(Imaging im, int n, Edge *e, int ink, int eofill, hline_handler h
|
|||
continue;
|
||||
}
|
||||
}
|
||||
(*hline)(im, x_start, ymin, x_end, ink);
|
||||
(*hline)(im, x_start, ymin, x_end, ink, mask);
|
||||
x_pos = x_end + 1;
|
||||
}
|
||||
draw_horizontal_lines(im, n, e, ink, &x_pos, ymin, hline);
|
||||
draw_horizontal_lines(im, n, e, ink, &x_pos, ymin, hline, mask);
|
||||
} else {
|
||||
for (i = 1; i < j; i += 2) {
|
||||
(*hline)(im, ROUND_UP(xx[i - 1]), ymin, ROUND_DOWN(xx[i]), ink);
|
||||
(*hline)(im, ROUND_UP(xx[i - 1]), ymin, ROUND_DOWN(xx[i]), ink, mask);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -623,7 +652,7 @@ add_edge(Edge *e, int x0, int y0, int x1, int y1) {
|
|||
|
||||
typedef struct {
|
||||
void (*point)(Imaging im, int x, int y, int ink);
|
||||
void (*hline)(Imaging im, int x0, int y0, int x1, int ink);
|
||||
void (*hline)(Imaging im, int x0, int y0, int x1, int ink, Imaging mask);
|
||||
void (*line)(Imaging im, int x0, int y0, int x1, int y1, int ink);
|
||||
} DRAW;
|
||||
|
||||
|
@ -674,7 +703,15 @@ ImagingDrawLine(Imaging im, int x0, int y0, int x1, int y1, const void *ink_, in
|
|||
|
||||
int
|
||||
ImagingDrawWideLine(
|
||||
Imaging im, int x0, int y0, int x1, int y1, const void *ink_, int width, int op
|
||||
Imaging im,
|
||||
int x0,
|
||||
int y0,
|
||||
int x1,
|
||||
int y1,
|
||||
const void *ink_,
|
||||
int width,
|
||||
int op,
|
||||
Imaging mask
|
||||
) {
|
||||
DRAW *draw;
|
||||
INT32 ink;
|
||||
|
@ -714,7 +751,7 @@ ImagingDrawWideLine(
|
|||
add_edge(e + 2, vertices[2][0], vertices[2][1], vertices[3][0], vertices[3][1]);
|
||||
add_edge(e + 3, vertices[3][0], vertices[3][1], vertices[0][0], vertices[0][1]);
|
||||
|
||||
polygon_generic(im, 4, e, ink, 0, draw->hline);
|
||||
polygon_generic(im, 4, e, ink, 0, draw->hline, mask);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -757,7 +794,7 @@ ImagingDrawRectangle(
|
|||
}
|
||||
|
||||
for (y = y0; y <= y1; y++) {
|
||||
draw->hline(im, x0, y, x1, ink);
|
||||
draw->hline(im, x0, y, x1, ink, NULL);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
@ -766,8 +803,8 @@ ImagingDrawRectangle(
|
|||
width = 1;
|
||||
}
|
||||
for (i = 0; i < width; i++) {
|
||||
draw->hline(im, x0, y0 + i, x1, ink);
|
||||
draw->hline(im, x0, y1 - i, x1, ink);
|
||||
draw->hline(im, x0, y0 + i, x1, ink, NULL);
|
||||
draw->hline(im, x0, y1 - i, x1, ink, NULL);
|
||||
draw->line(im, x1 - i, y0 + width, x1 - i, y1 - width + 1, ink);
|
||||
draw->line(im, x0 + i, y0 + width, x0 + i, y1 - width + 1, ink);
|
||||
}
|
||||
|
@ -778,7 +815,14 @@ ImagingDrawRectangle(
|
|||
|
||||
int
|
||||
ImagingDrawPolygon(
|
||||
Imaging im, int count, int *xy, const void *ink_, int fill, int width, int op
|
||||
Imaging im,
|
||||
int count,
|
||||
int *xy,
|
||||
const void *ink_,
|
||||
int fill,
|
||||
int width,
|
||||
int op,
|
||||
Imaging mask
|
||||
) {
|
||||
int i, n, x0, y0, x1, y1;
|
||||
DRAW *draw;
|
||||
|
@ -822,7 +866,7 @@ ImagingDrawPolygon(
|
|||
if (xy[i * 2] != xy[0] || xy[i * 2 + 1] != xy[1]) {
|
||||
add_edge(&e[n++], xy[i * 2], xy[i * 2 + 1], xy[0], xy[1]);
|
||||
}
|
||||
polygon_generic(im, n, e, ink, 0, draw->hline);
|
||||
polygon_generic(im, n, e, ink, 0, draw->hline, mask);
|
||||
free(e);
|
||||
|
||||
} else {
|
||||
|
@ -844,11 +888,12 @@ ImagingDrawPolygon(
|
|||
xy[i * 2 + 3],
|
||||
ink_,
|
||||
width,
|
||||
op
|
||||
op,
|
||||
mask
|
||||
);
|
||||
}
|
||||
ImagingDrawWideLine(
|
||||
im, xy[i * 2], xy[i * 2 + 1], xy[0], xy[1], ink_, width, op
|
||||
im, xy[i * 2], xy[i * 2 + 1], xy[0], xy[1], ink_, width, op, mask
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1519,7 +1564,9 @@ ellipseNew(
|
|||
ellipse_init(&st, a, b, width);
|
||||
int32_t X0, Y, X1;
|
||||
while (ellipse_next(&st, &X0, &Y, &X1) != -1) {
|
||||
draw->hline(im, x0 + (X0 + a) / 2, y0 + (Y + b) / 2, x0 + (X1 + a) / 2, ink);
|
||||
draw->hline(
|
||||
im, x0 + (X0 + a) / 2, y0 + (Y + b) / 2, x0 + (X1 + a) / 2, ink, NULL
|
||||
);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -1554,7 +1601,9 @@ clipEllipseNew(
|
|||
int32_t X0, Y, X1;
|
||||
int next_code;
|
||||
while ((next_code = clip_ellipse_next(&st, &X0, &Y, &X1)) >= 0) {
|
||||
draw->hline(im, x0 + (X0 + a) / 2, y0 + (Y + b) / 2, x0 + (X1 + a) / 2, ink);
|
||||
draw->hline(
|
||||
im, x0 + (X0 + a) / 2, y0 + (Y + b) / 2, x0 + (X1 + a) / 2, ink, NULL
|
||||
);
|
||||
}
|
||||
clip_ellipse_free(&st);
|
||||
return next_code == -1 ? 0 : -1;
|
||||
|
@ -1972,7 +2021,7 @@ ImagingDrawOutline(
|
|||
|
||||
DRAWINIT();
|
||||
|
||||
polygon_generic(im, outline->count, outline->edges, ink, 0, draw->hline);
|
||||
polygon_generic(im, outline->count, outline->edges, ink, 0, draw->hline, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -510,7 +510,15 @@ extern int
|
|||
ImagingDrawLine(Imaging im, int x0, int y0, int x1, int y1, const void *ink, int op);
|
||||
extern int
|
||||
ImagingDrawWideLine(
|
||||
Imaging im, int x0, int y0, int x1, int y1, const void *ink, int width, int op
|
||||
Imaging im,
|
||||
int x0,
|
||||
int y0,
|
||||
int x1,
|
||||
int y1,
|
||||
const void *ink,
|
||||
int width,
|
||||
int op,
|
||||
Imaging mask
|
||||
);
|
||||
extern int
|
||||
ImagingDrawPieslice(
|
||||
|
@ -530,7 +538,14 @@ extern int
|
|||
ImagingDrawPoint(Imaging im, int x, int y, const void *ink, int op);
|
||||
extern int
|
||||
ImagingDrawPolygon(
|
||||
Imaging im, int points, int *xy, const void *ink, int fill, int width, int op
|
||||
Imaging im,
|
||||
int points,
|
||||
int *xy,
|
||||
const void *ink,
|
||||
int fill,
|
||||
int width,
|
||||
int op,
|
||||
Imaging mask
|
||||
);
|
||||
extern int
|
||||
ImagingDrawRectangle(
|
||||
|
|
Loading…
Reference in New Issue
Block a user