summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdrian Johnson <ajohnson@redneon.com>2016-10-01 22:46:49 +0930
committerAdrian Johnson <ajohnson@redneon.com>2016-10-01 22:46:49 +0930
commit2d6a0f5d16d61c8f4236760c71061a0c4c3a199c (patch)
tree4b98a5cde00839c8b8c2b3f5578a21566270630e
parent26b3f83ff652a284b79557ec1555b398c566a7eb (diff)
pdf: thumbnail API
-rw-r--r--doc/public/cairo-sections.txt1
-rw-r--r--src/cairo-paginated-private.h18
-rw-r--r--src/cairo-paginated-surface.c64
-rw-r--r--src/cairo-pdf-surface-private.h4
-rw-r--r--src/cairo-pdf-surface.c79
-rw-r--r--src/cairo-pdf.h5
6 files changed, 169 insertions, 2 deletions
diff --git a/doc/public/cairo-sections.txt b/doc/public/cairo-sections.txt
index 51bf48c72..7b04ae7b3 100644
--- a/doc/public/cairo-sections.txt
+++ b/doc/public/cairo-sections.txt
@@ -81,6 +81,7 @@ cairo_pdf_surface_set_size
cairo_pdf_surface_add_outline
cairo_pdf_surface_set_metadata
cairo_pdf_surface_set_page_label
+cairo_pdf_surface_set_thumbnail_size
</SECTION>
<SECTION>
diff --git a/src/cairo-paginated-private.h b/src/cairo-paginated-private.h
index 29eefc76a..b85a5db6b 100644
--- a/src/cairo-paginated-private.h
+++ b/src/cairo-paginated-private.h
@@ -77,7 +77,23 @@ struct _cairo_paginated_surface_backend {
cairo_bool_t fallbacks_required);
cairo_bool_t
- (*supports_fine_grained_fallbacks) (void *surface);
+ (*supports_fine_grained_fallbacks) (void *surface);
+
+ /* Optional. Indicates whether the page requires a thumbnail image to be
+ * supplied. If a thumbnail is required, set width, heigh to size required
+ * and return TRUE.
+ */
+ cairo_bool_t
+ (*requires_thumbnail_image) (void *surface,
+ int *width,
+ int *height);
+
+ /* If thumbbail image requested, this function will be called before
+ * _show_page().
+ */
+ cairo_warn cairo_int_status_t
+ (*set_thumbnail_image) (void *surface,
+ cairo_image_surface_t *image);
};
/* A #cairo_paginated_surface_t provides a very convenient wrapper that
diff --git a/src/cairo-paginated-surface.c b/src/cairo-paginated-surface.c
index 749f0de73..e9454d416 100644
--- a/src/cairo-paginated-surface.c
+++ b/src/cairo-paginated-surface.c
@@ -291,6 +291,63 @@ _cairo_paginated_surface_release_source_image (void *abstract_surface,
}
static cairo_int_status_t
+_paint_thumbnail_image (cairo_paginated_surface_t *surface,
+ int width,
+ int height)
+{
+ cairo_surface_pattern_t pattern;
+ cairo_rectangle_int_t extents;
+ double x_scale;
+ double y_scale;
+ cairo_surface_t *image = NULL;
+ cairo_surface_t *opaque = NULL;
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
+
+ _cairo_surface_get_extents (surface->target, &extents);
+ x_scale = (double)width / extents.width;
+ y_scale = (double)height / extents.height;
+
+ image = _cairo_paginated_surface_create_image_surface (surface, width, height);
+ cairo_surface_set_device_scale (image, x_scale, y_scale);
+ cairo_surface_set_device_offset (image, -extents.x*x_scale, -extents.y*y_scale);
+ status = _cairo_recording_surface_replay (surface->recording_surface, image);
+ if (unlikely (status))
+ goto cleanup;
+
+ /* flatten transparency */
+
+ opaque = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height);
+ if (unlikely (opaque->status)) {
+ status = opaque->status;
+ goto cleanup;
+ }
+
+ status = _cairo_surface_paint (opaque,
+ CAIRO_OPERATOR_SOURCE,
+ &_cairo_pattern_white.base,
+ NULL);
+ if (unlikely (status))
+ goto cleanup;
+
+ _cairo_pattern_init_for_surface (&pattern, image);
+ pattern.base.filter = CAIRO_FILTER_NEAREST;
+ status = _cairo_surface_paint (opaque, CAIRO_OPERATOR_OVER, &pattern.base, NULL);
+ _cairo_pattern_fini (&pattern.base);
+ if (unlikely (status))
+ goto cleanup;
+
+ status = surface->backend->set_thumbnail_image (surface->target, (cairo_image_surface_t *)opaque);
+
+ cleanup:
+ if (image)
+ cairo_surface_destroy (image);
+ if (opaque)
+ cairo_surface_destroy (opaque);
+
+ return status;
+}
+
+static cairo_int_status_t
_paint_fallback_image (cairo_paginated_surface_t *surface,
cairo_rectangle_int_t *rect)
{
@@ -460,6 +517,13 @@ _paint_page (cairo_paginated_surface_t *surface)
}
}
+ if (surface->backend->requires_thumbnail_image) {
+ int width, height;
+
+ if (surface->backend->requires_thumbnail_image (surface->target, &width, &height))
+ _paint_thumbnail_image (surface, width, height);
+ }
+
FAIL:
cairo_surface_destroy (analysis);
diff --git a/src/cairo-pdf-surface-private.h b/src/cairo-pdf-surface-private.h
index 960e07cd9..c1fd11a91 100644
--- a/src/cairo-pdf-surface-private.h
+++ b/src/cairo-pdf-surface-private.h
@@ -330,6 +330,10 @@ struct _cairo_pdf_surface {
cairo_pdf_resource_t docinfo_res;
cairo_pdf_resource_t page_labels_res;
+ int thumbnail_width;
+ int thumbnail_height;
+ cairo_image_surface_t *thumbnail_image;
+
cairo_surface_t *paginated_surface;
};
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index 900055431..e60d0b9a6 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -453,6 +453,9 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output,
surface->names_dict_res.id = 0;
surface->docinfo_res.id = 0;
surface->page_labels_res.id = 0;
+ surface->thumbnail_width = 0;
+ surface->thumbnail_height = 0;
+ surface->thumbnail_image = NULL;
surface->paginated_surface = _cairo_paginated_surface_create (
&surface->base,
@@ -832,6 +835,32 @@ cairo_pdf_surface_set_page_label (cairo_surface_t *surface,
pdf_surface->current_page_label = utf8 ? strdup (utf8) : NULL;
}
+/**
+ * cairo_pdf_surface_set_thumbnail_size:
+ * @surface: a PDF #cairo_surface_t
+ * @width: Thumbnail width.
+ * @height: Thumbnail height
+ *
+ * Set the thumbnail image size for the current and all subsequent
+ * pages. Setting a width or height of 0 disables thumbnails for the
+ * current and subsequent pages.
+ *
+ * Since: 1.16
+ **/
+void
+cairo_pdf_surface_set_thumbnail_size (cairo_surface_t *surface,
+ int width,
+ int height)
+{
+ cairo_pdf_surface_t *pdf_surface = NULL; /* hide compiler warning */
+
+ if (! _extract_pdf_surface (surface, &pdf_surface))
+ return;
+
+ pdf_surface->thumbnail_width = width;
+ pdf_surface->thumbnail_height = height;
+}
+
static void
_cairo_pdf_surface_clear (cairo_pdf_surface_t *surface)
{
@@ -862,6 +891,9 @@ _cairo_pdf_surface_clear (cairo_pdf_surface_t *surface)
_cairo_array_truncate (&surface->smask_groups, 0);
_cairo_array_truncate (&surface->knockout_group, 0);
_cairo_array_truncate (&surface->page_annots, 0);
+
+ cairo_surface_destroy (&surface->thumbnail_image->base);
+ surface->thumbnail_image = NULL;
}
static void
@@ -2365,6 +2397,33 @@ _cairo_pdf_surface_supports_fine_grained_fallbacks (void *abstract_surface)
return TRUE;
}
+static cairo_bool_t
+_cairo_pdf_surface_requires_thumbnail_image (void *abstract_surface,
+ int *width,
+ int *height)
+{
+ cairo_pdf_surface_t *surface = abstract_surface;
+
+ if (surface->thumbnail_width > 0 && surface->thumbnail_height > 0) {
+ *width = surface->thumbnail_width;
+ *height = surface->thumbnail_height;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static cairo_int_status_t
+_cairo_pdf_surface_set_thumbnail_image (void *abstract_surface,
+ cairo_image_surface_t *image)
+{
+ cairo_pdf_surface_t *surface = abstract_surface;
+
+ surface->thumbnail_image = (cairo_image_surface_t *)cairo_surface_reference(&image->base);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
static cairo_int_status_t
_cairo_pdf_surface_add_padded_image_surface (cairo_pdf_surface_t *surface,
const cairo_pattern_t *source,
@@ -6590,7 +6649,7 @@ _cairo_pdf_surface_write_patterns_and_smask_groups (cairo_pdf_surface_t *surface
static cairo_int_status_t
_cairo_pdf_surface_write_page (cairo_pdf_surface_t *surface)
{
- cairo_pdf_resource_t knockout, res;
+ cairo_pdf_resource_t knockout, res, thumbnail_res;
cairo_pdf_resource_t *page;
cairo_int_status_t status;
unsigned int i, len, page_num, num_annots;
@@ -6651,6 +6710,16 @@ _cairo_pdf_surface_write_page (cairo_pdf_surface_t *surface)
return status;
}
+ thumbnail_res.id = 0;
+ if (surface->thumbnail_image) {
+ cairo_pdf_source_surface_entry_t entry;
+
+ memset (&entry, 0, sizeof (entry));
+ thumbnail_res = _cairo_pdf_surface_new_object (surface);
+ entry.surface_res = thumbnail_res;
+ _cairo_pdf_surface_emit_image (surface, surface->thumbnail_image, &entry);
+ }
+
page_num = _cairo_array_num_elements (&surface->pages);
page = _cairo_array_index (&surface->pages, page_num - 1);
_cairo_pdf_surface_update_object (surface, *page);
@@ -6693,6 +6762,12 @@ _cairo_pdf_surface_write_page (cairo_pdf_surface_t *surface)
_cairo_output_stream_printf (surface->output, "]\n");
}
+ if (thumbnail_res.id) {
+ _cairo_output_stream_printf (surface->output,
+ " /Thumb %d 0 R\n",
+ thumbnail_res.id);
+ }
+
_cairo_output_stream_printf (surface->output,
">>\n"
"endobj\n");
@@ -8209,4 +8284,6 @@ cairo_pdf_surface_paginated_backend = {
NULL, /* set_bounding_box */
_cairo_pdf_surface_has_fallback_images,
_cairo_pdf_surface_supports_fine_grained_fallbacks,
+ _cairo_pdf_surface_requires_thumbnail_image,
+ _cairo_pdf_surface_set_thumbnail_image,
};
diff --git a/src/cairo-pdf.h b/src/cairo-pdf.h
index 9bf69fedd..62bf41fca 100644
--- a/src/cairo-pdf.h
+++ b/src/cairo-pdf.h
@@ -148,6 +148,11 @@ void
cairo_pdf_surface_set_page_label (cairo_surface_t *surface,
const char *utf8);
+void
+cairo_pdf_surface_set_thumbnail_size (cairo_surface_t *surface,
+ int width,
+ int height);
+
CAIRO_END_DECLS
#else /* CAIRO_HAS_PDF_SURFACE */