ConvertToPDFA הופך מסמך רגיל למסמך ארכיוני בקריאה אחת: הוא מסיר את מה שהחלק שנבחר אוסר, מוסיף את מה שהחלק דורש, מצהיר על החלק שהמסמך טוען לו, ואז בודק את התוצאה. הטענה מדווחת כמתקיימת רק כשהבדיקה עוברת, ו-GetPDFAConversionReport מפרט מה נעשה ומה עדיין עומד בדרך
התכונה האחרונה היא החלטת התכנון שכדאי לשהות עליה. ממיר שמטביע את הטענה בלי לבדוק גרוע מאשר שום ממיר כלל, מפני שקובץ שאומר על עצמו שהוא ארכיוני ואינו כזה חולף ישירות דרך אותן מערכות שאחרת היו תופסות אותו. הכישלון מתגלה שנים מאוחר יותר, בביקורת, על מסמך שאיש אינו יכול לייצר מחדש
למה PDF תקין-למראה נכשל בבדיקת PDF/A?
לרוב משום ששני המקומות שבהם PDF אומר מי כתב אותו חלוקים. מאמת קורא גם את מילון מידע המסמך וגם את מנת ה-XMP ודוחה קובץ שבו הם שונים — ורוב הקבצים שנכשלים בנקודה זו פשוט מעולם לא כתבו את מחצית ה-XMP כלל
RepairDocumentMetadata מביא אותם לידי הסכמה ומחזיר כמה רשומות תיקן. כשרק מחצית אחת נושאת ערך, השנייה מתמלאת ממנה, כך ששום דבר שכבר נרשם אינו מושלך. אף אחד צריך להכריע איזה עותק סמכותי, כי בפועל עותק אחד ריק
יש תיקון שני באותה קריאה שתופס מקרה עדין יותר. מסמך שהוגדר למצב PDF/A מקבל בחזרה את זיהוי התקנים שלו אם אבד, מה שקורה בכל פעם שקורא מספק מנת XXP משלו. בלי זיהוי זה מאמת קורא את הקובץ כ-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 ומדיה עשירה, ומצב 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 ברשימת החבילות גרמה לכך שחיטוי דיווח על הסרת סקריפטים בעוד שלא הסיר כלל, כך שמסמך שחוטא עדיין הריץ את הסקריפטים שלו בפתיחה. זה נימוק טוב לעיקרון הכללי שעליו נשען כל המאמר הזה — יש לאמת את התוצאה במקום לבטוח בפעולה, בצינור שלך לא פחות מאשר בספרייה
לעבודה הארכיונית הסובבת, ראה הסקירות של preflight של PDF/A ו-PDF/UA, גילוי נכון והסרת תוכן, ו-סכמות הרחבת XMP של PDF/A-3 עבור Factur-X, שמכסה את צד המטא-נתונים כשהמסמך המאורכי נושא גם נתוני חשבונית מובנים
PDFlibPas היא ספריית PDF מקורית בפסקל לדלפי, C++Builder ו-Lazarus, כך שהמרה, תיקון ותיקוף כולם מתרחשים בתוך התהליך שלך ללא כלי חיצוני בשרשרת — ראה את דף המוצר של PDFlibPas לחלקי PDF/A והפלטפורמות הנתמכים