meyfa/php-svg

使用PHP读取、编辑、写入和渲染SVG文件

安装数7,437,502

依赖项: 38

建议者: 1

安全性: 0

星标: 503

关注者: 16

分支: 92

开放问题: 26

v0.16.0 2024-07-12 11:40 UTC

README

PHP应用程序的无依赖矢量图形库

CI Maintainability Test Coverage Packagist PHP Version Packagist Downloads

特性

PHP-SVG可以帮助完成以下一系列任务

  • 使用PHP代码程序生成矢量图形。生成的SVG字符串可以写入文件或作为HTTP响应的一部分发送。
  • 加载和解析SVG图像到易于修改和追加的文档树中。
  • 将矢量图形转换为位图图像格式,如PNG或JPEG(光栅化)。

请注意,PHP-SVG仍处于alpha阶段,可能不适合复杂的应用程序,但目前欢迎贡献。有关如何贡献的信息,请参阅此处

安装

需求

PHP-SVG无依赖。它只需要一个满足以下要求的PHP安装

  • PHP版本7.4或更高。此库已针对所有版本进行测试,包括PHP 8.3。
  • 如果您想加载SVG文件或包含SVG代码的字符串,您需要安装'simplexml' PHP扩展
  • 如果您想使用光栅化功能将SVG转换为位图图像(PNG、JPEG等),您需要安装'gd' PHP扩展

这些扩展几乎总是在典型的PHP安装上可用。但是,您可能需要确保您的托管服务提供商确实拥有它们。如果SimpleXML或GD缺失,PHP-SVG仍然可以执行除了需要缺失扩展的任务之外的所有任务。例如,程序生成SVG图像并作为XML输出始终有效,即使没有任何扩展。

Composer(推荐)

此软件包可在Packagist上找到,并可以使用Composer进行安装

composer require meyfa/php-svg

这将添加对您的composer.json文件的依赖。如果尚未设置,请通过在您的PHP脚本顶部添加以下require语句来设置Composer依赖项的自动加载

<?php
require_once __DIR__ . '/vendor/autoload.php';

您可能需要根据您的脚本位于另一个文件夹中调整路径。

手动安装

下载此存储库的最新版本发布或当前的开发版本版本,并在您的项目中某处提取源代码。然后您可以使用我们自己的自动加载器来提供SVG命名空间

<?php
require_once __DIR__ . '/<path_to_php_svg>/autoloader.php';

其余部分的工作方式与Composer完全相同,只是没有包管理器的优势。

入门指南

本节包含一些简单的示例,帮助您开始使用PHP-SVG。

程序创建SVG

以下代码生成一个包含蓝色正方形的SVG,然后设置Content-Type头,并将SVG作为文本发送到客户端

<?php
require __DIR__ . '/vendor/autoload.php';

use SVG\SVG;
use SVG\Nodes\Shapes\SVGRect;

// image with dimensions 100x100
$image = new SVG(100, 100);
$doc = $image->getDocument();

// blue 40x40 square at the origin
$square = new SVGRect(0, 0, 40, 40);
$square->setStyle('fill', '#0000FF');
$doc->addChild($square);

header('Content-Type: image/svg+xml');
echo $image;

将SVG转换为字符串

上面的示例使用echo,它隐式地将SVG转换为包含其XML表示的字符串。此转换也可以显式进行

// This will include the leading <?xml ... ?> tag needed for standalone SVG files:
$xmlString = $image->toXMLString();
file_put_contents('my-image.svg', $xmlString);

// This will omit the <?xml ... ?> tag for outputting directly into HTML:
$xmlString = $image->toXMLString(false);
echo '<div class="svg-container">' . $xmlString . '</div>';

从字符串加载SVG

除了从头开始程序生成图像之外,还可以从字符串或文件中解析图像。以下代码解析SVG字符串,修改图像的一部分,并将结果输出到客户端

