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

Создание необязательных слоёв содержимого (OCG)

Помещайте содержимое в именованные группы необязательного содержимого (OCG), которые часто называют слоями. Программа просмотра PDF может переключать каждый слой на панели слоёв, а один слой по умолчанию остаётся скрытым. Этот рецепт следует примеру examples/26-layers.php.

OCG — это словарь группы необязательного содержимого по ISO 32000-2 со значением Type /OCG. NextPDF заключает помеченное содержимое слоя между BDC/EMC и использует тег помеченного содержимого OC.

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

Дополнительное расширение не требуется. API слоёв стабилен начиная с версии 1.0.0 и работает на матрице обратной совместимости 8.1–8.4.

startLayer($name, $visible) открывает OCG. Всё, что вы рисуете до соответствующего endLayer(), принадлежит этой группе. $name — это подпись, которую программа просмотра PDF показывает на панели слоёв. ISO 32000-2 требует, чтобы у OCG был ключ Name — строка, видимая пользователю. Передача $visible: false регистрирует группу в конфигурации по умолчанию в состоянии OFF, поэтому программа просмотра скрывает её, пока пользователь не включит слой.

Видимость зависит от поддержки в программе просмотра. Для словаря принадлежности к необязательному содержимому (OCMD) политика видимости по умолчанию — AnyOn. Слой виден, если любая из указанных групп находится в состоянии ON. Скрытый слой скрывается только по соглашению программы просмотра. Он не удаляется, не защищается и не является ни редактированием для удаления данных, ни средством защиты. Чтобы удалить содержимое, не рисуйте его.

PHPDoc автоматически формирует перечень API. В этом рецепте используются два метода:

  • startLayer(string $name, bool $visible = true): static — открывает именованный OCG; $visible: false скрывает его по умолчанию.
  • endLayer(): static — закрывает последний открытый слой (парный с startLayer()).
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();
$doc->addPage();
$doc->startLayer('Content', visible: true);
$doc->setFont('helvetica', '', 12);
$doc->cell(0, 8, 'Always-visible body content.', newLine: true);
$doc->endLayer();
$doc->startLayer('Debug Grid', visible: false); // hidden until toggled
$doc->setDrawColor(200, 200, 200);
for ($x = 0.0; $x <= 210.0; $x += 10.0) {
$doc->line($x, 0, $x, 297);
}
$doc->endLayer();
$doc->save(getenv('NEXTPDF_COOKBOOK_OUTPUT') ?: __DIR__ . '/layers.pdf');

Используйте этот полный пример, готовый к запуску в тестовом окружении. Он учитывает NEXTPDF_COOKBOOK_OUTPUT и не вносит собственной энтропии.

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Contracts\Alignment;
use NextPDF\Core\Document;
$doc = Document::createStandalone();
$doc->setTitle('Layer Examples (OCG)');
$doc->addPage();
// Layer 1 — background, visible by default.
$doc->startLayer('Background', visible: true);
$doc->setFillColor(230, 240, 250);
$doc->rect(10, 10, 190, 277, 'F');
$doc->endLayer();
// Layer 2 — watermark, visible by default; can be toggled off.
$doc->startLayer('Watermark', visible: true);
$doc->setFont('helvetica', 'B', 54);
$doc->setTextColor(200, 200, 200);
$doc->startTransform();
$doc->rotate(45, 105, 148);
$doc->setXY(30, 135);
$doc->cell(150, 20, 'DRAFT', align: Alignment::Center);
$doc->stopTransform();
$doc->endLayer();
// Layer 3 — main content, visible by default.
$doc->startLayer('Content', visible: true);
$doc->setTextColor(0);
$doc->setFont('helvetica', 'B', 20);
$doc->setXY(10, 15);
$doc->cell(0, 14, 'Layer Examples (OCG)', newLine: true);
$doc->ln(4);
$doc->setFont('helvetica', '', 11);
$doc->multiCell(0, 7, 'This document contains four optional content groups. '
. "Toggle them in your reader's Layers panel.");
$doc->endLayer();
// Layer 4 — debug grid, hidden by default.
$doc->startLayer('Debug Grid', visible: false);
$doc->setDrawColor(180, 180, 180);
$doc->setLineWidth(0.15);
for ($x = 0.0; $x <= 210.0; $x += 10.0) {
$doc->line($x, 0, $x, 297);
}
for ($y = 0.0; $y <= 297.0; $y += 10.0) {
$doc->line(0, $y, 210, $y);
}
$doc->endLayer();
$out = getenv('NEXTPDF_COOKBOOK_OUTPUT') ?: __DIR__ . '/layers.pdf';
$doc->save($out);
echo "Created layers.pdf\n";
  • Для каждого startLayer() добавляйте парный endLayer(). Незакрытый слой оставляет висящий BDC без EMC и делает структуру документа некорректной. Сопоставляйте каждый открывающий вызов с закрывающим.
  • Скрытый слой не удаляется. visible: false скрывает содержимое только по соглашению программы просмотра. Метки и любой текст остаются в файле и могут быть восстановлены. Это не редактирование для удаления данных. Для конфиденциальных данных просто не рисуйте их.
  • Поддержка панели слоёв различается. Для переключения нужна программа просмотра, которая предоставляет доступ к необязательному содержимому. Конвейеры печати и упрощённые средства просмотра могут всегда показывать или всегда скрывать слои, отключённые по умолчанию.
  • Вложенность. Вложенные слои разрешены, но видимость каждой внутренней группы остаётся независимой. Не считайте, что внешний слой в состоянии OFF скрывает внутреннюю группу в состоянии ON, если вы не настроили политику принадлежности.

Каждый слой добавляет один словарь OCG и пару BDC/EMC вокруг своих меток. Накладные расходы пренебрежимо малы. Затраты растут вместе с содержимым внутри слоёв, а не с числом слоёв, поэтому всё с запасом укладывается в бюджет 2000 мс / 64 МБ.

Видимость необязательного содержимого зависит от поддержки в программе просмотра и не является контролем доступа. Скрытие слоя не шифрует, не редактирует для удаления данных и не удаляет его содержимое. Любой может снова включить слой или извлечь его байты. Никогда не используйте скрытый слой для сокрытия конфиденциального текста; вместо этого полностью опускайте такое содержимое. Этот рецепт не разбирает входные данные и не делает сетевых запросов.

УтверждениеСпецификацияПунктидентификатор ссылки (reference_id)
Словарь OCG имеет Type /OCG.ISO 32000-2§8.11.2
Ключ OCG Name — обязательная подпись, видимая пользователю.ISO 32000-2§8.11.2
Необязательное содержимое заключается между BDC/EMC с тегом OC.ISO 32000-2§8.11.3.2
Политики OCMD — AllOn/AnyOn/AnyOff/AllOff (по умолчанию AnyOn).ISO 32000-2§8.11.4.3

Профиль воспроизводимости — структурный. Поле /ID в трейлере и атомы даты меняются при каждом сохранении. Тестовое окружение удаляет эти атомы и сравнивает структуру, нормализованную qpdf. Этот рецепт описывает, как NextPDF формирует такую структуру. Он не утверждает общее соответствие ISO 32000-2.

Неприменимо. Группы необязательного содержимого — это возможность Core без ограничений для Premium.