רכיב PDFium מתקף את מגבלות המימוש של ISO 19005-1 נספח C — token שם של 127 בייט, 8191 אלמנטי מערך, 4095 רשומות מילון ו-28 רמות של קינון מיכל — ומדווח על גופן TrueType סימבולי שנושא רשומת /Encoding. שתי הבדיקות רצות בנתיב סריקת-הבייטים, כך שיישום דלפי או Lazarus מקבל את פסק הדין מבלי לטעון את ה-DLL של PDFium כלל
אלה הכישלונות שמבלבלים אנשים יותר מכול, מפני שהמסמך נראה בסדר. הוא מרונדר, מודפס, כל הגופנים מוטמעים, output intent נוכח. ואז מאמת דוחה אותו בגין מילון שיש לו 4096 רשומות, ושום דבר במסמך הגלוי אינו מסביר למה
מה מגבלות נספח C באמת מגנות?
פעולת-גומלין עם מימושים שקדמו לגנרטור שלך. נספח C מעביר הלאה את מגבלות המימוש של PDF Reference לכל חלק PDF/A, והמספרים אינם שרירותיים — הם מתארים מה קורא תואם נדרש היסטורית לטפל בו. קובץ שחורג אותן עשוי להיפתח בצורה מושלמת בקורא מודרני ולהיכשל בקורא הארכיוני שמערכת רשומות התקננה עליו לפני חמש-עשרה שנה, שזה בדיוק התרחיש ש-PDF/A קיים כדי למנוע
ארבע המגבלות כוללניות. token שם של בדיוק 127 בייט עובר; 128 לא. מערך עם בדיוק 8191 אלמנטים עובר; 8192 לא. רכיב PDFium מצמיד את שני הצדדים של כל גבול בחבילת הבדיקות שלו מסיבה זו, מפני ש-off-by-one בבדיקת מגבלה מייצר את סוג המאמת הגרוע ביותר: כזה שדוחה קבצים תואמים ועדיין מקבלים אותו כאמת
uses FPdfPdfa;
var
Src: TFileStream;
Res: TPdfAValidationResult;
begin
Src := TFileStream.Create('archive.pdf', fmOpenRead or fmShareDenyWrite);
try
Res := ValidatePdfACompliance(Src);
if pvaiArrayOverLimit in Res.Issues then
Memo1.Lines.Add('An array carries more than 8191 elements');
if pvaiDictOverLimit in Res.Issues then
Memo1.Lines.Add('A dictionary carries more than 4095 entries');
if pvaiNestingOverLimit in Res.Issues then
Memo1.Lines.Add('Containers nest deeper than 28 levels');
if pvaiNameOverLimit in Res.Issues then
Memo1.Lines.Add('A name token is longer than 127 bytes');
finally
Src.Free;
end;
end;
אילו גנרטורים באמת פוגעים במגבלות אלה?
כאלה שבונים מבנה פרוגרמטית, שזה רוב פלט line-of-business. טופס עם אלפי שדות אחדים מייצר מערך /Annots או מערך /Fields של AcroForm שגדל מעבר ל-8191. עמוד שמילון המשאבים שלו צובר רשומה אחת לכל תמונה או מופע גופן שנוצר חוצה את 4095. עצי מבנה שנוצרים עמוק — מסמך מתויג שנבנה על ידי רקורסיה על מודל נתונים מקונן — חולפים על פני 28 רמות מבלי שאף אחד יבחין, כי אף אחד אינו מסתכל על עומק קינון
שמות ארוכים באים מהרגל אחר: קידוד נתונים לתוך token שם. שם colorant שנבנה ממזהה לקוח, קבוצת תוכן-אופציונלי שנקראת על שם נתיב קובץ מלא, שדה טופס שהשם המוסמך-במלוא שלו משרשר שש רמות של היררכיה. שמות זולים לייצר וקלים להאריך, ו-127 בייט נעלמים מהר יותר ממה שהיית מצפה ברגע שתווית מקודדת UTF-8 מעורבת
התיקון מבני בכל מקרה. פצל את המערך, פצל את המילון, שטח את הקינון, קצר את השם — המלצת ה-preflight עבור כל בעיה נוקבת במגבלה הקונקרטית במקום לומר לך שהקובץ אינו תקין. הזרקת סמן אינה יכולה לעזור כאן: אלה אינן טענות מטא-נתונים, אלא צורת גרף האובייקטים
למה גופן TrueType סימבולי אסור שיישא /Encoding
מפני ש-ISO 19005-1 §6.3.7 מקבל רק את ה-cmap המובנה של הגופן עבור גופנים סימבוליים, ורשומת /Encoding הייתה סותרת אותו. גופן סימבולי ממפה קודים לגליפים בתנאים שלו — זה מה שסימבולי אומר. הוסף טבלת קידוד ויש עתה שתי תשובות לשאלה "איזה גליף בוחר בייט 0x41", ללא כלל בקובץ שאומר איזה מנצח. קוראים שונים פותרים את זה אחרת, ומסמך שמרונדר כטקסט בקורא אחד מרונדר כדינגבטים באחר
רכיב PDFium קורא את דגל ה-symbolic מתוך /FontDescriptor, בין אם ה-descriptor כתוב inline במילון הגופן ובין אם מופנה בעקיפין. גופן TrueType לא-סימבולי שומר על /WinAnsiEncoding או /MacRomanEncoding הנדרשים שלו מבלי להיות מסומן, מפני שעבור גופנים לא-סימבוליים הקידוד הוא בדיוק מה שהתקן מבקש. הבדיקה נורית על הסתירה, לא על נוכחות קידוד
if pvaiSymbolicTrueTypeEncoding in Res.Issues then
Memo1.Lines.Add(
'A symbolic TrueType font carries /Encoding; PDF/A admits only its ' +
'built-in cmap (ISO 19005-1 6.3.7)');
המקור המעשי של ליקוי זה הוא subsetting של גופנים שנעשה על ידי מפיק שמתייחס לכל גופן TrueType באותו אופן. Symbol, Wingdings, גופני ברקוד וגופני אייקון הם הנשאים הרגילים — בדיוק הגופנים שמסמך עסקי משתמש בהם לתיבות סימון, לוגואים וברקודים, ובדיוק אלה שאף אחד אינו בוחן מחדש כשמסמך נכשל בתיקוף על "גופנים"
כיצד הבעיות מגיעות לדוח preflight
ארבע מגבלות המיכל מסווגות תחת מבנה; בעיית הקידוד של TrueType סימבולי מסווגת תחת תוכן. חלוקה זו חשובה כשדוח הולך לשני אנשים שונים: ממצאי מבנה בדרך כלל שייכים למי שכתב את הגנרטור, וממצאי תוכן בדרך כלל שייכים למי שסיפק את הנכסים
כל בעיה נושאת המלצה שנוקבת בתרופה במונחים קונקרטיים — קצר token שם ל-127 בייט או פחות, פצל מערכים כך שאף אחד לא יישא יותר מ-8191 אלמנטים, הסר /Encoding מגופני TrueType סימבוליים. דוח שאומר "לא תואם PDF/A" מתחיל חקירה. דוח שאומר איזו מגבלה חריגה ועל ידי מה מסיים אחת
תיקוף ללא ה-DLL, ולמה זה חשוב כאן
כל הבדיקות לעיל רצות כנגד בייטי הקובץ, כך שהן עובדות בשירות שאין לו בינארי PDFium פרוס, בצעד build, או על מכונה שבה טעינת DLL מקורית היא בעיית מדיניות. זוהי קו עיצוב מכוון ברכיב PDFium: הבדיקות שניתנות למענה ממבנה נענות ממבנה, וה-DLL שמור לאלה שבאמת זקוקות למנוע רינדור
לזרימת העבודה הסובבת — הרצת תיקוף על תיקייה, ייצור דוחות, והכרעה מה לעשות עם הממצאים — ראה הסקירות של תיקוף preflight של PDF/A בדלפי ושל CLI של דוח preflight אצוותי. לבחירת הפרופיל הארכיוני שיושבת מעל כל הבדיקות הללו, ההערות על תאימות ארכיונית PDF/A מכסות איזה חלק ורמה למקד לפני שמתחילים לתקן ממצאים
רכיב PDFium עוטף את מנוע PDFium לדלפי, C++Builder ו-Lazarus עם ממשק API VCL ברמה גבוהה וסט של מאמתי תאימות שרצים עם או בלי ה-DLL — ראה את דף המוצר של רכיב PDFium לתקנים והפלטפורמות הנתמכים