SVG Test Page

PeachPDF renders SVG through its own vector scene graph, reusing the same PDF path/fill/stroke/gradient/clip primitives already used for CSS backgrounds and borders — SVG content is never rasterized to a bitmap. Full SVG 1.0 coverage is now supported (minus a handful of PDF-incompatible features such as animation, scripting, and filters): all basic shapes, fill-rule, stroke dash/cap/join, rotate()/skewX()/skewY() transforms, full preserveAspectRatio and nested viewports, objectBoundingBox/spreadMethod/currentColor gradients, the style cascade (style= and <style>), <switch>/<a> links, <marker>, <pattern>, <mask>, <image>, and <text>/<tspan>/<tref>. See supported-svg-features.md for the full compatibility matrix.

1 — Path Primitives: Lines, Curves & Arcs

straight lines (M/L/Z)
path d="M50,10 L90,90 L10,90 Z"
cubic Bézier (C)
path d="M10,80 C10,20 90,20 90,80"
elliptical arc (A)
path d="M10,60 A40,40 0 0 1 90,60"
multiple subpaths
one path, two "M...Z" subpaths

2 — circle & polygon

circle
circle cx=50 cy=50 r=35
polygon (pentagon)
polygon points="..."
overlapping circles + opacity
two circles, opacity="0.7" each
polygon (5-point star)
polygon points="..."

3 — Linear & Radial Gradients

linearGradient, 2 stops
linearGradient x1/y1/x2/y2, 2 stops
linearGradient, 3 stops
diagonal, 3 stops
radialGradient, centered
radialGradient cx/cy/r
radialGradient + gradientTransform
gradientTransform squishes the radial into an ellipse

4 — Stroke Properties

stroke only, default miterlimit
stroke-width=4 stroke-miterlimit=10
thick stroke, low miterlimit
stroke-width=10 stroke-miterlimit=1
fill + stroke combined
fill and stroke on the same shape
stroke-only star
fill="none" stroke="#c0392b"

5 — Group Opacity & Transforms

nested group opacity (0.7 × 0.7)
g opacity="0.7" > g opacity="0.7"
group transform: translate + scale
transform="translate(15,15) scale(0.6)"
horizontal mirror via scale(-1,1)
transform="scale(-1,1) translate(-100,0)"
use + per-instance transform
two <use> of the same <circle>, each transformed

6 — clipPath + use

clip-path references a <clipPath> that itself contains a <use> of a shape defined once in <defs> — the same pattern used by the peach illustrations below.

gradient clipped to a circle
clipPath > use > circle
gradient clipped to a star
clipPath > use > polygon
use for simple repetition
use xlink:href="#dot" x=.. y=..
clip + group opacity combined
g clip-path="url(#clip3)" opacity="0.8"

7 — Basic Shapes: rect, ellipse, line & polyline

rect with rounded corners
rect x y width height rx=15
ellipse (percentage rx)
ellipse rx="35%" (percentage length)
line, round linecap
line x1 y1 x2 y2 stroke-linecap="round"
polyline (open, unclosed)
polyline points="..." fill="none"

8 — Stroke: Dash Arrays, Caps & Joins

stroke-dasharray + dashoffset
stroke-dasharray="14,8" stroke-dashoffset="4"
stroke-linecap: butt/round/square
stroke-linecap: butt, round, square
stroke-linejoin: miter/round/bevel
stroke-linejoin: miter, round, bevel
dashed rounded-rect border
dasharray + linecap + linejoin combined

9 — Fill Rule & Opacity

fill-rule="nonzero" (default)
same-direction inner square: solid (no hole)
fill-rule="evenodd"
identical path, evenodd: donut (hole visible)
fill-opacity, stroke fully opaque
fill-opacity="0.4" (stroke unaffected)
stroke-opacity, fill fully opaque
stroke-opacity="0.4" (fill unaffected)

10 — Transforms: rotate() & skew()

rotate(angle, cx, cy)
transform="rotate(30,50,50)"
rotate(-angle, cx, cy)
transform="rotate(-45,50,50)"
skewX()
transform="skewX(20)"
skewY()
transform="skewY(-20)"

