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.
This commit is contained in:
Adrian Johnson 2013-12-07 15:48:26 +10:30
parent 31eff5c6eb
commit dcbe16eb40
5 changed files with 84 additions and 61 deletions

View file

@ -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);

View file

@ -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)
{

View file

@ -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);

View file

@ -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);

View file

@ -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) {