[cairo] Patch for cairo - high resolution images in PDF surface.

Andrew McRae amcrae at employees.org
Sat Nov 25 19:24:49 PST 2006


Comrades,
Attached is a patch generated against the git mainline - I wasn't
entirely sure if the right thing to do was to send it here or somewhere
else. At least I'll learn the right way to do it for next time! :-)

This patch allows higher resolution images to be embedded in
PDF surfaces - the idea is that you can set the fallback resolution
on the image, and the PDF surface can use this as a hint for the
DPI of the image. One part of the change is to have a flag to
remember when the fallback resolution is actually set (as opposed
to just having default values).

    surface = cairo_pdf_surface_create("test.pdf",
                        8 * 72.0, 10 * 72.0);
    img = cairo_image_surface_create_from_png("large.png");
    cr = cairo_create (surface);
    // Use 300 DPI for image.
    cairo_surface_set_fallback_resolution(img, 300.0, 300.0);
    // Use 1/2 inch margin.
    cairo_set_source_surface(cr, img, 36.0, 36.0);
    cairo_paint(cr);
    cairo_show_page(cr);

Feedback welcome...
Cheers,
Andrew McRae
-------------- next part --------------
Subject: [PATCH] Use fallback resolution as a hint for embedded images in PDF surfaces.

---

 src/cairo-image-surface.c    |    1 +
 src/cairo-pdf-surface.c      |   35 ++++++++++++++++++++++++++---------
 src/cairo-surface-fallback.c |    5 +++++
 src/cairo-surface.c          |   15 ++++++++++++---
 src/cairoint.h               |    1 +
 5 files changed, 45 insertions(+), 12 deletions(-)

840229bcfddd66e4e0912e374729360278c4fc1f
diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
index 0021ae9..84fe588 100644
--- a/src/cairo-image-surface.c
+++ b/src/cairo-image-surface.c
@@ -57,6 +57,7 @@ const cairo_image_surface_t _cairo_image
 	  0.0, 1.0,
 	  0.0, 0.0
 	},				/* device_transform_inverse */
