Generating High‑Quality Vector PDFs with Cairo’s PDF Surface
Learn how to create fully vector PDFs with Cairo’s PDF surface, embed images, handle text, and verify the output. The guide covers code, trade‑offs, and practical checks for production use.
09 May 2026, 07:10 UTC

Why Cairo’s PDF Surface Matters
When a PDF is generated from raster data, every line, curve, and glyph becomes a pixel block. That means scaling the file up or down degrades quality, and editing text or shapes in downstream tools is impossible. Cairo’s cairo_pdf_surface_t solves this by emitting true vector content: paths, text outlines, and embedded images remain resolution‑independent and editable. For applications that need crisp, scalable reports or cross‑platform printouts, the PDF surface is a production‑ready choice.
Creating a Vector PDF in Practice
Setting Up the Surface
/* Compile with: gcc -o pdf_example pdf_example.c `pkg-config --cflags --libs cairo` */
#include <cairo.h>
#include <stdio.h>
int main(void) {
/* Create a 595x842 PDF surface (A4, 72 dpi). */
cairo_surface_t *surface = cairo_pdf_surface_create("output.pdf", 595, 842);
if (cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) {
fprintf(stderr, "Failed to create PDF surface\n");
return 1;
}
cairo_t *cr = cairo_create(surface);
/* ---- drawing code will go here ---- */
cairo_destroy(cr);
cairo_surface_destroy(surface);
return 0;
}
Drawing Primitives
Once the surface is created, Cairo’s normal drawing API applies. Every cairo_move_to, cairo_line_to, cairo_arc, etc., becomes a vector path in the PDF.
/* Draw a blue rectangle */
cairo_set_source_rgb(cr, 0, 0, 1); // blue
cairo_rectangle(cr, 50, 50, 200, 100);
cairo_fill(cr);
/* Draw a red circle */
cairo_set_source_rgb(cr, 1, 0, 0); // red
cairo_arc(cr, 300, 200, 50, 0, 2 * M_PI);
cairo_stroke(cr);
Embedding Images
Raster images can be inserted via cairo_image_surface_create_from_png. The image is embedded as a bitmap inside the PDF, but the surrounding drawing remains vector. Note that the PDF surface does not support alpha transparency; all image data is treated as opaque.
cairo_surface_t *img = cairo_image_surface_create_from_png("logo.png");
cairo_set_source_surface(cr, img, 400, 50);
cairo_paint(cr);
cairo_surface_destroy(img);
Adding Text
Text is rendered by Cairo’s font system. Cairo pulls system fonts; if a requested font is missing, it falls back to a default. The resulting glyphs are converted to outlines, preserving vector quality.
cairo_select_font_face(cr, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
cairo_set_font_size(cr, 24);
cairo_move_to(cr, 50, 300);
cairo_show_text(cr, "Hello, Cairo PDF!");
What You’ll Lose (and How to Mitigate)
- No alpha transparency: All drawing is opaque. If translucency is required, pre‑blend the image or use a different format.
- Font availability: Missing fonts are replaced, which can alter appearance. Bundle fonts or embed them using a font‑embedding library if consistency is critical.
- Advanced patterns and clipping: Complex patterns or clipping masks may not be preserved. Stick to simple fills and strokes for guaranteed fidelity.
Verifying Your PDF
- Check surface creation:
if (cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) { /* handle error */ } - After writing, open the file with a viewer (e.g., Acrobat, Okular) and confirm that shapes can be selected and resized without pixelation.
- Use
pdftotextorpdfinfoto verify the page count and basic metadata.pdftotext output.pdf - pdfinfo output.pdf - Measure performance: compare
cairo_pdf_surface_createrendering time against a raster surface for a large document. Expect a CPU‑bound slowdown for very large PDFs.
Bottom Line
Cairo’s PDF surface delivers fully vector PDFs that scale cleanly and remain editable, making it a solid choice for report generators, print workflows, and cross‑platform document export. Be mindful of the lack of alpha support and font dependencies, and verify the output with simple tools before shipping to users.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.