[poppler] 2 commits - poppler/CairoOutputDev.cc poppler/CairoOutputDev.h

Carlos Garcia Campos carlosgc at kemper.freedesktop.org
Sun Aug 28 04:10:04 PDT 2011


 poppler/CairoOutputDev.cc |   56 ++++++++++++++++++++++++++++++++++++++++++----
 poppler/CairoOutputDev.h  |    4 +++
 2 files changed, 56 insertions(+), 4 deletions(-)

New commits:
commit 91fafce028ca6620c0eb22e370fb4c6fd3404e3c
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Tue Aug 23 21:02:02 2011 +0930

    cairo: align strokes when Stroke Adjust is true and line width <= 1
    
    If the stroke coordinates are not aligned, lines in cairo may be up to
    1 pixel wider than the requested width. This is most obvious when the
    line width is 1 and the rendered line is 2 pixels.
    
    When Stroke Adjust is true, the PDF standard requires that stroke
    coordinates be adjusted to ensure the stroke width is within half a
    pixel of the requested width.
    
    If Stroke Adjust is enabled and the width is <= 1 pixel (the previous
    commit adjusts the width to be at least 1 pixel), use the method
    documented at http://www.cairographics.org/FAQ/#sharp_lines to align
    the coordinates to ensure the rendered width is 1 pixel.
    
    Fixes bug #4536.

