RecursiveAI.OnePdf.Layout draws SVG as native PDF vector content: paths, fills, strokes, shadings, clips, soft masks and real text. Nothing is rasterised except the pictures the SVG itself embeds. Core gains no SVG code; the code is in the layout package, over core's public content builder.
// In a layout: sized like an image (contain, cover, stretch, fit width, fit height, a DPI for the natural size). doc.Page(page => page.Content().Column(col => { col.Item().Width(120).Svg(File.ReadAllBytes("logo.svg")).Contain().AltText("Company logo"); })); // With the content builder (a canvas, a page overlay, a form). SvgImage logo = SvgImage.Parse(File.ReadAllBytes("logo.svg")); IReadOnlyList<string> notes = logo.Draw(builder, x: 40, y: 700, width: 120, height: 60); // or inside a canvas element: surface.DrawSvg(logo, 0, 0, surface.Width, surface.Height);
SvgImage.Parse(bytes | string, SvgLimits?)reads the document at once. A malformed or over-limit document throwsPdfFormatExceptionorPdfLimitExceptionthere, before layout.Width/Heightare the natural size in points (one CSS pixel is 0.75 pt),TitleandDescriptioncome from the root's<title>and<desc>.Drawreturns the notes (what was dropped or approximated), each once. In layout the notes go toLayoutDocument.Diagnostics.SvgPictureis the element (Slot.Svg(...)in the fluent API). It never splits across pages.- Text is shaped through OneFont with the layout's registered fonts, then the Liberation defaults, and is extractable (
/ToUnicodeas for layout text).SvgDrawOptions.Fontschooses the registry for a plain builder.
Tagging
A tagged layout document writes an SVG picture as a Figure. Alternate text is the author's AltText, else the SVG's <title>, else its <desc>. With none of them, and the picture not marked Artifact, layout records the same diagnostic as for an image and PDF/UA-1 saves refuse the document (checkpoint 13). A tagged PDF/UA-1 document with an SVG passes veraPDF's ua1 profile.
Supported
- Structure:
svg(nested too),g,defs,use,symbol,switch,a,viewBox,preserveAspectRatio,transform,transform-origin(also on gradients and patterns),display,visibility,overflow, rootbackground-color. - Shapes:
rect(with rounded corners),circle,ellipse,line,polyline,polygon,pathwith every command including arcs (arcs and quadratics become cubics). - Paint: colours (hex,
rgb(),hsl(), names,currentColor),fill-rule,fill-opacity,strokewidth, dash and offset, caps, joins, miter limit,stroke-opacity,paint-order,context-fill/context-stroke(a gradient or pattern keeps the context element's box and coordinate system), zero-length subpaths drawn as dots under round and square caps, the fallback colour after aurl()when the server cannot paint a shape with no size,opacity(group opacity through a transparency group),mix-blend-mode,isolation. - Paint servers: linear and radial gradients (with
hrefinheritance,gradientTransform, both unit systems,fx/fy/fr, stop opacity) as PDF shadings; patterns (patternUnits,patternContentUnits,patternTransform,viewBox); gradients and patterns on fills and on strokes. - Clipping and masks:
clipPath(units,transform,clip-pathon the element and on its children,clip-ruleper child, text children). A clip of one non-even-odd shape is a PDF clip path; a clip with text, nested clips or several shapes with even-odd rules is built as a luminosity soft mask instead,mask(luminance, nested) as PDF soft masks. - Markers: on
path,line,polyline,polygonand the basic shapes (rect,circle,ellipse);marker-start/mid/end,markerUnits,orient,refX/refY,viewBox. - Images:
data:URIs holding PNG or JPEG, through core's PNG reader and JPEG passthrough. - Text:
text,tspan,x/y/dx/dylists,text-anchor,font-family/size/weight/style,letter-spacing,word-spacing,text-decoration,baseline-shift,dominant-baseline(approximate), fill and stroke,direction/unicode-bidi. - CSS: presentation attributes, the
styleattribute and<style>sheets (type, class, id, attribute, descendant, child and sibling selectors, structural pseudo-classes such as:first-childand:nth-child(),:not(),!important) andinherit. CSS custom properties (var()) are not supported.
Approximations
spreadMethod="repeat"and"reflect"are unrolled into stops (up to 64 periods; beyond that the last band extends, with a note).- A stroke with a gradient whose stops have different opacities is drawn opaque (fills handle varying stop opacity with a soft mask).
- Patterns are drawn as repeated forms clipped to the shape (up to 4096 tiles per shape); on strokes they are PDF tiling patterns.
- Blend modes are PDF's; the backdrop is the page, which in a document is usually white.
hue,saturation,color,luminosityandplus-lighterare not mapped. - Gradients and patterns on text are drawn as one solid colour, with a note.
shape-renderingandimage-renderingare ignored (PDF viewers choose their own anti-aliasing and interpolation). Glyph positions and baselines can differ from a browser by a fraction of a point.
Dropped, never run, never fetched
Scripts, SMIL animation, event attributes, foreignObject, external references (files, URLs, other SVG files, use of another document) are dropped with a note. A filter draws the unfiltered content with a note (no filter is mapped). Also not drawn: textPath, tref, vertical writing, rotate and textLength on text, SVG or GIF/WebP data URIs inside an image. The XML reader refuses DTD entity expansion and external entities; nothing opens a file or a connection.
Limits
SvgLimits (all checked before the work they guard; a document over one fails with PdfLimitException): document bytes (32 MiB), elements (500,000), depth (256), attributes per element, names, namespace bindings, instantiated elements through use (500,000), use chain depth (32), layer depth (32), path segments (4,000,000), CSS bytes, rules and matching steps, data-URI image bytes (16 MiB each, 64 MiB together), text characters (1,000,000, counted again for each use copy). Element visits for bounding boxes share the instance bound. Gradient stops are capped at 250 and tiles at 4096 per shape. The svg fuzz target (fuzz/) runs the whole path.
Checked against
tools/OnePdf.Layout.SvgCompare renders each SVG twice: through a layout PDF (viewed by RecursiveAI.OneImage.Pdf) and directly by RecursiveAI.OneImage.Svg, both black boxes, and counts pixels that differ. A page passes when at most 0.5 % of its pixels differ by more than 32 levels. testdata/layout-svg/ holds our own sample files and testdata/layout-references/documents/svg.pdf a reference document.