11 — Advanced Gradients: objectBoundingBox, spreadMethod & Radial Focus

objectBoundingBox (default)
no gradientUnits: x1/x2 are 0..1 fractions of the rect's own box
spreadMethod="repeat"
narrow x1..x2 range tiles across the rect
spreadMethod="reflect"
same idea, mirrored at each repeat
radial fx/fy off-center highlight
fx/fy offset from cx/cy: sphere-shading highlight

12 — preserveAspectRatio & Nested Viewports

default: xMidYMid meet
2:1 viewBox into a square box: letterboxed
xMidYMid slice
same viewBox, slice: cropped, fills the box
preserveAspectRatio="none"
stretched independently per axis: distorted
nested <svg>, own viewport
nested svg establishes its own coordinate system

13 — Style Cascade & currentColor

style= overrides presentation attribute
fill="red" style="fill:#2ecc71": style wins
currentColor
fill="currentColor" resolves the ancestor's CSS color
<style> class selector
.hi/.lo rules, via <img> (see note below)
<style> id selector
#target rule, via <img> (see note below)

Note: a <style> element nested inside an inline <svg> has a known limitation in PeachPDF's HTML tokenizer, so the two <style> swatches above use the standalone <img src="data:image/svg+xml"> path, which is unaffected — see supported-svg-features.md.

14 — <switch> & <a> Links

switch: first child wins
no requiredFeatures evaluation: always shows child 1
ignored
switch: skips an unbuildable child
<metadata> isn't renderable, so child 2 is used
<a href>: real PDF link
becomes a clickable PDF link annotation
<a> with no href
renders children normally, just isn't a link

15 — Markers

marker-end, orient="auto"
marker rotates to follow the path's tangent
marker-start/mid/end on every vertex
one marker def, placed at start/mid/end vertices
markerUnits="strokeWidth" (default)
same marker, scales with each line's own stroke-width
orient: fixed angle
orient="45": same fixed rotation at every vertex

16 — Pattern Fill

checkerboard
pattern of 4 <rect> tiles, patternUnits="userSpaceOnUse"
polka dots
dot pattern clipped to the circle's own geometry
patternTransform="rotate(45)"
stripe tile rotated 45° via patternTransform
pattern filling a star shape
pattern respects the star's own fill geometry

17 — Mask

linear-gradient luminance fade
gradient mask fades the purple rect over a yellow backdrop
radial vignette
radial mask: spotlight/vignette fade
vector shape as mask
a shape, not just a gradient, as the mask's luminance
PDF
<text> as mask content
gradient shows only through the letter shapes

18 — <image> Element

raster data:image/png
a real embedded raster image XObject
vector data:image/svg+xml
stays real vector content, never rasterized
preserveAspectRatio="none" on <image>
raster image stretched non-uniformly to fit its box
<image> with clip-path
clip-path applies to <image> like any other element

19 — Text, tspan & tref

Peach
<text x y fill font-size>
plain positioned text, baseline at (x, y)
startmiddleend
text-anchor: start/middle/end
all three anchored at x=50 (dashed guideline)
Hello World
<tspan> restyles mid-run
tspan flows right after "Hello ", own fill+weight
BoldItalicRegular
<tspan x y>: new line + font variety
own x/y starts a new line; size/weight/style vary

20 — Inline <svg> vs <img src="data:image/svg+xml">

The identical SVG markup rendered two ways: embedded directly in the HTML, and encoded as a base64 data: URI on an <img> tag. Both go through the same vector renderer.

inline <svg>
<svg>...</svg> inline in the HTML body
<img src="data:...">
same markup, base64 data: URI

21 — Peach Showcase

Two original peach illustrations, built entirely from the elements above: cubic-curve paths, radial gradients for shading, and a clipPath + use for the cross-section.

Whole Peach

path (M/C/Z) body + leaf + stroked stem, radialGradient shading, radial blush with alpha stops

Peach Slice

clipPath + use round the flesh, opacity-grouped striations, pit path, use for the skin outline

Prunus persica

Peach Branch & Blossoms

<marker> blossoms/leaf tip along a curved branch, italic <text> caption

Peach Basket

pattern-woven basket, rotate() on individual peaches, gradient drop-shadow via mask