Skip to content

Rendering

Rodrigo Agurto edited this page May 30, 2026 · 2 revisions

Rendering

SVG (default, no feature)

let svg: String = tk.render_to_svg(page)?;
// Buffer reuse
let mut buf = String::new();
tk.render_to_svg_into(page, &mut buf)?;
// Streaming-shape write into any io::Write
let mut file = std::fs::File::create("page.svg")?;
tk.render_to_svg_writer(page, &mut file)?;

Honest disclaimer: Verovio's C++ side allocates a full std::string per render. The _writer and _into variants save the caller's intermediate allocation but the C++ heap traffic persists. True streaming would need an upstream RenderToSVG(std::ostream&) overload.

Measure-range rendering

Render only a slice of measures (preserves layout for the slice):

let svg = tk.render_svg_measure_range(4, 8, "\n")?;

Internally: sets Verovio's measureFrom / measureTo options, redoes layout, renders the resulting pages, and restores prior options. Use for click-to-zoom UIs that want one bar at a time.

PNG (png feature)

let png: Vec<u8> = tk.render_to_png(page, 2.0)?;     // 2x scale (HiDPI)
let pngs: Vec<Vec<u8>> = tk.render_to_png_all_pages(1.0)?;
// Pure-function form for SVG you already have:
let png = verovio::raster::svg_to_png(&svg, 1.0)?;

PDF (pdf feature)

Per-page:

let pdf: Vec<u8> = tk.render_to_pdf(page)?;

Multi-page (single document with every page sized to its rendered SVG):

let pdf: Vec<u8> = tk.render_to_pdf_all_pages()?;

Implementation: each page's SVG is converted to a Form XObject via svg2pdf::to_chunk, renumbered against a unified ref allocator, and referenced from a Page with the right MediaBox. The result is a single proper PDF document.

// Pure-function form for a slice of SVG strings:
let pdf = verovio::raster::svgs_to_pdf(&svgs)?;

Layout setters

Convenience over set_options(json):

tk.set_font("Leland")?;            // SMuFL font swap
tk.set_scale(150)?;                // 150% scale (typed; no JSON round-trip)
tk.set_page_size(2100, 2970)?;     // dimensions in Verovio units
tk.set_breaks("smart")?;           // "auto" | "none" | "encoded" | "smart" | "line"
tk.set_landscape(true)?;           // swap page dimensions

Read one option without parsing the whole JSON document:

let scale = tk.option_value("scale").and_then(|v| v.as_u64());
// or, typed:
let scale = tk.scale();   // u32

Batched layout changes (LayoutOptions)

Chaining set_font / set_scale / set_page_size triggers one layout invalidation per call. For batch changes, use LayoutOptions — unset fields are omitted from the emitted JSON, so one call applies everything in a single layout pass:

use verovio::LayoutOptions;

tk.set_layout_options(&LayoutOptions {
    font: Some("Leland".into()),
    scale: Some(150),
    page_width: Some(2100),
    page_height: Some(2970),
    breaks: Some("smart".into()),
    ..Default::default()
})?;

Schema discovery + reset

For UIs that need to enumerate every option (CLI help generators, options-editor panels, pre-FFI validation):

let schema: serde_json::Value =
    serde_json::from_str(&tk.available_options()).unwrap();
// schema is the upstream `GetAvailableOptions` shape — grouped by
// category, with type / default / min / max per option.

Reset every option to its compile-time default:

tk.reset_options();

Cheap partial relayout

When only note vertical positions changed (e.g. accidental fine-tuning), skip the full horizontal layout pass:

tk.redo_page_pitch_pos_layout();

Available SMuFL fonts

for font in verovio_data::AVAILABLE_FONTS {
    println!("{font}");
}
// Bravura, Leipzig, Gootville, Leland, Petaluma

SVG theming

Embed CSS inside the rendered SVG with SvgOptions:

use verovio::SvgOptions;

let css = r#"
    svg { background: #fafaf5; }
    g.note { fill: #14213d; }
    g.note.playing { fill: #fca311; }
    g.measure line { stroke: #999; }
"#;

tk.set_svg_options(&SvgOptions {
    css: css.into(),
    ..Default::default()
})?;

Common CSS targets: note, notehead, stem, chord, rest, measure, staff, layer, beam, tie, slur, clef, keysig, metersig, barline.

For runtime highlighting, toggle a class (e.g. .playing) on the SVG <g> element from JS. The SVG IDs match the MEI IDs returned by Toolkit::timemap / verovio::lookup::sounding_at.

Per-track CSS generators (verovio::styling)

let staff_map = tk.staff_map()?;
let palette = &["#1f77b4", "#ff7f0e", "#2ca02c"];
let css = verovio::styling::stripe_tracks_by_id(&staff_map, palette);
tk.set_svg_options(&verovio::SvgOptions { css, ..Default::default() })?;
// Solo a single track visually by fading everything else:
let keep_ids = /* ids for the soloed track */ Vec::new();
let css = verovio::styling::fade_others(&keep_ids, "#888");

Clone this wiki locally