Python interface for cairo graphics library providing 2D vector graphics, drawing operations, and rendering to multiple output formats
—
Surface classes provide the rendering targets for Cairo drawing operations. Each surface type represents a different output format or backend, from in-memory image buffers to vector formats like PDF and SVG. Surfaces manage the destination for all drawing operations performed through a Context.
class Surface:
def finish(self) -> None:
"""Do any pending drawing and free resources used by surface."""
def flush(self) -> None:
"""Do any pending drawing for the surface."""
def get_content(self) -> Content:
"""Get content type of surface (COLOR, ALPHA, or COLOR_ALPHA)."""
def get_device(self) -> Device:
"""Get device associated with surface."""
def get_font_options(self, options: FontOptions) -> None:
"""Retrieve default font rendering options for surface."""
def mark_dirty(self) -> None:
"""Tell cairo that drawing has been done to surface."""
def mark_dirty_rectangle(self, x: int, y: int, width: int, height: int) -> None:
"""Mark a rectangular region as dirty."""
def set_device_scale(self, x_scale: float, y_scale: float) -> None:
"""Set device scale factors."""
def get_device_scale(self) -> tuple[float, float]:
"""Get device scale factors."""
def set_device_offset(self, x_offset: float, y_offset: float) -> None:
"""Set device offset."""
def get_device_offset(self) -> tuple[float, float]:
"""Get device offset."""
def get_fallback_resolution(self) -> tuple[float, float]:
"""Get fallback resolution in pixels per inch."""
def set_fallback_resolution(self, x_pixels_per_inch: float, y_pixels_per_inch: float) -> None:
"""Set fallback resolution."""
def copy_page(self) -> None:
"""Emit current page for backends that support multiple pages."""
def show_page(self) -> None:
"""Emit and clear current page for backends that support multiple pages."""
def has_show_text_glyphs(self) -> bool:
"""Check if surface can render text and glyphs simultaneously."""
def set_mime_data(self, mime_type: str, data: bytes) -> None:
"""Attach MIME data to surface."""
def get_mime_data(self, mime_type: str) -> bytes:
"""Get MIME data previously attached to surface."""
def supports_mime_type(self, mime_type: str) -> bool:
"""Check if surface supports given MIME type."""
def create_for_rectangle(self, x: float, y: float, width: float, height: float) -> Surface:
"""Create sub-surface from rectangular region of this surface."""
def create_similar_image(self, format: Format, width: int, height: int) -> ImageSurface:
"""Create similar image surface with specified format and dimensions."""
def map_to_image(self, extents: Rectangle | None = None) -> ImageSurface:
"""Map surface or region to image surface for direct pixel access."""
def unmap_image(self, image: ImageSurface) -> None:
"""Unmap previously mapped image surface."""
def __enter__(self) -> Surface:
"""Enter context manager."""
def __exit__(self, exc_type, exc_val, exc_tb) -> None:
"""Exit context manager and finish surface."""class ImageSurface(Surface):
def __init__(self, format: Format, width: int, height: int) -> None:
"""Create image surface with specified format and dimensions.
Args:
format: Pixel format (FORMAT_ARGB32, FORMAT_RGB24, etc.)
width: Width in pixels
height: Height in pixels
"""
@classmethod
def create_from_png(cls, filename: str) -> ImageSurface:
"""Create image surface from PNG file."""
@classmethod
def create_from_png_stream(cls, file: BinaryIO) -> ImageSurface:
"""Create image surface from PNG data stream."""
@classmethod
def create_for_data(cls, data: memoryview, format: Format, width: int, height: int, stride: int) -> ImageSurface:
"""Create image surface using provided data buffer."""
def write_to_png(self, filename: str) -> None:
"""Write surface contents to PNG file."""
def write_to_png_stream(self, file: BinaryIO) -> None:
"""Write surface contents to PNG data stream."""
def get_data(self) -> memoryview:
"""Get raw pixel data as memory view."""
def get_format(self) -> Format:
"""Get pixel format of surface."""
def get_width(self) -> int:
"""Get width in pixels."""
def get_height(self) -> int:
"""Get height in pixels."""
def get_stride(self) -> int:
"""Get stride (bytes per row) of surface."""
@staticmethod
def format_stride_for_width(format: Format, width: int) -> int:
"""Calculate stride for given format and width."""class PDFSurface(Surface):
def __init__(self, filename: str, width_in_points: float, height_in_points: float) -> None:
"""Create PDF surface writing to file.
Args:
filename: Output PDF filename
width_in_points: Page width in points (1/72 inch)
height_in_points: Page height in points (1/72 inch)
"""
@classmethod
def create_for_stream(cls, file: BinaryIO, width_in_points: float, height_in_points: float) -> PDFSurface:
"""Create PDF surface writing to stream."""
def restrict_to_version(self, version: PDFVersion) -> None:
"""Restrict output to specific PDF version."""
@staticmethod
def get_versions() -> list[PDFVersion]:
"""Get list of supported PDF versions."""
@staticmethod
def version_to_string(version: PDFVersion) -> str:
"""Get string representation of PDF version."""
def set_size(self, width_in_points: float, height_in_points: float) -> None:
"""Change size of PDF surface for subsequent pages."""
def add_outline(self, parent_id: int, text: str, link_attribs: str, flags: PDFOutlineFlags) -> int:
"""Add item to PDF outline (bookmarks).
Args:
parent_id: Parent outline item ID (use PDF_OUTLINE_ROOT for root)
text: Display text for outline item
link_attribs: Link attributes string
flags: Outline item flags
Returns:
ID of created outline item
"""
def set_metadata(self, metadata: PDFMetadata, value: str) -> None:
"""Set PDF metadata."""
def set_page_label(self, label: str) -> None:
"""Set label for current page."""
def set_thumbnail_size(self, width: int, height: int) -> None:
"""Set thumbnail image size for pages."""
def set_custom_metadata(self, name: str, value: str) -> None:
"""Set custom metadata field."""class PSSurface(Surface):
def __init__(self, filename: str, width_in_points: float, height_in_points: float) -> None:
"""Create PostScript surface writing to file.
Args:
filename: Output PostScript filename
width_in_points: Page width in points
height_in_points: Page height in points
"""
@classmethod
def create_for_stream(cls, file: BinaryIO, width_in_points: float, height_in_points: float) -> PSSurface:
"""Create PostScript surface writing to stream."""
def restrict_to_level(self, level: PSLevel) -> None:
"""Restrict output to specific PostScript level."""
@staticmethod
def get_levels() -> list[PSLevel]:
"""Get list of supported PostScript levels."""
@staticmethod
def level_to_string(level: PSLevel) -> str:
"""Get string representation of PostScript level."""
def set_eps(self, eps: bool) -> None:
"""Enable/disable Encapsulated PostScript mode."""
def get_eps(self) -> bool:
"""Check if EPS mode is enabled."""
def set_size(self, width_in_points: float, height_in_points: float) -> None:
"""Change size for subsequent pages."""
def dsc_comment(self, comment: str) -> None:
"""Emit DSC comment to PostScript output."""
def dsc_begin_setup(self) -> None:
"""Begin setup section in DSC-compliant PostScript."""
def dsc_begin_page_setup(self) -> None:
"""Begin page setup section."""class SVGSurface(Surface):
def __init__(self, filename: str, width_in_points: float, height_in_points: float) -> None:
"""Create SVG surface writing to file.
Args:
filename: Output SVG filename
width_in_points: Surface width in points
height_in_points: Surface height in points
"""
@classmethod
def create_for_stream(cls, file: BinaryIO, width_in_points: float, height_in_points: float) -> SVGSurface:
"""Create SVG surface writing to stream."""
def restrict_to_version(self, version: SVGVersion) -> None:
"""Restrict output to specific SVG version."""
@staticmethod
def get_versions() -> list[SVGVersion]:
"""Get list of supported SVG versions."""
@staticmethod
def version_to_string(version: SVGVersion) -> str:
"""Get string representation of SVG version."""
def set_document_unit(self, unit: SVGUnit) -> None:
"""Set unit used for SVG surface."""
def get_document_unit(self) -> SVGUnit:
"""Get unit used for SVG surface."""class RecordingSurface(Surface):
def __init__(self, content: Content, extents: Rectangle | None = None) -> None:
"""Create recording surface for caching drawing operations.
Args:
content: Content type (COLOR, ALPHA, or COLOR_ALPHA)
extents: Recording extents or None for unbounded
"""
def ink_extents(self) -> tuple[float, float, float, float]:
"""Get bounding box of recorded operations."""
def get_extents(self) -> tuple[bool, float, float, float, float]:
"""Get recording extents."""class Win32Surface(Surface):
def __init__(self, hdc: int) -> None:
"""Create surface targeting Windows HDC."""
class Win32PrintingSurface(Surface):
def __init__(self, hdc: int) -> None:
"""Create surface for Windows printing."""
class XCBSurface(Surface):
pass # Platform-specific initialization
class XlibSurface(Surface):
pass # Platform-specific initialization
class TeeSurface(Surface):
def __init__(self, primary: Surface) -> None:
"""Create tee surface directing to primary surface."""
def add(self, target: Surface) -> None:
"""Add additional target surface."""
def remove(self, target: Surface) -> None:
"""Remove target surface."""
def index(self, index: int) -> Surface:
"""Get surface at given index."""
class ScriptSurface(Surface):
def __init__(self, device: ScriptDevice, content: Content, width: float, height: float) -> None:
"""Create surface for Cairo script recording."""class Device:
def __init__(self) -> None:
"""Base device class (typically not instantiated directly)."""
def finish(self) -> None:
"""Finish device and free associated resources."""
def flush(self) -> None:
"""Flush pending operations on device."""
def get_type(self) -> DeviceType:
"""Get device type."""
class ScriptDevice(Device):
def __init__(self, filename: str) -> None:
"""Create script recording device writing to file.
Args:
filename: Output script filename
"""
@classmethod
def create_for_stream(cls, file: BinaryIO) -> ScriptDevice:
"""Create script device writing to stream."""
def set_mode(self, mode: ScriptMode) -> None:
"""Set script recording mode (ASCII or BINARY)."""
def get_mode(self) -> ScriptMode:
"""Get current script recording mode."""
def write_comment(self, comment: str) -> None:
"""Write comment to script output."""
def from_recording_surface(self, recording_surface: RecordingSurface) -> None:
"""Replay recording surface to script device."""import cairo
# Image surface (in-memory bitmap)
image_surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 800, 600)
# PDF surface
pdf_surface = cairo.PDFSurface("output.pdf", 612, 792) # US Letter size
# SVG surface
svg_surface = cairo.SVGSurface("output.svg", 400, 300)
# PostScript surface
ps_surface = cairo.PSSurface("output.ps", 612, 792)
# Recording surface (unbounded)
recording_surface = cairo.RecordingSurface(cairo.CONTENT_COLOR_ALPHA, None)import cairo
# Create image surface
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 400, 300)
ctx = cairo.Context(surface)
# Draw something
ctx.set_source_rgb(0.8, 0.2, 0.2)
ctx.rectangle(50, 50, 100, 80)
ctx.fill()
# Save to PNG
surface.write_to_png("output.png")
# Access raw pixel data
data = surface.get_data()
width = surface.get_width()
height = surface.get_height()
stride = surface.get_stride()
format = surface.get_format()
print(f"Surface: {width}x{height}, format: {format}, stride: {stride}")import cairo
# Create PDF surface
surface = cairo.PDFSurface("document.pdf", 612, 792) # US Letter
ctx = cairo.Context(surface)
# Configure PDF metadata
surface.set_metadata(cairo.PDF_METADATA_TITLE, "My Document")
surface.set_metadata(cairo.PDF_METADATA_AUTHOR, "Author Name")
# Page 1
ctx.set_source_rgb(0, 0, 0)
ctx.select_font_face("Arial", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL)
ctx.set_font_size(24)
ctx.move_to(50, 100)
ctx.show_text("Page 1")
# Add outline entry
outline_id = surface.add_outline(cairo.PDF_OUTLINE_ROOT, "Chapter 1", "page=1", 0)
surface.show_page()
# Page 2
ctx.move_to(50, 100)
ctx.show_text("Page 2")
surface.show_page()
surface.finish()import cairo
# Create recording surface
recording = cairo.RecordingSurface(cairo.CONTENT_COLOR_ALPHA, None)
ctx = cairo.Context(recording)
# Record some operations
ctx.set_source_rgb(0.2, 0.4, 0.8)
ctx.rectangle(10, 10, 80, 60)
ctx.fill()
ctx.set_source_rgb(0.8, 0.4, 0.2)
ctx.arc(50, 40, 20, 0, 2 * 3.14159)
ctx.fill()
# Get recorded extents
x, y, width, height = recording.ink_extents()
print(f"Recorded operations cover: {x}, {y}, {width}, {height}")
# Play back to image surface
image = cairo.ImageSurface(cairo.FORMAT_ARGB32, 200, 150)
ctx2 = cairo.Context(image)
ctx2.set_source_surface(recording)
ctx2.paint()
image.write_to_png("playback.png")import cairo
import io
# Create PDF in memory
pdf_buffer = io.BytesIO()
surface = cairo.PDFSurface.create_for_stream(pdf_buffer, 400, 300)
ctx = cairo.Context(surface)
# Draw content
ctx.set_source_rgb(0.8, 0.2, 0.2)
ctx.rectangle(50, 50, 100, 80)
ctx.fill()
surface.finish()
# Get PDF data
pdf_data = pdf_buffer.getvalue()
print(f"Generated PDF size: {len(pdf_data)} bytes")
# Write to file
with open("output_from_stream.pdf", "wb") as f:
f.write(pdf_data)Install with Tessl CLI
npx tessl i tessl/pypi-pycairo