/* * Page Structure of the Generated PDF: * * Each page requiring fallbacks images contains a knockout group at * the top level. The first operation of the knockout group paints a * group containing all the supported drawing operations. Fallback * images (if any) are painted in the knockout group. This ensures * that fallback images do not composite with any content under the * fallback images. * * Streams: * * This PDF surface has three types of streams: * - PDF Stream * - Content Stream * - Group Stream * - Object stream * * Calling _cairo_output_stream_printf (surface->output, ...) will * write to the currently open stream. * * PDF Stream: * A PDF Stream may be opened and closed with the following functions: * _cairo_pdf_surface_open stream () * _cairo_pdf_surface_close_stream () * * PDF Streams are written directly to the PDF file. They are used for * fonts, images and patterns. * * Content Stream: * The Content Stream is opened and closed with the following functions: * _cairo_pdf_surface_open_content_stream () * _cairo_pdf_surface_close_content_stream () * * The Content Stream contains the text and graphics operators. * * Group Stream: * A Group Stream may be opened and closed with the following functions: * _cairo_pdf_surface_open_group () * _cairo_pdf_surface_close_group () * * A Group Stream is a Form XObject. It is used for short sequences * of operators. As the content is very short the group is stored in * memory until it is closed. This allows some optimization such as * including the Resource dictionary and stream length inside the * XObject instead of using an indirect object. * * Object Stream (PDF 1.5) * An Object Stream may be opened and closed with the following functions: * _cairo_pdf_surface_open_object_stream () * _cairo_pdf_surface_close_object_stream () * * An Object Stream contains one or more objects compressed into a stream. * Only non stream objects are permitted. When emitting objects intended for * the Object Stream, enclose the emit object operation with * _cairo_pdf_surface_object_begin()/_cairo_pdf_surface_object_end().
*/
/** * SECTION:cairo-pdf * @Title: PDF Surfaces * @Short_Description: Rendering PDF documents * @See_Also: #cairo_surface_t * * The PDF surface is used to render cairo graphics to Adobe * PDF files and is a multi-page vector surface backend. * * The following mime types are supported on source patterns: * %CAIRO_MIME_TYPE_JPEG, %CAIRO_MIME_TYPE_JP2, * %CAIRO_MIME_TYPE_UNIQUE_ID, %CAIRO_MIME_TYPE_JBIG2, * %CAIRO_MIME_TYPE_JBIG2_GLOBAL, %CAIRO_MIME_TYPE_JBIG2_GLOBAL_ID, * %CAIRO_MIME_TYPE_CCITT_FAX, %CAIRO_MIME_TYPE_CCITT_FAX_PARAMS. * * # JBIG2 Images # * JBIG2 data in PDF must be in the embedded format as described in * ISO/IEC 11544. Image specific JBIG2 data must be in * %CAIRO_MIME_TYPE_JBIG2. Any global segments in the JBIG2 data * (segments with page association field set to 0) must be in * %CAIRO_MIME_TYPE_JBIG2_GLOBAL. The global data may be shared by * multiple images. All images sharing the same global data must set * %CAIRO_MIME_TYPE_JBIG2_GLOBAL_ID to a unique identifier. At least * one of the images must provide the global data using * %CAIRO_MIME_TYPE_JBIG2_GLOBAL. The global data will only be * embedded once and shared by all JBIG2 images with the same * %CAIRO_MIME_TYPE_JBIG2_GLOBAL_ID. * * # CCITT Fax Images # {#ccitt} * The %CAIRO_MIME_TYPE_CCITT_FAX mime data requires a number of decoding * parameters These parameters are specified using %CAIRO_MIME_TYPE_CCITT_FAX_PARAMS. * * %CAIRO_MIME_TYPE_CCITT_FAX_PARAMS mime data must contain a string of the form * "param1=value1 param2=value2 ...". * * @Columns: [required] An integer specifying the width of the image in pixels. * * @Rows: [required] An integer specifying the height of the image in scan lines. * * @K: [optional] An integer identifying the encoding scheme used. < 0 * is 2 dimensional Group 4, = 0 is Group3 1 dimensional, > 0 is mixed 1 * and 2 dimensional encoding. Default is 0. * * @EndOfLine: [optional] If true end-of-line bit patterns are present. Default is false. * * @EncodedByteAlign: [optional] If true the end of line is padded * with 0 bits so the next line begins on a byte boundary. Default is false. * * @EndOfBlock: [optional] If true the data contains an end-of-block pattern. Default is true. * * @BlackIs1: [optional] If true 1 bits are black pixels. Default is false. * * @DamagedRowsBeforeError: [optional] An integer specifying the * number of damages rows tolerated before an error occurs. Default is 0. * * Boolean values may be "true" or "false", or 1 or 0. * * These parameters are the same as the CCITTFaxDecode parameters in the * [PostScript Language Reference](https://www.adobe.com/products/postscript/pdfs/PLRM.pdf) * and [Portable Document Format (PDF)](https://www.adobe.com/content/dam/Adobe/en/devnet/pdf/pdfs/PDF32000_2008.pdf). * Refer to these documents for further details. * * An example %CAIRO_MIME_TYPE_CCITT_FAX_PARAMS string is: * * <programlisting> * "Columns=10230 Rows=40000 K=1 EndOfLine=true EncodedByteAlign=1 BlackIs1=false" * </programlisting> *
**/
/** * CAIRO_HAS_PDF_SURFACE: * * Defined if the PDF surface backend is available. * This macro can be used to conditionally compile backend-specific code. * * Since: 1.2
**/
/* Default to Uncompressed. If this object is used with * _cairo_pdf_surface_object_begin() and Object Streams are
* enabled it will be changed to Compressed. */
object.type = PDF_OBJECT_UNCOMPRESSED;
object.u.offset = _cairo_output_stream_get_position (surface->output);
status = _cairo_array_append (&surface->objects, &object); if (unlikely (status)) {
resource.id = 0; return resource;
}
status = surface->paginated_surface->status; if (status == CAIRO_STATUS_SUCCESS) { /* paginated keeps the only reference to surface now, drop ours */
cairo_surface_destroy (&surface->base); return surface->paginated_surface;
}
/* destroy stream on behalf of caller */
status_ignored = _cairo_output_stream_destroy (output);
return _cairo_surface_create_in_error (status);
}
/** * cairo_pdf_surface_create_for_stream: * @write_func: a #cairo_write_func_t to accept the output data, may be %NULL * to indicate a no-op @write_func. With a no-op @write_func, * the surface may be queried or used as a source without * generating any temporary files. * @closure: the closure argument for @write_func * @width_in_points: width of the surface, in points (1 point == 1/72.0 inch) * @height_in_points: height of the surface, in points (1 point == 1/72.0 inch) * * Creates a PDF surface of the specified size in points to be written * incrementally to the stream represented by @write_func and @closure. * * Return value: a pointer to the newly created surface. The caller * owns the surface and should call cairo_surface_destroy() when done * with it. * * This function always returns a valid pointer, but it will return a * pointer to a "nil" surface if an error such as out of memory * occurs. You can use cairo_surface_status() to check for this. * * Since: 1.2
**/
cairo_surface_t *
cairo_pdf_surface_create_for_stream (cairo_write_func_t write_func, void *closure, double width_in_points, double height_in_points)
{
cairo_output_stream_t *output;
/** * cairo_pdf_surface_create: * @filename: a filename for the PDF output (must be writable), %NULL may be * used to specify no output. This will generate a PDF surface that * may be queried and used as a source, without generating a * temporary file. * @width_in_points: width of the surface, in points (1 point == 1/72.0 inch) * @height_in_points: height of the surface, in points (1 point == 1/72.0 inch) * * Creates a PDF surface of the specified size in points to be written * to @filename. * * Return value: a pointer to the newly created surface. The caller * owns the surface and should call cairo_surface_destroy() when done * with it. * * This function always returns a valid pointer, but it will return a * pointer to a "nil" surface if an error such as out of memory * occurs. You can use cairo_surface_status() to check for this. * * Since: 1.2
**/
cairo_surface_t *
cairo_pdf_surface_create (constchar *filename, double width_in_points, double height_in_points)
{
cairo_output_stream_t *output;
/* If the abstract_surface is a paginated surface, and that paginated * surface's target is a pdf_surface, then set pdf_surface to that * target. Otherwise return FALSE.
*/ static cairo_bool_t
_extract_pdf_surface (cairo_surface_t *surface,
cairo_pdf_surface_t **pdf_surface)
{
cairo_surface_t *target;
cairo_status_t status_ignored;
if (surface->status) returnFALSE; if (surface->finished) {
status_ignored = _cairo_surface_set_error (surface,
_cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); returnFALSE;
}
/** * cairo_pdf_surface_restrict_to_version: * @surface: a PDF #cairo_surface_t * @version: PDF version * * Restricts the generated PDF file to @version. See cairo_pdf_get_versions() * for a list of available version values that can be used here. * * This function should only be called before any drawing operations * have been performed on the given surface. The simplest way to do * this is to call this function immediately after creating the * surface. * * Since: 1.10
**/ void
cairo_pdf_surface_restrict_to_version (cairo_surface_t *abstract_surface,
cairo_pdf_version_t version)
{
cairo_pdf_surface_t *surface = NULL; /* hide compiler warning */
if (! _extract_pdf_surface (abstract_surface, &surface)) return;
if (version < CAIRO_PDF_VERSION_LAST)
surface->pdf_version = version;
_cairo_pdf_operators_enable_actual_text(&surface->pdf_operators,
version >= CAIRO_PDF_VERSION_1_5);
}
/** * cairo_pdf_get_versions: * @versions: supported version list * @num_versions: list length * * Used to retrieve the list of supported versions. See * cairo_pdf_surface_restrict_to_version(). * * Since: 1.10
**/ void
cairo_pdf_get_versions (cairo_pdf_version_t const **versions, int *num_versions)
{ if (versions != NULL)
*versions = _cairo_pdf_versions;
if (num_versions != NULL)
*num_versions = CAIRO_PDF_VERSION_LAST;
}
/** * cairo_pdf_version_to_string: * @version: a version id * * Get the string representation of the given @version id. This function * will return %NULL if @version isn't valid. See cairo_pdf_get_versions() * for a way to get the list of valid version ids. * * Return value: the string associated to given version. * * Since: 1.10
**/ constchar *
cairo_pdf_version_to_string (cairo_pdf_version_t version)
{ if (version < 0 || version >= CAIRO_PDF_VERSION_LAST) return NULL;
return _cairo_pdf_version_strings[version];
}
/** * cairo_pdf_surface_set_size: * @surface: a PDF #cairo_surface_t * @width_in_points: new surface width, in points (1 point == 1/72.0 inch) * @height_in_points: new surface height, in points (1 point == 1/72.0 inch) * * Changes the size of a PDF surface for the current (and * subsequent) pages. * * This function should only be called before any drawing operations * have been performed on the current page. The simplest way to do * this is to call this function immediately after creating the * surface or immediately after completing a page with either * cairo_show_page() or cairo_copy_page(). * * Since: 1.2
**/ void
cairo_pdf_surface_set_size (cairo_surface_t *surface, double width_in_points, double height_in_points)
{
cairo_pdf_surface_t *pdf_surface = NULL; /* hide compiler warning */
cairo_status_t status;
if (! _extract_pdf_surface (surface, &pdf_surface)) return;
_cairo_pdf_surface_set_size_internal (pdf_surface,
width_in_points,
height_in_points);
status = _cairo_paginated_surface_set_size (pdf_surface->paginated_surface,
width_in_points,
height_in_points); if (status)
status = _cairo_surface_set_error (surface, status);
}
/** * CAIRO_PDF_OUTLINE_ROOT: * * The root outline item in cairo_pdf_surface_add_outline(). * * Since: 1.16
**/
/** * cairo_pdf_surface_add_outline: * @surface: a PDF #cairo_surface_t * @parent_id: the id of the parent item or %CAIRO_PDF_OUTLINE_ROOT if this is a top level item. * @utf8: the name of the outline * @link_attribs: the link attributes specifying where this outline links to * @flags: outline item flags * * Add an item to the document outline hierarchy with the name @utf8 * that links to the location specified by @link_attribs. Link * attributes have the same keys and values as the [Link Tag][link], * excluding the "rect" attribute. The item will be a child of the * item with id @parent_id. Use %CAIRO_PDF_OUTLINE_ROOT as the parent * id of top level items. * * Return value: the id for the added item. * * Since: 1.16
**/ int
cairo_pdf_surface_add_outline (cairo_surface_t *surface, int parent_id, constchar *utf8, constchar *link_attribs,
cairo_pdf_outline_flags_t flags)
{
cairo_pdf_surface_t *pdf_surface = NULL; /* hide compiler warning */
cairo_status_t status; int id = 0;
if (! _extract_pdf_surface (surface, &pdf_surface)) return 0;
status = _cairo_pdf_interchange_add_outline (pdf_surface,
parent_id,
utf8,
link_attribs,
flags,
&id); if (status)
status = _cairo_surface_set_error (surface, status);
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, constchar *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);
}
/** * cairo_pdf_surface_set_custom_metadata: * @surface: a PDF #cairo_surface_t * @name: The name of the custom metadata item to set (utf8). * @value: The value of the metadata (utf8). * * Set custom document metadata. @name may be any string except for * the following names reserved by PDF: "Title", "Author", "Subject", * "Keywords", "Creator", "Producer", "CreationDate", "ModDate", * "Trapped". * * If @value is NULL or an empty string, the @name metadata will not be set. * * For example: * <informalexample><programlisting> * cairo_pdf_surface_set_custom_metadata (surface, "ISBN", "978-0123456789"); * </programlisting></informalexample> * * Since: 1.18
**/ void
cairo_pdf_surface_set_custom_metadata (cairo_surface_t *surface, constchar *name, constchar *value)
{
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_custom_metadata (pdf_surface, name, value); if (status)
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, constchar *utf8)
{
cairo_pdf_surface_t *pdf_surface = NULL; /* hide compiler warning */
if (! _extract_pdf_surface (surface, &pdf_surface)) return;
/** * 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;
staticconstchar *
_cairo_operator_to_pdf_blend_mode (cairo_operator_t op)
{ switch (op) { /* The extend blend mode operators */ case CAIRO_OPERATOR_MULTIPLY: return"Multiply"; case CAIRO_OPERATOR_SCREEN: return"Screen"; case CAIRO_OPERATOR_OVERLAY: return"Overlay"; case CAIRO_OPERATOR_DARKEN: return"Darken"; case CAIRO_OPERATOR_LIGHTEN: return"Lighten"; case CAIRO_OPERATOR_COLOR_DODGE: return"ColorDodge"; case CAIRO_OPERATOR_COLOR_BURN: return"ColorBurn"; case CAIRO_OPERATOR_HARD_LIGHT: return"HardLight"; case CAIRO_OPERATOR_SOFT_LIGHT: return"SoftLight"; case CAIRO_OPERATOR_DIFFERENCE: return"Difference"; case CAIRO_OPERATOR_EXCLUSION: return"Exclusion"; case CAIRO_OPERATOR_HSL_HUE: return"Hue"; case CAIRO_OPERATOR_HSL_SATURATION: return"Saturation"; case CAIRO_OPERATOR_HSL_COLOR: return"Color"; case CAIRO_OPERATOR_HSL_LUMINOSITY: return"Luminosity";
default: /* The original Porter-Duff set */ case CAIRO_OPERATOR_CLEAR: case CAIRO_OPERATOR_SOURCE: case CAIRO_OPERATOR_OVER: case CAIRO_OPERATOR_IN: case CAIRO_OPERATOR_OUT: case CAIRO_OPERATOR_ATOP: case CAIRO_OPERATOR_DEST: case CAIRO_OPERATOR_DEST_OVER: case CAIRO_OPERATOR_DEST_IN: case CAIRO_OPERATOR_DEST_OUT: case CAIRO_OPERATOR_DEST_ATOP: case CAIRO_OPERATOR_XOR: case CAIRO_OPERATOR_ADD: case CAIRO_OPERATOR_SATURATE: return"Normal";
}
}
for (i = 0; i < CAIRO_NUM_OPERATORS; i++) { if (res->operators[i]) {
_cairo_output_stream_printf (surface->output, " /b%d << /BM /%s >>\n",
i, _cairo_operator_to_pdf_blend_mode(i));
}
}
for (i = 0; i < num_alphas; i++) {
_cairo_array_copy_element (&res->alphas, i, &alpha);
_cairo_output_stream_printf (surface->output, " /a%d << /CA %f /ca %f >>\n",
i, alpha, alpha);
}
for (i = 0; i < num_smasks; i++) {
smask = _cairo_array_index (&res->smasks, i);
_cairo_output_stream_printf (surface->output, " /s%d %d 0 R\n",
smask->id, smask->id);
}
case CAIRO_PATTERN_TYPE_SOLID: case CAIRO_PATTERN_TYPE_LINEAR: case CAIRO_PATTERN_TYPE_RADIAL: case CAIRO_PATTERN_TYPE_MESH: default:
ASSERT_NOT_REACHED; break;
}
/** * _cairo_pdf_surface_add_source_surface: * @surface: [in] the pdf surface * @source_surface: [in] A #cairo_surface_t to use as the source surface * @source_pattern: [in] A #cairo_pattern_t of type SURFACE or RASTER_SOURCE to use as the source * @region_id: [in] Surfaces containing tags set this to the recording * surface region id. When tags are used in a XObject, PDF requires a * separate object for each use (section 14.7.4.2) @region_id is used * as a key to ensure a separate object is emitted for each use. Set * to 0 for surfaces without tags. * @op: [in] the operator used to composite this source * @filter: [in] filter type of the source pattern * @stencil_mask: [in] if true, the surface will be written to the PDF as an /ImageMask * @smask: [in] if true, only the alpha channel will be written (images only) * @need_transp_group: [in] if true and an XObject is used, make it a Transparency group * @extents: [in] extents of the operation that is using this source * @smask_res: [in] if not NULL, the image written will specify this resource as the smask for * the image (images only) * @pdf_source: [out] return pdf_source_surface entry in hash table * @x_offset: [out] if not NULL return x offset of surface * @y_offset: [out] if not NULL return y offset of surface * @source_extents: [out] if not NULL return operation extents in source space * * Add surface or raster_source pattern to list of surfaces to be * written to the PDF file when the current page is finished. Returns * a PDF resource to reference the surface. A hash table of all * surfaces in the PDF file (keyed by CAIRO_MIME_TYPE_UNIQUE_ID or * surface unique_id) is used to ensure surfaces with the same id are * only written once to the PDF file. * * Only one of @source_pattern or @source_surface is to be * specified. Set the other to NULL.
**/ static cairo_int_status_t
_cairo_pdf_surface_add_source_surface (cairo_pdf_surface_t *surface,
cairo_surface_t *source_surface, const cairo_pattern_t *source_pattern, int region_id,
cairo_operator_t op,
cairo_filter_t filter,
cairo_bool_t stencil_mask,
cairo_bool_t smask,
cairo_bool_t need_transp_group, const cairo_rectangle_int_t *extents,
cairo_pdf_resource_t *smask_res,
cairo_pdf_source_surface_entry_t **pdf_source, double *x_offset, double *y_offset,
cairo_rectangle_int_t *source_extents)
{
cairo_pdf_source_surface_t src_surface;
cairo_pdf_source_surface_entry_t surface_key;
cairo_pdf_source_surface_entry_t *surface_entry;
cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
cairo_bool_t interpolate; unsignedchar *unique_id = NULL; unsignedlong unique_id_length = 0;
cairo_image_surface_t *image; void *image_extra;
cairo_box_t box;
cairo_rectangle_int_t op_extents; double x, y;
cairo_bool_t subsurface;
cairo_bool_t emit_image;
switch (filter) { default: case CAIRO_FILTER_GOOD: case CAIRO_FILTER_BEST: case CAIRO_FILTER_BILINEAR:
interpolate = TRUE; break; case CAIRO_FILTER_FAST: case CAIRO_FILTER_NEAREST: case CAIRO_FILTER_GAUSSIAN:
interpolate = FALSE; break;
}
x = 0;
y = 0; if (source_pattern) { if (source_pattern->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE) {
status = _cairo_pdf_surface_acquire_source_image_from_pattern (surface, source_pattern,
&image, &image_extra); if (unlikely (status)) return status;
source_surface = &image->base;
cairo_surface_get_device_offset (source_surface, &x, &y);
} else {
cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) source_pattern;
source_surface = surface_pattern->surface;
}
} if (x_offset)
*x_offset = x; if (y_offset)
*y_offset = y;
/* transform operation extents to pattern space */
op_extents = *extents; if (source_pattern)
{
_cairo_box_from_rectangle (&box, extents);
_cairo_matrix_transform_bounding_box_fixed (&source_pattern->matrix, &box, NULL);
_cairo_box_round_to_rectangle (&box, &op_extents);
} if (source_extents)
*source_extents = op_extents;
surface_key.id = source_surface->unique_id;
/* Recording surfaces do not use interpolate. Ensure it is always * false for recording surfaces. This is because pdf-interchange * needs to lookup recording surfaces in the hash table using * interpolate = FALSE in the key since it does not know the * interpolate value passed to this function.
*/
emit_image = source_surface->type != CAIRO_SURFACE_TYPE_RECORDING;
surface_key.interpolate = emit_image ? interpolate : FALSE;
*pattern_res = pdf_pattern.pattern_res;
*gstate_res = pdf_pattern.gstate_res; /* If the pattern requires a gstate it will be drawn from within * an XObject. The initial space of each XObject has an inverted
* Y-axis. */
pdf_pattern.inverted_y_axis = pdf_pattern.gstate_res.id ? TRUE : surface->in_xobject;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.