diff --git a/.gitignore b/.gitignore index 95ed4bac5..aa45f946f 100644 --- a/.gitignore +++ b/.gitignore @@ -34,6 +34,9 @@ htmlcov/ nosetests.xml coverage.xml +# Test files +test_images + # Translations *.mo diff --git a/PIL/ImageDraw.py b/PIL/ImageDraw.py index ddf669f78..71e29ee48 100644 --- a/PIL/ImageDraw.py +++ b/PIL/ImageDraw.py @@ -283,6 +283,7 @@ def Draw(im, mode=None): except AttributeError: return ImageDraw(im, mode) + # experimental access to the outline API try: Outline = Image.core.outline diff --git a/Tests/images/imagedraw_arc_end_le_start.png b/Tests/images/imagedraw_arc_end_le_start.png new file mode 100644 index 000000000..aee48e1c6 Binary files /dev/null and b/Tests/images/imagedraw_arc_end_le_start.png differ diff --git a/Tests/images/imagedraw_arc_no_loops.png b/Tests/images/imagedraw_arc_no_loops.png new file mode 100644 index 000000000..e45ad57a5 Binary files /dev/null and b/Tests/images/imagedraw_arc_no_loops.png differ diff --git a/Tests/images/imagedraw_big_rectangle.png b/Tests/images/imagedraw_big_rectangle.png new file mode 100644 index 000000000..fa2370b28 Binary files /dev/null and b/Tests/images/imagedraw_big_rectangle.png differ diff --git a/Tests/images/imagedraw_chord.png b/Tests/images/imagedraw_chord.png deleted file mode 100644 index db3b35310..000000000 Binary files a/Tests/images/imagedraw_chord.png and /dev/null differ diff --git a/Tests/images/imagedraw_chord_L.png b/Tests/images/imagedraw_chord_L.png new file mode 100644 index 000000000..a5a0078d0 Binary files /dev/null and b/Tests/images/imagedraw_chord_L.png differ diff --git a/Tests/images/imagedraw_chord_RGB.png b/Tests/images/imagedraw_chord_RGB.png new file mode 100644 index 000000000..af6fc7660 Binary files /dev/null and b/Tests/images/imagedraw_chord_RGB.png differ diff --git a/Tests/images/imagedraw_ellipse_L.png b/Tests/images/imagedraw_ellipse_L.png new file mode 100644 index 000000000..e47e6e441 Binary files /dev/null and b/Tests/images/imagedraw_ellipse_L.png differ diff --git a/Tests/images/imagedraw_ellipse.png b/Tests/images/imagedraw_ellipse_RGB.png similarity index 100% rename from Tests/images/imagedraw_ellipse.png rename to Tests/images/imagedraw_ellipse_RGB.png diff --git a/Tests/images/imagedraw_polygon_kite_L.png b/Tests/images/imagedraw_polygon_kite_L.png new file mode 100644 index 000000000..241d86bf4 Binary files /dev/null and b/Tests/images/imagedraw_polygon_kite_L.png differ diff --git a/Tests/images/imagedraw_polygon_kite_RGB.png b/Tests/images/imagedraw_polygon_kite_RGB.png new file mode 100644 index 000000000..e48d6660f Binary files /dev/null and b/Tests/images/imagedraw_polygon_kite_RGB.png differ diff --git a/Tests/images/imagedraw_wide_line_dot.png b/Tests/images/imagedraw_wide_line_dot.png new file mode 100644 index 000000000..d6f0e789c Binary files /dev/null and b/Tests/images/imagedraw_wide_line_dot.png differ diff --git a/Tests/test_imagedraw.py b/Tests/test_imagedraw.py index 441a34a88..2ca5d0882 100644 --- a/Tests/test_imagedraw.py +++ b/Tests/test_imagedraw.py @@ -30,6 +30,8 @@ BBOX2 = [X0, Y0, X1, Y1] POINTS1 = [(10, 10), (20, 40), (30, 30)] POINTS2 = [10, 10, 20, 40, 30, 30] +KITE_POINTS = [(10, 50), (70, 10), (90, 50), (70, 90), (10, 50)] + class TestImageDraw(PillowTestCase): @@ -78,6 +80,37 @@ class TestImageDraw(PillowTestCase): self.helper_arc(BBOX2, 0, 180) self.helper_arc(BBOX2, 0.5, 180.4) + def test_arc_end_le_start(self): + # Arrange + im = Image.new("RGB", (W, H)) + draw = ImageDraw.Draw(im) + start = 270.5 + end = 0 + + # Act + draw.arc(BBOX1, start=start, end=end) + del draw + + # Assert + self.assert_image_equal( + im, Image.open("Tests/images/imagedraw_arc_end_le_start.png")) + + def test_arc_no_loops(self): + # No need to go in loops + # Arrange + im = Image.new("RGB", (W, H)) + draw = ImageDraw.Draw(im) + start = 5 + end = 370 + + # Act + draw.arc(BBOX1, start=start, end=end) + del draw + + # Assert + self.assert_image_similar( + im, Image.open("Tests/images/imagedraw_arc_no_loops.png"), 1) + def test_bitmap(self): # Arrange small = Image.open("Tests/images/pil123rgba.png").resize((50, 50)) @@ -92,45 +125,49 @@ class TestImageDraw(PillowTestCase): self.assert_image_equal( im, Image.open("Tests/images/imagedraw_bitmap.png")) - def helper_chord(self, bbox, start, end): + def helper_chord(self, mode, bbox, start, end): # Arrange - im = Image.new("RGB", (W, H)) + im = Image.new(mode, (W, H)) draw = ImageDraw.Draw(im) + expected = "Tests/images/imagedraw_chord_{}.png".format(mode) # Act draw.chord(bbox, start, end, fill="red", outline="yellow") del draw # Assert - self.assert_image_similar( - im, Image.open("Tests/images/imagedraw_chord.png"), 1) + self.assert_image_similar(im, Image.open(expected), 1) def test_chord1(self): - self.helper_chord(BBOX1, 0, 180) - self.helper_chord(BBOX1, 0.5, 180.4) + for mode in ["RGB", "L"]: + self.helper_chord(mode, BBOX1, 0, 180) + self.helper_chord(mode, BBOX1, 0.5, 180.4) def test_chord2(self): - self.helper_chord(BBOX2, 0, 180) - self.helper_chord(BBOX2, 0.5, 180.4) + for mode in ["RGB", "L"]: + self.helper_chord(mode, BBOX2, 0, 180) + self.helper_chord(mode, BBOX2, 0.5, 180.4) - def helper_ellipse(self, bbox): + def helper_ellipse(self, mode, bbox): # Arrange - im = Image.new("RGB", (W, H)) + im = Image.new(mode, (W, H)) draw = ImageDraw.Draw(im) + expected = "Tests/images/imagedraw_ellipse_{}.png".format(mode) # Act draw.ellipse(bbox, fill="green", outline="blue") del draw # Assert - self.assert_image_similar( - im, Image.open("Tests/images/imagedraw_ellipse.png"), 1) + self.assert_image_similar(im, Image.open(expected), 1) def test_ellipse1(self): - self.helper_ellipse(BBOX1) + for mode in ["RGB", "L"]: + self.helper_ellipse(mode, BBOX1) def test_ellipse2(self): - self.helper_ellipse(BBOX2) + for mode in ["RGB", "L"]: + self.helper_ellipse(mode, BBOX2) def test_ellipse_edge(self): # Arrange @@ -267,6 +304,23 @@ class TestImageDraw(PillowTestCase): def test_polygon2(self): self.helper_polygon(POINTS2) + def test_polygon_kite(self): + # Test drawing lines of different gradients (dx>dy, dy>dx) and + # vertical (dx==0) and horizontal (dy==0) lines + for mode in ["RGB", "L"]: + # Arrange + im = Image.new(mode, (W, H)) + draw = ImageDraw.Draw(im) + expected = "Tests/images/imagedraw_polygon_kite_{}.png".format( + mode) + + # Act + draw.polygon(KITE_POINTS, fill="blue", outline="yellow") + del draw + + # Assert + self.assert_image_equal(im, Image.open(expected)) + def helper_rectangle(self, bbox): # Arrange im = Image.new("RGB", (W, H)) @@ -286,6 +340,21 @@ class TestImageDraw(PillowTestCase): def test_rectangle2(self): self.helper_rectangle(BBOX2) + def test_big_rectangle(self): + # Test drawing a rectangle bigger than the image + # Arrange + im = Image.new("RGB", (W, H)) + bbox = [(-1, -1), (W+1, H+1)] + draw = ImageDraw.Draw(im) + expected = "Tests/images/imagedraw_big_rectangle.png" + + # Act + draw.rectangle(bbox, fill="orange") + del draw + + # Assert + self.assert_image_similar(im, Image.open(expected), 1) + def test_floodfill(self): # Arrange im = Image.new("RGB", (W, H)) @@ -478,6 +547,21 @@ class TestImageDraw(PillowTestCase): self.assert_image_equal(img, expected, 'line oblique 45 inverted 3px wide B failed') + def test_wide_line_dot(self): + # Test drawing a wide "line" from one point to another just draws + # a single point + # Arrange + im = Image.new("RGB", (W, H)) + draw = ImageDraw.Draw(im) + expected = "Tests/images/imagedraw_wide_line_dot.png" + + # Act + draw.line([(50, 50), (50, 50)], width=3) + del draw + + # Assert + self.assert_image_similar(im, Image.open(expected), 1) + if __name__ == '__main__': unittest.main() diff --git a/libImaging/Draw.c b/libImaging/Draw.c index ca26282be..65ab34a66 100644 --- a/libImaging/Draw.c +++ b/libImaging/Draw.c @@ -605,11 +605,6 @@ ImagingDrawWideLine(Imaging im, int x0, int y0, int x1, int y1, DRAWINIT(); - if (width <= 1) { - draw->line(im, x0, y0, x1, y1, ink); - return 0; - } - dx = x1-x0; dy = y1-y0; if (dx == 0 && dy == 0) { @@ -1030,20 +1025,6 @@ ImagingOutlineCurve(ImagingOutline outline, float x1, float y1, return 0; } -int -ImagingOutlineCurve2(ImagingOutline outline, float cx, float cy, - float x3, float y3) -{ - /* add bezier curve based on three control points (as - in the Flash file format) */ - - return ImagingOutlineCurve( - outline, - (outline->x + cx + cx)/3, (outline->y + cy + cy)/3, - (cx + cx + x3)/3, (cy + cy + y3)/3, - x3, y3); -} - int ImagingOutlineClose(ImagingOutline outline) {