Using the PostScript surface

Coordinate system

The PostScript surface coordinate space is in points. One point is 1/72 inch. The user space ctm can be scaled to work in other units:

millimeters:

cairo_scale (cr, 72/25.4, 72/25.4);

inches

cairo_scale (cr, 72, 72);

Page Size

The page size is in points. For example A4 paper is 595 points wide by 842 points high. Letter paper is 612 by 792 points.

The gv documentation lists some Common paper sizes and the size in points.

Page size can be changed for each page using cairo_ps_surface_set_size ().

PostScript Level

By default cairo will emit Language Level 3 PostScript. The cairo_ps_surface_restrict_to_level () function may be used to limit the Language Level used.

The benefit of using language level 3 is support for additional features such as gradient patterns. However Language Level 2 printers cannot print PostScript containing Language Level 3 features.

Note that when when Language Level 3 is permitted the, "LanguageLevel" DSC comment in the output may still indicate 2 if no level 3 features are used.

Encapsulated PostScript (EPS)

When generating PostScript output that will be imported as diagrams into applications the EPS format is used. EPS files must contain only one page. Language level 2 or 3 can be used with EPS mode.

Note that cairo does not include the device independent preview.

The Encapsulated PostScript Specification contains describes how to embed EPS files into PostScript.

Printing in Landscape

The method for printing in landscape depends on whether PostScript or Encapsulated PostScript is being generated.

PostScript

When generating landscape PostScript output the surface should not be created with a width greater than the height. Instead create the surface with a height greater than the width and rotate the cairo drawing context. The "%PageOrientation" DSC comment is used by PostScript viewers to indicate the orientation of the page.

The steps to create a landscape page are:

  1. Set the page size to a portrait size eg (595, 842) for A4.

  2. Rotate user space 90 degrees counterclockwise and move the origin to the correct location

  3. Insert the "%PageOrientation: Landscape" DSC comment.

Evince, gv, or okular can be used to check that the output.

The following code prints one portrait page followed by one landscape page.

#include <cairo.h>
#include <cairo-ps.h>

#define PAGE_WIDTH 595
#define PAGE_HEIGHT 842

#define BORDER 50

void draw (cairo_t *cr, const char *text, int width, int height)
{
    char buf[100];

    cairo_rectangle (cr, BORDER, BORDER, width - 2*BORDER, height - 2*BORDER);
    cairo_set_line_width (cr, 2);
    cairo_stroke (cr);

    cairo_select_font_face (cr, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
    cairo_set_font_size (cr, 60);
    cairo_move_to (cr, 200, height/3);
    cairo_show_text (cr, text);

    sprintf (buf, "Width: %d points      Height: %d points", width, height);
    cairo_set_font_size (cr, 18);
    cairo_move_to (cr, 120, height*2/3);
    cairo_show_text (cr, buf);
}

int main()
{
    cairo_surface_t *surface;
    cairo_t *cr;
    cairo_matrix_t matrix;

    surface = cairo_ps_surface_create ("output.ps", PAGE_WIDTH, PAGE_HEIGHT);
    cr = cairo_create (surface);

    /* Print portrait page */
    cairo_ps_surface_dsc_begin_page_setup (surface);
    cairo_ps_surface_dsc_comment (surface, "%%PageOrientation: Portrait");
    draw (cr, "Portrait", PAGE_WIDTH, PAGE_HEIGHT);
    cairo_surface_show_page (surface);

    /* Print landscape page */
    cairo_ps_surface_dsc_begin_page_setup (surface);
    cairo_ps_surface_dsc_comment (surface, "%%PageOrientation: Landscape");

    /* Move the origin to landscape origin and rotate counterclockwise
     * 90 degrees.
     *
     * This is equivilent to:
     *    cairo_translate (cr, 0, PAGE_HEIGHT);
     *    cairo_rotate (cr, -M_PI/2);
     */
    cairo_translate (cr, 0, PAGE_HEIGHT);
    cairo_matrix_init (&matrix, 0, -1, 1, 0, 0,  0);
    cairo_transform (cr, &matrix);

    draw (cr, "Landscape", PAGE_HEIGHT, PAGE_WIDTH);
    cairo_surface_show_page (surface);

    cairo_destroy (cr);
    cairo_surface_finish (surface);
    cairo_surface_destroy (surface);

    return 0;
}

Encapsulated PostScript

When generating landscape EPS output the surface width can be greater than the height.

For example:

surface = cairo_ps_surface_create (filename, 400, 200)
cairo_ps_surface_set_eps (surface, TRUE);

Fonts

The PostScript surface natively supports Type 1 and TrueType fonts. All other fonts types (including OpenType/PS) are converted to Type 1.

Fonts are always subsetted and embedded.

Fallback images

Cairo will ensure that the PostScript output looks the same as the image surface for the same set of cairo commands. When cairo drawing operations are performed that cannot be natively represented in PostScript, the drawing is rasterized and embedded in the output.

Since cairo 1.6 the rasterization of unsupported operations is limited to the smallest rectangle or set of rectangles required to draw the unsupported operations.

Fallback images are the main cause of large file sizes and slow printing times. Fallback images have a comment containing the size and location of the fallback.

> grep 'Fallback' output.ps
output.ps:% Fallback Image: x=100, y=100, w=299, h=50 res=300dpi size=783750
output.ps:% Fallback Image: x=100, y=150, w=350, h=250 res=300dpi size=4560834
output.ps:% Fallback Image: x=150, y=400, w=299, h=50 res=300dpi size=783750

Features support by the PostScript surface

The following table lists the features that are natively supported by the PostScript surface. Natively supported operations will result in vector PostScript output. Unsupported operations will be rasterized and printed as a fallback image.

Feature                             Supported

cairo_paint/cairo_fill/
 cairo_stroke/cairo_show_glyphs     yes, depending on pattern
cairo_mask                          no
fonts                               yes - some font types are converted to Type 1
translucent colors                  no, opaque colors only
images                              yes
linear gradients                    level 3 only
radial gradients                    level 3 only. Only when one circle is inside the other and extent is CAIRO_EXTEND_NONE or CAIRO_EXTEND_PAD
push_group/create_similar           yes
CAIRO_OPERATOR_SOURCE               yes
CAIRO_OPERATOR_OVER                 yes (opaque colors only)
all other operators                 no