+    	FALSE,                          /* fallback_set */
 	0.0,				/* x_fallback_resolution */
 	0.0,				/* y_fallback_resolution */
 	NULL,				/* clip */
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index 25d367e..0d3208a 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -850,6 +850,7 @@ emit_surface_pattern (cairo_pdf_surface_
     cairo_extend_t extend = cairo_pattern_get_extend (&pattern->base);
     int xstep, ystep;
     cairo_rectangle_int16_t surface_extents;
+    double xscale, yscale;
 
     /* XXX: Should do something clever here for PDF source surfaces ? */
 
@@ -889,6 +890,18 @@ emit_surface_pattern (cairo_pdf_surface_
 	xstep = 0;
 	ystep = 0;
     }
+    /*
+     * If the fallback resolution has been set on this image,
+     * then use that as the image resolution instead of using
+     * the surface's space.
+     */
+    if (image->base.fallback_set) {
+        xscale = image->width * 72.0 / image->base.x_fallback_resolution;
+        yscale = image->height * 72.0 / image->base.y_fallback_resolution;
+    } else {
+        xscale = image->width;
+        yscale = image->height;
+    }
 
     /* At this point, (that is, within the surface backend interface),
      * the pattern's matrix maps from cairo's device space to cairo's
@@ -899,7 +912,7 @@ emit_surface_pattern (cairo_pdf_surface_
      * 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
+     * on each page). So the PDF patterns matrix maps from a
      * (width,height) pattern space to a device space with the origin
      * in the lower-left corner.
      *
@@ -909,13 +922,14 @@ emit_surface_pattern (cairo_pdf_surface_
      * 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.
+     * we translate back down by the image height (scaled by the DPI
+     * resolution) 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.
+     * have to scale it up by the image width and height (in the
+     * desired fallback resolution) to fill our pattern cell.
      */
     cairo_p2d = pattern->base.matrix;
     cairo_matrix_invert (&cairo_p2d);
@@ -924,7 +938,7 @@ emit_surface_pattern (cairo_pdf_surface_
     cairo_matrix_translate (&pdf_p2d, 0.0, surface_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_translate (&pdf_p2d, 0.0, xscale);
     cairo_matrix_scale (&pdf_p2d, 1.0, -1.0);
 
     stream = _cairo_pdf_surface_open_stream (surface,
@@ -944,10 +958,13 @@ emit_surface_pattern (cairo_pdf_surface_
 					     image_resource.id,
 					     image_resource.id);
 
+    /*
+     * Output a transformation matrix that uses the fallback scaling
+     * so that the bitmapped image is mapped to the desired resolution
+     */
     _cairo_output_stream_printf (surface->output,
-				 "q %d 0 0 %d 0 0 cm /res%d Do Q\r\n",
-				 image->width, image->height,
-				 image_resource.id);
+				 "q %f 0 0 %f 0 0 cm /res%d Do Q\r\n",
+                                 xscale, yscale, image_resource.id);
 
     _cairo_pdf_surface_close_stream (surface);
 
diff --git a/src/cairo-surface-fallback.c b/src/cairo-surface-fallback.c
index 2d23411..1287b75 100644
--- a/src/cairo-surface-fallback.c
+++ b/src/cairo-surface-fallback.c
@@ -988,6 +988,11 @@ _cairo_surface_fallback_snapshot (cairo_
 
     snapshot->device_transform = surface->device_transform;
     snapshot->device_transform_inverse = surface->device_transform_inverse;
+    if (surface->fallback_set) {
+        cairo_surface_set_fallback_resolution (snapshot,
+                                               surface->x_fallback_resolution,
+                                               surface->y_fallback_resolution);
+    }
 
     snapshot->is_snapshot = TRUE;
 
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index dfcf39d..f90d535 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -61,6 +61,7 @@ const cairo_surface_t _cairo_surface_nil
       0.0, 1.0,
       0.0, 0.0
     },					/* device_transform_inverse */
+    FALSE,                              /* fallback_set */
     0.0,				/* x_fallback_resolution */
     0.0,				/* y_fallback_resolution */
     NULL,				/* clip */
@@ -95,6 +96,7 @@ const cairo_surface_t _cairo_surface_nil
       0.0, 1.0,
       0.0, 0.0
     },					/* device_transform_inverse */
+    FALSE,                              /* fallback_set */
     0.0,				/* x_fallback_resolution */
     0.0,				/* y_fallback_resolution */
     NULL,				/* clip */
@@ -129,6 +131,7 @@ const cairo_surface_t _cairo_surface_nil
       0.0, 1.0,
       0.0, 0.0
     },					/* device_transform_inverse */
+    FALSE,                              /* fallback_set */
     0.0,				/* x_fallback_resolution */
     0.0,				/* y_fallback_resolution */
     NULL,				/* clip */
@@ -255,6 +258,7 @@ _cairo_surface_init (cairo_surface_t			*
     cairo_matrix_init_identity (&surface->device_transform);
     cairo_matrix_init_identity (&surface->device_transform_inverse);
 
+    surface->fallback_set = FALSE;
     surface->x_fallback_resolution = CAIRO_SURFACE_FALLBACK_RESOLUTION_DEFAULT;
     surface->y_fallback_resolution = CAIRO_SURFACE_FALLBACK_RESOLUTION_DEFAULT;
 
@@ -290,9 +294,10 @@ _cairo_surface_create_similar_scratch (c
     cairo_surface_get_font_options (other, &options);
     _cairo_surface_set_font_options (surface, &options);
 
-    cairo_surface_set_fallback_resolution (surface,
-					   other->x_fallback_resolution,
-					   other->y_fallback_resolution);
+    if (other->fallback_set)
+        cairo_surface_set_fallback_resolution (surface,
+                                               other->x_fallback_resolution,
+                                               other->y_fallback_resolution);
 
     return surface;
 }
@@ -835,6 +840,9 @@ slim_hidden_def (cairo_surface_get_devic
  * resolution used for these image fallbacks, (larger values will
  * result in more detailed images, but also larger file sizes).
  *
+ * If the backend supports the operation, it can still use the
+ * fallback resolution as a hint for the operation.
+ *
  * Some examples of natively vector-oriented backends are the ps, pdf,
  * and svg backends.
  *
@@ -857,6 +865,7 @@ cairo_surface_set_fallback_resolution (c
 {
     surface->x_fallback_resolution = x_pixels_per_inch;
     surface->y_fallback_resolution = y_pixels_per_inch;
+    surface->fallback_set = TRUE;
 }
 slim_hidden_def (cairo_surface_set_fallback_resolution);
 
diff --git a/src/cairoint.h b/src/cairoint.h
index 1f74d62..f0c987f 100755
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -951,6 +951,7 @@ struct _cairo_surface {
     cairo_matrix_t device_transform;
     cairo_matrix_t device_transform_inverse;
 
+    cairo_bool_t fallback_set;
     double x_fallback_resolution;
     double y_fallback_resolution;
 
-- 
1.1.3


More information about the cairo mailing list