[poppler] poppler/Annot.cc poppler/Annot.h

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Sat Nov 14 19:19:08 UTC 2020


 poppler/Annot.cc |   87 ++++++++++++++++++++-----------------------------------
 poppler/Annot.h  |    1 
 2 files changed, 34 insertions(+), 54 deletions(-)

New commits:
commit bd41274e4537a321bb2ab1ae89eb72fa302a2062
Author: Tobias Deiminger <haxtibal at posteo.de>
Date:   Fri Nov 13 09:55:26 2020 +0100

    Draw better circles for circle annotations
    
    Because PDF spec has no built in circle operator, we can only approximate
    a circle by joining cubic bezier curve segments.
    
    We already did good approximation for line endings and radio buttons by
    setting distance of bezier control point to (4 * (sqrt(2) - 1) / 3) * r.
    But the older AnnotGeometry::draw code for subtype circle still used
    an equivalent of 0.5 * r, which yields a visibly non-circular circle.
    Fix it by using the bezierCircle define for AnnotGeometry too.
    
    Does minor refactoring by introducing AnnotAppearanceBuilder::drawEllipse,
    and forwarding drawCircle to it. typeSquare code is slightly touched as
    a consequence, but remains functionally unchanged.
    
    Also changes 'S' (stroke path) to 's' (close and stroke path). To my
    understanding 'close and stroke' is the correct thing to do here,
    it's in line with drawCircle and the original commit 6c4fa513 didn't
    explain why it left the path open by using 'S'.
    
    Fixes #989.

diff --git a/poppler/Annot.cc b/poppler/Annot.cc
index d472a6e6..0816f257 100644
--- a/poppler/Annot.cc
+++ b/poppler/Annot.cc
@@ -1630,12 +1630,29 @@ void AnnotAppearanceBuilder::setLineStyleForBorder(const AnnotBorder *border)
 // If <fill> is true, the circle is filled; otherwise it is stroked.
 void AnnotAppearanceBuilder::drawCircle(double cx, double cy, double r, bool fill)
 {
-    appearBuf->appendf("{0:.2f} {1:.2f} m\n", cx + r, cy);
-    appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n", cx + r, cy + bezierCircle * r, cx + bezierCircle * r, cy + r, cx, cy + r);
-    appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n", cx - bezierCircle * r, cy + r, cx - r, cy + bezierCircle * r, cx - r, cy);
-    appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n", cx - r, cy - bezierCircle * r, cx - bezierCircle * r, cy - r, cx, cy - r);
-    appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n", cx + bezierCircle * r, cy - r, cx + r, cy - bezierCircle * r, cx + r, cy);
-    appearBuf->append(fill ? "f\n" : "s\n");
+    if (fill)
+        drawEllipse(cx, cy, r, r, true, false);
+    else
+        drawEllipse(cx, cy, r, r, false, true);
+}
+
+// Draw an (approximate) ellipse of radius <rx> on x-axis and <ry> on y-axis, centered at (<cx>, <cy>).
+// If <fill> is true, the ellipse is filled with current color for non-stroking operations.
+// If <stroke> is true, the ellipse path ist stroked with current color and color space for stroking operations.
+// Path will be closed if either fill or stroke is true; otherwise it's left open.
+void AnnotAppearanceBuilder::drawEllipse(double cx, double cy, double rx, double ry, bool fill, bool stroke)
+{
+    appearBuf->appendf("{0:.2f} {1:.2f} m\n", cx + rx, cy);
+    appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n", cx + rx, cy + bezierCircle * ry, cx + bezierCircle * rx, cy + ry, cx, cy + ry);
+    appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n", cx - bezierCircle * rx, cy + ry, cx - rx, cy + bezierCircle * ry, cx - rx, cy);
+    appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n", cx - rx, cy - bezierCircle * ry, cx - bezierCircle * rx, cy - ry, cx, cy - ry);
+    appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n", cx + bezierCircle * rx, cy - ry, cx + rx, cy - bezierCircle * ry, cx + rx, cy);
+    if (!fill && stroke)
+        appearBuf->append("s\n");
+    else if (fill && !stroke)
+        appearBuf->append("f\n");
+    else if (fill && stroke)
+        appearBuf->append("b\n");
 }
 
 // Draw the top-left half of an (approximate) circle of radius <r>
