diff --git a/Tests/test_imagedraw.py b/Tests/test_imagedraw.py index f9377634f..1c8fe3153 100644 --- a/Tests/test_imagedraw.py +++ b/Tests/test_imagedraw.py @@ -169,6 +169,16 @@ class TestImageDraw(PillowTestCase): self.assert_image_similar( im, Image.open("Tests/images/imagedraw_ellipse_edge.png"), 1) + def test_ellipse_symmetric(self): + for bbox in [ + (25, 25, 76, 76), + (25, 25, 75, 75) + ]: + im = Image.new("RGB", (101, 101)) + draw = ImageDraw.Draw(im) + draw.ellipse(bbox, fill="green", outline="blue") + self.assert_image_equal(im, im.transpose(Image.FLIP_LEFT_RIGHT)) + def helper_line(self, points): # Arrange im = Image.new("RGB", (W, H)) diff --git a/src/libImaging/Draw.c b/src/libImaging/Draw.c index 69cd88444..7b7c5fac0 100644 --- a/src/libImaging/Draw.c +++ b/src/libImaging/Draw.c @@ -732,6 +732,29 @@ ImagingDrawBitmap(Imaging im, int x0, int y0, Imaging bitmap, const void* ink, #define CHORD 1 #define PIESLICE 2 +static void +ellipsePoint(int cx, int cy, int w, int h, + float i, int *x, int *y) +{ + float i_cos, i_sin; + float x_f, y_f; + double modf_int; + i_cos = cos(i*M_PI/180); + i_sin = sin(i*M_PI/180); + x_f = (i_cos * w/2) + cx; + y_f = (i_sin * h/2) + cy; + if (modf(x_f, &modf_int) == 0.5) { + *x = i_cos > 0 ? FLOOR(x_f) : CEIL(x_f); + } else { + *x = FLOOR(x_f + 0.5); + } + if (modf(y_f, &modf_int) == 0.5) { + *y = i_sin > 0 ? FLOOR(y_f) : CEIL(y_f); + } else { + *y = FLOOR(y_f + 0.5); + } +} + static int ellipse(Imaging im, int x0, int y0, int x1, int y1, float start, float end, const void* ink_, int fill, @@ -781,8 +804,7 @@ ellipse(Imaging im, int x0, int y0, int x1, int y1, if (i > end) { i = end; } - x = FLOOR((cos(i*M_PI/180) * w/2) + cx + 0.5); - y = FLOOR((sin(i*M_PI/180) * h/2) + cy + 0.5); + ellipsePoint(cx, cy, w, h, i, &x, &y); if (i != start) add_edge(&e[n++], lx, ly, x, y); else @@ -812,8 +834,7 @@ ellipse(Imaging im, int x0, int y0, int x1, int y1, if (i > end) { i = end; } - x = FLOOR((cos(i*M_PI/180) * w/2) + cx + 0.5); - y = FLOOR((sin(i*M_PI/180) * h/2) + cy + 0.5); + ellipsePoint(cx, cy, w, h, i, &x, &y); if (i != start) draw->line(im, lx, ly, x, y, ink); else