跳转到内容

绘制矢量图形——形状、颜色与线条样式

本示例会绘制带填充或描边的基本图元:矩形、圆角矩形、圆形、椭圆和线条。 每一种图元都可以设置填充颜色、描边颜色(绘制颜色)以及线宽。 本示例遵循 examples/06-colors-and-drawing.php

每个图元都会映射到一个 ISO 32000-2 路径对象。 路径对象是由线段和曲线段组成的形状。 它以一个绘图运算符结束,由该运算符决定这个形状是描边、填充,还是两者都执行。

Terminal window
composer require nextpdf/core:^3

不需要任何可选扩展。 绘图与颜色 API 自 1.0.0 起即为稳定版,并可在 8.1–8.4 的 backport 兼容矩阵上运行。

先设置状态,再执行绘制。 setFillColor()setDrawColor()setLineWidth() 会更新绘图状态。 随后的 rect()circle()ellipse()roundedRect()line() 会使用该状态。 这些形状方法都接受一个样式参数:'F' 表示填充,'S' 表示描边(默认值),'DF'/'FD' 则表示两者都执行。 在内部,一个填充矩形就是路径构造运算符 re 后接填充绘图运算符。 ISO 32000-2 §8.5.3 将 S 指定为描边、f 指定为填充,作为主要的路径绘图运算符。

颜色属于设备颜色(device colour)。 setFillColor(r, g, b) 会选用 DeviceRGB。 ISO 32000-2 §8.6.4.3 将 rg 定义为 DeviceRGB 的非描边颜色运算符,并将 g 定义为对应的 DeviceGray 运算符。 单参数形式的 setFillColor($v) 表示一个灰度值。 线宽默认为 1.0,虚线样式默认为实线(§8.4.3.6)。

此 API 接口从 PHPDoc 自动生成。 本示例会用到以下方法:

  • rect(float $x, float $y, float $w, float $h, string $style = 'S'): static
  • roundedRect(float $x, float $y, float $w, float $h, float $r, string $style = 'S'): static
  • circle(float $x, float $y, float $r, string $style = 'S'): static
  • ellipse(float $x, float $y, float $rx, float $ry, string $style = 'S'): static
  • line(float $x1, float $y1, float $x2, float $y2): static
  • setFillColor(int $r, int $g = -1, int $b = -1): static / setDrawColor(...)
  • setLineWidth(float $width): static
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();
$doc->addPage();
$doc->setFillColor(30, 58, 138);
$doc->rect(20, 30, 60, 40, 'F'); // filled rectangle
$doc->setDrawColor(217, 119, 6);
$doc->setLineWidth(1.0);
$doc->circle(140, 50, 20, 'S'); // stroked circle
$doc->setLineWidth(0.3);
$doc->line(20, 90, 190, 90); // thin rule
$doc->save(getenv('NEXTPDF_COOKBOOK_OUTPUT') ?: __DIR__ . '/vector.pdf');

这是完整示例,可直接在测试运行环境中执行。 它会遵循 NEXTPDF_COOKBOOK_OUTPUT,且不会自行引入任何熵。

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();
$doc->setTitle('Colors and Drawing');
$doc->addPage();
$doc->setFont('helvetica', 'B', 18);
$doc->cell(0, 12, 'Colors and Drawing', newLine: true);
$doc->ln(5);
// --- Filled rectangles: set fill colour, then draw with style 'F' ---
$palette = [
[30, 58, 138], [217, 119, 6], [30, 27, 75],
[239, 66, 35], [21, 128, 61],
];
$x = 15.0;
$rowY = $doc->getY();
foreach ($palette as [$r, $g, $b]) {
$doc->setFillColor($r, $g, $b);
$doc->rect($x, $rowY, 30, 20, 'F');
$x += 35.0;
}
$doc->ln(28);
// --- Outlined shapes: set draw colour + line width, draw with 'S' ---
$doc->setDrawColor(30, 58, 138);
$doc->setLineWidth(0.5);
$y = $doc->getY();
$doc->rect(15, $y, 30, 25, 'S');
$doc->roundedRect(55, $y, 30, 25, 5, 'S');
$doc->circle(110, $y + 12.5, 12.5, 'S');
$doc->ellipse(150, $y + 12.5, 18, 10, 'S');
$doc->ln(33);
// --- Lines at three widths ---
$y = $doc->getY();
$doc->setDrawColor(0);
$doc->setLineWidth(0.2);
$doc->line(15, $y, 195, $y);
$doc->setLineWidth(0.8);
$doc->line(15, $y + 5, 195, $y + 5);
$doc->setLineWidth(1.5);
$doc->line(15, $y + 12, 195, $y + 12);
$out = getenv('NEXTPDF_COOKBOOK_OUTPUT') ?: __DIR__ . '/vector.pdf';
$doc->save($out);
echo "Created vector.pdf\n";
  • 样式默认为描边。 若省略样式参数,形状会以描边方式呈现('S')。 如果某个形状看起来不可见,通常是因为没有设置描边颜色,或被填充为与页面背景相同的颜色。 传入 'F' 即可填充它。
  • 颜色状态会持续保留。 setFillColor() 会一直生效,直到你修改它为止。 在进入下一个不相关的区块之前先重置它(例如 setFillColor(255)),否则该颜色会继续沿用。
  • 灰度与 RGB 重载的差别。 setFillColor(128) 是一个灰度值。 setFillColor(128, 0, 0) 则是 RGB。 单参数形式并不是“红色 128”的意思。
  • 在 API 中 Y 轴从上到下递增。 这些绘图辅助方法使用文档左上角作为原点。 引擎会替你把它映射到 PDF 以左下角为原点的用户空间。

每个图元只会生成少量内容流(content stream)运算符。 每页数千个形状仍能轻松落在 2000 ms / 64 MB 的预算之内。 成本会随图元数量线性增长。 过程中不会进行栅格化,因此输出会保持为矢量。

此示例只会绘制你的代码所指定的几何图形。 它不会解析任何输入,也不会进行任何网络访问。 对任何来自不可信数据的坐标,都要做范围检查。 范围检查可以阻止恶意值把标记推到远离页面之外的位置。

陈述规范条款参考 ID
路径对象由线段、矩形和贝塞尔(Bézier)曲线组成,并以一个绘图运算符结束。ISO 32000-2§8.5
S 对路径进行描边,f 对路径进行填充。ISO 32000-2§8.5.3
rg 设定 DeviceRGB 的非描边颜色;g 设定 DeviceGray。ISO 32000-2§8.6.4.3
虚线样式的初始值是 [] 0,也就是实线。ISO 32000-2§8.4.3.6

可复现性配置文件 —— 结构性。 矢量绘图本身不带任何熵。 即便如此,每份保存的文档都会带有一个 trailer /ID 与日期原子(atom)。 ISO 32000-2 §8.3.4 也指出,绘图状态运算符的确切排列顺序并无语义上的意义,因此规范化器可以重新排列等价的状态。 严格来说,这里能成立的主张是经过 qpdf 规范化之后的结构相等。 此示例说明 NextPDF 如何生成这样的结构。 它并未主张全面符合 ISO 32000-2。

不适用。 矢量绘图是核心(Core)功能,没有 Premium 限制。