diff --git a/poppler/CairoOutputDev.cc b/poppler/CairoOutputDev.cc
index 5c29f94..30c69f1 100644
--- a/poppler/CairoOutputDev.cc
+++ b/poppler/CairoOutputDev.cc
@@ -157,6 +157,8 @@ CairoOutputDev::CairoOutputDev() {
   // the SA parameter supposedly defaults to false, but Acrobat
   // apparently hardwires it to true
   stroke_adjust = globalParams->getStrokeAdjust();
+  align_stroke_coords = gFalse;
+  adjusted_stroke_width = gFalse;
 }
 
 CairoOutputDev::~CairoOutputDev() {
@@ -412,6 +414,7 @@ void CairoOutputDev::updateMiterLimit(GfxState *state) {
 
 void CairoOutputDev::updateLineWidth(GfxState *state) {
   LOG(printf ("line width: %f\n", state->getLineWidth()));
+  adjusted_stroke_width = gFalse;
   if (state->getLineWidth() == 0.0) {
     /* find out how big pixels (device unit) are in the x and y directions
      * choose the smaller of the two as our line width */
@@ -431,11 +434,12 @@ void CairoOutputDev::updateLineWidth(GfxState *state) {
 
       /* find out line width in device units */
       cairo_user_to_device_distance(cairo, &x, &y);
-      if (x < 0.5 && y < 0.5) {
+      if (x <= 1.0 && y <= 1.0) {
 	/* adjust width to at least one device pixel */
-	x = y = 0.5;
+	x = y = 1.0;
 	cairo_device_to_user_distance(cairo, &x, &y);
 	width = MIN(fabs(x),fabs(y));
+	adjusted_stroke_width = gTrue;
       }
     }
     cairo_set_line_width (cairo, width);
@@ -632,6 +636,15 @@ void CairoOutputDev::updateFont(GfxState *state) {
   cairo_set_font_matrix (cairo, &matrix);
 }
 
+void CairoOutputDev::alignStrokeCoords(double *x, double *y)
+{
+  /* see http://www.cairographics.org/FAQ/#sharp_lines */
+  cairo_user_to_device (cairo, x, y);
+  *x = floor(*x) + 0.5;
+  *y = floor(*y) + 0.5;
+  cairo_device_to_user (cairo, x, y);
+}
+
 void CairoOutputDev::doPath(cairo_t *cairo, GfxState *state, GfxPath *path) {
   GfxSubpath *subpath;
   int i, j;
@@ -639,8 +652,15 @@ void CairoOutputDev::doPath(cairo_t *cairo, GfxState *state, GfxPath *path) {
   for (i = 0; i < path->getNumSubpaths(); ++i) {
     subpath = path->getSubpath(i);
     if (subpath->getNumPoints() > 0) {
-      cairo_move_to (cairo, subpath->getX(0), subpath->getY(0));
-         j = 1;
+      if (align_stroke_coords) {
+	double x = subpath->getX(0);
+	double y = subpath->getY(0);
+	alignStrokeCoords(&x, &y);
+	cairo_move_to (cairo, x, y);
+      } else {
+	cairo_move_to (cairo, subpath->getX(0), subpath->getY(0));
+      }
+      j = 1;
       while (j < subpath->getNumPoints()) {
 	if (subpath->getCurve(j)) {
 	  cairo_curve_to( cairo,
@@ -650,7 +670,14 @@ void CairoOutputDev::doPath(cairo_t *cairo, GfxState *state, GfxPath *path) {
 
 	  j += 3;
 	} else {
-	  cairo_line_to (cairo, subpath->getX(j), subpath->getY(j));
+	  if (align_stroke_coords) {
+	    double x = subpath->getX(j);
+	    double y = subpath->getY(j);
+	    alignStrokeCoords(&x, &y);
+	    cairo_line_to (cairo, x, y);
+	  } else {
+	    cairo_line_to (cairo, subpath->getX(j), subpath->getY(j));
+	  }
 	  ++j;
 	}
       }
@@ -670,7 +697,10 @@ void CairoOutputDev::stroke(GfxState *state) {
 	  return;
   }
 
+  if (adjusted_stroke_width)
+    align_stroke_coords = gTrue;
   doPath (cairo, state, state->getPath());
+  align_stroke_coords = gFalse;
   cairo_set_source (cairo, stroke_pattern);
   LOG(printf ("stroke\n"));
   cairo_stroke (cairo);
diff --git a/poppler/CairoOutputDev.h b/poppler/CairoOutputDev.h
index 7cf4157..effa9dd 100644
--- a/poppler/CairoOutputDev.h
+++ b/poppler/CairoOutputDev.h
@@ -282,12 +282,15 @@ protected:
   GBool getStreamData (Stream *str, char **buffer, int *length);
   void setMimeData(Stream *str, Object *ref, cairo_surface_t *image);
   void fillToStrokePathClip();
+  void alignStrokeCoords(double *x, double *y);
 
   GfxRGB fill_color, stroke_color;
   cairo_pattern_t *fill_pattern, *stroke_pattern;
   double fill_opacity;
   double stroke_opacity;
   GBool stroke_adjust;
+  GBool adjusted_stroke_width;
+  GBool align_stroke_coords;
   CairoFont *currentFont;
 
   struct StrokePathClip {
commit cfc67afe80b963ba662018674cadf3085466bb9f
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Tue Aug 23 20:46:24 2011 +0930

    cairo: fix stroking of very thin lines
    
    Lines with a width less than 1.0 are almost invisible in cairo output
    due to antialising. The PDF standard states that when the Stroke
    Adjust graphics parameter is true, all lines must be at least one pixel wide.
    
    Add a stroke_adjust flag to the CairoOuputDev. Like splash, use the
    globalParam strokeAdjust setting (which defaults to true) to
    initialize the flag and ignore the Stroke Adjust settng in PDF
    files. This emulates Acrobat behavior.
    
    When stroke_adjust is true, find the line width in device pixels and
    if less than 0.5 set the line width to 0.5 device pixels. The value
    0.5 pixels seems to make horizontal and vertical lines look better
    because integer aligned 1.0 wide lines in cairo are rendered two
    pixels wide which looks too fat.

diff --git a/poppler/CairoOutputDev.cc b/poppler/CairoOutputDev.cc
index cec2039..5c29f94 100644
--- a/poppler/CairoOutputDev.cc
+++ b/poppler/CairoOutputDev.cc
@@ -153,6 +153,10 @@ CairoOutputDev::CairoOutputDev() {
 
   text = NULL;
   actualText = NULL;
+
+  // the SA parameter supposedly defaults to false, but Acrobat
+  // apparently hardwires it to true
+  stroke_adjust = globalParams->getStrokeAdjust();
 }
 
 CairoOutputDev::~CairoOutputDev() {
@@ -420,7 +424,21 @@ void CairoOutputDev::updateLineWidth(GfxState *state) {
     cairo_device_to_user_distance(cairo, &x, &y);
     cairo_set_line_width (cairo, MIN(fabs(x),fabs(y)));
   } else {
-    cairo_set_line_width (cairo, state->getLineWidth());
+    double width = state->getLineWidth();
+    if (stroke_adjust && !printing) {
+      double x, y;
+      x = y = width;
+
+      /* find out line width in device units */
+      cairo_user_to_device_distance(cairo, &x, &y);
+      if (x < 0.5 && y < 0.5) {
+	/* adjust width to at least one device pixel */
+	x = y = 0.5;
+	cairo_device_to_user_distance(cairo, &x, &y);
+	width = MIN(fabs(x),fabs(y));
+      }
+    }
+    cairo_set_line_width (cairo, width);
   }
   if (cairo_shape)
     cairo_set_line_width (cairo_shape, cairo_get_line_width (cairo));
diff --git a/poppler/CairoOutputDev.h b/poppler/CairoOutputDev.h
index ca64ad5..7cf4157 100644
--- a/poppler/CairoOutputDev.h
+++ b/poppler/CairoOutputDev.h
@@ -287,6 +287,7 @@ protected:
   cairo_pattern_t *fill_pattern, *stroke_pattern;
   double fill_opacity;
   double stroke_opacity;
+  GBool stroke_adjust;
   CairoFont *currentFont;
 
   struct StrokePathClip {


More information about the poppler mailing list