[cairo-commit] src/cairo-output-stream.c src/cairo-output-stream-private.h src/cairo-pdf-operators.c src/cairo-pdf-surface.c src/cairo-ps-surface.c

Adrian Johnson ajohnson at kemper.freedesktop.org
Fri Dec 6 21:27:29 PST 2013


 src/cairo-output-stream-private.h |    5 ++++
 src/cairo-output-stream.c         |   39 +++++++++++++++++++++++++++++++++
 src/cairo-pdf-operators.c         |   17 ++++----------
 src/cairo-pdf-surface.c           |   44 ++++++++++++++++----------------------
 src/cairo-ps-surface.c            |   40 +++++++++++++---------------------
 5 files changed, 84 insertions(+), 61 deletions(-)

New commits:
commit dcbe16eb40b488f89f2398181f4c3f8a65f84b52
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Sat Dec 7 15:48:26 2013 +1030

    pdf/ps: avoid outputting excess decimal places in matrices
    
    Sometimes as a result of rounding errors in matrix transformations the
    matrices in ps/pdf output look like:
    
        0.000000000000000061 1 1 -0.000000000000000061 0 842 cm
    
    This patch rounds to zero matrix elements that are very small compared to
    other elements in the same matrix.

diff --git a/src/cairo-output-stream-private.h b/src/cairo-output-stream-private.h
index edaabbe..38a137f 100644
--- a/src/cairo-output-stream-private.h
+++ b/src/cairo-output-stream-private.h
@@ -135,6 +135,11 @@ _cairo_output_stream_printf (cairo_output_stream_t *stream,
 			     const char *fmt,
 			     ...) CAIRO_PRINTF_FORMAT (2, 3);
 
+/* Print matrix element values with rounding of insignificant digits. */
+void
+_cairo_output_stream_print_matrix (cairo_output_stream_t *stream,
+				   const cairo_matrix_t  *matrix);
+
 cairo_private long
 _cairo_output_stream_get_position (cairo_output_stream_t *stream);
 
diff --git a/src/cairo-output-stream.c b/src/cairo-output-stream.c
index cc7e300..6d6c180 100644
--- a/src/cairo-output-stream.c
+++ b/src/cairo-output-stream.c
@@ -530,6 +530,45 @@ _cairo_output_stream_printf (cairo_output_stream_t *stream,
     va_end (ap);
 }
 
