Перейти к содержимому

Graphics: примитивы контуров, заливок и преобразований

Модуль Graphics преобразует намерения рисования в графические операторы Portable Document Format (PDF). Он работает с контурами, стилями линий, цветовыми пространствами, преобразованиями, заливками, узорами, растровыми сетками и загрузкой изображений.

Окно терминала
composer require nextpdf/core:^3

Graphics — это слой векторного и растрового рисования. Он создаёт последовательности операторов, которые модули ContentStream и Writer сериализуют в PDF. Поток содержимого кодирует содержимое страницы как упорядоченную последовательность графических операторов согласно International Organization for Standardization (ISO) 32000-2 §8. Модуль формирует эти операторы, но не записывает файл.

DrawingEngine — это основной программный интерфейс (API). Это построитель с fluent-интерфейсом и сохранением состояния. Каждый сеттер возвращает self, фиксирует изменение графического состояния или оператор рисования контура и добавляет данные во внутренний буфер, который вы читаете с помощью getStream(). Движок напрямую моделирует графическое состояние PDF: толщина линии, стиль линии, цвет обводки и заливки, альфа-канал и режим наложения, ограничение угла соединения, мягкая маска, отсечение, надпечатка, плоскостность, гладкость, цель цветопередачи, генерация чёрного и удаление подложечного цвета — все эти параметры сопоставлены с документированными операторами. Сеттеры цвета принимают объект-значение Color или явное ColorSpace, поэтому аппаратные пространства и пространства на основе International Commission on Illumination (CIE) используют одну и ту же форму вызова.

Рядом с движком есть три семейства компонентов. Первое отвечает за ввод изображений. ImageLoader декодирует файл или бинарный объект в памяти в ImageLoadResult. ImageRegistry устраняет дубликаты и отслеживает декодированные изображения через MemoryReport, чтобы крупные документы оставались в пределах бюджета памяти. Для импорта векторных данных SvgParser и EpsParser преобразуют входные данные Scalable Vector Graphics (SVG) и Encapsulated PostScript (EPS) в тот же поток операторов, а для макета доступен getBoundingBox(). Третье семейство отвечает за точность аппаратного цвета: заливки (ShadingManager, семейства Type2/Type3 и сеточные семейства), узоры (PatternFill), растровые сетки (Type1/Type5/Type6/Type10/Type16), передаточные функции и цветовые пространства на основе International Color Consortium (ICC).

TransformEngine — это специализированный компонент для координатных преобразований. Он обрамляет преобразование вызовами startTransform() и stopTransform(), которые формируют пару save/restore q и Q. Он предоставляет именованные вспомогательные методы для аффинных преобразований: scale, translate, rotate, skew, mirrorH и mirrorV. Каждый вспомогательный метод принимает необязательную точку опоры. Матрица преобразования отображает внутреннее координатное пространство в целевое. Это та же модель, которую ISO 32000-2 применяет к областям определения заливок — §8.7.4.

Управление цветом следует Architectural Decision Record (ADR)-012: цветовые пространства ICCBased и на основе CIE формируют явные операторы потока содержимого cs/CS вместо резервного варианта с аппаратным цветом. Профили ICC упаковываются в поток ICCBased с правильным числом компонентов согласно ISO 32000-2 §8.6.5.5.

КлассКлючевые методыНазначение
DrawingEnginegetStream(), reset(), setLineWidth(), setLineStyle(), setDrawColor(), setFillColor(), setAlpha(), setSoftMask(), clip(), setOverprint(), setRenderingIntent(), line(), rect(), circle(), ellipse(), polygon(), linearGradient()Построитель операторов контуров и графического состояния, сохраняющий состояние
TransformEnginestartTransform(), stopTransform(), scale(), translate(), rotate(), skew(), mirrorH(), mirrorV(), getStream()Аффинные координатные преобразования
ImageLoaderload(string $filePath), loadFromString(string $data, string $mimeType)Декодирует изображения в ImageLoadResult
ImageRegistryload(), loadFromString(), getMetadata(), memoryUsage(), reset()Кэш изображений с устранением дубликатов и отчётами по памяти
SvgParserparse(), parseFile()Преобразует SVG в поток операторов
EpsParserparse(), parseFile(), getBoundingBox()Преобразует EPS в поток операторов
ShadingManagerРегистрация заливок и формирование словарейОсевые, радиальные и сеточные заливки
Halftone (абстрактный)halftoneType(), toDict(), hasStream(), getStream()Растровые сетки Type 1/5/6/10/16

Выполните composer docs:generate-api-php -- --module=Graphics, чтобы сформировать полную таблицу PHPDoc.

Источник: examples/06-colors-and-drawing.php.

<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Graphics\Color;
use NextPDF\Graphics\DrawingEngine;
use NextPDF\Graphics\LineStyle;
$engine = new DrawingEngine();
$engine
->setLineWidth(1.5)
->setDrawColor(Color::rgb(0, 51, 102))
->setFillColor(Color::rgb(230, 240, 250))
->rect(20.0, 20.0, 160.0, 80.0)
->line(20.0, 110.0, 180.0, 110.0, new LineStyle(dash: [3.0, 2.0]));
$contentStreamBytes = $engine->getStream();

Этот пример объединяет реестр изображений с отчётами по памяти и обрамлением преобразования. Он повторяет структуру, используемую в examples/07-images.php и examples/21-transforms.php.

