Fixed ImageDraw arc gaps (#3824)

Fixed ImageDraw arc gaps
This commit is contained in:
Hugo 2019-05-04 18:50:07 +03:00 committed by GitHub
commit c3ed8cc67e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 151 additions and 91 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 402 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

@ -114,6 +114,19 @@ class TestImageDraw(PillowTestCase):
# Assert
self.assert_image_similar(im, Image.open(expected), 1)
def test_arc_width_pieslice_large(self):
# Tests an arc with a large enough width that it is a pieslice
# Arrange
im = Image.new("RGB", (W, H))
draw = ImageDraw.Draw(im)
expected = "Tests/images/imagedraw_arc_width_pieslice.png"
# Act
draw.arc(BBOX1, 10, 260, fill="yellow", width=100)
# Assert
self.assert_image_similar(im, Image.open(expected), 1)
def test_arc_width_fill(self):
# Arrange
im = Image.new("RGB", (W, H))
@ -239,6 +252,18 @@ class TestImageDraw(PillowTestCase):
# Assert
self.assert_image_similar(im, Image.open(expected), 1)
def test_ellipse_width_large(self):
# Arrange
im = Image.new("RGB", (500, 500))
draw = ImageDraw.Draw(im)
expected = "Tests/images/imagedraw_ellipse_width_large.png"
# Act
draw.ellipse((25, 25, 475, 475), outline="blue", width=75)
# Assert
self.assert_image_similar(im, Image.open(expected), 1)
def test_ellipse_width_fill(self):
# Arrange
im = Image.new("RGB", (W, H))

View File

@ -765,115 +765,150 @@ ellipse(Imaging im, int x0, int y0, int x1, int y1,
int width, int mode, int op)
{
float i;
int j;
int inner;
int n;
int cx, cy;
int maxEdgeCount;
int w, h;
int x = 0, y = 0;
int lx = 0, ly = 0;
int sx = 0, sy = 0;
int x, y;
int cx, cy;
int lx, ly;
int sx, sy;
int lx_inner, ly_inner;
int sx_inner, sy_inner;
DRAW* draw;
INT32 ink;
Edge* e;
DRAWINIT();
if (width == 0) {
width = 1;
while (end < start)
end += 360;
if (end - start > 360) {
// no need to go in loops
end = start + 361;
}
for (j = 0; j < width; j++) {
w = x1 - x0;
h = y1 - y0;
if (w <= 0 || h <= 0)
return 0;
w = x1 - x0;
h = y1 - y0;
if (w < 0 || h < 0)
cx = (x0 + x1) / 2;
cy = (y0 + y1) / 2;
if (!fill && width <= 1) {
for (i = start; i < end+1; i++) {
if (i > end) {
i = end;
}
ellipsePoint(cx, cy, w, h, i, &x, &y);
if (i != start)
draw->line(im, lx, ly, x, y, ink);
else
sx = x, sy = y;
lx = x, ly = y;
}
if (i != start) {
if (mode == PIESLICE) {
if (x != cx || y != cy) {
draw->line(im, x, y, cx, cy, ink);
draw->line(im, cx, cy, sx, sy, ink);
}
} else if (mode == CHORD) {
if (x != sx || y != sy)
draw->line(im, x, y, sx, sy, ink);
}
}
} else {
inner = (mode == ARC || !fill) ? 1 : 0;
// Build edge list
// malloc check UNDONE, FLOAT?
maxEdgeCount = end - start;
if (inner) {
maxEdgeCount *= 2;
}
maxEdgeCount += 3;
e = calloc(maxEdgeCount, sizeof(Edge));
if (!e) {
ImagingError_MemoryError();
return -1;
}
// Outer circle
n = 0;
for (i = start; i < end+1; i++) {
if (i > end) {
i = end;
}
ellipsePoint(cx, cy, w, h, i, &x, &y);
if (i == start) {
sx = x, sy = y;
} else {
add_edge(&e[n++], lx, ly, x, y);
}
lx = x, ly = y;
}
if (n == 0)
return 0;
cx = (x0 + x1) / 2;
cy = (y0 + y1) / 2;
if (inner) {
// Inner circle
x0 += width - 1;
y0 += width - 1;
x1 -= width - 1;
y1 -= width - 1;
while (end < start)
end += 360;
if (end - start > 360) {
/* no need to go in loops */
end = start + 361;
}
if (mode != ARC && fill) {
/* Build edge list */
/* malloc check UNDONE, FLOAT? */
Edge* e = calloc((end - start + 3), sizeof(Edge));
if (!e) {
ImagingError_MemoryError();
return -1;
}
n = 0;
for (i = start; i < end+1; i++) {
if (i > end) {
i = end;
}
ellipsePoint(cx, cy, w, h, i, &x, &y);
if (i != start)
add_edge(&e[n++], lx, ly, x, y);
else
sx = x, sy = y;
lx = x, ly = y;
}
if (n > 0) {
/* close and draw polygon */
if (mode == PIESLICE) {
if (x != cx || y != cy) {
add_edge(&e[n++], x, y, cx, cy);
add_edge(&e[n++], cx, cy, sx, sy);
w = x1 - x0;
h = y1 - y0;
if (w <= 0 || h <= 0) {
// ARC with no gap in the middle is a PIESLICE
mode = PIESLICE;
inner = 0;
} else {
for (i = start; i < end+1; i++) {
if (i > end) {
i = end;
}
} else {
if (x != sx || y != sy)
add_edge(&e[n++], x, y, sx, sy);
}
draw->polygon(im, n, e, ink, 0);
}
free(e);
} else {
for (i = start; i < end+1; i++) {
if (i > end) {
i = end;
}
ellipsePoint(cx, cy, w, h, i, &x, &y);
if (i != start)
draw->line(im, lx, ly, x, y, ink);
else
sx = x, sy = y;
lx = x, ly = y;
}
if (i != start) {
if (mode == PIESLICE) {
if (j == 0 && (x != cx || y != cy)) {
if (width == 1) {
draw->line(im, x, y, cx, cy, ink);
draw->line(im, cx, cy, sx, sy, ink);
} else {
ImagingDrawWideLine(im, x, y, cx, cy, &ink, width, op);
ImagingDrawWideLine(im, cx, cy, sx, sy, &ink, width, op);
}
}
} else if (mode == CHORD) {
if (x != sx || y != sy)
draw->line(im, x, y, sx, sy, ink);
ellipsePoint(cx, cy, w, h, i, &x, &y);
if (i == start)
sx_inner = x, sy_inner = y;
else
add_edge(&e[n++], lx_inner, ly_inner, x, y);
lx_inner = x, ly_inner = y;
}
}
}
x0++;
y0++;
x1--;
y1--;
if (end - start < 360) {
// Close polygon
if (mode == PIESLICE) {
if (x != cx || y != cy) {
add_edge(&e[n++], sx, sy, cx, cy);
add_edge(&e[n++], cx, cy, lx, ly);
if (inner) {
ImagingDrawWideLine(im, sx, sy, cx, cy, &ink, width, op);
ImagingDrawWideLine(im, cx, cy, lx, ly, &ink, width, op);
}
}
} else if (mode == CHORD) {
add_edge(&e[n++], sx, sy, lx, ly);
if (inner) {
add_edge(&e[n++], sx_inner, sy_inner, lx_inner, ly_inner);
}
} else if (mode == ARC) {
add_edge(&e[n++], sx, sy, sx_inner, sy_inner);
add_edge(&e[n++], lx, ly, lx_inner, ly_inner);
}
}
draw->polygon(im, n, e, ink, 0);
free(e);
}
return 0;
}