+/* Matrix elements that are smaller than the value of the largest element * MATRIX_ROUNDING_TOLERANCE
+ * are rounded down to zero. */
+#define MATRIX_ROUNDING_TOLERANCE 1e-12
+
+void
+_cairo_output_stream_print_matrix (cairo_output_stream_t *stream,
+				   const cairo_matrix_t  *matrix)
+{
+    cairo_matrix_t m;
+    double s, e;
+
+    m = *matrix;
+    s = fabs (m.xx);
+    if (fabs (m.xy) > s)
+	s = fabs (m.xy);
+    if (fabs (m.yx) > s)
+	s = fabs (m.yx);
+    if (fabs (m.yy) > s)
+	s = fabs (m.yy);
+
+    e = s * MATRIX_ROUNDING_TOLERANCE;
+    if (fabs(m.xx) < e)
+	m.xx = 0;
+    if (fabs(m.xy) < e)
+	m.xy = 0;
+    if (fabs(m.yx) < e)
+	m.yx = 0;
+    if (fabs(m.yy) < e)
+	m.yy = 0;
+    if (fabs(m.x0) < e)
+	m.x0 = 0;
+    if (fabs(m.y0) < e)
+	m.y0 = 0;
+
+    _cairo_output_stream_printf (stream,
+				 "%f %f %f %f %f %f",
+				 m.xx, m.yx, m.xy, m.yy, m.x0, m.y0);
+}
+
 long
 _cairo_output_stream_get_position (cairo_output_stream_t *stream)
 {
diff --git a/src/cairo-pdf-operators.c b/src/cairo-pdf-operators.c
index fceaf1c..84d2441 100644
--- a/src/cairo-pdf-operators.c
+++ b/src/cairo-pdf-operators.c
@@ -828,10 +828,9 @@ _cairo_pdf_operators_emit_stroke (cairo_pdf_operators_t		*pdf_operators,
 	return status;
 
     if (has_ctm) {
-	_cairo_output_stream_printf (pdf_operators->stream,
-				     "q %f %f %f %f %f %f cm\n",
-				     m.xx, m.yx, m.xy, m.yy,
-				     m.x0, m.y0);
+	_cairo_output_stream_printf (pdf_operators->stream, "q ");
+	_cairo_output_stream_print_matrix (pdf_operators->stream, &m);
+	_cairo_output_stream_printf (pdf_operators->stream, " cm\n");
     } else {
 	path_transform = pdf_operators->cairo_to_pdf;
     }
@@ -1120,14 +1119,8 @@ _cairo_pdf_operators_set_text_matrix (cairo_pdf_operators_t  *pdf_operators,
     pdf_operators->cur_x = 0;
     pdf_operators->cur_y = 0;
     pdf_operators->glyph_buf_x_pos = 0;
-    _cairo_output_stream_printf (pdf_operators->stream,
-				 "%f %f %f %f %f %f Tm\n",
-				 pdf_operators->text_matrix.xx,
-				 pdf_operators->text_matrix.yx,
-				 pdf_operators->text_matrix.xy,
-				 pdf_operators->text_matrix.yy,
-				 pdf_operators->text_matrix.x0,
-				 pdf_operators->text_matrix.y0);
+    _cairo_output_stream_print_matrix (pdf_operators->stream, &pdf_operators->text_matrix);
+    _cairo_output_stream_printf (pdf_operators->stream, " Tm\n");
 
     pdf_operators->cairo_to_pdftext = *matrix;
     status = cairo_matrix_invert (&pdf_operators->cairo_to_pdftext);
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index a8a1217..c200c28 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -3843,11 +3843,11 @@ _cairo_pdf_surface_output_gradient (cairo_pdf_surface_t        *surface,
 	_cairo_output_stream_printf (surface->output,
 				     "<< /Type /Pattern\n"
 				     "   /PatternType 2\n"
-				     "   /Matrix [ %f %f %f %f %f %f ]\n"
-				     "   /Shading\n",
-				     pat_to_pdf->xx, pat_to_pdf->yx,
-				     pat_to_pdf->xy, pat_to_pdf->yy,
-				     pat_to_pdf->x0, pat_to_pdf->y0);
+				     "   /Matrix [ ");
+	_cairo_output_stream_print_matrix (surface->output, pat_to_pdf);
+	_cairo_output_stream_printf (surface->output,
+				     " ]\n"
+				     "   /Shading\n");
     }
 
     if (pdf_pattern->pattern->type == CAIRO_PATTERN_TYPE_LINEAR) {
@@ -4105,14 +4105,14 @@ _cairo_pdf_surface_emit_mesh_pattern (cairo_pdf_surface_t    *surface,
                                  "%d 0 obj\n"
                                  "<< /Type /Pattern\n"
                                  "   /PatternType 2\n"
-                                 "   /Matrix [ %f %f %f %f %f %f ]\n"
+                                 "   /Matrix [ ",
+				 pdf_pattern->pattern_res.id);
+    _cairo_output_stream_print_matrix (surface->output, &pat_to_pdf);
+    _cairo_output_stream_printf (surface->output,
+                                 " ]\n"
                                  "   /Shading %d 0 R\n"
 				 ">>\n"
 				 "endobj\n",
-				 pdf_pattern->pattern_res.id,
-                                 pat_to_pdf.xx, pat_to_pdf.yx,
-                                 pat_to_pdf.xy, pat_to_pdf.yy,
-                                 pat_to_pdf.x0, pat_to_pdf.y0,
 				 res.id);
 
     if (pdf_pattern->gstate_res.id != 0) {
@@ -4166,14 +4166,14 @@ _cairo_pdf_surface_emit_mesh_pattern (cairo_pdf_surface_t    *surface,
 				     "%d 0 obj\n"
 				     "<< /Type /Pattern\n"
 				     "   /PatternType 2\n"
-				     "   /Matrix [ %f %f %f %f %f %f ]\n"
+				     "   /Matrix [ ",
+				     mask_resource.id);
+	_cairo_output_stream_print_matrix (surface->output, &pat_to_pdf);
+	_cairo_output_stream_printf (surface->output,
+				     " ]\n"
 				     "   /Shading %d 0 R\n"
 				     ">>\n"
 				     "endobj\n",
-				     mask_resource.id,
-				     pat_to_pdf.xx, pat_to_pdf.yx,
-				     pat_to_pdf.xy, pat_to_pdf.yy,
-				     pat_to_pdf.x0, pat_to_pdf.y0,
 				     res.id);
 
 	status = cairo_pdf_surface_emit_transparency_group (surface,
@@ -4302,11 +4302,8 @@ _cairo_pdf_surface_paint_surface_pattern (cairo_pdf_surface_t          *surface,
 	return status;
 
     if (! _cairo_matrix_is_identity (&pdf_p2d)) {
-	_cairo_output_stream_printf (surface->output,
-				     "%f %f %f %f %f %f cm\n",
-				     pdf_p2d.xx, pdf_p2d.yx,
-				     pdf_p2d.xy, pdf_p2d.yy,
-				     pdf_p2d.x0, pdf_p2d.y0);
+	_cairo_output_stream_print_matrix (surface->output, &pdf_p2d);
+	_cairo_output_stream_printf (surface->output, " cm\n");
     }
 
     status = _cairo_pdf_surface_add_alpha (surface, 1.0, &alpha);
@@ -4357,11 +4354,8 @@ _cairo_pdf_surface_paint_gradient (cairo_pdf_surface_t         *surface,
 	return status;
 
     if (! _cairo_matrix_is_identity (&pat_to_pdf)) {
-	_cairo_output_stream_printf (surface->output,
-				     "%f %f %f %f %f %f cm\n",
-				     pat_to_pdf.xx, pat_to_pdf.yx,
-				     pat_to_pdf.xy, pat_to_pdf.yy,
-				     pat_to_pdf.x0, pat_to_pdf.y0);
+	_cairo_output_stream_print_matrix (surface->output, &pat_to_pdf);
+	_cairo_output_stream_printf (surface->output, " cm\n");
     }
 
     status = _cairo_pdf_surface_add_shading (surface, shading_res);
diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index dfab4f7..f4ae3a8 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -3251,11 +3251,9 @@ _cairo_ps_surface_paint_surface (cairo_ps_surface_t     *surface,
     cairo_matrix_scale (&ps_p2d, 1.0, -1.0);
 
     if (! _cairo_matrix_is_identity (&ps_p2d)) {
-	_cairo_output_stream_printf (surface->stream,
-				     "[ %f %f %f %f %f %f ] concat\n",
-				     ps_p2d.xx, ps_p2d.yx,
-				     ps_p2d.xy, ps_p2d.yy,
-				     ps_p2d.x0, ps_p2d.y0);
+	_cairo_output_stream_printf (surface->stream, "[ ");
+	_cairo_output_stream_print_matrix (surface->stream, &ps_p2d);
+	_cairo_output_stream_printf (surface->stream, " ] concat\n");
     }
 
     status = _cairo_ps_surface_emit_surface (surface,
@@ -3444,12 +3442,10 @@ _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t      *surface,
     cairo_matrix_translate (&ps_p2d, 0.0, pattern_height);
     cairo_matrix_scale (&ps_p2d, 1.0, -1.0);
 
+    _cairo_output_stream_printf (surface->stream, "[ ");
+    _cairo_output_stream_print_matrix (surface->stream, &ps_p2d);
     _cairo_output_stream_printf (surface->stream,
-				 "[ %f %f %f %f %f %f ]\n",
-				 ps_p2d.xx, ps_p2d.yx,
-				 ps_p2d.xy, ps_p2d.yy,
-				 ps_p2d.x0, ps_p2d.y0);
-    _cairo_output_stream_printf (surface->stream,
+				 " ]\n"
 				 "makepattern setpattern\n");
 
   release_source:
@@ -3823,11 +3819,10 @@ _cairo_ps_surface_emit_gradient (cairo_ps_surface_t       *surface,
     if (is_ps_pattern) {
 	_cairo_output_stream_printf (surface->stream,
 				     ">>\n"
-				     "[ %f %f %f %f %f %f ]\n"
-				     "makepattern setpattern\n",
-				     pat_to_ps.xx, pat_to_ps.yx,
-				     pat_to_ps.xy, pat_to_ps.yy,
-				     pat_to_ps.x0, pat_to_ps.y0);
+				     "[ ");
+    _cairo_output_stream_print_matrix (surface->stream, &pat_to_ps);
+    _cairo_output_stream_printf (surface->stream, " ]\n"
+				 "makepattern setpattern\n");
     } else {
 	_cairo_output_stream_printf (surface->stream,
 				     "shfill\n");
@@ -3905,11 +3900,10 @@ _cairo_ps_surface_emit_mesh_pattern (cairo_ps_surface_t     *surface,
     if (is_ps_pattern) {
 	_cairo_output_stream_printf (surface->stream,
 				     ">>\n"
-				     "[ %f %f %f %f %f %f ]\n",
-				     pat_to_ps.xx, pat_to_ps.yx,
-				     pat_to_ps.xy, pat_to_ps.yy,
-				     pat_to_ps.x0, pat_to_ps.y0);
+				     "[ \n");
+	_cairo_output_stream_print_matrix (surface->stream, &pat_to_ps);
 	_cairo_output_stream_printf (surface->stream,
+				     " ]\n"
 				     "makepattern\n"
 				     "setpattern\n");
     } else {
@@ -4008,11 +4002,9 @@ _cairo_ps_surface_paint_gradient (cairo_ps_surface_t          *surface,
     cairo_matrix_multiply (&pat_to_ps, &pat_to_ps, &surface->cairo_to_ps);
 
     if (! _cairo_matrix_is_identity (&pat_to_ps)) {
-	_cairo_output_stream_printf (surface->stream,
-				     "[%f %f %f %f %f %f] concat\n",
-				     pat_to_ps.xx, pat_to_ps.yx,
-				     pat_to_ps.xy, pat_to_ps.yy,
-				     pat_to_ps.x0, pat_to_ps.y0);
+	_cairo_output_stream_printf (surface->stream, "[");
+	_cairo_output_stream_print_matrix (surface->stream, &pat_to_ps);
+	_cairo_output_stream_printf (surface->stream, "] concat\n");
     }
 
     if (source->type == CAIRO_PATTERN_TYPE_MESH) {


More information about the cairo-commit mailing list