Skip to content

Commit

Permalink
Fixed ImageDraw arc gaps (#3824)
Browse files Browse the repository at this point in the history
Fixed ImageDraw arc gaps
  • Loading branch information
hugovk committed May 4, 2019
2 parents 5090bba + 21c7fd2 commit c3ed8cc
Show file tree
Hide file tree
Showing 4 changed files with 142 additions and 82 deletions.
Binary file added Tests/images/imagedraw_arc_width_pieslice.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Tests/images/imagedraw_ellipse_width_large.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
25 changes: 25 additions & 0 deletions Tests/test_imagedraw.py
Expand Up @@ -114,6 +114,19 @@ def test_arc_width(self):
# 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))
Expand Down Expand Up @@ -239,6 +252,18 @@ def test_ellipse_width(self):
# 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))
Expand Down
199 changes: 117 additions & 82 deletions src/libImaging/Draw.c
Expand Up @@ -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;

for (j = 0; j < width; j++) {
if (end - start > 360) {
// no need to go in loops
end = start + 361;
}

w = x1 - x0;
h = y1 - y0;
if (w < 0 || h < 0)
return 0;
w = x1 - x0;
h = y1 - y0;
if (w <= 0 || h <= 0)
return 0;

cx = (x0 + x1) / 2;
cy = (y0 + y1) / 2;
cx = (x0 + x1) / 2;
cy = (y0 + y1) / 2;

while (end < start)
end += 360;
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 (end - start > 360) {
/* no need to go in loops */
end = start + 361;
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;

if (mode != ARC && fill) {
// 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;
}

/* Build edge list */
/* malloc check UNDONE, FLOAT? */
Edge* e = calloc((end - start + 3), sizeof(Edge));
if (!e) {
ImagingError_MemoryError();
return -1;
// Outer circle
n = 0;
for (i = start; i < end+1; i++) {
if (i > end) {
i = end;
}
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;
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 (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);
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;
}
} 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)
sx_inner = x, sy_inner = y;
else
add_edge(&e[n++], lx_inner, ly_inner, x, y);
lx_inner = x, ly_inner = y;
}
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);
}
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) {
if (x != sx || y != sy)
draw->line(im, x, y, sx, sy, ink);
}
} 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);
}
}
x0++;
y0++;
x1--;
y1--;

draw->polygon(im, n, e, ink, 0);

free(e);
}

return 0;
}

Expand Down

0 comments on commit c3ed8cc

Please sign in to comment.