summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdrian Johnson <ajohnson@redneon.com>2016-10-01 22:41:36 +0930
committerAdrian Johnson <ajohnson@redneon.com>2016-10-01 22:41:36 +0930
commit5bfadd5530623d3b12fadf8cd22f95cec4132b65 (patch)
tree1049b3c839becb9abad35825fbfbf72682e307e1
parentdfc7b9e6698d5923a858ae9a77345c983ab51e4c (diff)
pdf: metadata API
-rw-r--r--doc/public/cairo-sections.txt2
-rw-r--r--src/cairo-pdf-interchange.c177
-rw-r--r--src/cairo-pdf-surface-private.h17
-rw-r--r--src/cairo-pdf-surface.c69
-rw-r--r--src/cairo-pdf.h31
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 */