mathiasreker / php-svg-optimizer
php-svg-optimizer is a PHP library designed to optimize SVG files by applying various transformations and cleanup operations.
Requires
- php: ^8.3
- ext-dom: *
- ext-libxml: *
- ext-mbstring: *
Requires (Dev)
- brainbits/phpstan-rules: ^4.0
- ergebnis/composer-normalize: ^2.54
- ergebnis/phpstan-rules: ^2.14
- friendsofphp/php-cs-fixer: ^3.95
- hiperdk/phpstan-rules: ^1.0
- infection/infection: ^0.35
- kubawerlos/php-cs-fixer-custom-fixers: ^3.37
- marc-mabe/php-enum-phpstan: ^3.0
- odan/phpstan-rules: ^0.2
- phpstan/extension-installer: ^1.4
- phpstan/phpstan: ^2.3
- phpstan/phpstan-deprecation-rules: ^2.0
- phpstan/phpstan-mockery: ^2.0
- phpstan/phpstan-phpunit: ^2.1
- phpstan/phpstan-strict-rules: ^2.1
- phpunit/php-code-coverage: ^12.5
- phpunit/phpunit: ^12.5
- povils/phpmnd: ^3.6
- rector/rector: ^2.7
- shipmonk/composer-dependency-analyser: ^1.8
- shipmonk/phpstan-rules: ^4.4
- spaze/phpstan-disallowed-calls: ^4.14
- squizlabs/php_codesniffer: ^4.0
- symfony/var-dumper: ^7.4
- symplify/phpstan-rules: ^14.18
- tomasvotruba/cognitive-complexity: ^1.3
- tomasvotruba/type-coverage: ^2.5
- voku/phpstan-rules: ^3.7
Suggests
None
Provides
None
Conflicts
None
Replaces
None
- dev-develop
- 9.0.0
- 8.7.1
- 8.7.0
- 8.6.0
- 8.5.9
- 8.5.8
- 8.5.7
- 8.5.6
- 8.5.5
- 8.5.4
- 8.5.3
- 8.5.2
- 8.5.1
- 8.5.0
- 8.4.1
- 8.4.0
- 8.3.1
- 8.3.0
- 8.2.6
- 8.2.5
- 8.2.4
- 8.2.3
- 8.2.2
- 8.2.1
- 8.2.0
- 8.1.0
- 8.0.3
- 8.0.2
- 8.0.1
- 8.0
- 7.3.0
- 7.2.0
- 7.1.4
- 7.1.3
- 7.1.2
- 7.1.1
- 7.1.0
- 7.0.4
- 7.0.3
- 7.0.2
- 7.0.1
- 7.0.0
- 6.0.4
- 6.0.3
- 6.0.2
- 6.0.1
- 6.0.0
- 5.3.5
- 5.3.4
- 5.3.3
- 5.3.1
- 5.3.0
- 5.2.8
- 5.2.7
- 5.2.6
- 5.2.5
- 5.2.4
- 5.2.3
- 5.2.2
- 5.2.1
- 5.2.0
- 5.1.2
- 5.1.1
- 5.1.0
- 5.0.3
- 5.0.2
- 5.0.1
- 5.0.0
- 4.1.0
- 4.0.5
- 4.0.3
- 4.0.2
- 4.0.0
- 3.0.5
- 3.0.4
- 3.0.3
- 3.0.2
- 3.0.1
- 3.0.0
- 2.0.1
- 2.0.0
- 1.0.5
- 1.0.4
- 1.0.3
- 1.0.2
- 1.0.0
This package is auto-updated.
Last update: 2026-10-13 15:49:01 UTC
README
php-svg-optimizer is a lightweight PHP library designed to optimize, minify, and sanitize SVG files.
It applies various transformations and cleanup operations while ensuring compliance with SVG 2.0 specifications.
The resulting SVGs remain visually identical to the original but are smaller, cleaner, and safer.
Versions & Dependencies
| Version | PHP | Documentation |
|---|---|---|
| ^9.0 | ^8.3 | current |
| ^8.7 | ^8.3 | v8 |
Requirements
ext-dom: Required PHP extension for XML handling.ext-libxml: Required PHP extension for XML error handling.ext-mbstring: Required PHP extension for multibyte string handling.
Installation
To install the library, run:
composer require mathiasreker/php-svg-optimizer
Using the Library
You can use this library in two main ways:
- Command-Line Interface (CLI): Run the optimizer directly from your terminal to process SVG files quickly. This is ideal for batch processing or integrating into build scripts.
- Standalone Package: Use it as a PHP package in your project to optimize SVGs programmatically. This allows you to integrate SVG optimization directly into your application workflow or custom scripts.
CLI tool
vendor/bin/svg-optimizer [options] process <path1> <path2> ...
Options: -h , --help Display help for the command. -c , --config Path to a JSON file, or a raw JSON string, with the optimization rules to enable. Without --config and --with-all-rules, no rules are applied. -d , --dry-run Only calculate potential savings without modifying the files. -r , --allow-risky Explicitly enables risky rules, allowing them to be applied. -a , --with-all-rules Enable all non-risky rules. Use --allow-risky to include risky rules as well. -q , --quiet Suppress all output except errors. -v , --version Display the version of the library. --ansi Force ANSI color output, even when output is not an interactive terminal. --no-ansi Disable ANSI color output. Commands: Process Provide a list of directories or files to process.
Options can be placed anywhere before a -- argument; everything after -- is treated as a path. The value of
--config (-c) can be given as --config=value or --config value.
Errors are written to stderr, also with --quiet. The command exits with code 1 if the arguments or the
configuration are invalid, or if any file could not be optimized, and with code 0 otherwise.
Examples:
vendor/bin/svg-optimizer --with-all-rules --dry-run process /path/to/svgs
vendor/bin/svg-optimizer --config=config.json process /path/to/file.svg
vendor/bin/svg-optimizer --config='{"removeInkscapeFootprints": true}' process /path/to/file.svg
vendor/bin/svg-optimizer --quiet --with-all-rules process /path/to/file.svg
vendor/bin/svg-optimizer --with-all-rules --allow-risky process /path/to/file.svg
vendor/bin/svg-optimizer --with-all-rules process /path/to/file.svg
Config file example:
{
"convertColorsToHex": true,
"convertCssClassesToAttributes": true,
"convertEllipseToCircle": true,
"convertEmptyTagsToSelfClosing": true,
"convertInlineStylesToAttributes": true,
"convertOneStopGradients": true,
"convertShapesToPath": true,
"fixAttributeNames": false,
"flattenGroups": true,
"minifyListValues": true,
"minifyNumericValues": true,
"minifyPathData": true,
"minifySvgCoordinates": true,
"minifyTransformations": true,
"removeAriaAndRole": true,
"removeComments": true,
"removeDataAttributes": false,
"removeDefaultAttributes": true,
"removeDeprecatedAttributes": true,
"removeDoctype": true,
"removeDuplicateElements": true,
"removeEmptyAttributes": true,
"removeEmptyContainers": true,
"removeEmptyGroups": true,
"removeEmptyTextElements": true,
"removeEnableBackgroundAttribute": false,
"removeInkscapeFootprints": true,
"removeInvisibleCharacters": true,
"removeMetadata": true,
"removeNonStandardAttributes": false,
"removeNonStandardTags": false,
"removeStyleTypeAttributes": true,
"removeTitleAndDesc": true,
"removeUnnecessaryWhitespace": true,
"removeUnsafeElements": false,
"removeUnusedIds": false,
"removeUnusedMasks": true,
"removeUnusedNamespaces": true,
"removeUselessDefs": true,
"removeWidthHeightAttributes": false,
"removeXmlSpaceDefault": true,
"removeZeroSizeShapes": true,
"scopeSvgStyles": false,
"sortAttributes": true
}
Each value must be the JSON boolean true or false; any other value, such as "false" or 0, is reported as an
error. Rules that are left out are not applied.
Example Workflow for GitHub Actions
name: Optimize SVGs on: [ push, pull_request ] jobs: run-optimizer: runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 - uses: shivammathur/setup-php@v2 with: php-version: '8.5' - run: composer install --no-dev --optimize-autoloader --no-interaction --no-progress - run: php vendor/bin/svg-optimizer -a -q process /path/to/svgs
Package
It is recommended to catch exceptions when using this library. Doing so ensures that your application can handle unexpected input gracefully and avoid unintended crashes. Every exception thrown by the library implements
MathiasReker\PhpSvgOptimizer\Contract\Exception\SvgOptimizerExceptionInterface, so you can catch them all at once.
Example specifying rules
<?php declare(strict_types=1); require_once __DIR__ . '/vendor/autoload.php'; use MathiasReker\PhpSvgOptimizer\Service\Facade\SvgOptimizerFacade; try { $svgOptimizer = SvgOptimizerFacade::fromFile('path/to/source.svg') ->withRules( convertColorsToHex: true, convertCssClassesToAttributes: true, convertEllipseToCircle: true, convertEmptyTagsToSelfClosing: true, convertInlineStylesToAttributes: true, convertOneStopGradients: true, convertShapesToPath: true, fixAttributeNames: false, flattenGroups: true, minifyListValues: true, minifyNumericValues: true, minifyPathData: true, minifySvgCoordinates: true, minifyTransformations: true, removeAriaAndRole: true, removeComments: true, removeDataAttributes: false, removeDefaultAttributes: true, removeDeprecatedAttributes: true, removeDoctype: true, removeDuplicateElements: true, removeEmptyAttributes: true, removeEmptyContainers: true, removeEmptyGroups: true, removeEmptyTextElements: true, removeEnableBackgroundAttribute: false, removeInkscapeFootprints: true, removeInvisibleCharacters: true, removeMetadata: true, removeNonStandardAttributes: false, removeNonStandardTags: false, removeStyleTypeAttributes: true, removeTitleAndDesc: true, removeUnnecessaryWhitespace: true, removeUnsafeElements: false, removeUnusedIds: false, removeUnusedMasks: true, removeUnusedNamespaces: true, removeUselessDefs: true, removeWidthHeightAttributes: false, removeXmlSpaceDefault: true, removeZeroSizeShapes: true, scopeSvgStyles: false, sortAttributes: true, ) ->optimize() ->saveToFile('path/to/output.svg'); } catch (\Exception $exception) { echo $exception->getMessage(); }
Example parsing from a file and saving to a file using default rules
<?php declare(strict_types=1); require_once __DIR__ . '/vendor/autoload.php'; use MathiasReker\PhpSvgOptimizer\Service\Facade\SvgOptimizerFacade; try { $svgOptimizer = SvgOptimizerFacade::fromFile('path/to/source.svg') ->withAllRules() ->optimize() ->saveToFile('path/to/output.svg'); $metaData = $svgOptimizer->getMetaData(); echo sprintf('Optimized size: %d bytes%s', $metaData->getOptimizedSize(), \PHP_EOL); echo sprintf('Original size: %d bytes%s', $metaData->getOriginalSize(), \PHP_EOL); echo sprintf('Size reduction: %d bytes%s', $metaData->getSavedBytes(), \PHP_EOL); echo sprintf('Reduction percentage: %s %%%s', $metaData->getSavedPercentage(), \PHP_EOL); echo sprintf('Processing time: %s seconds%s', $metaData->getOptimizationTime(), \PHP_EOL); } catch (\Exception $exception) { echo $exception->getMessage(); }
Example parsing from a file and returning the content using default rules
<?php declare(strict_types=1); require_once __DIR__ . '/vendor/autoload.php'; use MathiasReker\PhpSvgOptimizer\Service\Facade\SvgOptimizerFacade; try { $svgOptimizer = SvgOptimizerFacade::fromFile('path/to/source.svg') ->withAllRules() ->optimize(); echo sprintf('Get content: %s%s', $svgOptimizer->getContent(), \PHP_EOL); $metaData = $svgOptimizer->getMetaData(); echo sprintf('Optimized size: %d bytes%s', $metaData->getOptimizedSize(), \PHP_EOL); echo sprintf('Original size: %d bytes%s', $metaData->getOriginalSize(), \PHP_EOL); echo sprintf('Size reduction: %d bytes%s', $metaData->getSavedBytes(), \PHP_EOL); echo sprintf('Reduction percentage: %s %%%s', $metaData->getSavedPercentage(), \PHP_EOL); echo sprintf('Processing time: %s seconds%s', $metaData->getOptimizationTime(), \PHP_EOL); } catch (\Exception $exception) { echo $exception->getMessage(); }
Example parsing from a string and returning the content using default rules
<?php declare(strict_types=1); require_once __DIR__ . '/vendor/autoload.php'; use MathiasReker\PhpSvgOptimizer\Service\Facade\SvgOptimizerFacade; try { $svgOptimizer = SvgOptimizerFacade::fromString('<svg>...</svg>') ->withAllRules() ->optimize(); echo sprintf('Content: %s%s', $svgOptimizer->getContent(), \PHP_EOL); $metaData = $svgOptimizer->getMetaData(); echo sprintf('Optimized size: %d bytes%s', $metaData->getOptimizedSize(), \PHP_EOL); echo sprintf('Original size: %d bytes%s', $metaData->getOriginalSize(), \PHP_EOL); echo sprintf('Size reduction: %d bytes%s', $metaData->getSavedBytes(), \PHP_EOL); echo sprintf('Reduction percentage: %s %%%s', $metaData->getSavedPercentage(), \PHP_EOL); echo sprintf('Processing time: %s seconds%s', $metaData->getOptimizationTime(), \PHP_EOL); } catch (\Exception $exception) { echo $exception->getMessage(); }
Example applying risky rules
<?php declare(strict_types=1); require_once __DIR__ . '/vendor/autoload.php'; use MathiasReker\PhpSvgOptimizer\Service\Facade\SvgOptimizerFacade; try { $svgOptimizer = SvgOptimizerFacade::fromFile('path/to/source.svg') ->withRules( removeDataAttributes: true, removeEnableBackgroundAttribute: true, removeUnusedIds: true, removeWidthHeightAttributes: true, scopeSvgStyles: true, ) ->allowRisky() ->optimize() ->saveToFile('path/to/output.svg'); echo sprintf('Content: %s%s', $svgOptimizer->getContent(), \PHP_EOL); $metaData = $svgOptimizer->getMetaData(); echo sprintf('Optimized size: %d bytes%s', $metaData->getOptimizedSize(), \PHP_EOL); echo sprintf('Original size: %d bytes%s', $metaData->getOriginalSize(), \PHP_EOL); echo sprintf('Size reduction: %d bytes%s', $metaData->getSavedBytes(), \PHP_EOL); echo sprintf('Reduction percentage: %s %%%s', $metaData->getSavedPercentage(), \PHP_EOL); echo sprintf('Processing time: %s seconds%s', $metaData->getOptimizationTime(), \PHP_EOL); } catch (\Exception $exception) { echo $exception->getMessage(); }
Security: Sanitizing Untrusted SVGs
When accepting SVG uploads from users or other untrusted sources, it is critical to sanitize them to prevent Cross-Site Scripting (XSS) attacks. Malicious SVGs can contain scripts, event handlers, or external references that can execute code in the user's browser.
The php-svg-optimizer provides a powerful set of rules to mitigate these risks. The most important rule is
removeUnsafeElements, which strips out known dangerous tags and attributes. For a stricter policy, you can combine it
with removeNonStandardTags and removeNonStandardAttributes.
<?php declare(strict_types=1); require_once __DIR__ . '/vendor/autoload.php'; use MathiasReker\PhpSvgOptimizer\Service\Facade\SvgOptimizerFacade; try { $svgOptimizer = SvgOptimizerFacade::fromFile('path/to/source.svg') ->withRules( removeNonStandardAttributes: true, removeNonStandardTags: true, removeUnsafeElements: true, ) ->optimize() ->saveToFile('path/to/output.svg'); } catch (\Exception $exception) { echo $exception->getMessage(); }
Documentation
SvgOptimizerFacade
Static factory method to create SvgOptimizerFacade from a file path.
$svgOptimizer = SvgOptimizerFacade::fromFile('path/to/source.svg');
Static factory method to create SvgOptimizerFacade from a string.
$svgOptimizer = SvgOptimizerFacade::fromString('<svg>...</svg>');
withRules
Configure which SVG optimization rules to apply. The method accepts boolean parameters that determine whether specific rules should be enabled or disabled.
$svgOptimizer->withRules();
Rules always run in the same order, whatever order they are enabled in: untrusted content is sanitized first, styles
are turned into attributes before attributes are cleaned up, and values are minified before shapes are converted, so
optimizing an optimized file again leaves it (almost always) unchanged. A rule enabled more than once, for example with
both withAllRules() and withRules(), runs once.
Parameters
Below is a detailed description of each available optimization rule. Each rule focuses on either reducing file size, improving consistency, modernizing SVG output, or increasing security. Some rules are marked risky, meaning they may alter behavior or semantics in certain use cases and should be enabled with care.
convertColorsToHex
Normalizes color definitions to their shortest exact notation. Functional formats (such as rgb() or rgba()) are
converted to hexadecimal, #aabbcc is shortened to #abc, and a CSS color name and its hexadecimal value are swapped
when the other form is shorter (for example #ff0000 becomes red and white becomes #fff). currentColor,
transparent, none and url() references are left as they are.
$svgOptimizer->withRules(convertColorsToHex: true);
convertCssClassesToAttributes
Replaces CSS class-based styling with equivalent inline SVG attributes on each affected element.
$svgOptimizer->withRules(convertCssClassesToAttributes: true);
convertEllipseToCircle
Converts <ellipse> elements whose rx and ry are equal into <circle> elements with a single r. The radius is
copied as written, so no value is recalculated. Ellipses with child elements, a style attribute, or in a document
with a <style> element are kept.
$svgOptimizer->withRules(convertEllipseToCircle: true);
convertEmptyTagsToSelfClosing
Converts elements without child nodes into self-closing tags. This simplifies the markup structure and reduces unnecessary characters, resulting in cleaner and more compact SVG output without affecting rendering.
$svgOptimizer->withRules(convertEmptyTagsToSelfClosing: true);
convertInlineStylesToAttributes
Extracts individual style declarations from inline style attributes and converts them into their corresponding SVG
presentation attributes. This improves compatibility with SVG renderers and tooling that do not fully support CSS
styling, and makes attribute-level optimizations more effective downstream.
$svgOptimizer->withRules(convertInlineStylesToAttributes: true);
convertOneStopGradients
Replaces a gradient that has a single <stop> with that stop's color where it is used as a fill or stroke, and
removes the gradient. Gradients referenced in any other way, stops with an opacity, a style or a color that is not a
plain hex or named color, and documents with a <style> or <script> element are left untouched. A gradient in object
bounding box units is only replaced on rects, circles and ellipses, as it is not rendered on, for example, a straight
line.
$svgOptimizer->withRules(convertOneStopGradients: true);
convertShapesToPath
Converts <rect>, <line>, <polyline> and <polygon> elements into <path> elements when that makes the file
smaller. The path data reuses the original numbers (a rect is drawn with relative moves), so no coordinate is
recalculated or rounded. Rounded rects, values with units, points lists that are invalid or have an odd number of
coordinates, shapes with child elements or a style attribute, and documents with a <style> or <marker> element
are kept as they are.
$svgOptimizer->withRules(convertShapesToPath: true);
fixAttributeNames
Normalizes SVG attribute names to their canonical, specification-compliant casing and hyphenation. Attribute names are matched against a known set of valid SVG attributes and corrected where case differences or missing hyphens occur. This improves standards compliance, avoids duplicate or conflicting attributes, and ensures consistent output across different SVG sources and editors.
$svgOptimizer->withRules(fixAttributeNames: true);
flattenGroups
Removes unnecessary nested <g> (group) elements by moving their child elements directly into the parent group. This
reduces DOM depth, simplifies the SVG structure, and can marginally reduce file size while preserving visual output.
$svgOptimizer->withRules(flattenGroups: true);
minifyListValues
Shortens the notation of number lists such as viewBox, points, stroke-dasharray, keyTimes and the values of
numeric animations. Numbers are shortened without rounding and lists use the fewest separators the attribute allows.
Values with units, percentages or keywords are left untouched.
$svgOptimizer->withRules(minifyListValues: true);
minifyNumericValues
Shortens the notation of single-number attribute values such as opacity, stroke-width, x or font-size:
leading and trailing zeros and a + sign are dropped, and px is removed from lengths, as one pixel equals one user
unit. px is kept where the attribute is a plain number on that element (such as dx/dy on <feOffset> or x/y
on <fePointLight>), and integer attributes such as numOctaves are only shortened when written as plain integers.
Only the notation changes; values are never rounded.
$svgOptimizer->withRules(minifyNumericValues: true);
minifyPathData
Rewrites path data (d) in its shortest equivalent form: repeated command letters and unneeded separators are
dropped, number literals are shortened, and relative linetos along one axis become h/v. Coordinates are never
recalculated or rounded, and path data that is not valid is left untouched.
$svgOptimizer->withRules(minifyPathData: true);
minifySvgCoordinates
Shortens the number literals in coordinates, path data, points, viewBox and enable-background without changing
their values. Leading and trailing zeros, redundant decimal points, explicit plus signs and zero exponents are removed,
and a separator is kept wherever two numbers would otherwise merge. Values that cannot be tokenized safely are left
untouched.
$svgOptimizer->withRules(minifySvgCoordinates: true);
minifyTransformations
Shortens transform, gradientTransform and patternTransform values without recalculating them: numbers and
separators are written in their shortest form, identity transformations such as translate(0), scale(1) and
rotate(0) are removed, default arguments are dropped (translate(10 0) becomes translate(10)), and a matrix that
only translates or scales is written as translate() or scale(). An identity gradientTransform or
patternTransform on an element with href or xlink:href is kept (as scale(1) when shorter), since removing it
would inherit the transform of the referenced element. Values that do not parse as a transform list are left untouched.
$svgOptimizer->withRules(minifyTransformations: true);
removeAriaAndRole
Removes ARIA (aria-*) and role attributes that are often unnecessary in static or decorative SVGs. This reduces file
size and avoids redundant accessibility metadata when SVGs are not intended to be interactive or exposed to assistive
technologies.
$svgOptimizer->withRules(removeAriaAndRole: true);
removeComments
Deletes all non-essential XML comments from the SVG document, excluding legally required comments if applicable. This eliminates developer notes and editor artifacts that do not affect rendering, reducing file size.
$svgOptimizer->withRules(removeComments: true);
removeDataAttributes (risky)
Removes all data-* attributes from elements. These attributes are often used for application-specific metadata or
scripting hooks; removing them can significantly reduce file size but may break integrations or runtime behavior that
relies on them.
$svgOptimizer->withRules(removeDataAttributes: true)->allowRisky();
removeDefaultAttributes
Eliminates attributes whose values match SVG specification defaults and therefore do not affect rendering. By omitting redundant information, this rule reduces clutter and minimizes output size while preserving visual correctness.
$svgOptimizer->withRules(removeDefaultAttributes: true);
removeDeprecatedAttributes
Removes attributes that are deprecated or obsolete according to modern SVG specifications. This helps modernize SVG output, improves forward compatibility, and reduces reliance on legacy behavior.
$svgOptimizer->withRules(removeDeprecatedAttributes: true);
removeDoctype
Removes the <!DOCTYPE> declaration from the SVG document. This is typically unnecessary for inline SVGs or SVGs
embedded in HTML and slightly reduces file size.
$svgOptimizer->withRules(removeDoctype: true);
removeDuplicateElements
Detects and removes identical duplicate elements that do not contribute additional visual output. This reduces
redundancy in the SVG structure and helps minimize file size without altering appearance. Nothing is removed when a
style sheet uses sibling combinators or structural pseudo-classes (such as g + rect or :nth-child()), whose matches
depend on the surrounding elements.
$svgOptimizer->withRules(removeDuplicateElements: true);
removeEmptyAttributes
Removes attributes that have empty values. Such attributes add noise to the markup without affecting rendering and can
safely be removed to produce cleaner output. Empty conditional processing attributes (systemLanguage,
requiredExtensions, requiredFeatures), which keep an element from rendering, and attributes on elements outside the
SVG namespace, such as <foreignObject> content, are kept.
$svgOptimizer->withRules(removeEmptyAttributes: true);
removeEmptyContainers
Removes container elements such as <defs>, <g>, <symbol>, <mask>, <clipPath>, <pattern>, <marker> and
<switch> when they have no content and no id. Containers that become empty are removed as well. Groups with a
filter are kept, as a filter can paint on its own. Nothing is removed when a style sheet uses sibling combinators or
structural pseudo-classes (such as g + rect or :nth-child()), whose matches depend on the surrounding elements.
$svgOptimizer->withRules(removeEmptyContainers: true);
removeEmptyGroups
Deletes <g> elements that have no attributes and do not contain any child elements, text or comments. This simplifies
the DOM tree and removes unnecessary structural nodes. removeEmptyContainers applies the same clean-up to more
container types and also removes empty groups that carry attributes other than id and filter. Nothing is removed
when a style sheet uses sibling combinators or structural pseudo-classes (such as g + rect or :nth-child()), whose
matches depend on the surrounding elements.
$svgOptimizer->withRules(removeEmptyGroups: true);
removeEmptyTextElements
Removes <text> and <tspan> elements that contain no text at all, and <tref> elements without a reference. These
elements have no visual impact and can safely be eliminated to reduce file size. Whitespace-only elements are kept,
since their whitespace may render as a space between the surrounding text.
$svgOptimizer->withRules(removeEmptyTextElements: true);
removeEnableBackgroundAttribute (risky)
Removes the enable-background attribute from the root <svg> element. While often unnecessary, this attribute can
affect certain filters or compositing behaviors. Removing it may improve performance and reduce size but could alter
rendering in advanced use cases.
$svgOptimizer->withRules(removeEnableBackgroundAttribute: true)->allowRisky();
removeInkscapeFootprints
Strips editor-specific metadata, attributes, and elements that are added during export but are not required for
rendering. This covers Inkscape, Sodipodi, Adobe Illustrator, Sketch, Serif and Microsoft Visio, matched by namespace
URI, including Illustrator's private data in a <foreignObject> that requires an Illustrator extension.
$svgOptimizer->withRules(removeInkscapeFootprints: true);
removeInvisibleCharacters
Removes invisible or non-printable Unicode characters, such as zero-width spaces, that may inadvertently appear in SVG files. This prevents subtle rendering or parsing issues and ensures clean textual content.
$svgOptimizer->withRules(removeInvisibleCharacters: true);
removeMetadata
Deletes <metadata> elements, which often contain authoring information, editor data, or descriptive metadata not
required for rendering. This reduces file size and removes non-essential content.
$svgOptimizer->withRules(removeMetadata: true);
removeNonStandardAttributes
Removes SVG attributes that are non-standard, unsafe, or not part of the official SVG specification.
Each SVG element keeps only the attributes the specification defines for it, plus the shared attribute groups that
apply to it (core, presentation, ARIA, conditional processing, animation, filter primitive and similar), so for example
points is removed from a <rect>. Elements the specification does not define fall back to the full list of known SVG
attributes, without HTML-only attributes such as src, srcset and action. Event handler attributes (on*) and
xml:base are always removed.
Prefixed attributes are matched by namespace: only known xlink:, xml: and ev: attributes are kept, and attributes bound to any
other namespace are removed. data-* attributes are kept when their name is valid. Elements outside the SVG namespace
and the content of a <foreignObject>, such as XHTML, are left untouched.
$svgOptimizer->withRules(removeNonStandardAttributes: true);
removeNonStandardTags
Removes elements (tags) that are not part of the official SVG specification, keeping their content.
This is useful for cleaning up SVGs that may contain unknown elements. Elements outside the SVG namespace, whose content
does not render, and the content of a <foreignObject>, such as XHTML, are left untouched.
$svgOptimizer->withRules(removeNonStandardTags: true);
removeStyleTypeAttributes
Removes the type attribute of <style> when it is text/css and of <script> when it is a JavaScript MIME type,
as these are the defaults. Other values, such as module, are kept.
$svgOptimizer->withRules(removeStyleTypeAttributes: true);
removeTitleAndDesc
Removes <title> and <desc> elements. While these elements provide accessibility and descriptive information, they
are optional in many contexts. Removing them reduces file size but should only be done when accessibility metadata is
not required.
$svgOptimizer->withRules(removeTitleAndDesc: true);
removeUnnecessaryWhitespace
Collapses or removes redundant whitespace such as extra spaces, tabs, and line breaks. This produces more compact SVG output while preserving semantic structure and rendering.
$svgOptimizer->withRules(removeUnnecessaryWhitespace: true);
removeUnusedNamespaces
Removes XML namespace declarations that are never referenced within the document. This cleans up the root element, reduces verbosity, and improves readability.
$svgOptimizer->withRules(removeUnusedNamespaces: true);
removeUselessDefs
Removes definitions that can never be used because neither they nor any descendant has an id: children of
<defs>, and gradients, patterns, clip paths, masks, markers, symbols and filters anywhere in the document. Definitions
that are or contain a <style>, a <script> or a font are kept, as these take effect anywhere. A <defs> left empty
is removed as well.
$svgOptimizer->withRules(removeUselessDefs: true);
removeWidthHeightAttributes (risky)
Removes the width and height attributes from the root <svg> element, relying solely on the viewBox for scaling.
This enables responsive resizing but may break layouts that depend on fixed dimensions.
$svgOptimizer->withRules(removeWidthHeightAttributes: true)->allowRisky();
removeXmlSpaceDefault
Removes xml:space="default" where it has no effect, that is, when no ancestor sets xml:space="preserve" and no
CSS white-space could be affected by it.
$svgOptimizer->withRules(removeXmlSpaceDefault: true);
removeZeroSizeShapes
Removes shapes the SVG specification says are not rendered: circles and ellipses with a zero radius, rects with a
zero width or height, and paths, polylines and polygons without any data. Shapes with an id, child elements or a
style attribute, and documents with a <style> element, are kept.
$svgOptimizer->withRules(removeZeroSizeShapes: true);
removeUnsafeElements
Sanitizes SVG content by removing elements and attributes that can pose security risks. This includes scripting
capabilities, external resource references, and interactive event handlers. The rule is intended for use with untrusted
SVG input and helps prevent script execution, data exfiltration, and other attack vectors when embedding SVGs in web
applications. It also removes processing instructions, comments that could break out when the SVG is inlined in HTML,
elements from non-SVG namespaces (such as XHTML or MathML), and animations that rewrite href.
$svgOptimizer->withRules(removeUnsafeElements: true);
removeUnusedIds (risky)
Removes id attributes that nothing in the document references, through url(#id), href, ARIA attributes,
animation timing or <style> rules (id selectors and attribute selectors such as [id="a"]). The ids of the root
<svg>, <symbol> and <view> elements are kept, and nothing is removed when the document contains a script, an event
handler attribute, or an attribute selector that may match several ids (such as [id^="a"]). The rule is risky because
CSS, JavaScript or links outside the SVG may target the removed ids.
$svgOptimizer->withRules(removeUnusedIds: true)->allowRisky();
removeUnusedMasks
Removes <mask> elements that are defined but never referenced by any element in the document. This reduces file size
and eliminates unused definitions without affecting rendering.
$svgOptimizer->withRules(removeUnusedMasks: true);
scopeSvgStyles (risky)
Scopes all IDs and class names within SVG elements to avoid style collisions.
Each embedded SVG gets unique identifiers, and CSS rules are rewritten accordingly.
This ensures multiple SVGs can coexist in the same document without interfering with each other.
Rules with a bare element selector (such as rect) or the universal selector (*) cannot be scoped and would style
the whole page, so they are removed; a style sheet left without rules is removed too.
Names that are already scoped are left unchanged, so optimizing a scoped SVG again does not change it.
Documents whose style sheets nest rules in at-rule blocks (such as @media or @supports) or use @import are left
untouched, as those rules cannot be rewritten.
$svgOptimizer->withRules(scopeSvgStyles: true)->allowRisky();
sortAttributes
Sorts element attributes alphabetically. This improves consistency, makes diffs easier to read in version control systems, and results in more deterministic SVG output across optimization runs.
$svgOptimizer->withRules(sortAttributes: true);
withRules
Every parameter defaults to false, so only the rules you explicitly pass as true are applied. Below is the full list
of available rules, shown with the values that withAllRules() (without allowRisky()) would enable:
$svgOptimizer->withRules( convertColorsToHex: true, convertCssClassesToAttributes: true, convertEllipseToCircle: true, convertEmptyTagsToSelfClosing: true, convertInlineStylesToAttributes: true, convertOneStopGradients: true, convertShapesToPath: true, fixAttributeNames: true, flattenGroups: true, minifyListValues: true, minifyNumericValues: true, minifyPathData: true, minifySvgCoordinates: true, minifyTransformations: true, removeAriaAndRole: true, removeComments: true, removeDataAttributes: false, removeDefaultAttributes: true, removeDeprecatedAttributes: true, removeDoctype: true, removeDuplicateElements: true, removeEmptyAttributes: true, removeEmptyContainers: true, removeEmptyGroups: true, removeEmptyTextElements: true, removeEnableBackgroundAttribute: false, removeInkscapeFootprints: true, removeInvisibleCharacters: true, removeMetadata: true, removeNonStandardAttributes: true, removeNonStandardTags: true, removeStyleTypeAttributes: true, removeTitleAndDesc: true, removeUnnecessaryWhitespace: true, removeUnsafeElements: true, removeUnusedIds: false, removeUnusedMasks: true, removeUnusedNamespaces: true, removeUselessDefs: true, removeWidthHeightAttributes: false, removeXmlSpaceDefault: true, removeZeroSizeShapes: true, scopeSvgStyles: false, sortAttributes: true, );
withAllRules
Enable all rules. Risky rules are only included when risky rules are allowed with allowRisky(), no matter whether
allowRisky() is called before or after withAllRules().
$svgOptimizer->withAllRules();
allowRisky
Allow risky rules. By default, optimize() throws a RiskyRulesNotAllowedException if a risky rule is enabled with
withRules(), and withAllRules() leaves the risky rules out.
$svgOptimizer->allowRisky();
optimize
Finalizes the optimization process and generates the optimized SVG file.
$svgOptimizer->optimize();
saveToFile
Saves the optimized SVG file to the specified path, creating missing directories. Throws a \LogicException if optimize() has not been called.
$svgOptimizer->saveToFile('path/to/output.svg');
getContent
Returns the optimized SVG content. Throws a \LogicException if optimize() has not been called.
$svgOptimizer->getContent();
getOptimizedSize
Returns the size of the optimized SVG file.
$svgOptimizer->getMetaData()->getOptimizedSize();
getOriginalSize
Returns the size of the original SVG file.
$svgOptimizer->getMetaData()->getOriginalSize();
getSavedBytes
Returns the number of bytes saved by the optimization process.
$svgOptimizer->getMetaData()->getSavedBytes();
hasSavedBytes
Returns a boolean indicating whether any bytes were saved by the optimization process.
$svgOptimizer->getMetaData()->hasSavedBytes();
getSavedPercentage
Returns the percentage of bytes saved by the optimization process.
$svgOptimizer->getMetaData()->getSavedPercentage();
getOptimizationTime
Returns the time taken to optimize the SVG file, in seconds.
$svgOptimizer->getMetaData()->getOptimizationTime();
Roadmap
For a complete list of proposed features and known issues, see the open issues.
Contributing
We welcome all contributions! If you have ideas for improvements, feel free to fork the repository and submit a pull request. You can also open an issue. If you find this project helpful, don’t forget to give it a star!
Library Structure and Contribution Guide
The library implements the Strategy Pattern, where strategies are encapsulated as "rules" located in the
/src/Service/Rule directory. Logic shared by several rules lives in traits in /src/Service/Rule/Trait. The
command-line tool lives in /src/Console. Classes tagged @api are the public API; classes tagged @internal may
change in any release.
Adding a New Rule
1. Create the Rule
Create a new final readonly class in the /src/Service/Rule directory and implement
the SvgOptimizerRuleInterface. This interface will define the logic for your rule.
2. Write Tests
Write comprehensive unit tests for your rule in the /tests/Unit/Service/Rule directory. Ensure the tests cover
various scenarios to verify the correct behavior and edge cases for your rule.
3. Integrate the Rule
- Add your rule to the rule enum in
/src/Type/Rule.php, and add it toRule::EXECUTION_ORDERafter the rules it depends on. - Register the rule in the SVG optimizer builder located at
/src/Service/Facade/SvgOptimizerFacade.php. Append the new parameter towithRules(), so existing calls with positional arguments keep working.
4. Update Documentation
Document the functionality and purpose of your rule in the README.md to ensure users understand its behavior and
usage.
Docker
To use the project with Docker, you can start the container using:
docker-compose up --build -d
Then, access the container:
docker exec -it php-svg-optimizer bash
Tools
Run static analysis:
composer analyze:all
Run tests:
composer test
Run mutation testing:
composer test:mutation
Run the benchmark (--save=<file> stores checksums of the optimized output and --compare=<file> checks that a change
keeps the output identical):
composer test:benchmark
Fix code style:
composer lint:all
Build badges:
composer build:badges
Build baseline:
composer build:baseline
License
This project is licensed under the MIT License. See the LICENSE file for more information.
Disclaimer
Use of this tool is entirely at your own risk. The authors and maintainers make no warranties regarding the correctness, reliability, or suitability of the tool for any particular purpose. Users are solely responsible for verifying the results and ensuring that files are properly backed up before use. It is strongly recommended to test the tool on non-critical files and confirm compatibility with your workflow prior to deploying it in any production environment.
