diff options
author | Carl Worth <cworth@cworth.org> | 2006-04-24 16:11:21 -0700 |
---|---|---|
committer | Carl Worth <cworth@cworth.org> | 2006-04-24 16:11:21 -0700 |
commit | 32a7edc42dae507678e4eed98fcb41802b8ee69c (patch) | |
tree | 1b56c6f43304904dee65b11828c294900d9e3293 /src | |
parent | a1bba71eb9442a1c3a5f9fb227353971d58cecba (diff) |
PDF: Fix surface pattern transformation and support for EXTEND_NONE.
There's a bunch of careful matrix transformation here needed to
resolve the differences between cairo and PDF pattern matrices,
(primarily due to the different location for the origin).
This fixes the several PDF test suite failures that recently appeared
when we switched from ARGB32 to RGB24 source surface patterns.
Diffstat (limited to 'src')
-rw-r--r-- | src/cairo-pdf-surface.c | 85 |
1 files changed, 72 insertions, 13 deletions
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c index 046a4d13d..a2e7c9567 100644 --- a/src/cairo-pdf-surface.c +++ b/src/cairo-pdf-surface.c @@ -931,7 +931,10 @@ emit_surface_pattern (cairo_pdf_surface_t *dst, void *image_extra; cairo_status_t status = CAIRO_STATUS_SUCCESS; unsigned int id, alpha; - cairo_matrix_t i2u; + cairo_matrix_t cairo_p2d, pdf_p2d; + cairo_extend_t extend = cairo_pattern_get_extend (&pattern->base); + int xstep, ystep; + cairo_rectangle_t dst_extents; /* XXX: This is broken. We need new code here to actually emit the * PDF surface. */ @@ -948,29 +951,85 @@ emit_surface_pattern (cairo_pdf_surface_t *dst, if (status) goto BAIL; - /* BBox must be smaller than XStep by YStep or acroread wont - * display the pattern. */ + _cairo_surface_get_extents (&dst->base, &dst_extents); + + /* In PDF, (as far as I can tell), all patterns are repeating. So + * we support cairo's EXTEND_NONE semantics by setting the repeat + * step size to the larger of the image size and the extents of + * the destination surface. That way we guarantee the pattern will + * not repeat. + */ + switch (extend) { + case CAIRO_EXTEND_NONE: + xstep = MAX(image->width, dst_extents.width); + ystep = MAX(image->height, dst_extents.height); + break; + case CAIRO_EXTEND_REPEAT: + xstep = image->width; + ystep = image->height; + break; + default: + ASSERT_NOT_REACHED; /* all others should be analyzed away */ + xstep = 0; + ystep = 0; + } + + /* At this point, (that is, within the surface backend interface), + * the pattern's matrix maps from cairo's device space to cairo's + * pattern space, (both with their origin at the upper-left, and + * cairo's pattern space of size width,height). + * + * Then, we must emit a PDF pattern object that maps from its own + * pattern space, (which has a size that we establish in the BBox + * dictionary entry), to the PDF page's *initial* space, (which + * does not benefit from the Y-axis flipping matrix that we emit + * on each page). So the PDF patterns patrix maps from a + * (width,height) pattern space to a device space with the origin + * in the lower-left corner. + * + * So to handle all of that, we start with an identity matrix for + * the PDF pattern to device matrix. We translate it up by the + * image height then flip it in the Y direction, (moving us from + * the PDF origin to cairo's origin). We then multiply in the + * inverse of the cairo pattern matrix, (since it maps from device + * to pattern, while we're setting up pattern to device). Finally, + * we translate back down by the image height and flip again to + * end up at the lower-left origin that PDF expects. + * + * Additionally, within the stream that paints the pattern itself, + * we are using a PDF image object that has a size of (1,1) so we + * have to scale it up by the image width and height to fill our + * pattern cell. + */ + cairo_p2d = pattern->base.matrix; + cairo_matrix_invert (&cairo_p2d); + + cairo_matrix_init_identity (&pdf_p2d); + cairo_matrix_translate (&pdf_p2d, 0.0, dst_extents.height); + cairo_matrix_scale (&pdf_p2d, 1.0, -1.0); + cairo_matrix_multiply (&pdf_p2d, &cairo_p2d, &pdf_p2d); + cairo_matrix_translate (&pdf_p2d, 0.0, image->height); + cairo_matrix_scale (&pdf_p2d, 1.0, -1.0); + stream = _cairo_pdf_document_open_stream (document, - " /BBox [ 0 0 %d %d ]\r\n" + " /BBox [0 0 %d %d]\r\n" " /XStep %d\r\n" " /YStep %d\r\n" " /PatternType 1\r\n" " /TilingType 1\r\n" " /PaintType 1\r\n" + " /Matrix [ %f %f %f %f %f %f ]\r\n" " /Resources << /XObject << /res%d %d 0 R >> >>\r\n", image->width, image->height, - image->width, image->height, + xstep, ystep, + pdf_p2d.xx, pdf_p2d.yx, + pdf_p2d.xy, pdf_p2d.yy, + pdf_p2d.x0, pdf_p2d.y0, id, id); - i2u = pattern->base.matrix; - cairo_matrix_invert (&i2u); - cairo_matrix_scale (&i2u, image->width, image->height); - _cairo_output_stream_printf (output, - "q %f %f %f %f %f %f cm /res%d Do Q\r\n", - i2u.xx, i2u.yx, - i2u.xy, i2u.yy, - i2u.x0, i2u.y0, + "q %d 0 0 %d 0 0 cm /res%d Do Q\r\n", + image->width, image->height, id); _cairo_pdf_surface_add_pattern (dst, stream->id); |