<?php
require __DIR__ . '/vendor/autoload.php';

use SVG\SVG;

$svg  = '<svg width="100" height="100">';
$svg .= '<rect width="40" height="40" fill="#00F" id="my-rect" />';
$svg .= '</svg>';

$image = SVG::fromString($svg);
$rect = $image->getDocument()->getElementById('my-rect');
$rect->setX(25)->setY(25);

header('Content-Type: image/svg+xml');
echo $image;

从文件加载SVG

要从文件而不是字符串中加载,请调用SVG::fromFile($file)。此函数支持本地文件系统上的路径以及远程URL。例如

// load from the local file system:
$image = SVG::fromFile('path/to/file.svg');

// or from the web (worse performance due to HTTP request):
$image = SVG::fromFile('https://upload.wikimedia.org/wikipedia/commons/8/8c/Even-odd_and_non-zero_winding_fill_rules.svg');

光栅化

⚠️ 这个功能目前正在积极开发中。 许多东西看起来可能不正确,渲染大图像可能非常缓慢。

使用toRasterImage($width, $height [, $background])方法将SVG渲染为光栅图像。结果是GD图像资源。GD提供将此资源编码为多种格式的方法

<?php
require __DIR__ . '/vendor/autoload.php';

use SVG\SVG;
use SVG\Nodes\Shapes\SVGCircle;

$image = new SVG(100, 100);
$doc = $image->getDocument();

// circle with radius 20 and green border, center at (50, 50)
$doc->addChild(
    (new SVGCircle(50, 50, 20))
        ->setStyle('fill', 'none')
        ->setStyle('stroke', '#0F0')
        ->setStyle('stroke-width', '2px')
);

// rasterize to a 200x200 image, i.e. the original SVG size scaled by 2.
// the background will be transparent by default.
$rasterImage = $image->toRasterImage(200, 200);

header('Content-Type: image/png');
imagepng($rasterImage);

光栅图像默认会保留SVG中存在的任何透明度。对于需要不透明图像的情况,可以指定背景颜色。在输出到某些格式(如JPEG)时,可能需要这样做,因为这些格式不能编码alpha通道信息。例如

// white background
$rasterImage = $image->toRasterImage(200, 200, '#FFFFFF');
imagejpeg($rasterImage, 'path/to/output.jpg');

文本渲染(加载字体)

PHP-SVG使用自定义的TTF解析器实现了对TrueType字体(.ttf文件)的支持。由于PHP没有自带任何字体文件,您需要提供自己的字体文件。以下示例显示了如何加载一组字体文件。PHP-SVG将尝试根据CSS规范中的算法为给定的文本元素选择最佳匹配的字体。

<?php
require __DIR__ . '/vendor/autoload.php';

use SVG\SVG;

// load a set of fonts from the "fonts" directory relative to the script directory
SVG::addFont(__DIR__ . '/fonts/Ubuntu-Regular.ttf');
SVG::addFont(__DIR__ . '/fonts/Ubuntu-Bold.ttf');
SVG::addFont(__DIR__ . '/fonts/Ubuntu-Italic.ttf');
SVG::addFont(__DIR__ . '/fonts/Ubuntu-BoldItalic.ttf');

