PDF 對自己知道些什麼:中介資料與 XMP 封包
Spec: ISO 16684-1:2019ISO 16684-1:2019Spec: ISO 32000-2ISO 32000-2
開啟一份現代的 PDF,它可能會把自己描述兩遍。有一份小巧、古老、稱為文件資訊字典的鍵/值清單,而且可能還有一塊 XML——XMP 封包——以更豐富、更具結構的形式說著大致相同的事。本頁談的就是這兩套平行的系統、為何兩者都存續至今,以及為何封存與搜尋管線堅持它們必須一致。
對於標題的簡短回答:一份 PDF 知道自己的標題、作者、主題、關鍵字、製作它的工具,以及製作的時間。它把這份知識同時存放在兩處,而有意思的工程在於讓它們保持誠實。
為何這很重要
標題為「為何這很重要」的區段中介資料是文件中人鮮少看見、而機器幾乎總是讀取的部分。你作業系統的檔案預覽、一套數位資產管理系統、一份圖書館目錄、一個搜尋索引、一個法律證據揭示工具——它們之中有許多會在讀取文件文字之前、或與之並行地讀取中介資料,並信任它所陳述的內容。
因此,當這兩套系統各說各話時——資訊字典說是某位作者、XMP 封包卻說是另一位——下游某處便會挑出一個,而你無法選擇是哪一個。搜尋索引可能浮現錯誤的標題。封存驗證器可能直接拒絕該檔案。這種偏移在被某條管線絆倒之前都是隱形的,而那正是發現它最糟糕的時機。
簡短版本
標題為「簡短版本」的區段- PDF 能以兩套平行的系統攜帶中介資料:舊有的文件資訊字典,以及由 RDF/XML 構成的現代 XMP 封包。
- XMP 封包被包裹在一個 xpacket 處理指令中——一個
begin標頭與一個end尾段——讓工具能夠找到它,甚至無須重新解析整個檔案就能就地改寫它。 - 屬性住在命名空間裡:
dc(Dublin Core)負責標題與建立者,xmp負責建立與修改日期,pdf負責製作者,xmpMM負責文件識別與歷程。 - PDF/A 要求 XMP 中介資料,而具有 XMP 對應項的 DocInfo 項目必須與之相符——彼此不一致即為一次驗證失敗。
- NextPDF 把這兩者視為一件工作:它同時寫入兩者、把 XMP 讀回,並為封包的大小把關,寧可失敗封閉也不輸出一個格式錯誤的檔案。
NextPDF 如何處理
標題為「NextPDF 如何處理」的區段誠實的描述是:這是一個被裝扮成格式問題的同步問題。文件資訊字典(Spec: ISO 32000-2, §14.3.3ISO 32000-2 §14.3.3)由尾段透過 /Info 項目參照,是一份扁平的字串清單:Title、Author、Subject、Keywords、Creator、Producer,外加幾個日期。它很簡單,早於 XML,而且因為太多工具仍會率先讀它,它至今仍幾乎搭乘在每一個檔案之中。
XMP 封包(Spec: ISO 16684-1:2019, §7ISO 16684-1:2019 §7)是現代的那一半。它是一份 XML 文件——精確地說是 RDF/XML——把檔案建模成一組分群進綱要的具名屬性,而每個綱要都繫結到一個命名空間(Spec: ISO 16684-1:2019, §6ISO 16684-1:2019 §6)。那種結構正是扁平字典所做不到的:一個值可以是有序清單、可以是帶語言標記的替代值(「英文標題、法文標題」),也可以是一筆結構化記錄。在 PDF 中,那段 XML 住在一個附加於文件目錄的中介資料串流裡(Spec: ISO 32000-2, §14.3.2ISO 32000-2 §14.3.2),那正是當代讀取器查看的標準位置。
有三個細節值得剖析,因為工具正是在這些地方把封包弄錯。
那個包裹。 XMP 封包被一個處理指令所框住,如此一來,在封包以可直接搜尋之位元組形式儲存的那些格式中,程式無須完整解析就能定位中介資料;而在 PDF 中,目錄的中介資料串流才是標準的定位器。begin 標頭攜帶一個宣告文字編碼的位元組順序標記;end 尾段攜帶一個旗標,陳述封包是唯讀的、還是可以就地編輯。當它可寫入時,序列化器會在 XML 之後留下一段空白填補,好讓編輯器能稍微增長內容、而不必位移其後的每一個位元組。那段填補不是裝飾——它正是讓就地中介資料編輯得以成立的東西。
那些命名空間。 一個屬性唯有對照其命名空間才有意義,而其中少數幾個近乎通用。Dublin Core(dc)保有標題與建立者。XMP 基本綱要(xmp)保有建立與修改日期,以及撰寫工具。PDF 綱要(pdf)保有製作者字串與關鍵字。媒體管理綱要(xmpMM)保有文件的識別與其衍生歷程——那條說著「這個檔案源自那一個」的軌跡。就這些命名空間 URI 與屬性名稱達成共識——通常以慣用前綴呈現——正是這些核心綱要的全部用意所在(Spec: ISO 16684-1:2019, Annex BISO 16684-1:2019 Annex B);兩個都會說 Dublin Core 標題屬性的工具,無須事先約定就能互通。
那條一致性規則。 因為兩套系統都能命名同一個屬性,它們便可能各說各話。封存設定檔拒絕允許這種情況。一份 PDF/A 檔案必須攜帶一個 XMP 中介資料串流,而任何具有 XMP 對應項的文件資訊項目都必須與之相符;彼此不一致即為一次驗證失敗。實務上的結論很直接:在一條封存管線中,這兩者並非各自獨立的欄位,而是被寫了兩遍的同一件事實,它們必須步調一致。
NextPDF 把這三者當成單一一個關注點來處理。中介資料的流程是一條路徑,而非兩條互相競爭的路徑。
- Collect the values onceTitle, author, subject, keywords, creator, producer and dates are set on the document a single time, so there is one source of truth, not two.
- Write the Info dictionaryThe DocInfo writer emits the legacy Title, Author, Subject, Keywords, Creator, Producer and date entries that older tools read first.
- Build the XMP packetThe XMP builder serializes the same values as RDF/XML under dc, xmp, pdf and xmpMM, wrapped in the xpacket header and trailer with writable padding.
- Guard the packet sizeBefore serialization is accepted, the engine checks the packet against a size bound and fails closed with a typed exception rather than emit a malformed or oversized stream.
- Read XMP back to verifyThe XMP reader parses the packet so a pipeline can confirm the engine wrote the metadata it was given — the kind of check an archival validator builds on.
實際範例
標題為「實際範例」的區段下方的形態把中介資料設定一次,並讓引擎將其散播到兩套系統,接著把 XMP 標題讀回來,好讓管線能加以檢視。那道大小防護,正是把「大概沒問題」轉成「如果不行就可被證明地拒絕」的那一行。
<?php
declare(strict_types=1);
use NextPDF\Core\Document;use NextPDF\Metadata\Exception\XmpPacketTooLargeException;
$document = Document::createStandalone();
// Set the values ONCE. The engine writes them to both the Info dictionary// and the XMP packet, so the two systems cannot drift apart at the source.$document->setTitle('Annual Report 2026');$document->setAuthor('Records Office');$document->setSubject('Statutory annual filing');$document->setKeywords('annual report, statutory, 2026');
try { // Building the document serializes the XMP packet. The engine guards the // packet size and fails closed: a packet that exceeds the bound is a // typed exception, never a silently truncated or malformed stream. $bytes = $document->getPdfData();} catch (XmpPacketTooLargeException $e) { // Decide deliberately: trim the metadata, not the guarantees. error_log('XMP packet exceeded the size bound: ' . $e->getMessage()); throw $e;}
// Read the packet back. This confirms the XMP the engine serialized carries the// value you set — the kind of integrity check an archival pipeline runs before// it trusts the file. (Both systems are written from one source, so they agree// by construction; reading the XMP back proves it serialized as intended.)$xmp = $document->readXmpMetadata($bytes);$xmpTitle = $xmp->get('dc', 'title'); // 'Annual Report 2026'
if ($xmpTitle !== $document->getTitle()) { throw new \RuntimeException('XMP title does not match the value that was set.');}這裡沒有任何路徑會讓兩套系統悄悄分歧:值只進入一次,兩個寫入器消費的是同一個來源,而讀取器讓管線得以檢查結果。
常見的誤解
標題為「常見的誤解」的區段常見的信念是,資訊字典已經過時,你可以忽略它。你不能——至少現在還不能。大量已安裝的軟體,包括某些作業系統的檔案預覽與較舊的封存工具,仍然率先、甚至只讀取資訊字典。丟掉它並不會讓檔案變得現代化;它只會讓那份檔案在任何尚未採用 XMP 的東西眼中看起來像是無標題。
與之鏡像相反的錯誤,是把這兩者當成你各自分別填寫的獨立欄位。那正是它們發生偏移的方式。它們是同一件事實的兩種序列化。要嘛從同一個來源寫入它們,要嘛接受下游某處將挑出你並不打算採用的那個版本。
限制與邊界
標題為「限制與邊界」的區段- NextPDF 同時寫入兩套系統並把 XMP 讀回。 它的範圍是 XMP 中介資料建構器、DocInfo 寫入器,以及一個 XMP 讀取器。它並不承諾要成為一個通用的 RDF/XML 查詢引擎。
- XMP 封包受大小防護並失敗封閉。 一個超出引擎界限的封包會引發一個型別化例外。引擎不會為了讓一個過大的請求「塞得下」,而輸出一個被截斷、填補超出界限、或以其他方式格式錯誤的封包。
- 一致性是在寫入時、由單一來源強制達成的;它不是對你並未產生之檔案的某種魔法調和。 如果你匯入一份其兩套系統早已各說各話的文件,要怎麼解決那是你的決定,而非一次隱含的改寫。
- PDF/A 的中介資料要求是封存設定檔的一部分。 本頁解釋規則;標準符合性的裁決則一如封存工作的慣例,歸屬於驗證器。關於那條邊界,參見封存頁面。
中介資料建構器、DocInfo 寫入器,以及 XMP 讀取器都是核心能力。那句誠實的但書,隨那道大小防護一同陳述於下。
| Edition | Availability |
|---|---|
| Core | The XMP metadata builder, the Document Information dictionary writer, and the XMP reader ship in Core, with the size guard that fails closed on an oversized packet — including the PDF/A conformance output and validation that make the XMP metadata stream mandatory and require DocInfo to match it. |
| Pro | Adds batch and templated metadata workflows over the same Core writer and reader. |
| Enterprise | Adds the broader conformance policy and reporting surface across a document estate. |
相關文件
標題為「相關文件」的區段- 封存與 PDF/A — XMP 封包在何處不再可有可無,而 DocInfo 與 XMP 的一致性規則在何處變成一項過或不過的要求。
- 可以交給稽核員的法規遵循 — 為何能往返且自洽的中介資料,是一份可稽核產物的一部分。
- PDF 檔案剖析 — 尾段、目錄與中介資料串流在檔案結構中坐落於何處。
- 串流與篩選器 — 中介資料串流就是一個串流;這就是 PDF 串流被編碼並保持確定性的方式。
詞彙表
標題為「詞彙表」的區段- 文件資訊字典 — 由尾段透過
/Info項目參照的舊有、扁平的鍵/值中介資料:Title、Author、Subject、Keywords、Creator、Producer,以及日期。早於 XMP;至今仍被廣泛讀取。 - XMP — 可擴充中介資料平台(Extensible Metadata Platform),一種以具名屬性(分群進綱要)描述資源的 XML(RDF/XML)格式。標準化為 ISO 16684-1。
- xpacket — 包裹一個 XMP 封包的處理指令,帶有一個
begin標頭(編碼標記)與一個end尾段(唯讀或可寫入旗標),讓工具無須完整解析就能定位並編輯封包。 - 命名空間/綱要 — 一套繫結到某個 URI 的具名屬性詞彙。常見前綴:
dc(Dublin Core)、xmp(XMP 基本)、pdf(PDF 專屬)、xmpMM(媒體管理/文件識別)。 - 中介資料串流 — 附加於文件目錄、攜帶 XMP 封包的那個 PDF 物件。現代讀取器最先查看的標準位置。
- PDF/A — 封存 PDF 的設定檔家族(ISO 19005)。它要求一個 XMP 中介資料串流,並要求任何具有 XMP 對應項的文件資訊項目都須與之相符,否則驗證失敗。