Блог

Поля метаданных PDF: title, language, author, subject, creator, producer

Разбор полей: шесть стандартных полей метаданных PDF, которые экспонирует gPdf — title, language, author, subject, creator, producer. Для чего каждое, кто его читает, типичные ошибки и как проверить отгруженное.

Спутник к В свойствах PDF должен значиться ваш бренд, а не чужой инструмент — та статья обосновывала, почему вообще стоит заботиться о метаданных PDF. Эта — рабочее руководство: для чего каждое поле в спецификации PDF, кто его читает, типичные ошибки и как убедиться, что ваш вывод действительно отгрузил то, что вы задумали.

gPdf экспонирует шесть стандартных полей, которые спецификация PDF определяет для метаданных уровня документа. Они живут под settings.metadata в JSON DocumentRequest. Каждое поле опционально — если вы его не задаёте, gPdf откатывается либо на default_metadata токена (фича Enterprise-политики), либо на системный default.

{
  "settings": {
    "metadata": {
      "title":    "...",
      "language": "...",
      "author":   "...",
      "subject":  "...",
      "creator":  "...",
      "producer": "..."
    }
  }
}

Дальше — по разделу на каждое поле. Каждый раздел следует одной форме: что это за поле, где оно всплывает, типичные ошибки, правило большого пальца. Порядок — что заполнять в первую → во вторую → … → в последнюю очередь.

title — что это за документ

Спецификация PDF описывает это как «заголовок документа».

Где всплывает:

  • Заголовок окна в просмотрщиках PDF (Adobe Reader, Preview, Foxit, PDF-просмотрщик Chromium — все его показывают).
  • Вкладка браузера, когда PDF открывается inline (Content-Disposition: inline).
  • Индексы поиска — Spotlight, Outlook, SharePoint, full-text индексатор Google Drive — все читают title и придают ему большой вес.

Типичные ошибки:

  • Делать title равным имени файла. invoice-20260318.pdf — это имя файла. Title должен быть тем, что читает человек, например Invoice INV-2026-3401. Имя файла и title — разные вещи; имя файла для файловых систем, title — для просмотрщиков и поиска.
  • Оставлять title пустым. Просмотрщики откатываются на имя файла. Результат читается как автосгенерированный и машинно-выданный.
  • Добавлять бренд в title. Acme Logistics — Invoice INV-2026-3401 захламляет заголовок окна. Бренду место в author, а не в title.

Правило большого пальца: title должен совпадать с H1 отрисованной страницы. Если верхняя строка вашего шаблона счёта — «Invoice INV-2026-3401», это и есть title.

language — для доступности, поиска и комплаенса

language — это языковая метка BCP-47: en, de, zh-Hans, pt-BR, ar-SA. Задавайте её для каждого документа. Из шести полей у него самые конкретные downstream-последствия при наименьшей стоимости внедрения — поэтому оно на позиции 2, а не закопано ниже.

Где всплывает:

  • Скринридеры — JAWS, NVDA, VoiceOver используют её, чтобы выбрать правильный набор фонем. Английский скринридер, читающий PDF с language: "de", будет корректно произносить немецкие слова; без метки просодия выходит неправильной.
  • Поисковые системы и индексаторы — влияет на то, какие правила стемминга и список стоп-слов локали применяются. Счёт с language: "zh-Hans" индексируется с китайской сегментацией; отсутствие метки часто откатывается на английский, и индекс становится непригоден.
  • Соответствие PDF/A — PDF/A-2a и PDF/A-3a (профили доступности) требуют языковую метку. Без неё валидация veraPDF проваливается.

Типичные ошибки:

  • Оставлять незаданным. По умолчанию используйте «локаль получателя», а не «default платформы». Большинство «протекающих» стеков просто не пишут это поле; результат — скринридеры, которые произносят неправильно, и поисковые индексы, которые неправильно стеммируют.
  • Использовать строку не по BCP-47 вроде "english" или "EN-US". Спецификация PDF ожидает теги RFC 5646: en, en-US, de, pt-BR.
  • Жёстко зашивать default платформы (например, всегда "en") без учёта реального языка содержимого документа. Счёт на португальском, помеченный как "en", хуже непомеченного — он активно вводит индексатор в заблуждение.

