{"record":{"id":"f5a873fc04f7543d","repo":"run-llama/liteparse","slug":"could-not-read-pixmap","errorCode":null,"errorMessage":"could not read pixmap","messagePattern":"could not read pixmap","errorType":"exception","errorClass":"std::io::Error","httpStatus":null,"severity":"error","filePath":"crates/liteparse/src/conversion.rs","lineNumber":649,"sourceCode":"            return Some((width, height, components));\n        }\n        i += seg_len;\n    }\n    None\n}\n\n/// Rasterizes an SVG file to RGBA8 bytes + dimensions using resvg.\nfn rasterize_svg(data: &[u8]) -> Result<(Vec<u8>, u32, u32), LiteParseError> {\n    let opt = Options::default();\n    let tree =\n        Tree::from_data(data, &opt).map_err(|e| LiteParseError::Conversion(e.to_string()))?;\n\n    let size = tree.size();\n    let width = size.width().ceil() as u32;\n    let height = size.height().ceil() as u32;\n\n    let mut pixmap = Pixmap::new(width.max(1), height.max(1))\n        .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, \"could not read pixmap\"))?;\n\n    resvg::render(\n        &tree,\n        resvg::tiny_skia::Transform::identity(),\n        &mut pixmap.as_mut(),\n    );\n\n    // tiny_skia's Pixmap stores premultiplied RGBA; un-premultiply so the\n    // PDF's separate RGB/SMask streams composite correctly.\n    let mut rgba = pixmap.data().to_vec();\n    for px in rgba.chunks_exact_mut(4) {\n        let a = px[3];\n        if a != 0 && a != 255 {\n            px[0] = ((px[0] as u16 * 255) / a as u16) as u8;\n            px[1] = ((px[1] as u16 * 255) / a as u16) as u8;\n            px[2] = ((px[2] as u16 * 255) / a as u16) as u8;\n        }\n    }","sourceCodeStart":631,"sourceCodeEnd":667,"githubUrl":"https://github.com/run-llama/liteparse/blob/22d2dd8cd7f7b9320102b57ddaf0e663ff7d15a8/crates/liteparse/src/conversion.rs#L631-L667","documentation":"In rasterize_svg, resvg parses the SVG into a scene tree and then allocates a tiny_skia Pixmap at the SVG's intrinsic size (ceil'd width/height, minimum 1px). Pixmap::new returns None only when allocation fails or the dimensions are beyond tiny-skia's limits (e.g. area exceeding i32::MAX or extreme width/height). LiteParse surfaces that as this InvalidData io::Error rather than panicking, so the caller (prepare_image) can fail conversion of the SVG gracefully.","triggerScenarios":"Calling parse on a PDF (or directly on an SVG) whose conversion path calls prepare_image -> rasterize_svg, where the SVG's tree.size() produces width/height whose product or individual values exceed Pixmap's allocation limits (effectively width*height > ~4 billion pixels or allocation failure).","commonSituations":"SVG files with gigantic viewBox dimensions (e.g. values like 100000x100000 or corrupt/malicious SVGs with huge size attributes); malformed SVG that resvg parses but for which it reports an absurd size; memory-constrained build/runtime environments where the large raster allocation fails.","solutions":["Open the SVG and check its width/height or viewBox attributes; clamp or reduce them to sane pixel dimensions (e.g. under 10000x10000) before parsing.","If the SVG lacks sane intrinsic dimensions, add explicit width/height attributes to the root <svg> element.","If the SVG is untrusted, sanitize/validate its dimensions before feeding it to LiteParse.","Increase available memory if the document is legitimately large, and retry."],"exampleFix":"// before: SVG with absurd intrinsic size\n<svg width=\"500000\" height=\"500000\" viewBox=\"0 0 500000 500000\">...</svg>\n\n// after: clamped to a reasonable raster size\n<svg width=\"2000\" height=\"2000\" viewBox=\"0 0 500000 500000\">...</svg>","handlingStrategy":"validation","validationCode":"// Rust: check SVG intrinsic size before conversion\nfn svg_dims_ok(svg: &[u8]) -> bool {\n    if let Ok(opts) = usvg::Options::parse(svg, &usvg::Options::default()) {\n        let s = usvg::Tree::from_xmlsvg(svg, &opts).map(|t| t.size());\n        matches!(s, Ok(sz) if sz.width() > 0.0 && sz.height() > 0.0\n            && (sz.width() * sz.height()) < 100_000_000.0)\n    } else { false }\n}","typeGuard":null,"tryCatchPattern":"match liteparse.parse(\"doc.pdf\") {\n    Ok(res) => use(res),\n    Err(e) if e.to_string().contains(\"could not read pixmap\") => {\n        // treat document as unsuitable for image conversion\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Sanitize SVG dimensions (width/height/viewBox) before parsing untrusted documents","Cap raster output size in your pipeline (e.g. max 10000x10000)","Fuzz-test the conversion path with extreme-size SVGs"],"tags":["svg","rasterization","image-conversion","memory-allocation"],"backgroundTag":"invalid-argument-value","analyzedSha":"22d2dd8cd7f7b9320102b57ddaf0e663ff7d15a8","analyzedAt":"2026-09-08T06:09:49.009Z","contentChangedAt":"2026-09-08T06:09:49.009Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}