PDF/R, שתוקנן כ-ISO 23504-1, הוא פרופיל ה-PDF למסמכים סרוקים: כל עמוד נושא בדיוק תמונת רצועה אחת ושום דבר מעבר. רכיב PDFium מתקף אותו מדלפי, Lazarus ו-C++Builder דרך ValidatePdfRCompliance, שקורא זרם ומחזיר את רמת התאימות בתוספת סט של בעיות קונקרטיות
הפרופיל קיים מפני שסורקים ומערכות לכידת-מסמכים נזקקו ליעד צר יותר מ-PDF/A. PDF ארכיוני עשוי להכיל כל דבר שהחלק מתיר; PDF ראסטרי מורעב בכוונה, כך שכל קורא תואם יכול להציגו בצורה זהה וכל כותב תואם יכול לייצרו מסריקה ללא מנוע authoring
מה PDF/R אוסר ש-PDF/A מתיר?
טקסט, למעשה. עמוד ראסטרי נושא את התמונה הסרוקה ושום דבר נוסף, כך שמשאב גופן בעמוד הוא הפרה — המדווחת כ-pvriFontForbidden תחת ISO 23504-1 §6.5.2. זה מפתיע אנשים שמוסיפים שכבת טקסט OCR בלתי-נראית לחיפוש, שהיא דבר נורמלי ושימושי לעשות בזרימת עבודה של PDF/A ופשוט אינה PDF/R
יחס העמוד-לתמונה קפדני באותה מידה. §6.5.1 הופך כל עמוד לתמונת רצועה אחת בדיוק, כך ש-pvriPageImageMismatch נורה כשספירת התמונות אינה תואמת את ספירת העמודים — עמוד ללא תמונה ועמוד עם שתיים שניהם בלתי-תואמים. ו-pvriBadMediaBox מדווח על עמוד שה-MediaBox שלו אינו בעל הצורה [0 0 w h] (§6.5.3), מפני שלסריקה אין סיבה לשבת בראשית מוסטת
uses FPdfPdfr;
var
Src: TFileStream;
Res: TPdfRValidationResult;
begin
Src := TFileStream.Create('scan-batch-0142.pdf', fmOpenRead or fmShareDenyWrite);
try
Res := ValidatePdfRCompliance(Src);
if Res.IsCompliant then
Memo1.Lines.Add('PDF/R-1 conformant')
else
begin
if pvriFontForbidden in Res.Issues then
Memo1.Lines.Add('A page names a font resource; a raster page carries no text');
if pvriPageImageMismatch in Res.Issues then
Memo1.Lines.Add('Image count does not match page count');
if pvriForbiddenImageFilter in Res.Issues then
Memo1.Lines.Add('A strip image uses an encoding outside the white list');
end;
finally
Src.Free;
end;
end;
אילו קידודי תמונה מותרים
ארבעה, והרשימה הלבנה קצרה מסיבה. §6.6 מקבל את /CCITTFaxDecode, /DCTDecode, /JPXDecode ו-/FlateDecode — פקס דו-רמתי, JPEG, JPEG 2000 ו-deflate ללא-איבוד, שביניהם הם מכסים כל פלט סורק שחשוב. כל דבר אחר מדווח כ-pvriForbiddenImageFilter, כולל /LZWDecode, /RunLengthDecode, /ASCII85Decode, /ASCIIHexDecode, /JBIG2Decode ו-/Crypt
שתיים מאותן דחיות כדאי להבין במקום לשנן. /JBIG2Decode דוחס סריקות דו-רמתיות טוב ביותר וחוקי לחלוטין ב-PDF/A, אך סידות-מחדש של מילון הסימנים שלו יכול להחליף גליפים דומים-חזותית — אופן כשל מתועד עבור ספרות סרוקות — ופרופיל שכל מטרתו היא רבייה ראסטרית נאמנה אינו יכול לקבל סיכון זה. מסנני ASCII אינם כלולים מהסיבה ההפוכה: הם מנפחים את הקובץ מבלי להוסיף דבר שפרופיל ראסטרי זקוק לו
כללי מבנה שנורים לפני קריאת כל עמוד
PDF/R מגביל גם את המיכל. pvriObjStmPresent מדווח על זרם /Type /ObjStm, שהפרופיל אוסר לחלוטין — זרמי אובייקטים מסבכים את הניתוח הפשוט והסדרתי שקורא ראסטרי אמור להיות מסוגל לבצע. pvriBadHeader מדווח על כותרת מחוץ ל-%PDF-1.4 עד 1.7 ו-%PDF-2.0, ו-pvriEncryptVersionMismatch מדווח על קובץ מוצפן שכותרתו אינה %PDF-2.0, לפי §6.2.3
הקטלוג ומילון Info ברשימה-לבנה, לא רק נבדקים. pvriProhibitedCatalogEntry ו-pvriProhibitedInfoEntry נורים עבור רשומות מחוץ לסט המותר, ו-pvriInfoXmpMismatch נורה כשרשומת Info אינה מסכימה עם המקבילה ה-XMP שלה. למילון /Metadata חסר בקטלוג, ל-/ID חסר ב-trailer ולסמן כף-הרגל %PDF-raster-1.0 נעדר לכל אחד מהם יש בעיה משלו גם כן
למה רשומת אפשרויות השמירה משמיטה Title ו-Author
TPdfRSaveOptions נושאת Creator, Producer, CreationDate, ModDate, DocumentId ו-InstanceId, ובכוונה אין לה שדה עבור Title, Author, Subject או Keywords. ארבעת אלה הן הרשומות ש-§6.4.3 אוסר, כך שרשומה שחשפה אותן הייתה מזמינה קוראים לכתוב קובץ לא-תואם דרך API תואם
שתי אפשרויות בוליאניות שולטות בניקוי בעת המרת PDF קיים. StripInfoOptionalEntries ברירת המחדל True ומסיר Title, Author, Subject, Keywords ו-Trapped מתוך מילון Info של המקור. StripCatalogOptionalEntries גם ברירת המחדל True ומסיר Names, Outlines, StructTreeRoot, OutputIntents, Lang ואת השאר, ומשאיר רק את הרשימה-הלבנה של §6.3. הגדר אחת מהן ל-False ואתה שומר על הרשומות — ומאבד תאימות, שזה לעיתים מה שקורא באמת רוצה עבור קובץ פנימי
var
Opts: TPdfRSaveOptions;
Src, Dest: TFileStream;
begin
Opts := TPdfRSaveOptions.Default;
Opts.Creator := 'Capture Station 4';
Opts.Producer := 'PDFium Component';
Src := TFileStream.Create('scan-in.pdf', fmOpenRead or fmShareDenyWrite);
try
Dest := TFileStream.Create('scan-pdfr.pdf', fmCreate);
try
InjectPdfRMarkers(Src, Dest, Opts); // markers + metadata, not page content
finally
Dest.Free;
end;
finally
Src.Free;
end;
end;
שים לב מה הזרקת סמנים אינה עושה: היא מוסיפה מטא-נתונים וזיהוי, ואינה יכולה לספק תוכן עמוד. עמוד מקור שאינו נושא תמונת רצועה עדיין ייכשל ב-pvriPageImageMismatch לאחר הזרקה, מפני שהתמונה החסרה מעולם לא הייתה בעיית מטא-נתונים
היכן PDF/R משתלב בצינור לכידה
השתמש בו כשה deliverable הוא הסריקה עצמה והנאמנות היא כל החוזה — הדמיה ראייתית, לכידת המחאות ותשלומים, ארכיוני שרטוטי הנדסה מסורקר פורמט-גדול. השתמש ב-PDF/A במקום ברגע שהמסמך זקוק לטקסט הניתן-לחיפוש, לתיוג, לקבצים מוטמעים או כל דבר אחר שהפרופיל הראסטרי מפשיט
סידור נפוץ ועובד הוא לייצר את שניהם: מקור PDF/R שלעולם אינו משתנה, ונגזרת PDF/A עם שכבת OCR לשליפה. המאמתים עצמאיים, כך שאותה עבודת אצווה יכולה לבדוק כל פריט מול הפרופיל שהוא באמת טוען לו. לצד הארכיוני של אותו זוג, ראה ההערות על תאימות ארכיונית PDF/A ותיקוף preflight של PDF/A, ולפלט מוכוון-דפוס הסקירה של תיקוף מסמכי PDF/X מוכני-דפוס
רכיב PDFium מביא את מנוע PDFium לדלפי, C++Builder ו-Lazarus עם ממשק API VCL ומאמתי תאימות עבור PDF/A, PDF/X, PDF/E, PDF/UA ו-PDF/R — דף המוצר של רכיב PDFium מפרט את התקנים וגרסאות ה-IDE הנתמכים