Правило большого пальца: метка должна совпадать с реальным языком содержимого. Для клиента в Бразилии, получающего счёт на португальском, задайте "language": "pt-BR", а не "en". Для многоязычных документов выберите доминирующий язык и используйте атрибут Lang на отдельных элементах содержимого для остального — это фича доступности tagged-PDF, отдельная от поля language уровня документа.

author — кому принадлежит документ

В спецификации PDF author — это «имя человека или организации, создавшей документ». Для бизнес-PDF, отгружаемых получателям, ответ почти всегда — организация — но правильная форма реально зависит от контекста.

Где всплывает:

  • Диалог свойств в каждом просмотрщике PDF, заметно подписанный как «Author».
  • Индексаторы DMS / архивов, часто используется как фильтр.
  • XMP-поток метаданных PDF/A, где он переносится в долгосрочные архивы.

Типичные ошибки:

  • "author": "[email protected]" — случайно сливает почту оператора в каждый PDF, попадает в каждый поисковый индекс, становится долгосрочной PII-проблемой.
  • "author": "PDF Generator Service" — внутреннее имя инструмента; ничего не значит для получателя.
  • ❌ Пусто — Preview и большинство просмотрщиков буквально показывают «(no author)» в диалоге свойств, что читается как «никому не принадлежит».

Формы, которые работают:

  • "author": "Acme Logistics, Inc." — простая организация.
  • "author": "Acme Logistics — Billing" — организация + отдел, для документов, идущих на конкретный стол.
  • "author": "Bridge Capital Partners — Fund III" — полезно в финансах/юриспруденции, где атрибуция к конкретной сущности.
  • "author": "Maria López, RICS Surveyor" — для одноавторных публикаций (отчётов, оценок, юридических заключений), где личность ЕСТЬ редакционная атрибуция.

Правило большого пальца: author — сущность, с которой получатель должен ассоциировать документ. В multi-tenant SaaS, где платформа генерирует PDF от имени клиентов, author должен быть именем организации клиента, а не именем платформы. (Имя платформы место в creator — см. ниже.) Для консалтинговых / издательских / юридических контекстов, где личности и есть бренд, личности подходят.

subject — какого типа этот документ

subject — это краткое-описание-документа. Просмотрщики не выводят его на видное место — большинство пользователей никогда его не увидят, если не откроют диалог свойств. Но системы документооборота, архивные системы и правило-ориентированный роутинг почты/файлов им пользуются.

Где всплывает:

  • Диалог свойств, вторичная позиция.
  • Правила роутинга DMS, логика бакетинга в архиве.
  • XMP-поток метаданных (PDF/A).

Типичные ошибки:

  • "subject": "Invoice for Acme on 2026-03-18 for $4,532.10" — это описание экземпляра документа, а не типа. Место — в title.
  • ❌ Пусто — теряете бесплатный «крючок» для роутинга downstream-системами.
  • ❌ Мешать классы непоследовательно ("Invoice" vs "Invoice/2026-03" vs "Monthly invoice") — фильтры DMS не могут бакетить по движущейся цели.

Формы, которые работают:

  • "subject": "Invoice"
  • "subject": "Monthly account statement"
  • "subject": "Shipping label — 4×6 thermal"
  • "subject": "Q3 2026 board pack"

Правило большого пальца: правильная гранулярность — класс документа, а не экземпляр. DMS с тысячами входящих PDF может роутить по subject, если вы дадите ему стабильный словарь. Выберите конечное множество классов для своей платформы и никогда не отклоняйтесь — каждый счёт, который генерирует ваша платформа, должен иметь ровно "subject": "Invoice".

creator vs producer — самая часто путаемая пара

Здесь большинство команд перестаёт читать спецификацию PDF и начинает гадать. Спецификация точна; два поля означают разное.

  • creator — приложение, произведшее исходный контент (upstream-система, решившая, что должно быть в документе).
  • producer — приложение, произведшее байты PDF (рендеринг-движок, превративший этот контент в PDF-файл).

