diff options
author | Adrian Johnson <ajohnson@redneon.com> | 2016-10-01 22:44:22 +0930 |
---|---|---|
committer | Adrian Johnson <ajohnson@redneon.com> | 2016-10-01 22:44:22 +0930 |
commit | 26b3f83ff652a284b79557ec1555b398c566a7eb (patch) | |
tree | 8a5aff3112e7853293a401f0f3ea023230b3e6c3 | |
parent | 5bfadd5530623d3b12fadf8cd22f95cec4132b65 (diff) |
pdf: page label API
-rw-r--r-- | doc/public/cairo-sections.txt | 1 | ||||
-rw-r--r-- | src/cairo-pdf-interchange.c | 115 | ||||
-rw-r--r-- | src/cairo-pdf-surface-private.h | 3 | ||||
-rw-r--r-- | src/cairo-pdf-surface.c | 43 | ||||
-rw-r--r-- | src/cairo-pdf.h | 4 |
5 files changed, 166 insertions, 0 deletions
diff --git a/doc/public/cairo-sections.txt b/doc/public/cairo-sections.txt index 200c9b21d..51bf48c72 100644 --- a/doc/public/cairo-sections.txt +++ b/doc/public/cairo-sections.txt @@ -80,6 +80,7 @@ cairo_pdf_version_to_string cairo_pdf_surface_set_size cairo_pdf_surface_add_outline cairo_pdf_surface_set_metadata +cairo_pdf_surface_set_page_label </SECTION> <SECTION> diff --git a/src/cairo-pdf-interchange.c b/src/cairo-pdf-interchange.c index a84f0ccfa..622f3b3f3 100644 --- a/src/cairo-pdf-interchange.c +++ b/src/cairo-pdf-interchange.c @@ -599,6 +599,117 @@ cairo_pdf_interchange_write_outline (cairo_pdf_surface_t *surface) return status; } +/* + * Split a page label into a text prefix and numeric suffix. Leading '0's are + * included in the prefix. eg + * "3" => NULL, 3 + * "cover" => "cover", 0 + * "A-2" => "A-", 2 + * "A-002" => "A-00", 2 + */ +static char * +split_label (const char* label, int *num) +{ + int len, i; + + *num = 0; + len = strlen (label); + if (len == 0) + return NULL; + + i = len; + while (i > 0 && _cairo_isdigit (label[i-1])) + i--; + + while (i < len && label[i] == '0') + i++; + + if (i < len) + sscanf (label + i, "%d", num); + + if (i > 0) + return strndup (label, i); + + return NULL; +} + +/* strcmp that handles NULL arguments */ +static cairo_bool_t +strcmp_null (const char *s1, const char *s2) +{ + if (s1 && s2) + return strcmp (s1, s2) == 0; + + if (!s1 && !s2) + return TRUE; + + return FALSE; +} + +static cairo_int_status_t +cairo_pdf_interchange_write_page_labels (cairo_pdf_surface_t *surface) +{ + int num_elems, i; + char *label; + char *prefix; + char *prev_prefix; + int num, prev_num; + cairo_int_status_t status; + + num_elems = _cairo_array_num_elements (&surface->page_labels); + if (num_elems > 0) { + surface->page_labels_res = _cairo_pdf_surface_new_object (surface); + _cairo_output_stream_printf (surface->output, + "%d 0 obj\n" + "<< /Nums [\n", + surface->page_labels_res.id); + prefix = NULL; + prev_prefix = NULL; + num = 0; + prev_num = 0; + for (i = 0; i < num_elems; i++) { + _cairo_array_copy_element (&surface->page_labels, i, &label); + if (label) { + prefix = split_label (label, &num); + } else { + prefix = NULL; + num = i + 1; + } + + if (!strcmp_null (prefix, prev_prefix) || num != prev_num + 1) { + _cairo_output_stream_printf (surface->output, " %d << ", i); + + if (num) + _cairo_output_stream_printf (surface->output, "/S /D /St %d ", num); + + if (prefix) { + char *s; + status = _cairo_utf8_to_pdf_string (prefix, &s); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->output, "/P %s ", s); + free (s); + } + + _cairo_output_stream_printf (surface->output, ">>\n"); + } + free (prev_prefix); + prev_prefix = prefix; + prefix = NULL; + prev_num = num; + } + free (prefix); + free (prev_prefix); + _cairo_output_stream_printf (surface->output, + " ]\n" + ">>\n" + "endobj\n"); + } + + return CAIRO_STATUS_SUCCESS; +} + static void _collect_dest (void *entry, void *closure) { @@ -1077,6 +1188,10 @@ _cairo_pdf_interchange_write_document_objects (cairo_pdf_surface_t *surface) if (unlikely (status)) return status; + status = cairo_pdf_interchange_write_page_labels (surface); + if (unlikely (status)) + return status; + status = cairo_pdf_interchange_write_names_dict (surface); if (unlikely (status)) return status; diff --git a/src/cairo-pdf-surface-private.h b/src/cairo-pdf-surface-private.h index a3d45d0ad..960e07cd9 100644 --- a/src/cairo-pdf-surface-private.h +++ b/src/cairo-pdf-surface-private.h @@ -323,9 +323,12 @@ struct _cairo_pdf_surface { int page_parent_tree; /* -1 if not used */ cairo_array_t page_annots; cairo_bool_t tagged; + char *current_page_label; + cairo_array_t page_labels; cairo_pdf_resource_t outlines_dict_res; cairo_pdf_resource_t names_dict_res; cairo_pdf_resource_t docinfo_res; + cairo_pdf_resource_t page_labels_res; cairo_surface_t *paginated_surface; }; diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c index 3a125e74f..900055431 100644 --- a/src/cairo-pdf-surface.c +++ b/src/cairo-pdf-surface.c @@ -447,8 +447,12 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output, surface->page_parent_tree = -1; _cairo_array_init (&surface->page_annots, sizeof (cairo_pdf_resource_t)); surface->tagged = FALSE; + surface->current_page_label = NULL; + _cairo_array_init (&surface->page_labels, sizeof (char *)); surface->outlines_dict_res.id = 0; surface->names_dict_res.id = 0; + surface->docinfo_res.id = 0; + surface->page_labels_res.id = 0; surface->paginated_surface = _cairo_paginated_surface_create ( &surface->base, @@ -806,6 +810,28 @@ cairo_pdf_surface_set_metadata (cairo_surface_t *surface, status = _cairo_surface_set_error (surface, status); } +/** + * cairo_pdf_surface_set_page_label: + * @surface: a PDF #cairo_surface_t + * @utf8: The page label. + * + * Set page label for the current page. + * + * Since: 1.16 + **/ +void +cairo_pdf_surface_set_page_label (cairo_surface_t *surface, + const char *utf8) +{ + cairo_pdf_surface_t *pdf_surface = NULL; /* hide compiler warning */ + + if (! _extract_pdf_surface (surface, &pdf_surface)) + return; + + free (pdf_surface->current_page_label); + pdf_surface->current_page_label = utf8 ? strdup (utf8) : NULL; +} + static void _cairo_pdf_surface_clear (cairo_pdf_surface_t *surface) { @@ -2158,6 +2184,7 @@ _cairo_pdf_surface_finish (void *abstract_surface) cairo_status_t status, status2; int size, i; cairo_pdf_jbig2_global_t *global; + char *label; status = surface->base.status; if (status == CAIRO_STATUS_SUCCESS) @@ -2255,6 +2282,13 @@ _cairo_pdf_surface_finish (void *abstract_surface) } _cairo_array_fini (&surface->jbig2_global); + size = _cairo_array_num_elements (&surface->page_labels); + for (i = 0; i < size; i++) { + _cairo_array_copy_element (&surface->page_labels, i, &label); + free (label); + } + _cairo_array_fini (&surface->page_labels); + _cairo_array_truncate (&surface->page_surfaces, 0); _cairo_surface_clipper_reset (&surface->clipper); @@ -4783,6 +4817,9 @@ _cairo_pdf_surface_show_page (void *abstract_surface) cairo_pdf_surface_t *surface = abstract_surface; cairo_int_status_t status; + status = _cairo_array_append (&surface->page_labels, &surface->current_page_label); + surface->current_page_label = NULL; + status = _cairo_pdf_interchange_end_page_content (surface); if (unlikely (status)) return status; @@ -6173,6 +6210,12 @@ _cairo_pdf_surface_write_catalog (cairo_pdf_surface_t *surface) surface->outlines_dict_res.id); } + if (surface->page_labels_res.id != 0) { + _cairo_output_stream_printf (surface->output, + " /PageLabels %d 0 R\n", + surface->page_labels_res.id); + } + if (surface->names_dict_res.id != 0) { _cairo_output_stream_printf (surface->output, " /Names %d 0 R\n", diff --git a/src/cairo-pdf.h b/src/cairo-pdf.h index 0589ba53a..9bf69fedd 100644 --- a/src/cairo-pdf.h +++ b/src/cairo-pdf.h @@ -144,6 +144,10 @@ cairo_pdf_surface_set_metadata (cairo_surface_t *surface, cairo_pdf_metadata_t metadata, const char *utf8); +void +cairo_pdf_surface_set_page_label (cairo_surface_t *surface, + const char *utf8); + CAIRO_END_DECLS #else /* CAIRO_HAS_PDF_SURFACE */ |