@@ -5331,6 +5348,7 @@ void AnnotGeometry::draw(Gfx *gfx, bool printing)
 
     annotLocker();
     if (appearance.isNull()) {
+        const bool fill = interiorColor && interiorColor->getSpace() != AnnotColor::colorTransparent;
         ca = opacity;
 
         AnnotAppearanceBuilder appearBuilder;
@@ -5346,55 +5364,16 @@ void AnnotGeometry::draw(Gfx *gfx, bool printing)
 
         if (type == typeSquare) {
             appearBuilder.appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} re\n", borderWidth / 2.0, borderWidth / 2.0, (rect->x2 - rect->x1) - borderWidth, (rect->y2 - rect->y1) - borderWidth);
+            if (fill)
+                appearBuilder.append("b\n");
+            else
+                appearBuilder.append("S\n");
         } else {
-            double width, height;
-            double b;
-            double x1, y1, x2, y2, x3, y3;
-
-            width = rect->x2 - rect->x1;
-            height = rect->y2 - rect->y1;
-            b = borderWidth / 2.0;
-
-            x1 = b;
-            y1 = height / 2.0;
-            appearBuilder.appendf("{0:.2f} {1:.2f} m\n", x1, y1);
-
-            y1 += height / 4.0;
-            x2 = width / 4.0;
-            y2 = height - b;
-            x3 = width / 2.0;
-            y3 = y2;
-            appearBuilder.appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n", x1, y1, x2, y2, x3, y3);
-            x2 = width - b;
-            y2 = y1;
-            x1 = x3 + (width / 4.0);
-            y1 = y3;
-            x3 = x2;
-            y3 = height / 2.0;
-            appearBuilder.appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n", x1, y1, x2, y2, x3, y3);
-
-            x2 = x1;
-            y2 = b;
-            x1 = x3;
-            y1 = height / 4.0;
-            x3 = width / 2.0;
-            y3 = b;
-            appearBuilder.appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n", x1, y1, x2, y2, x3, y3);
-
-            x2 = b;
-            y2 = y1;
-            x1 = width / 4.0;
-            y1 = b;
-            x3 = b;
-            y3 = height / 2.0;
-            appearBuilder.appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n", x1, y1, x2, y2, x3, y3);
-        }
-
-        if (interiorColor && interiorColor->getSpace() != AnnotColor::colorTransparent)
-            appearBuilder.append("b\n");
-        else
-            appearBuilder.append("S\n");
-
+            const double rx { (rect->x2 - rect->x1) / 2. };
+            const double ry { (rect->y2 - rect->y1) / 2. };
+            const double bwHalf { borderWidth / 2.0 };
+            appearBuilder.drawEllipse(rx, ry, rx - bwHalf, ry - bwHalf, fill, true);
+        }
         appearBuilder.append("Q\n");
 
         double bbox[4];
diff --git a/poppler/Annot.h b/poppler/Annot.h
index dea29514..9cea7b20 100644
--- a/poppler/Annot.h
+++ b/poppler/Annot.h
@@ -556,6 +556,7 @@ public:
     void setLineStyleForBorder(const AnnotBorder *border);
     void setTextFont(const Object &fontName, double fontSize);
     void drawCircle(double cx, double cy, double r, bool fill);
+    void drawEllipse(double cx, double cy, double rx, double ry, bool fill, bool stroke);
     void drawCircleTopLeft(double cx, double cy, double r);
     void drawCircleBottomRight(double cx, double cy, double r);
     void drawLineEnding(AnnotLineEndingStyle endingStyle, double x, double y, double size, bool fill, const Matrix &m);


More information about the poppler mailing list