Для биллинговой SaaS-платформы, генерирующей счета через JSON-to-PDF API вроде gPdf:

  • creator = биллинговая SaaS-платформа со своей версией. Это приложение решило, что это будет счёт Acme на $4 532,10.
  • producer = рендерер. По умолчанию это «gPdf». Но поскольку слой рендеринга — это инфраструктура, выбранная SaaS, SaaS вправе выставить producer в имя собственной платформы — её платформа в реальном смысле произвела байты PDF, делегировав gPdf как инфраструктуре.
{
  "creator":  "Acme Billing Platform v7.2",
  "producer": "Acme Billing Platform"
}

Где всплывают:

  • Диалог свойств, оба подписаны.
  • Вывод pdfinfo, бок о бок.
  • XMP-поток PDF/A (в PDF/A оба поля должны быть непустыми).

Типичные ошибки:

  • creator выставлен в строку user-agent Chromium / Mozilla. Случается, когда PDF-стек на headless-браузере автоматически прокидывает User-Agent в creator. Это версия браузера, а не источник правды. Переопределите.
  • producer оставлен как имя дефолтного рендерера. Большинство команд никогда его не переопределяют, поэтому каждый PDF говорит «Skia/PDF m120» или «wkhtmltopdf» — см. статью про white-label, почему это важно в B2B.
  • Класть одно и то же значение в оба. Допустимо, но расточительно — два поля существуют именно для того, чтобы просмотрщик мог отличить «исходное приложение» от «рендеринг-движка». Используйте их.

Правило большого пальца: creator — имя вашего приложения с версией (например, "Acme Billing Platform v7.2"); producer — бренд или имя платформы без версии (например, "Acme Billing Platform"). Оба должны быть значениями, которые получатель узнал бы.

Пустые поля, per-token defaults, downstream-сюрпризы

Три детали реализации, которые стоит знать перед отгрузкой:

  1. Пустые строки или строки только из пробелов трактуются как не переданные. Отправить "title": "" — то же, что не указать title — это не пишет пустую строку в PDF, а проходит цепочку фолбэка (default токена → default системы). Это причина наиболее распространённого отчёта о баге «я задал, не сработало».
  2. Политики токена могут вырезать или дефолтить поля метаданных. Multi-tenant SaaS, использующий gPdf, может задать default_metadata для каждого API-токена, чтобы каждый PDF, генерируемый этим токеном, нёс author и producer клиента, не полагаясь на то, что каждый разработчик задаст их в каждом запросе. Дефолт на уровне токена — правильный слой принуждения для «каждый PDF Acme должен говорить Acme».
  3. Downstream-пайплайны могут переписать ваши метаданные. Инструменты, постобрабатывающие PDF после возврата gPdf — Ghostscript без явных флагов сохранения метаданных, некоторые корпоративные DRM-инструменты, некоторые «оптимизаторы PDF» — могут перезаписать Producer собственным именем и отменить только что заданный брендинг. Проверяйте против реального production-пайплайна, а не только против сырого ответа gPdf.

Проверка ваших метаданных

После внедрения вышеописанных изменений три быстрых способа убедиться, что PDF действительно отгрузил задуманное:

Командная строка (macOS / Linux, требуется poppler-utils):

$ pdfinfo your-output.pdf | head -10
Title:           Invoice INV-2026-3401
Subject:         Monthly invoice 2026-03
Author:          Acme Logistics, Inc.
Creator:         Acme Billing Platform v7.2
Producer:        Acme Billing Platform
Language:        en

Acrobat / Adobe Reader: Файл → Свойства → вкладка Описание. Все шесть полей появляются, Title показывается в заголовке окна просмотрщика наверху.

Preview на macOS: ⌘+I (Получить информацию). Панель инспектора «PDF» показывает те же поля.

Если какое-то поле появляется пустым, бланковым или с именем инструмента, которое вы не задавали, пройдитесь по телу запроса заново — самая частая причина — отправка "" (пустой строки), которую API трактует как «не передано» и проходит по цепочке фолбэка до значения по умолчанию. Вторая по частоте причина — downstream-пайплайн (Ghostscript, DRM, оптимизатор), переписывающий поле после возврата gPdf; тестируйте против production, а не только против сырого ответа рендера.

Метаданные в архивировании PDF/A

