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 # Assert
self.assert_image_similar(im, Image.open(expected), 1) 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): def test_arc_width_fill(self):
# Arrange # Arrange
im = Image.new("RGB", (W, H)) im = Image.new("RGB", (W, H))
@ -239,6 +252,18 @@ class TestImageDraw(PillowTestCase):
# Assert # Assert
self.assert_image_similar(im, Image.open(expected), 1) 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): def test_ellipse_width_fill(self):
# Arrange # Arrange
im = Image.new("RGB", (W, H)) im = Image.new("RGB", (W, H))

View File

@ -765,81 +765,39 @@ ellipse(Imaging im, int x0, int y0, int x1, int y1,
int width, int mode, int op) int width, int mode, int op)
{ {
float i; float i;
int j; int inner;
int n; int n;
int cx, cy; int maxEdgeCount;
int w, h; int w, h;
int x = 0, y = 0; int x, y;
int lx = 0, ly = 0; int cx, cy;
int sx = 0, sy = 0; int lx, ly;
int sx, sy;
int lx_inner, ly_inner;
int sx_inner, sy_inner;
DRAW* draw; DRAW* draw;
INT32 ink; INT32 ink;
Edge* e;
DRAWINIT(); DRAWINIT();
if (width == 0) {
width = 1;
}
for (j = 0; j < width; j++) {
w = x1 - x0;
h = y1 - y0;
if (w < 0 || h < 0)
return 0;
cx = (x0 + x1) / 2;
cy = (y0 + y1) / 2;
while (end < start) while (end < start)
end += 360; end += 360;
if (end - start > 360) { if (end - start > 360) {
/* no need to go in loops */ // no need to go in loops
end = start + 361; end = start + 361;
} }
if (mode != ARC && fill) { w = x1 - x0;
h = y1 - y0;
if (w <= 0 || h <= 0)
return 0;
/* Build edge list */ cx = (x0 + x1) / 2;
/* malloc check UNDONE, FLOAT? */ cy = (y0 + y1) / 2;
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);
}
} else {
if (x != sx || y != sy)
add_edge(&e[n++], x, y, sx, sy);
}
draw->polygon(im, n, e, ink, 0);
}
free(e);
} else {
if (!fill && width <= 1) {
for (i = start; i < end+1; i++) { for (i = start; i < end+1; i++) {
if (i > end) { if (i > end) {
i = end; i = end;
@ -854,26 +812,103 @@ ellipse(Imaging im, int x0, int y0, int x1, int y1,
if (i != start) { if (i != start) {
if (mode == PIESLICE) { if (mode == PIESLICE) {
if (j == 0 && (x != cx || y != cy)) { if (x != cx || y != cy) {
if (width == 1) {
draw->line(im, x, y, cx, cy, ink); draw->line(im, x, y, cx, cy, ink);
draw->line(im, cx, cy, sx, sy, 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) { } else if (mode == CHORD) {
if (x != sx || y != sy) if (x != sx || y != sy)
draw->line(im, x, y, sx, sy, ink); 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;
} }
x0++; maxEdgeCount += 3;
y0++; e = calloc(maxEdgeCount, sizeof(Edge));
x1--; if (!e) {
y1--; 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;
if (inner) {
// Inner circle
x0 += width - 1;
y0 += width - 1;
x1 -= width - 1;
y1 -= width - 1;
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;
}
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;
}
}
}
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; return 0;
} }