Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Php Svg Lib Laravel Package

phenx/php-svg-lib

A lightweight PHP library for reading, parsing, and rendering SVG files. It handles paths, basic shapes, gradients, text, styles, and CSS, and is best known as the SVG engine behind Dompdf, letting PHP applications embed vector graphics in generated PDFs without external dependencies.

View on GitHub
Deep Wiki
Context7

Getting Started

Install it directly only if you need SVG parsing separate from a PDF engine — most projects get it transitively through dompdf/dompdf.

composer require phenx/php-svg-lib

Requires ext-dom and pulls in sabberworm/php-css-parser (for <style> blocks and style="") and phenx/php-font-lib (for text metrics). Read three files in this order, they are the whole mental model of the package:

  1. src/Surface/SurfaceInterface.php — the complete contract of drawing operations the library can emit. Everything else is just a producer of these calls.
  2. src/Surface/CPdf.php — the reference implementation (used by Dompdf). If you are writing your own backend, port this file method by method.
  3. src/Document.php and src/Node/ — parsing, node tree, style resolution.

First use case — render an SVG into a PDF and confirm the plumbing works:

use Svg\Document;
use Svg\Surface\CPdf; // bundled R&OS CPDF wrapper implementing SurfaceInterface

$doc = Document::load(__DIR__ . '/logo.svg');

// Only needed when the root uses percentages or has no units.
$doc->setWidth(200);
$doc->setHeight(100);

$surface = new CPdf([0, 0, 595, 842]); // verify constructor args in src/Surface/CPdf.php
$doc->render($surface);

file_put_contents('logo.pdf', $surface->output());

If that works, your next step is almost never "more features" — it's a logging surface (see below) so you can see exactly what the library asks of your backend.

Implementation Patterns

Write your own SurfaceInterface to target a new backend. This is the intended extension point. Map the calls to your engine's primitives: save/restore → q/Q (or gsave/grestore), transform → cm, moveTo/lineTo/curveTo/rectangle → m/l/c/re, fill/stroke/clip → f/S/W n, setFillColor/setStrokeColor → rg/RG, setFillAlpha/setStrokeAlpha → an ExtGState you allocate lazily, setFont+text → BT /Fn Tf Td Tj ET. Keep it thin; all SVG semantics (units, transforms, inheritance) are already resolved before you're called.

Decorator-over-reimplementation for debugging. Don't re-implement the interface from scratch just to inspect it — wrap the CPdf surface and log every call with its arguments. You will immediately see which <path> emits garbage coordinates, whether a gradient degrades to a solid color, and whether save/restore are balanced.

final class TracingSurface implements \Svg\Surface\SurfaceInterface
{
    public array $ops = [];
    public function __construct(private \Svg\Surface\SurfaceInterface $inner) {}

    public function moveTo($x, $y) { $this->ops[] = ['moveTo', $x, $y]; $this->inner->moveTo($x, $y); }
    // ...forward the rest verbatim, appending to $this->ops
}

Parse once, render many. Document::load() runs DOM parsing, CSS parsing, and style cascade — order of magnitude more expensive than render(). For icon sheets, map pins, or invoice logos rendered per page, memoize the Document keyed by md5_file($svg) and only create a fresh surface per target.

Handle sizing yourself. The library emits user units; it does not scale to a viewport. For predictable output, either pass absolute width/height via setWidth()/setHeight(), or ignore them entirely and call $surface->save(); $surface->translate(...); $surface->scale(...); around render() with a transform you compute from viewBox. Rasterizing at 96 DPI and 300 DPI produces the same op stream — the scale factor is your job.

Sanitize CSS upstream, not downstream. Inline presentation attributes and style="" are reliable; complex selectors, @media, custom properties, and calc() are largely ignored (silently). If a designer's export renders wrong, run it through SVGO/svgo-style flattening first so every property becomes a presentation attribute on the element.

Integrating with Dompdf: don't touch this package at all. Dompdf's Dompdf\Adapter\CPDF implements the surface. Instead, control it via Dompdf options — chroot and remote-asset settings govern whether <image href="..."> inside the SVG resolves, and base64 data URIs are the most portable way to embed raster art. Treat the Composer constraint as owned by Dompdf, not by you.

Gotchas and Tips

  • LGPL-3.0, not MIT. Fine as an unmodified Composer dependency; obligations appear if you fork and redistribute it, or bundle it into a distributed binary (Phar, desktop app, appliance image). Get a legal read before vendoring.
  • SurfaceInterface grows across majors. A backend written against 0.5 can fatal on 1.x when a method is added. Pin with a caret constraint, add a test that instantiates your surface class, and re-read SurfaceInterface on every minor bump. Prefer a decorator over a from-scratch implementation so upgrades surface at compile time rather than at render time.
  • Dompdf version coupling is the #1 real-world break. Dompdf pins a specific range here; forcing a different major to "get the newest SVG fix" breaks its adapter. Upgrade Dompdf, not this package.
  • Silent partial rendering. Malformed XML, a zero-size viewBox, or a width="100%" root without setWidth() typically yields a blank or clipped page rather than an exception. Wrap loads in libxml_use_internal_errors(true) and check libxml_get_errors(); after render(), assert your surface recorded at least one fill or stroke.
  • Untrusted SVGs are a security surface. You're handing arbitrary XML to DOM plus a backend that may fetch <image href> URLs — that's SSRF, plus potential local file disclosure if chroot-style restrictions aren't in place. Reject or rewrite external refs on upload; keep libxml_disable_entity_loader-era hardening in mind for old libxml.
  • Feature gaps to design around: filters (feGaussianBlur, feDropShadow) are not applied, mask and pattern support is weak, textPath is absent, text doesn't wrap or do full bidi, vector-effect and em/% font sizing are unreliable. Ask designers for SVGs without filters, or pre-flatten them with Inkscape/ImageMagick before they reach PHP.
  • Group opacity ≠ fill-opacity. Combined element opacity requires a transparency group in the backend; many custom surfaces just multiply fill alpha, which looks close but differs where strokes overlap. If visual parity matters, test overlapping semi-transparent shapes specifically.
  • Text metrics are the usual culprit for overlapping or clipped labels. The surface must supply real widths via getTextWidth() backed by actual font files (php-font-lib). If your PDF host lacks the font, sizes drift silently — embed fonts and test with the exact production font set.
  • Gradients are backend-dependent. The CPdf surface emits PDF shading patterns; naive surfaces only ever receive solid colors, so a gradient becomes a flat fill. Check src/Surface/CPdf.php for how LinearGradient/RadialGradient are dispatched before promising gradient fidelity to anyone.
  • Golden-op-stream tests beat pixel diffs. Record the surface calls for two or three representative SVGs and assert against a checked-in fixture. That's the fastest way to spot regressions after a Composer update, when nobody is looking at the icons.
  • Guard resource use. Large SVGs with hundreds of nodes cost real memory in DOM + CSS parse; enforce an upload size cap and, for user-supplied art, a node count sanity check before rendering.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource