跳到內容

建立選用內容圖層(OCG)

將內容包進具名的選用內容群組(OCG),也就是一般所稱的圖層。閱讀器可以在圖層面板中切換每個圖層,其中一個圖層會預設隱藏。本範例依循 examples/26-layers.php

OCG 是帶有 Type /OCG 的 ISO 32000-2 選用內容群組字典。NextPDF 會將分層內容的標記包夾在 BDC/EMC 之間,並使用 OC 標記內容標籤。

Terminal window
composer require nextpdf/core:^3

不需要任何選用擴充功能。圖層 API 自 1.0.0 起即為穩定版,並可在 8.1–8.4 的回溯相容矩陣上執行。

startLayer($name, $visible) 會開啟一個 OCG。在配對的 endLayer() 之前繪製的所有內容,都屬於該群組。$name 是閱讀器在圖層面板中顯示給使用者的標籤。ISO 32000-2 規定 OCG 的 Name 必須是面向使用者的字串。傳入 $visible: false 會將該群組以 OFF 狀態註冊到預設組態,因此閱讀器會預設將它隱藏,直到使用者將它開啟。

可見性取決於閱讀器是否配合。成員資格字典的預設可見性原則是 AnyOn,意思是只要任一被參照的群組為 ON,該圖層就會顯示。被隱藏的圖層只是依閱讀器慣例隱藏內容;它既未被移除,也不受保護,並不是塗黑遮蔽或安全控制機制。若要移除內容,就不要繪製它。

API 介面由 PHPDoc 自動產生。本範例會用到以下兩個方法:

  • 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 只是依閱讀器慣例隱藏內容。那些標記與任何文字仍然存在於檔案中,而且可被還原。這並不是塗黑遮蔽。對於敏感資料,請不要繪製它。
  • 圖層面板的支援程度各不相同。 若要切換圖層,需要使用會公開選用內容的閱讀器。列印管線與功能精簡的檢視器,可能一律顯示或一律隱藏預設關閉的圖層。
  • 巢狀。 允許使用巢狀圖層,但每個內層群組仍各自擁有獨立可見性。除非你設定成員資格原則,否則不要假設外層關閉時會隱藏內層開啟的群組。

每個圖層會新增一個 OCG 字典,以及包住其標記的一組 BDC/EMC 配對。這點額外負擔可以忽略不計。成本會隨圖層內的內容增加,而不是隨圖層數量增加,因此仍遠在 2000 ms / 64 MB 的預算之內。

選用內容的可見性取決於閱讀器是否配合,並非存取控制。 隱藏某個圖層並不會加密、塗黑遮蔽或移除它的內容。任何人都可以重新啟用該圖層,或擷取出那些位元組。絕對不要用隱藏圖層掩蓋機密文字;請改為完全省略該內容。本範例不做任何輸入剖析,也不做任何網路存取。

陳述規範條款參考 ID
OCG 字典帶有 Type /OCGISO 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 的限制門檻。