Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed ImageDraw arc gaps #3824

Merged
merged 1 commit into from May 4, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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