diff options
-rw-r--r-- | doc/public/cairo-sections.txt | 2 | ||||
-rw-r--r-- | src/cairo-pdf-interchange.c | 177 | ||||
-rw-r--r-- | src/cairo-pdf-surface-private.h | 17 | ||||
-rw-r--r-- | src/cairo-pdf-surface.c | 69 | ||||
-rw-r--r-- | src/cairo-pdf.h | 31 |
5 files changed, 265 insertions, 31 deletions
diff --git a/doc/public/cairo-sections.txt b/doc/public/cairo-sections.txt index 7446415ab..200c9b21d 100644 --- a/doc/public/cairo-sections.txt +++ b/doc/public/cairo-sections.txt @@ -70,6 +70,7 @@ cairo_image_surface_get_stride CAIRO_HAS_PDF_SURFACE CAIRO_PDF_OUTLINE_ROOT cairo_pdf_outline_flags_t +cairo_pdf_metadata_t cairo_pdf_surface_create cairo_pdf_surface_create_for_stream cairo_pdf_surface_restrict_to_version @@ -78,6 +79,7 @@ cairo_pdf_get_versions cairo_pdf_version_to_string cairo_pdf_surface_set_size cairo_pdf_surface_add_outline +cairo_pdf_surface_set_metadata </SECTION> <SECTION> diff --git a/src/cairo-pdf-interchange.c b/src/cairo-pdf-interchange.c index 38c5bac09..a84f0ccfa 100644 --- a/src/cairo-pdf-interchange.c +++ b/src/cairo-pdf-interchange.c @@ -699,6 +699,49 @@ cairo_pdf_interchange_write_names_dict (cairo_pdf_surface_t *surface) return CAIRO_STATUS_SUCCESS; } +static cairo_int_status_t +cairo_pdf_interchange_write_docinfo (cairo_pdf_surface_t *surface) +{ + cairo_pdf_interchange_t *ic = &surface->interchange; + + surface->docinfo_res = _cairo_pdf_surface_new_object (surface); + if (surface->docinfo_res.id == 0) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + _cairo_output_stream_printf (surface->output, + "%d 0 obj\n" + "<< /Producer (cairo %s (http://cairographics.org))\n", + surface->docinfo_res.id, + cairo_version_string ()); + + if (ic->docinfo.title) + _cairo_output_stream_printf (surface->output, " /Title %s\n", ic->docinfo.title); + + if (ic->docinfo.author) + _cairo_output_stream_printf (surface->output, " /Author %s\n", ic->docinfo.author); + + if (ic->docinfo.subject) + _cairo_output_stream_printf (surface->output, " /Subject %s\n", ic->docinfo.subject); + + if (ic->docinfo.keywords) + _cairo_output_stream_printf (surface->output, " /Keywords %s\n", ic->docinfo.keywords); + + if (ic->docinfo.creator) + _cairo_output_stream_printf (surface->output, " /Creator %s\n", ic->docinfo.creator); + + if (ic->docinfo.create_date) + _cairo_output_stream_printf (surface->output, " /CreationDate %s\n", ic->docinfo.create_date); + + if (ic->docinfo.mod_date) + _cairo_output_stream_printf (surface->output, " /ModDate %s\n", ic->docinfo.mod_date); + + _cairo_output_stream_printf (surface->output, + ">>\n" + "endobj\n"); + + return CAIRO_STATUS_SUCCESS; +} + static void init_named_dest_key (cairo_pdf_named_dest_t *dest) { @@ -1035,6 +1078,10 @@ _cairo_pdf_interchange_write_document_objects (cairo_pdf_surface_t *surface) return status; status = cairo_pdf_interchange_write_names_dict (surface); + if (unlikely (status)) + return status; + + status = cairo_pdf_interchange_write_docinfo (surface); return status; } @@ -1075,6 +1122,7 @@ _cairo_pdf_interchange_init (cairo_pdf_surface_t *surface) if (unlikely (outline_root == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); + memset (&ic->docinfo, 0, sizeof (ic->docinfo)); status = _cairo_array_append (&ic->outline, &outline_root); return status; @@ -1103,6 +1151,13 @@ _cairo_pdf_interchange_fini (cairo_pdf_surface_t *surface) free (outline); } _cairo_array_fini (&ic->outline); + free (ic->docinfo.title); + free (ic->docinfo.author); + free (ic->docinfo.subject); + free (ic->docinfo.keywords); + free (ic->docinfo.creator); + free (ic->docinfo.create_date); + free (ic->docinfo.mod_date); return CAIRO_STATUS_SUCCESS; } @@ -1171,3 +1226,125 @@ _cairo_pdf_interchange_add_outline (cairo_pdf_surface_t *surface, return CAIRO_STATUS_SUCCESS; } + +/* + * Date must be in the following format: + * + * YYYY-MM-DDThh:mm:ss[Z+-]hh:mm + * + * Only the year is required. If a field is included all preceding + * fields must be included. + */ +static char * +iso8601_to_pdf_date_string (const char *iso) +{ + char buf[40]; + const char *p; + int i; + + /* Check that utf8 contains only the characters "0123456789-T:Z+" */ + p = iso; + while (*p) { + if (!_cairo_isdigit (*p) && *p != '-' && *p != 'T' && + *p != ':' && *p != 'Z' && *p != '+') + return NULL; + p++; + } + + p = iso; + strcpy (buf, "("); + + /* YYYY (required) */ + if (strlen (p) < 4) + return NULL; + + strncat (buf, p, 4); + p += 4; + + /* -MM, -DD, Thh, :mm, :ss */ + for (i = 0; i < 5; i++) { + if (strlen (p) < 3) + goto finish; + + strncat (buf, p + 1, 2); + p += 3; + } + + /* Z, +, - */ + if (strlen (p) < 1) + goto finish; + strncat (buf, p, 1); + p += 1; + + /* hh */ + if (strlen (p) < 2) + goto finish; + + strncat (buf, p, 2); + strcat (buf, "'"); + p += 2; + + /* :mm */ + if (strlen (p) < 3) + goto finish; + + strncat (buf, p + 1, 3); + + finish: + strcat (buf, ")"); + return strdup (buf); +} + +cairo_int_status_t +_cairo_pdf_interchange_set_metadata (cairo_pdf_surface_t *surface, + cairo_pdf_metadata_t metadata, + const char *utf8) +{ + cairo_pdf_interchange_t *ic = &surface->interchange; + cairo_status_t status; + char *s = NULL; + + if (utf8) { + if (metadata == CAIRO_PDF_METADATA_CREATE_DATE || + metadata == CAIRO_PDF_METADATA_MOD_DATE) { + s = iso8601_to_pdf_date_string (utf8); + } else { + status = _cairo_utf8_to_pdf_string (utf8, &s); + if (unlikely (status)) + return status; + } + } + + switch (metadata) { + case CAIRO_PDF_METADATA_TITLE: + free (ic->docinfo.title); + ic->docinfo.title = s; + break; + case CAIRO_PDF_METADATA_AUTHOR: + free (ic->docinfo.author); + ic->docinfo.author = s; + break; + case CAIRO_PDF_METADATA_SUBJECT: + free (ic->docinfo.subject); + ic->docinfo.subject = s; + break; + case CAIRO_PDF_METADATA_KEYWORDS: + free (ic->docinfo.keywords); + ic->docinfo.keywords = s; + break; + case CAIRO_PDF_METADATA_CREATOR: + free (ic->docinfo.creator); + ic->docinfo.creator = s; + break; + case CAIRO_PDF_METADATA_CREATE_DATE: + free (ic->docinfo.create_date); + ic->docinfo.create_date = s; + break; + case CAIRO_PDF_METADATA_MOD_DATE: + free (ic->docinfo.mod_date); + ic->docinfo.mod_date = s; + break; + } + + return CAIRO_STATUS_SUCCESS; +} diff --git a/src/cairo-pdf-surface-private.h b/src/cairo-pdf-surface-private.h index 010b127de..a3d45d0ad 100644 --- a/src/cairo-pdf-surface-private.h +++ b/src/cairo-pdf-surface-private.h @@ -206,6 +206,16 @@ typedef struct _cairo_pdf_outline_entry { int count; } cairo_pdf_outline_entry_t; +struct docinfo { + char *title; + char *author; + char *subject; + char *keywords; + char *creator; + char *create_date; + char *mod_date; +}; + typedef struct _cairo_pdf_interchange { cairo_tag_stack_t analysis_tag_stack; cairo_tag_stack_t render_tag_stack; @@ -225,6 +235,7 @@ typedef struct _cairo_pdf_interchange { cairo_pdf_resource_t dests_res; int annot_page; cairo_array_t outline; /* array of pointers to cairo_pdf_outline_entry_t; */ + struct docinfo docinfo; } cairo_pdf_interchange_t; @@ -314,6 +325,7 @@ struct _cairo_pdf_surface { cairo_bool_t tagged; cairo_pdf_resource_t outlines_dict_res; cairo_pdf_resource_t names_dict_res; + cairo_pdf_resource_t docinfo_res; cairo_surface_t *paginated_surface; }; @@ -367,4 +379,9 @@ _cairo_pdf_interchange_add_outline (cairo_pdf_surface_t *surface, cairo_pdf_outline_flags_t flags, int *id); +cairo_private cairo_int_status_t +_cairo_pdf_interchange_set_metadata (cairo_pdf_surface_t *surface, + cairo_pdf_metadata_t metadata, + const char *utf8); + #endif /* CAIRO_PDF_SURFACE_PRIVATE_H */ diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c index 98c780b91..3a125e74f 100644 --- a/src/cairo-pdf-surface.c +++ b/src/cairo-pdf-surface.c @@ -239,9 +239,6 @@ static void _cairo_pdf_surface_write_pages (cairo_pdf_surface_t *surface); static cairo_pdf_resource_t -_cairo_pdf_surface_write_info (cairo_pdf_surface_t *surface); - -static cairo_pdf_resource_t _cairo_pdf_surface_write_catalog (cairo_pdf_surface_t *surface); static long @@ -773,6 +770,42 @@ cairo_pdf_surface_add_outline (cairo_surface_t *surface, return id; } +/** + * cairo_pdf_surface_set_metadata: + * @surface: a PDF #cairo_surface_t + * @metadata: The metadata item to set. + * @utf8: metadata value + * + * Set document metadata. The %CAIRO_PDF_METADATA_CREATE_DATE and + * %CAIRO_PDF_METADATA_MOD_DATE values must be in ISO-8601 format: + * YYYY-MM-DDThh:mm:ss. An optional timezone of the form "[+/-]hh:mm" + * or "Z" for UTC time can be appended. All other metadata values can be any UTF-8 + * string. + * + * For example: + * <informalexample><programlisting> + * cairo_pdf_surface_set_metadata (surface, CAIRO_PDF_METADATA_TITLE, "My Document"); + * cairo_pdf_surface_set_metadata (surface, CAIRO_PDF_METADATA_CREATE_DATE, "2015-12-31T23:59+02:00"); + * </programlisting></informalexample> + * + * Since: 1.16 + **/ +void +cairo_pdf_surface_set_metadata (cairo_surface_t *surface, + cairo_pdf_metadata_t metadata, + const char *utf8) +{ + cairo_pdf_surface_t *pdf_surface = NULL; /* hide compiler warning */ + cairo_status_t status; + + if (! _extract_pdf_surface (surface, &pdf_surface)) + return; + + status = _cairo_pdf_interchange_set_metadata (pdf_surface, metadata, utf8); + if (status) + status = _cairo_surface_set_error (surface, status); +} + static void _cairo_pdf_surface_clear (cairo_pdf_surface_t *surface) { @@ -2121,7 +2154,7 @@ _cairo_pdf_surface_finish (void *abstract_surface) { cairo_pdf_surface_t *surface = abstract_surface; long offset; - cairo_pdf_resource_t info, catalog; + cairo_pdf_resource_t catalog; cairo_status_t status, status2; int size, i; cairo_pdf_jbig2_global_t *global; @@ -2136,10 +2169,6 @@ _cairo_pdf_surface_finish (void *abstract_surface) if (unlikely (status)) return status; - info = _cairo_pdf_surface_write_info (surface); - if (info.id == 0 && status == CAIRO_STATUS_SUCCESS) - status = _cairo_error (CAIRO_STATUS_NO_MEMORY); - catalog = _cairo_pdf_surface_write_catalog (surface); if (catalog.id == 0 && status == CAIRO_STATUS_SUCCESS) status = _cairo_error (CAIRO_STATUS_NO_MEMORY); @@ -2154,7 +2183,7 @@ _cairo_pdf_surface_finish (void *abstract_surface) ">>\n", surface->next_available_resource.id, catalog.id, - info.id); + surface->docinfo_res.id); _cairo_output_stream_printf (surface->output, "startxref\n" @@ -4797,28 +4826,6 @@ _cairo_pdf_surface_get_font_options (void *abstract_surface, _cairo_font_options_set_round_glyph_positions (options, CAIRO_ROUND_GLYPH_POS_OFF); } -static cairo_pdf_resource_t -_cairo_pdf_surface_write_info (cairo_pdf_surface_t *surface) -{ - cairo_pdf_resource_t info; - - info = _cairo_pdf_surface_new_object (surface); - if (info.id == 0) - return info; - - _cairo_output_stream_printf (surface->output, - "%d 0 obj\n" - "<< /Creator (cairo %s (http://cairographics.org))\n" - " /Producer (cairo %s (http://cairographics.org))\n" - ">>\n" - "endobj\n", - info.id, - cairo_version_string (), - cairo_version_string ()); - - return info; -} - static void _cairo_pdf_surface_write_pages (cairo_pdf_surface_t *surface) { diff --git a/src/cairo-pdf.h b/src/cairo-pdf.h index e8ea80115..0589ba53a 100644 --- a/src/cairo-pdf.h +++ b/src/cairo-pdf.h @@ -113,6 +113,37 @@ cairo_pdf_surface_add_outline (cairo_surface_t *surface, const char *dest, cairo_pdf_outline_flags_t flags); +/** + * cairo_pdf_metadata_t: + * @CAIRO_PDF_METADATA_TITLE: The document title (Since 1.16) + * @CAIRO_PDF_METADATA_AUTHOR: The document author (Since 1.16) + * @CAIRO_PDF_METADATA_SUBJECT: The document subject (Since 1.16) + * @CAIRO_PDF_METADATA_KEYWORDS: The document keywords (Since 1.16) + * @CAIRO_PDF_METADATA_CREATOR: The document creator (Since 1.16) + * @CAIRO_PDF_METADATA_TITLE: The document title (Since 1.16) + * @CAIRO_PDF_METADATA_CREATE_DATE: The document creation date (Since 1.16) + * @CAIRO_PDF_METADATA_MOD_DATE: The document modification date (Since 1.16) + * + * #cairo_pdf_metadata_t is used by the + * cairo_pdf_surface_set_metadata() function specify the metadata to set. + * + * Since: 1.16 + **/ +typedef enum _cairo_pdf_metadata { + CAIRO_PDF_METADATA_TITLE, + CAIRO_PDF_METADATA_AUTHOR, + CAIRO_PDF_METADATA_SUBJECT, + CAIRO_PDF_METADATA_KEYWORDS, + CAIRO_PDF_METADATA_CREATOR, + CAIRO_PDF_METADATA_CREATE_DATE, + CAIRO_PDF_METADATA_MOD_DATE, +} cairo_pdf_metadata_t; + +void +cairo_pdf_surface_set_metadata (cairo_surface_t *surface, + cairo_pdf_metadata_t metadata, + const char *utf8); + CAIRO_END_DECLS #else /* CAIRO_HAS_PDF_SURFACE */ |