$image = SVG::fromString('
<svg width="220" height="220">
  <rect x="0" y="0" width="100%" height="100%" fill="lightgray"/>
  <g font-size="15">
    <text y="20">hello world</text>
    <text y="100" font-weight="bold">in bold!</text>
    <text y="120" font-style="italic">and italic!</text>
    <text y="140" font-weight="bold" font-style="italic">bold and italic</text>
  </g>
</svg>
');

header('Content-Type: image/png');
imagepng($image->toRasterImage(220, 220));

注意,PHP在使用相对路径时往往会表现出意外行为,尤其是在字体方面。因此,建议使用绝对路径,或者使用__DIR__常量来在当前脚本的目录前添加路径。

文档模型

本节将更详细地解释对象结构和如何查询或修改文档的各个部分。

SVG根节点

SVG类的一个实例代表图像的抽象表示。它本身不存储DOM信息。这是文档根节点的责任,该节点对应于<svg> XML标签的对象。例如

<?php
require __DIR__ . '/vendor/autoload.php';

use SVG\SVG;

$svg  = '<svg width="100" height="100">';
$svg .= '<rect width="40" height="40" fill="#00F" id="my-rect" />';
$svg .= '</svg>';

$image = SVG::fromString($svg);

// obtain the <svg> node (an instance of \SVG\SVGDocumentFragment):
$doc = $image->getDocument();

子节点

可以通过以下方式获取任何元素的子节点

// Returns the number of children.
$numberOfChildren = $element->countChildren();

// Returns a child element by its index.
$firstChild = $element->getChild(0);

// Returns an array of matching child elements.
$childrenThatAreRects = $element->getElementsByTagName('rect');

// Returns an array of matching child elements.
$childrenWithClass = $element->getElementsByClassName('my-class-name');

根节点还有一个通过id属性获取唯一元素的功能

// Returns an element or null.
$element = $doc->getElementById('my-rect');

子节点可以添加、删除和替换

// Append a child at the end.
$doc->addChild(new \SVG\Nodes\Shapes\SVGLine(0, 0, 10, 10));

// Insert a new child between the children at positions 0 and 1.
$g = new \SVG\Nodes\Structures\SVGGroup();
$doc->addChild($g, 1);

// Remove the second child. (equivalent to $doc->removeChild($g);)
$doc->removeChild(1);

// replace the first child with $g
$doc->setChild(0, $g);

属性

每个属性都可以通过$element->getAttribute($name)访问。一些常用属性有额外的快捷方法,但它们仅适用于它们有效的类,因此请确保您访问的节点是正确的类型,以防止运行时错误。以下是一些示例

$doc->getWidth();
// equivalent to: $doc->getAttribute('width')

$doc->setWidth('200px');
// equivalent to: $doc->setAttribute('width', '200px');

$rect->setRX('10%');
// equivalent to: $rect->setAttribute('rx', '10%');

样式

一些表示属性被认为是SVG规范中的样式属性。这些将由PHP-SVG特别处理,并通过getStylesetStyle而不是getAttributesetAttribute提供。考虑以下节点

<circle x="10" y="10" r="5" style="fill: #red" stroke="blue" stroke-width="4" />
  • xyr是属性。
  • fillstrokestroke-width是样式。

调试

如果您没有输出但只有空白页面,请尝试暂时启用PHP的错误报告以找到问题的原因。

<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
// ... rest of the script ...

完成操作后,请确保禁用此功能,因为这可能会泄露有关您的服务器设置的敏感信息。此外,请确保在此模式下不要设置Content-Type标头为图像格式,因为您的浏览器会尝试将错误消息作为图像渲染,这将不会工作。

或者,您可以尝试找到服务器的错误日志文件。其位置取决于您如何运行PHP。

贡献

该项目免费向社区开放,还有很多工作要做。任何帮助都受欢迎!您可以通过以下方式做出贡献

  • 在GitHub上给PHP-SVG一个星号以传播消息。 越来越多人使用它,它就会变得越来越好!
  • 通过报告您遇到的任何错误或缺失功能。请快速搜索问题标签,查看是否有人已经报告了相同的问题。也许您可以添加一些讨论内容?
  • 通过贡献代码。您可以查看目前开放的问题,了解需要解决的问题。如果您知道如何解决遇到的错误,直接提交修复作为pull request应该是比较安全的。对于新功能,建议首先为您的建议创建一个问题,以收集反馈并讨论实施策略。

请阅读

通过通过pull request或commit向PHP-SVG贡献材料或代码,您确认您拥有该材料或代码的必要权利,并同意在MIT许可的条款下提供该材料或代码。