<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Graphics\DrawingEngine;
use NextPDF\Graphics\ImageRegistry;
use NextPDF\Graphics\TransformEngine;
$registry = new ImageRegistry();
$image = $registry->load('/srv/assets/logo.png');
$report = $registry->memoryUsage();
if ($report->bytes > 32 * 1024 * 1024) {
// Decoded image cache exceeded the budget — reset before the next page.
$registry->reset();
}
$transform = new TransformEngine();
$transform
->startTransform()
->translate(40.0, 700.0)
->scale(0.5, 0.5)
->stopTransform();
$engine = new DrawingEngine();
$engine->reset();
$page = $transform->getStream() . $engine->getStream();
  • DrawingEngine сохраняет состояние. Вызывайте reset() между независимыми страницами, чтобы предыдущее графическое состояние не попадало в следующий поток.
  • TransformEngine требует согласованной пары startTransform()/stopTransform(). Несбалансированное обрамление оставляет незакрытый q и дальше по конвейеру повреждает стек save/restore в Writer.
  • setSoftMask(), setOverprint(), setBlackGeneration() и setUnderColorRemoval() записывают маркеры расширенного графического состояния. Если профиль отклоняет эту возможность, они не применяются. Проверяйте ограничение профиля, прежде чем полагаться на визуальный результат.
  • ImageRegistry устраняет дубликаты по содержимому. Два пути с идентичными байтами совместно используют один объект. Не считайте, что каждому вызову load() соответствует отдельное изображение PDF.
  • EpsParser::getBoundingBox() возвращает разобранную ограничивающую рамку, а не рамку страницы. Применяйте собственное отсечение, если EPS выходит за пределы целевого прямоугольника.
  • Компенсация чёрной точки носит рекомендательный характер и основана на маркерах. Сама по себе она не преобразует пиксели.

Два изменения в поведении производителя являются ломающими. Оба превращают ранее молчаливое повреждение данных в явный сбой в месте вызова.

Проверка входных данных теперь выбрасывает исключение (примечание о миграции). Входные данные рисования проверяются до попадания в поток операторов, а некорректные значения отклоняются с InvalidArgumentException. Вызывающий код, который передавал NaN, Infinity или значения вне диапазона, раньше молча создавал повреждённые операторы; теперь те же входные данные вызывают исключение. Проверяемые ограничения:

  • Альфа-канал цвета должен быть конечным и находиться в пределах [0, 1].
  • Операнды текущей матрицы преобразования (CTM), размеры шаблона, координаты вершин градиента и координаты сеточных патчей должны быть конечными — без NaN или Infinity.
  • Флаг края градиентного патча должен быть одним из {0, 1, 2, 3}.
  • Параметры функций Type 2/3/4 и параметры растровых сеток проверяются на границы.
  • Имена красителей экранируются.
  • Имя слоя группы необязательного содержимого (OCG) не должно быть пустым.

Перед обновлением проверьте места вызова, которые вычисляют координаты или альфа-канал из данных выше по конвейеру: значение, которое раньше проходило, теперь является жёсткой ошибкой.

ICCBased /N по умолчанию работает по принципу fail-closed. Обычный вывод PDF отклоняет цветовое пространство ICCBased, у которого число компонентов /N находится вне {1, 3, 4}, и сверяет объявленное /N со встроенным профилем и пространством /Alternate. Это соответствует правилу ISO 32000-2 §8.6.5.5 для потока ICCBased, который несёт /N вместе с пространством /Alternate. N-канальный профиль ICC, например профиль hexachrome с N = 6, сохраняется только при активном профиле PDF/A или PDF/X, при явном включении через IccConformancePolicy::ProfileGated. Это структурное ограничение по числу компонентов, а не заявление о сертификации PDF/A или PDF/X.

Формирование операторов линейно по числу вызовов рисования: O(n) добавлений в буфер, без повторного формирования. Стоимость декодирования изображения определяется кодеком и числом пикселей, а не реестром. Устранение дубликатов по хешу содержимого в реестре — основной способ оптимизации крупных документов: повторно используемые ресурсы требуют одного декодирования и одного объекта PDF. Значение performance_budget для эталонной нагрузки этого модуля составляет 1500 мс реального времени и 64 МБ пикового потребления. Используйте ImageRegistry::memoryUsage(), чтобы отслеживать объём, занимаемый декодированными изображениями, и reset(), чтобы освобождать его между группами страниц.

SvgParser и EpsParser обрабатывают недоверенные векторные входные данные. Относитесь к обоим как к парсерам враждебных данных. Применяйте ограничения на размер входных данных перед вызовом parse(). Выполняйте извлечение в изолированном рабочем процессе, если источник предоставлен пользователем. EPS — это диалект PostScript. Парсер преобразует ограниченное подмножество и не выполняет полноценный интерпретатор, но вам всё равно следует ограничивать размер входных данных и время разбора. Загрузчики изображений декодируют сторонние кодеки. Поддерживайте расширения изображений в среде выполнения актуальными и ограничивайте размеры после декодирования. См. модель угроз движка в /modules/core/security/, где приведены сведения о границе доверия и изоляции рабочих процессов.

Модуль формирует структуры графических операторов PDF, согласованные с ISO 32000-2 §8, словари цветовых пространств ICCBased согласно §8.6.5.5 и словари заливок, у которых Domain, Function, Matrix и BBox следуют §8.7.4. Это факты реализации: src/Graphics/ генерирует формы операторов и словарей, а tests/Unit/Graphics/ вместе с эталонами tests/Golden/PdfWriter/PdfWriterShadingGoldenBaselineSmokeTest и PdfWriterExtGStateGoldenSmokeTest проверяют их. Они не являются заявлением о сквозном соответствии PDF 2.0 или PDF/X. Соответствие на уровне всего документа проверяется отдельно с помощью оракула и эталонных наборов, описанных в /modules/core/conformance/. Поведение профилей для ICC OutputIntents определяется ADR-011 и ADR-012, а не только этим модулем.