From ca15c684eaa55755891d4dc70082b1ef51da0ee6 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Mon, 15 Nov 2021 23:28:29 +1100 Subject: [PATCH 1/2] Only prevent repeated polygon pixels when drawing with transparency --- src/libImaging/Draw.c | 61 +++++++++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 26 deletions(-) diff --git a/src/libImaging/Draw.c b/src/libImaging/Draw.c index 161895dc6b3..1cd9a95ad0b 100644 --- a/src/libImaging/Draw.c +++ b/src/libImaging/Draw.c @@ -444,7 +444,7 @@ draw_horizontal_lines( * Filled polygon draw function using scan line algorithm. */ static inline int -polygon_generic(Imaging im, int n, Edge *e, int ink, int eofill, hline_handler hline) { +polygon_generic(Imaging im, int n, Edge *e, int ink, int eofill, hline_handler hline, int hasAlpha) { Edge **edge_table; float *xx; int edge_count = 0; @@ -471,6 +471,9 @@ polygon_generic(Imaging im, int n, Edge *e, int ink, int eofill, hline_handler h ymax = e[i].ymax; } if (e[i].ymin == e[i].ymax) { + if (hasAlpha != 1) { + (*hline)(im, e[i].xmin, e[i].ymin, e[i].xmax, ink); + } continue; } edge_table[edge_count++] = (e + i); @@ -491,7 +494,6 @@ polygon_generic(Imaging im, int n, Edge *e, int ink, int eofill, hline_handler h } for (; ymin <= ymax; ymin++) { int j = 0; - int x_pos = 0; for (i = 0; i < edge_count; i++) { Edge *current = edge_table[i]; if (ymin >= current->ymin && ymin <= current->ymax) { @@ -504,31 +506,38 @@ polygon_generic(Imaging im, int n, Edge *e, int ink, int eofill, hline_handler h } } qsort(xx, j, sizeof(float), x_cmp); - for (i = 1; i < j; i += 2) { - int x_end = ROUND_DOWN(xx[i]); - if (x_end < x_pos) { - // Line would be before the current position - continue; - } - draw_horizontal_lines(im, n, e, ink, &x_pos, ymin, hline); - if (x_end < x_pos) { - // Line would be before the current position - continue; - } - - int x_start = ROUND_UP(xx[i - 1]); - if (x_pos > x_start) { - // Line would be partway through x_pos, so increase the starting point - x_start = x_pos; - if (x_end < x_start) { - // Line would now end before it started + if (hasAlpha == 1) { + int x_pos = 0; + for (i = 1; i < j; i += 2) { + int x_end = ROUND_DOWN(xx[i]); + if (x_end < x_pos) { + // Line would be before the current position + continue; + } + draw_horizontal_lines(im, n, e, ink, &x_pos, ymin, hline); + if (x_end < x_pos) { + // Line would be before the current position continue; } + + int x_start = ROUND_UP(xx[i - 1]); + if (x_pos > x_start) { + // Line would be partway through x_pos, so increase the starting point + x_start = x_pos; + if (x_end < x_start) { + // Line would now end before it started + continue; + } + } + (*hline)(im, x_start, ymin, x_end, ink); + x_pos = x_end + 1; + } + draw_horizontal_lines(im, n, e, ink, &x_pos, ymin, hline); + } else { + for (i = 1; i < j; i += 2) { + (*hline)(im, ROUND_UP(xx[i - 1]), ymin, ROUND_DOWN(xx[i]), ink); } - (*hline)(im, x_start, ymin, x_end, ink); - x_pos = x_end + 1; } - draw_horizontal_lines(im, n, e, ink, &x_pos, ymin, hline); } free(xx); @@ -538,17 +547,17 @@ polygon_generic(Imaging im, int n, Edge *e, int ink, int eofill, hline_handler h static inline int polygon8(Imaging im, int n, Edge *e, int ink, int eofill) { - return polygon_generic(im, n, e, ink, eofill, hline8); + return polygon_generic(im, n, e, ink, eofill, hline8, 0); } static inline int polygon32(Imaging im, int n, Edge *e, int ink, int eofill) { - return polygon_generic(im, n, e, ink, eofill, hline32); + return polygon_generic(im, n, e, ink, eofill, hline32, 0); } static inline int polygon32rgba(Imaging im, int n, Edge *e, int ink, int eofill) { - return polygon_generic(im, n, e, ink, eofill, hline32rgba); + return polygon_generic(im, n, e, ink, eofill, hline32rgba, 1); } static inline void From d7873e02ab81815f613c5b7e3ebf8662211f052a Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Tue, 16 Nov 2021 11:12:48 +1100 Subject: [PATCH 2/2] Added test that translucent polygon pixels do not combine --- Tests/images/imagedraw_polygon_translucent.png | Bin 0 -> 385 bytes Tests/test_imagedraw.py | 13 +++++++++++++ 2 files changed, 13 insertions(+) create mode 100644 Tests/images/imagedraw_polygon_translucent.png diff --git a/Tests/images/imagedraw_polygon_translucent.png b/Tests/images/imagedraw_polygon_translucent.png new file mode 100644 index 0000000000000000000000000000000000000000..da8d790a36fe574e3924063d5a443e0c01dfee82 GIT binary patch literal 385 zcmeAS@N?(olHy`uVBq!ia0vp^DImcK+Q8;9vC-7Ii(!pnkk9d1Dn~Qc zBnF*1I!pa%z?z9cK1XJ09kp0qS^{?q^N^QL6 zd9ihCV3*jMr9oGc-%ed5k-b%9YQ*iO8i%VKx}?^aFVQ$q<<_-6Lf>;H0{o5NZ@W-# VPel7{2Vl@Lc)I$ztaD0e0synDs#gF2 literal 0 HcmV?d00001 diff --git a/Tests/test_imagedraw.py b/Tests/test_imagedraw.py index 6be8fafa1e8..1b2909bed7c 100644 --- a/Tests/test_imagedraw.py +++ b/Tests/test_imagedraw.py @@ -638,6 +638,19 @@ def test_polygon_1px_high(): assert_image_equal_tofile(im, expected) +def test_polygon_translucent(): + # Arrange + im = Image.new("RGB", (W, H)) + draw = ImageDraw.Draw(im, "RGBA") + + # Act + draw.polygon([(20, 80), (80, 80), (80, 20)], fill=(0, 255, 0, 127)) + + # Assert + expected = "Tests/images/imagedraw_polygon_translucent.png" + assert_image_equal_tofile(im, expected) + + def helper_rectangle(bbox): # Arrange im = Image.new("RGB", (W, H))