מאמר טכני

פלט PDF/A, PDF/X ו-PDF/UA ב-Delphi: מדריך ל-HotPDF

PDF/A, PDF/X ו-PDF/UA הם שלושה תקנים שונים הפותרים שלוש בעיות שונות: ארכיון לטווח ארוך, החלפה לדפוס, ונגישות. הם אינם שלושה תיבות סימון בטופס תאימות אחד, והטעות הנפוצה ביותר היא לטפל בהם כאילו היו כאלה. קובץ יכול להיות PDF/A מושלם ולא שימושי לבית דפוס; מאסטר דפוס מושלם יכול להיות בלתי קריא לקורא מסך. גרוע מכך, שלושתם הם אילוצים על המבנה הפנימי של הקובץ, לא על מראהו. מסמך שנפתח באופן תקין בכל מציג שברשותך עדיין יכול להיכשל באימות בניסיון הראשון, ובדרך כלל כך גם קורה

HotPDF, ספריית ה-PDF המקורית מסוג VCL של losLab, מתייחסת לתאימות כמשהו שמצהירים עליו לפני שעמוד ראשון קיים. מגדירים מאפיין תאימות, מצרפים את המבנים שהתקן דורש, והספרייה דוחה תצורות שסותרות את הפרופיל בזמן שמירה. זה מודל טוב יותר מאשר יצירת קובץ ותקווה שמעבד לאחר עיבוד יוכל להוסיף לו את הדרישות בדיעבד, כיוון שרוב מה שתקנים אלה דורשים אינו ניתן להוספה לאחר העובדה

שלושה תקני ISO, שלושה הבטחות שונות

PDF/A (ISO 19005) עוסק בזמן. הוא מבטיח שקובץ עדיין יעובד באופן זהה עשרות שנים מעכשיו, ולכן הוא דורש עצמאות מוחלטת: כל גופן מוטמע, כל צבע מקבל משמעות בלתי-תלויה-התקן באמצעות OutputIntent, מטא-נתוני XMP מלאים, ואיסור על כל דבר שהתנהגותו תלויה בסביבה. הצפנה ו-JavaScript אסורים, כיוון שאיש אינו יכול להבטיח שמפענח ההצפנה או מנוע הסקריפט יקיימו קיום בשנת 2050

PDF/X (ISO 15930) עוסק בצבע על נייר. הוא קיים כדי שמעצב יוכל למסור קובץ לבית דפוס מבלי שאף אחד מהם יצטרך לדון בכך, מה שאומר תנאי הדפסה מאופיינים, מפתח /Trapped חובה, גיאומטריה מוגדרת של חיתוך ודימום, ובגרסת X-1a, ללא שקיפות חי שה-RIP יצטרך לנחש. PDF/UA (ISO 14289) עוסק במי שיכול לקרוא את התוצאה. טכנולוגיה מסייעת זקוקה לעץ תגים מלא, סדר קריאה הגיוני, שפת מסמך מוצהרת, וחלופות טקסט לכל מה שאינו טקסט

מכיוון ששלושתם מושכים לכיוונים שונים, בחרו את התקן המנחה לפי ערוץ הפלט ולא תרדפו אחרי קובץ אחד שמספק את כולם. מאסטר דפוס ב-CMYK בלבד הוא בדיוק הדבר הלא נכון למסור למשתמש קורא מסך שאינו רואה צבע מעולם, ונעילת פרופיל הארכיון על התנהגות דינמית מתנגשת עם כל דבר אינטראקטיבי. צרו לפי ערוץ מאותם נתוני מקור ותעקפו את הסכסוך כולו

PDF/A: ה-OutputIntent הוא החלק שכולם שוכחים

אם קובץ PDF/A נכשל באימות, ה-OutputIntent הוא הדבר הראשון לבדוק. זהו המבנה שגנרטורים מדלגים עליו לרוב, בדיוק מכיוון שאף דבר גלוי אינו תלוי בו. ISO 19005 דורש אחד: פרופיל ICC מוטמע שמקבע את משמעות צבעי ההתקן של המסמך. HotPDF הופך את אותו פרופיל לקלט מפורש ולא לדבר שנוסף בדיעבד:

var
  Pdf: THotPDF;
  ICC: TFileStream;
