mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-05-05 07:38:22 +02:00
pdf: metadata API
This commit is contained in:
parent
dfc7b9e669
commit
5bfadd5530
5 changed files with 265 additions and 31 deletions
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -238,9 +238,6 @@ _cairo_pdf_surface_write_page (cairo_pdf_surface_t *surface);
|
|||
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);
|
||||
|
||||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue