mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-07-10 16:22:22 +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
|
# use the fill as a mask
|
||||||
mask = Image.new("1", self.im.size)
|
mask = Image.new("1", self.im.size)
|
||||||
mask_ink = self._getink(1)[0]
|
mask_ink = self._getink(1)[0]
|
||||||
|
draw = Draw(mask)
|
||||||
fill_im = mask.copy()
|
|
||||||
draw = Draw(fill_im)
|
|
||||||
draw.draw.draw_polygon(xy, mask_ink, 1)
|
draw.draw.draw_polygon(xy, mask_ink, 1)
|
||||||
|
|
||||||
ink_im = mask.copy()
|
self.draw.draw_polygon(xy, ink, 0, width * 2 - 1, mask.im)
|
||||||
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)
|
|
||||||
|
|
||||||
def regular_polygon(
|
def regular_polygon(
|
||||||
self,
|
self,
|
||||||
|
|
|
@ -3220,7 +3220,8 @@ _draw_lines(ImagingDrawObject *self, PyObject *args) {
|
||||||
(int)p[3],
|
(int)p[3],
|
||||||
&ink,
|
&ink,
|
||||||
width,
|
width,
|
||||||
self->blend
|
self->blend,
|
||||||
|
NULL
|
||||||
) < 0) {
|
) < 0) {
|
||||||
free(xy);
|
free(xy);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -3358,7 +3359,10 @@ _draw_polygon(ImagingDrawObject *self, PyObject *args) {
|
||||||
int ink;
|
int ink;
|
||||||
int fill = 0;
|
int fill = 0;
|
||||||
int width = 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;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3388,8 +3392,16 @@ _draw_polygon(ImagingDrawObject *self, PyObject *args) {
|
||||||
|
|
||||||
free(xy);
|
free(xy);
|
||||||
|
|
||||||
if (ImagingDrawPolygon(self->image->image, n, ixy, &ink, fill, width, self->blend) <
|
if (ImagingDrawPolygon(
|
||||||
0) {
|
self->image->image,
|
||||||
|
n,
|
||||||
|
ixy,
|
||||||
|
&ink,
|
||||||
|
fill,
|
||||||
|
width,
|
||||||
|
self->blend,
|
||||||
|
maskp ? maskp->image : NULL
|
||||||
|
) < 0) {
|
||||||
free(ixy);
|
free(ixy);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,7 +63,7 @@ typedef struct {
|
||||||
} Edge;
|
} Edge;
|
||||||
|
|
||||||
/* Type used in "polygon*" functions */
|
/* 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
|
static inline void
|
||||||
point8(Imaging im, int x, int y, int ink) {
|
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
|
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;
|
int pixelwidth;
|
||||||
|
|
||||||
if (y0 >= 0 && y0 < im->ysize) {
|
if (y0 >= 0 && y0 < im->ysize) {
|
||||||
|
@ -119,15 +119,30 @@ hline8(Imaging im, int x0, int y0, int x1, int ink) {
|
||||||
}
|
}
|
||||||
if (x0 <= x1) {
|
if (x0 <= x1) {
|
||||||
pixelwidth = strncmp(im->mode, "I;16", 4) == 0 ? 2 : 1;
|
pixelwidth = strncmp(im->mode, "I;16", 4) == 0 ? 2 : 1;
|
||||||
memset(
|
if (mask == NULL) {
|
||||||
im->image8[y0] + x0 * pixelwidth, (UINT8)ink, (x1 - x0 + 1) * pixelwidth
|
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
|
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;
|
INT32 *p;
|
||||||
|
|
||||||
if (y0 >= 0 && y0 < im->ysize) {
|
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];
|
p = im->image32[y0];
|
||||||
while (x0 <= x1) {
|
while (x0 <= x1) {
|
||||||
p[x0++] = ink;
|
if (mask == NULL || mask->image8[y0][x0]) {
|
||||||
|
p[x0] = ink;
|
||||||
|
}
|
||||||
|
x0++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
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;
|
unsigned int tmp;
|
||||||
|
|
||||||
if (y0 >= 0 && y0 < im->ysize) {
|
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 *out = (UINT8 *)im->image[y0] + x0 * 4;
|
||||||
UINT8 *in = (UINT8 *)&ink;
|
UINT8 *in = (UINT8 *)&ink;
|
||||||
while (x0 <= x1) {
|
while (x0 <= x1) {
|
||||||
out[0] = BLEND(in[3], out[0], in[0], tmp);
|
if (mask == NULL || mask->image8[y0][x0]) {
|
||||||
out[1] = BLEND(in[3], out[1], in[1], tmp);
|
out[0] = BLEND(in[3], out[0], in[0], tmp);
|
||||||
out[2] = BLEND(in[3], out[2], in[2], tmp);
|
out[1] = BLEND(in[3], out[1], in[1], tmp);
|
||||||
|
out[2] = BLEND(in[3], out[2], in[2], tmp);
|
||||||
|
}
|
||||||
x0++;
|
x0++;
|
||||||
out += 4;
|
out += 4;
|
||||||
}
|
}
|
||||||
|
@ -407,7 +427,14 @@ x_cmp(const void *x0, const void *x1) {
|
||||||
|
|
||||||
static void
|
static void
|
||||||
draw_horizontal_lines(
|
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;
|
int i;
|
||||||
for (i = 0; i < n; 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;
|
*x_pos = xmax + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -439,7 +466,9 @@ draw_horizontal_lines(
|
||||||
* Filled polygon draw function using scan line algorithm.
|
* Filled polygon draw function using scan line algorithm.
|
||||||
*/
|
*/
|
||||||
static inline int
|
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;
|
Edge **edge_table;
|
||||||
float *xx;
|
float *xx;
|
||||||
int edge_count = 0;
|
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 (e[i].ymin == e[i].ymax) {
|
||||||
if (hasAlpha != 1) {
|
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;
|
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
|
// Line would be before the current position
|
||||||
continue;
|
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) {
|
if (x_end < x_pos) {
|
||||||
// Line would be before the current position
|
// Line would be before the current position
|
||||||
continue;
|
continue;
|
||||||
|
@ -573,13 +602,13 @@ polygon_generic(Imaging im, int n, Edge *e, int ink, int eofill, hline_handler h
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(*hline)(im, x_start, ymin, x_end, ink);
|
(*hline)(im, x_start, ymin, x_end, ink, mask);
|
||||||
x_pos = x_end + 1;
|
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 {
|
} else {
|
||||||
for (i = 1; i < j; i += 2) {
|
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 {
|
typedef struct {
|
||||||
void (*point)(Imaging im, int x, int y, int ink);
|
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);
|
void (*line)(Imaging im, int x0, int y0, int x1, int y1, int ink);
|
||||||
} DRAW;
|
} DRAW;
|
||||||
|
|
||||||
|
@ -674,7 +703,15 @@ ImagingDrawLine(Imaging im, int x0, int y0, int x1, int y1, const void *ink_, in
|
||||||
|
|
||||||
int
|
int
|
||||||
ImagingDrawWideLine(
|
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;
|
DRAW *draw;
|
||||||
INT32 ink;
|
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 + 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]);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -757,7 +794,7 @@ ImagingDrawRectangle(
|
||||||
}
|
}
|
||||||
|
|
||||||
for (y = y0; y <= y1; y++) {
|
for (y = y0; y <= y1; y++) {
|
||||||
draw->hline(im, x0, y, x1, ink);
|
draw->hline(im, x0, y, x1, ink, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
@ -766,8 +803,8 @@ ImagingDrawRectangle(
|
||||||
width = 1;
|
width = 1;
|
||||||
}
|
}
|
||||||
for (i = 0; i < width; i++) {
|
for (i = 0; i < width; i++) {
|
||||||
draw->hline(im, x0, y0 + i, x1, ink);
|
draw->hline(im, x0, y0 + i, x1, ink, NULL);
|
||||||
draw->hline(im, x0, y1 - i, x1, ink);
|
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, x1 - i, y0 + width, x1 - i, y1 - width + 1, ink);
|
||||||
draw->line(im, x0 + i, y0 + width, x0 + i, y1 - width + 1, ink);
|
draw->line(im, x0 + i, y0 + width, x0 + i, y1 - width + 1, ink);
|
||||||
}
|
}
|
||||||
|
@ -778,7 +815,14 @@ ImagingDrawRectangle(
|
||||||
|
|
||||||
int
|
int
|
||||||
ImagingDrawPolygon(
|
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;
|
int i, n, x0, y0, x1, y1;
|
||||||
DRAW *draw;
|
DRAW *draw;
|
||||||
|
@ -822,7 +866,7 @@ ImagingDrawPolygon(
|
||||||
if (xy[i * 2] != xy[0] || xy[i * 2 + 1] != xy[1]) {
|
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]);
|
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);
|
free(e);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
@ -844,11 +888,12 @@ ImagingDrawPolygon(
|
||||||
xy[i * 2 + 3],
|
xy[i * 2 + 3],
|
||||||
ink_,
|
ink_,
|
||||||
width,
|
width,
|
||||||
op
|
op,
|
||||||
|
mask
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
ImagingDrawWideLine(
|
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);
|
ellipse_init(&st, a, b, width);
|
||||||
int32_t X0, Y, X1;
|
int32_t X0, Y, X1;
|
||||||
while (ellipse_next(&st, &X0, &Y, &X1) != -1) {
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1554,7 +1601,9 @@ clipEllipseNew(
|
||||||
int32_t X0, Y, X1;
|
int32_t X0, Y, X1;
|
||||||
int next_code;
|
int next_code;
|
||||||
while ((next_code = clip_ellipse_next(&st, &X0, &Y, &X1)) >= 0) {
|
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);
|
clip_ellipse_free(&st);
|
||||||
return next_code == -1 ? 0 : -1;
|
return next_code == -1 ? 0 : -1;
|
||||||
|
@ -1972,7 +2021,7 @@ ImagingDrawOutline(
|
||||||
|
|
||||||
DRAWINIT();
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -510,7 +510,15 @@ extern int
|
||||||
ImagingDrawLine(Imaging im, int x0, int y0, int x1, int y1, const void *ink, int op);
|
ImagingDrawLine(Imaging im, int x0, int y0, int x1, int y1, const void *ink, int op);
|
||||||
extern int
|
extern int
|
||||||
ImagingDrawWideLine(
|
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
|
extern int
|
||||||
ImagingDrawPieslice(
|
ImagingDrawPieslice(
|
||||||
|
@ -530,7 +538,14 @@ extern int
|
||||||
ImagingDrawPoint(Imaging im, int x, int y, const void *ink, int op);
|
ImagingDrawPoint(Imaging im, int x, int y, const void *ink, int op);
|
||||||
extern int
|
extern int
|
||||||
ImagingDrawPolygon(
|
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
|
extern int
|
||||||
ImagingDrawRectangle(
|
ImagingDrawRectangle(
|
||||||
|
|
Loading…
Reference in New Issue
Block a user