begin
  Pdf := THotPDF.Create(nil);
  try
    Pdf.FileName := 'invoice-archival.pdf';
    Pdf.PDFACompliance := 'B';            // level B: visual fidelity
    Pdf.Lang := 'en-US';
    Pdf.StandardFontEmulation := False;   // embed real fonts, no Base-14 emulation
    ICC := TFileStream.Create('sRGB.icc', fmOpenRead);
    try
      Pdf.AddPDFAOutputIntent('sRGB IEC61966-2.1', '', ICC, 3, 'DeviceRGB');
    finally
      ICC.Free;
    end;
    Pdf.BeginDoc;
    Pdf.CurrentPage.SetFont('Arial', [], 11);
    Pdf.CurrentPage.TextOut(50, 760, 0, 'Archival invoice body');
    Pdf.EndDoc;
  finally
    Pdf.Free;
  end;
end;

כמה פרטים קובעים הצלחה או כישלון כאן. StandardFontEmulation חייב להיות כבוי: גופנים מדומים מסוג Base-14 אינם מוטמעים, והטמעה אינה ניתנת למיקוח תחת ISO 19005. הצפנה חייבת להישאר מושבתת, לכן לעולם אל תשלבו PDFACompliance עם ActivateProtection; קובץ ארכיון מוצפן הוא סתירה שה-validator תופס מיידית. ספירת הרכיבים ב-AddPDFAOutputIntent חייבת להתאים לפרופיל, שהוא 3 עבור פרופיל RGB כמו sRGB IEC61966-2.1 ו-4 עבור CMYK. HotPDF עוקב אחר שימוש ב-DeviceRGB ו-DeviceCMYK מול הכוונה המוצהרת בזמן הכתיבה, כך שצביעת CMYK אקראית במסמך בכוונת RGB הופכת לבעיה מדווחת ולא לשקטה

דבר אחד ראוי לציין לגבי פרופיל ה-ICC: יש להתייחס אליו כאל ארטיפקט פריסה עם גרסה, לא כקובץ שמישהו פעם הפיל על שרת הבנייה. הבייטים שלו מוטמעים בכל מסמך שמייצרים, לכן פרופיל קטוע או פגום מרעיל בשקט אצווה שלמה, ומגלים זאת רק בזמן האימות. שלחו אותו עם המתקין שלכם, רשמו את ה-checksum שלו ביומן ההרצה, וטענו אותו דרך התבנית של TFileStream המוצגת לעיל כדי שקובץ חסר ייכשל בקול בזמן היצירה ולא בשקט בשער הארכיון

PDF/X לדפוס: Trapped, CMYK ופרופיל המכבש

מאסטרי דפוס הופכים את סיפור הצבע. המכבש רוצה CMYK מאופיין, והתקן מחייב לציין האם שימוש ב-trapping בוצע גם כאשר התשובה הכנה היא שאין לך מושג. מפתח /Trapped הוא חובה ללא יוצא מן הכלל:

Pdf.PDFXCompliance := 'X-1a';
Pdf.Trapped := 'Unknown';        // mandatory key under ISO 15930
ICC := TFileStream.Create('FOGRA39.icc', fmOpenRead);
try
  Pdf.AddPDFXOutputIntent('FOGRA39 (ISO 12647-2:2004)', '', ICC, 4, 'DeviceCMYK');
finally
  ICC.Free;
end;
Pdf.BeginDoc;
// draw with CMYK-safe colors, no transparency, no encryption
Pdf.EndDoc;

ספירת הרכיבים היא עכשיו 4 עבור פרופיל מכבש ה-CMYK. X-1a גם אוסרת שקיפות חי, לכן בדקו כל קוד ציור שמשכב אלמנטים שקופים; מה שמציג מחבר על המסך הוא בדיוק מה שה-RIP יסרב לפרש. כאשר בית הדפוס שלכם שולח אפיון שונה, החליפו את בייטי הפרופיל ואת מחרוזת המזהה אך השאירו את המבנה הסובב ללא שינוי

PDF/UA: המבנה נוצר, לא מורכב לאחר מכן

נגישות היא התקן שצוותים מנסים לרוב להוסיף בסוף, והיא מענישה את הגישה הזו קשה יותר מהשניים האחרים. עץ התגים חייב לשקף את הסדר שבו תוכן נוצר באופן לוגי, שהיא מידע שאין לכם עוד ברגע שהקובץ נכתב. הגדרת PDFUACompliance מפעילה פלט מתויג, וה-API של המבנה קושר כל קריאת ציור לתפקידה הסמנטי תוך כדי התקדמות:

Pdf.PDFUACompliance := True;     // auto-enables tagged PDF
Pdf.Lang := 'en-US';             // set explicitly; empty falls back to 'en'
Pdf.BeginDoc;

