Технічна стаття

Перетворення PDF на PDF/A та відновлення метаданих

ConvertToPDFA перетворює звичайний документ на архівний за один виклик: прибирає те, що заборонено обраною частиною, додає те, що вона вимагає, вказує частину, на яку претендує документ, а тоді перевіряє результат. Заявка звітується як виконана лише тоді, коли перевірка проходить, а GetPDFAConversionReport перераховує, що було зроблено і що все ще заважає

Саме остання властивість і є тим дизайнерським рішенням, про яке варто зупинитись. Конвертер, що проставляє заявку без перевірки, гірший за відсутність конвертера взагалі, бо файл, що стверджує про свою архівність, не будучи нею, минає саме ті системи, які б його виловили. Відмова спливає через роки, під час аудиту, на документі, який ніхто вже не може перегенерувати

Чому візуально коректний PDF не проходить перевірку PDF/A?

Найчастіше через те, що два місця, де PDF вказує свого автора, не погоджуються між собою. Валідатор читає і словник інформації про документ, і XMP-пакет, відхиляючи файл, де вони різняться — а більшість файлів, що не проходять з цієї причини, просто ніколи не мали записаної XMP-половини взагалі

RepairDocumentMetadata приводить їх до згоди й повертає кількість відновлених записів. Якщо значення несе лише одна половина, інша заповнюється з неї, тож уже записане не викидається. Нікому не доводиться вирішувати, яка копія авторитетна, адже на практиці одна копія порожня

У тому ж виклику є друге відновлення, що ловить тонший випадок. Документ, установлений у режим PDF/A, отримує відновлену ідентифікацію стандартів, якщо її було втрачено, — а це стається щоразу, коли викличний код постачається власним XMP-пакетом. Без цієї ідентифікації валідатор читає файл як звичайний PDF і звітує про кожне правило заявленої частини як невиконане — вражаюча відмова з однією малою причиною

var
  Lib: TPDFlib;
  Repaired: Integer;
begin
  Lib := TPDFlib.Create;
  try
    Lib.LoadFromFile('incoming.pdf', '');
    Repaired := Lib.RepairDocumentMetadata;
    Log(Format('%d metadata entries brought into agreement', [Repaired]));
    Lib.SaveToFile('incoming-fixed.pdf');
  finally
    Lib.Free;
  end;
end;

Вибір частини до перетворення

SetPDFAMode та ConvertToPDFA мають спільну нумерацію режимів, і три зі значень є новими. Режим 9 — це PDF/A-4, частина, побудована на PDF 2.0. Режим 10 — PDF/A-4e, що додатково дозволяє 3D та rich media, а режим 11 — PDF/A-4f, який дозволяє вбудований файл будь-якого формату

Частина 4 ідентифікує себе інакше за попередні частини: номером частини та роком публікації, без літери відповідності для звичайного PDF/A-4 і з літерою E або F для двох розширень. Перевірка розпізнає частину 4, оцінює її файли за PDF 2.0, а не 1.7, і звітує про файл частини 4, який не вказує рік своєї редакції

Кожен вбудований файл у документі частини 4 вказує свій зв'язок із документом, як вимагають як частини 3, так і 4. Це правило, яке раніше ловило звичайні вкладення: зв'язок записувався лише для вкладень після першого й ніколи для останнього, тож документ з одним вкладенням — типовий випадок — не мав його взагалі й не проходив валідацію саме з цієї причини

var
  Verdict: Integer;
begin
  Lib.LoadFromFile('report.pdf', '');
  Verdict := Lib.ConvertToPDFA(9);        // 9 = PDF/A-4, 10 = 4e, 11 = 4f
  Memo1.Lines.Text := Lib.GetPDFAConversionReport;
  if Verdict = 1 then
    Lib.SaveToFile('report-pdfa4.pdf')
  else
    Log('conversion incomplete - see the report for what stands in the way');
end;

Навіщо потрібен звіт про перетворення

Щоб вирішити, що робити далі. Перетворення, що успішне, не потребує звіту; перетворення, що не успішне — це вся причина існування звіту. Деякі перепони можуть бути усунуті конвертером, а деякі — ні: шифрування, заборонений вміст зі смисловим навантаженням, шрифтовий код, якого просто немає на машині. Звіт відрізняє те, що зроблено, від того, що залишилось, перетворюючи «перетворення не вдалося» на робочий пункт

Ставтеся до вердикту як до шлюзу в пакетному конвеєрі. Перетворіть, прочитайте вердикт і спряміть файл: заархівуйте ті, що пройшли, поставте решту в чергу для людини зі звітом у додатку. Чого не варто робити — це зберігати результат невдалого перетворення в архіві, бо він краще виглядає за вхід — тепер він несе заявку, яку перевірка відмовилася підтвердити

Читання позначки, яку файл уже несе

Перш ніж щось перетворювати, дізнайтеся, що документ каже про себе. Перевірка PDF/A, яка не вміє читати наявну позначку стандартів, оцінює кожен файл за частиною 1, що б він не заявляв, тож цілком коректний документ PDF/A-2 або PDF/A-3 звітується як такий, що не має позначки і має занадто високу версію — протилежне істини

Позначка читається незалежно від того, чи написав її автор як XMP-елемент, чи як атрибут. Обидві форми — звичайний XMP, і прийняття лише однієї з них залишає файли від інших авторів такими, що виглядають непозначеними. Якщо ви коли-небудь дивувалися, чому документ, що валідується в інших місцях, не проходить у вашому власному конвеєрі, це хороше місце, щоб перевірити першим

Очищення перед архівуванням та вада, про яку варто знати

Архівне перетворення та очищення часто працюють разом, бо вміст, який хоче прибрати політика безпеки, значною мірою перетинається зі вмістом, який забороняє PDF/A. SanitizeDocument прибирає JavaScript, а видалення останнього скрипта також прибирає порожнє дерево імен, яке він залишає за собою — дерево, яке інакше й далі казало б читачеві, що документ мав скрипти

Друга половина була засвоєна важким способом: помилка off-by-one у списку пакунків означала, що очищення звітувало про видалення скриптів, не видаливши жодного, тож документ, який нібито пройшов очищення, усе ще запускав свої скрипти при відкритті. Це слушний аргумент на користь загального принципу, на якому тримається вся ця стаття — перевіряйте результат, а не довіряйте операції, як у власному конвеєрі, так і в самій бібліотеці

З приводу супутньої архівної роботи дивіться нариси префлайта PDF/A та PDF/UA, справжнього редагування та вилучення вмісту і схем розширення XMP для PDF/A-3 Factur-X, який описує бік метаданих, коли архівний документ також несе структуровані дані рахунка

PDFlibPas — це рідна Pascal-бібліотека PDF для Delphi, C++Builder та Lazarus, тож перетворення, відновлення та валідація відбуваються всередині вашого власного процесу без зовнішнього інструмента в ланцюжку — дивіться сторінку продукту PDFlibPas щодо підтримуваних частин PDF/A та платформ