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.
Поверхность API
Заголовок раздела «Поверхность API»| Класс | Ключевые методы | Назначение |
|---|---|---|
DrawingEngine | getStream(), reset(), setLineWidth(), setLineStyle(), setDrawColor(), setFillColor(), setAlpha(), setSoftMask(), clip(), setOverprint(), setRenderingIntent(), line(), rect(), circle(), ellipse(), polygon(), linearGradient() | Построитель операторов контуров и графического состояния, сохраняющий состояние |
TransformEngine | startTransform(), stopTransform(), scale(), translate(), rotate(), skew(), mirrorH(), mirrorV(), getStream() | Аффинные координатные преобразования |
ImageLoader | load(string $filePath), loadFromString(string $data, string $mimeType) | Декодирует изображения в ImageLoadResult |
ImageRegistry | load(), loadFromString(), getMetadata(), memoryUsage(), reset() | Кэш изображений с устранением дубликатов и отчётами по памяти |
SvgParser | parse(), parseFile() | Преобразует SVG в поток операторов |
EpsParser | parse(), 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, а не только этим модулем.