Root := Pdf.AddStructureElement(sstDocument, nil);
H1 := Pdf.EmitTaggedHeading(1, Root, 50, 700, 'Quarterly Report');
Para := Pdf.BeginTaggedContent('P', Root);
Pdf.CurrentPage.TextOut(50, 650, 0, 'Revenue grew in all regions.');
Pdf.EndTaggedContent;

Pdf.EndDoc;

הכישלון לשים לב אליו הוא טקסט שנצייר מחוץ לכל זוג BeginTaggedContent/EndTaggedContent. הוא מעובד בצורה מושלמת ונשאר בלתי נראה לקורא מסך, כך שאף בודק עם ראייה אינו מוצא אותו לעולם; הבאג נשלח ומשטח רק כאשר משתמש טכנולוגיה מסייעת אמיתי נתקל בפער. כאשר התבניות שלכם נושאות שמות תפקידי מבנה מותאמים אישית, מפו אותם על הקבוצה הסטנדרטית עם AddStructRoleMap('MyHead', 'H1') כדי שקוראים תואמים ידעו את משמעותם. ISO 14289 גם דורש שפה מוצהרת. HotPDF חוזר ל-'en' כאשר Lang ריק, אך זהו רשת ביטחון, לא סיבה להשאיר את שפת המסמך האמיתית לא מוגדרת

אימות: סמכו על ה-validator, לא על המציג

מציג שפותח את הקובץ שלכם לא מוכיח דבר לגבי תאימות, לכן האימות שייך לנתיב השחרור עם כלים שבודקים מבנה ולא עיבוד. עבור PDF/A ו-PDF/UA, veraPDF הוא ה-validator הפתוח ברמת ייחוס; הוא מדווח כישלונות לפי סעיף ISO, שמתמפה ישירות לתצורה לעיל. עבור PDF/X, פרופילי Preflight של Adobe Acrobat הם עדיין הבדיקה המעשית, כיוון שתאימות המכבש עוסקת בכוונת הצבע לא פחות מאשר בתחביר

הגנרטור עושה את חלקו שלו בכך. בזמן שמירה, HotPDF מפייס את דגלי הפיצ'רים מול גרסת ה-PDF המוגדרת, בהורדה שקטה של מה שהגרסה אינה יכולה לבטא, כמו AES-256 שיורד ל-AES-128 מתחת ל-PDF 1.7. שערי התאימות ב-EndDoc הולכים רחוק יותר ומעלים שגיאה ישירות על סתירות קשות, כמו בקשה ל-PDFACompliance יחד עם הצפנה. אף אחד מאלה אינו מחליף את ה-validator החיצוני. הם רק עוצרים תצורות בלתי אפשריות מלהגיע אליו

הרגל אחד משתלם שוב ושוב: גרסאו את כל הגדרת התאימות כיחידה. גרסת HotPDF, גרסת התבנית, ה-checksum של פרופיל ה-ICC, בניית ה-validator שחתמה. התאימות מסתחררת ברגע שאחד מהם משתנה תחת האחרים, והביקורות המכוערות ביותר הן אלה שבהן אף אחד לא יכול לשחזר איזה שילוב ייצר קובץ ארכיון בן חמש שנים. רשומת תצורה אחת לכל אצווה מסדרת את זה לצמיתות

לבסוף, הריצו את ה-validator על פלט ייצור אמיתי, לעולם לא על דוגמה מסודרת בנויה ביד. הכישלונות שנושכים מגיעים מנתונים שאף אחד לא ציפה להם: לוגו לקוח שמגיע כ-CMYK בעוד שהכוונה אומרת RGB, שינוי תבנית שמחליק גופן לא מוטמע, נתיב קוד חדש שמצייר טקסט מחוץ לעץ התגים. שמרו קובץ אחד ידוע-כרע מכל אירוע עבר כקלט רגרסיה ושער התאימות נשאר ישר לאורך זמן. לצד העיבוד של צינורות אלה, ראו את המאמר שלנו על פלט דוחות, גופנים ותמונות עם HotPDF; לחיבור validators לבנייה, יש מלווה על אוטומציה של בדיקות preflight ל-PDF

מאפייני התאימות, כוונות הפלט וה-API של תיוג המשמשים בדוגמאות אלה מגיעים עם HotPDF Component עבור Delphi ו-C++Builder; דף המוצר מקשר את הייחוס המלא לכל קריאה המוצגת כאן