mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-25 18:27:02 -06:00
SVG import: read the text once for the prepass's markers, with the data URLs left out
The prepass decided what to look for in the tree by a dozen substring searches over the whole SVG text (`:not(`, the event attributes, `script`, `transform:` and nine more), and a separate pass counted the elements' depth before roxmltree. With an embedded picture the text is mostly its data URL: a 1.35 MB card SVG (a 968 KB PNG) paid about 7 ms of searches and 1 ms of depth scan per import, on a 64 ms render, and a 54-page PDF export 54 times that. `depth::prescan` is the one pass: it counts the depth as `xml_too_deep` did (the DOCTYPE entity count included) and, in the same walk, notes every `data:` attribute value, answering the text with those values left out, their quotes kept. The prepass and `fx::blends` search that text; the edits are still made in the source. A data URL can hold no tag, attribute name, selector or CSS declaration, and everything else, a `style="display:none"` included, is kept, so what is found is what was found before. `vectorcraft-cli perf --deep` gains a tracked row, "import SVG, one embedded PNG", beside the export row it had. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
committed by
bflatastic
co-authored by
Claude Fable 5.1
parent
48792842ec
commit
5b919c0529
@@ -23,13 +23,16 @@ impl Rng {
|
||||
}
|
||||
}
|
||||
|
||||
/// The synthetic document's page, in points.
|
||||
const SYNTHETIC_PAGE: (f64, f64) = (1600.0, 1200.0);
|
||||
|
||||
/// `n` mixed paths (ellipses with strokes, translucent rectangles, stroked stars) on a 1600×1200 page.
|
||||
pub fn synthetic(n: usize) -> Result<Document, String> {
|
||||
let mut d = Document::new(1600.0, 1200.0);
|
||||
let mut d = Document::new(SYNTHETIC_PAGE.0, SYNTHETIC_PAGE.1);
|
||||
let l = d.layers.first().map(|l| l.id);
|
||||
let mut r = Rng(42);
|
||||
for i in 0..n {
|
||||
let (x, y, s) = (r.next() * 1600.0, r.next() * 1200.0, 3.0 + r.next() * 22.0);
|
||||
let (x, y, s) = (r.next() * SYNTHETIC_PAGE.0, r.next() * SYNTHETIC_PAGE.1, 3.0 + r.next() * 22.0);
|
||||
let c = Color::rgb(r.next() as f32, r.next() as f32, r.next() as f32);
|
||||
let id = d.alloc_id();
|
||||
let mut node = match i % 3 {
|
||||
@@ -296,6 +299,23 @@ fn deep(n: usize) -> Result<(), String> {
|
||||
rows.push(("render 4 embedded 24 MP photos with 3 renderers (cold)".into(), ms));
|
||||
note("after rendering the photos with 3 renderers");
|
||||
}
|
||||
// An SVG with one embedded picture opened from its text, as picture-heavy SVGs come: the
|
||||
// importer's passes over the text before usvg reads it, most of which is the data URL. The
|
||||
// picture is the synthetic page drawn at 1.25x (about a megabyte as a PNG, the size at which
|
||||
// the passes were measured); the hidden rectangle is a marker, so the prepass walks the tree
|
||||
// as it does for a file that has one, instead of returning at its first check.
|
||||
{
|
||||
let k = 1.25;
|
||||
let (w, h) = ((SYNTHETIC_PAGE.0 * k).round() as u32, (SYNTHETIC_PAGE.1 * k).round() as u32);
|
||||
let photo = Renderer::new().render(&synthetic(3000)?, w, h, Affine::scale(k), &opts).to_png()?;
|
||||
let data = vectorcraft_svg::base64_encode(&photo);
|
||||
let svg = format!(
|
||||
r#"<svg xmlns="http://www.w3.org/2000/svg" width="{w}" height="{h}"><image width="{w}" height="{h}" href="data:image/png;base64,{data}"/><rect width="100" height="100" style="display:none"/></svg>"#
|
||||
);
|
||||
let ms = median_ms(5, || drop(vectorcraft_svg::import_with_report(&svg)));
|
||||
rows.push((format!("import SVG, one embedded {} KB PNG", photo.len() / 1024), ms));
|
||||
note("after the import of an embedded picture");
|
||||
}
|
||||
// Output hashes, to compare builds: the SVG export and a save → open → save round trip.
|
||||
let fnv = |b: &[u8]| b.iter().fold(0xcbf2_9ce4_8422_2325u64, |h, &x| (h ^ u64::from(x)).wrapping_mul(0x100_0000_01b3));
|
||||
let doc = synthetic(n)?;
|
||||
|
||||
Reference in New Issue
Block a user