Если вы рендерите для долгосрочного архивирования с settings.profile: "pdfa-2b" (или -2a, -3a, -3b), метаданные перестают быть опциональными и становятся несущими:

  • Поле producer не может быть пустым в файле, соответствующем PDF/A — как минимум отгружается системный default.
  • language обязателен для профилей доступности (PDF/A-2a, PDF/A-3a). Без него валидация veraPDF проваливается напрямую.
  • XMP-поток метаданных, который требует PDF/A, генерируется автоматически из шести вышеперечисленных полей; вам не нужно конструировать его самостоятельно.
  • title, author, subject, creator, producer и language — все попадают в XMP-поток, так что индексатор метаданных downstream-архива (Preservica, Archivematica) может строить свой каталог из них без повторного парсинга тела документа.

Для архивного документа брендированные метаданные — не просто полировка бренда, а часть долговечности артефакта. Немецкая таможня, бразильская налоговая или любой долгосрочный архив, который откроет ваш PDF через десять лет, увидит то, что было в этих полях в день рендера. Задать их явно во время рендера — единственный шанс, который у вас есть.

Чего gPdf (ещё) не экспонирует

Чтобы быть честным про текущую поверхность: спецификация PDF также определяет Keywords (свободные поисковые термины) и XMP-поток метаданных, поддерживающий произвольные пользовательские key-value пары. gPdf не экспонирует ни то, ни другое в текущем API.

Если вам нужно прятать произвольные бизнес-данные внутри PDF (UUID заказа, код склада, версию шаблона), сегодняшние обходные пути:

  • Задавать subject в виде структурированной короткой строки, которую парсят downstream-системы.
  • Хранить бизнес-данные в собственной базе, индексированной по имени файла или хешу содержимого.
  • Подождать — пользовательские поля XMP в roadmap, и когда они появятся, они будут правильным ответом для скрытого машино-читаемого контекста workflow.

Смешивать «брендированные метаданные» (шесть стандартных полей, доступных сейчас) с «пользовательскими бизнес-метаданными» (пользовательские поля XMP, в будущем) — самый простой способ переобещать то, что возможно сегодня. Стоит держать их раздельно в собственном планировании.

Полный пример

Биллинговая SaaS-платформа (Acme Billing Platform), генерирующая счёт для немецкого клиента (Müller Versand GmbH), готовая к архивированию как PDF/A:

{
  "settings": {
    "profile": "pdfa-3b",
    "metadata": {
      "title":    "Rechnung RE-2026-0412",
      "language": "de",
      "author":   "Müller Versand GmbH",
      "subject":  "Monatsrechnung — März 2026",
      "creator":  "Acme Billing Platform v7.2",
      "producer": "Acme Billing Platform"
    }
  }
}

pdfinfo по получившемуся PDF:

$ pdfinfo invoice-2026-0412.pdf | head -10
Title:           Rechnung RE-2026-0412
Subject:         Monatsrechnung — März 2026
Author:          Müller Versand GmbH
Creator:         Acme Billing Platform v7.2
Producer:        Acme Billing Platform
Language:        de

Title на немецком, author — Müller Versand (GmbH-сущность клиента, получатель документа), creator — Acme Billing Platform (редакционная система, решившая, что положить на страницу), producer — бренд Acme Billing Platform, язык корректно помечен для немецкого скринридера и для немецкого full-text индексатора, который позже подхватит это в DMS Müller. Профиль PDF/A-3b означает, что этот набор метаданных также сериализуется в XMP-поток для долгосрочного архивирования.

Ничто в свойствах файла не называет gPdf, Chromium или какой-либо инструмент, который клиент не выбирал. Что и есть суть.

Минимально возможное улучшение

Если вы уже делаете POST на /api/v1/pdf/render, и в вашем текущем вызове нет settings.metadata, минимальное улучшение — три строки, добавленные в JSON, который вы уже отправляете:

 {
   "pages": [...],
   "settings": {
+    "metadata": {
+      "author":   "Your customer's organisation",
+      "producer": "Your platform"
+    }
   }
 }

Два поля, один новый ключ. Проверяется pdfinfo за секунды. После того как это приземлится, заполните title, language, subject и creator, когда будет время.

Где это приземляется