קבצי PDF מצורפים נשמרים בעץ הקבצים המוטמעים של המסמך, מבנה שרוב המציגים מציגים כפאנל אטב נייר או סרגל צד של קבצים מצורפים. מקוד Delphi, רכיב PDFium חושף עץ זה באמצעות סט קטן של מאפיינים מבוססי-אינדקס ב-TPdf: אתם מבצעים לולאה לפי אינדקס מספר שלם, קוראים שמות ובייטים של נתונים, יוצרים מקומות חדשים ומוחקים קיימים. ממשק ה-API צר; יש רק כמה מגבלות סדר וכלל ניקוי אחד שכדאי לדעת לפני כתיבת קוד ייצור סביבו
קריאת קבצים מצורפים ממסמך פתוח
המאפיין AttachmentCount נותן את מספר הקבצים המוטמעים שהמסמך מצהיר עליהם. הוא קורא ישירות מהקריאה הבסיסית של PDFium, כך שהוא משקף רק את מה שה-PDF מכיל בפועל. משם, AttachmentName[Index] מחזיר את שם התצוגה כ-WString, והמאפיין Attachment[Index] מספק את בייטי הנתונים הגולמיים כמערך TBytes. שניהם מבוססי 0. המסמך חייב להיות פתוח (Pdf.Active = True) לפני שתשאלו את אחד המאפיינים; קריאה להם במסמך סגור נותנת לכם אפס או תוצאה ריקה ללא חריגה
דבר אחד שיש לזכור: המאפיין Attachment[Index] מקצה ומחזיר את נתוני הקובץ המלאים בכל קריאה. עבור מסמך הנושא קובץ מוטמע גדול, מעבר על כל הקבצים המצורפים לבניית רשימת תצוגה פירושו תשלום עלות הקצאה זו בכל קריאה. אם אתם צריכים שמות רק לצורך תצוגה, קראו תחילה את AttachmentName ודחו את שליפת הבייטים עד שהמשתמש יבקש בפועל את הקובץ
procedure ListAttachments(Pdf: TPdf);
var
I: Integer;
Data: TBytes;
begin
if not Pdf.Active then
Exit;
for I := 0 to Pdf.AttachmentCount - 1 do
begin
Data := Pdf.Attachment[I];
Writeln(Format('%d: %s (%d bytes)',
[I, Pdf.AttachmentName[I], Length(Data)]));
end;
end;
חילוץ קובץ מצורף לדיסק
אין פונקציית עזר SaveAttachment. אתם קוראים את הבייטים וכותבים אותם היכן שאתם צריכים, מה שמטיל את בניית הנתיבים וניקויים לחלוטין על הקוד שלכם. זה חשוב כאשר שמות קבצים מצורפים מגיעים ממסמכים לא מהימנים. שמות קבצים מצורפים ב-PDF הם מחרוזות השמורות בתוך הקובץ; הם יכולים להכיל מפרידי נתיבים, תווי יוניקוד דומים, ותווים אחרים שיפיקו תוצאות לא צפויות אם תעבירו אותם ישירות ל-TFileStream.Create. העבירו תמיד את השם דרך ExtractFileName לפני בניית נתיב פלט כלשהו, ושקלו לדחות שמות המתחילים בנקודה או המכילים תווים מחוץ למה שהמערכת שלכם מצפה לו
מערך הבייטים המוחזר על ידי Attachment[Index] נמצא בבעלות הקורא. כיתבו אותו עם TFileStream רגיל והוא שלכם לעשות בו כרצונכם, כולל בדיקת הבייטים הראשונים כדי לאמת את פורמט הקובץ בפועל במקום לבטוח בשם המוצהר
procedure ExtractAttachment(Pdf: TPdf; Index: Integer; const OutputDir: string);
var
SafeName: string;
OutPath: string;
Data: TBytes;
FS: TFileStream;
begin
SafeName := ExtractFileName(Pdf.AttachmentName[Index]);
if SafeName = '' then
SafeName := Format('attachment_%d', [Index]);
OutPath := IncludeTrailingPathDelimiter(OutputDir) + SafeName;
Data := Pdf.Attachment[Index];
FS := TFileStream.Create(OutPath, fmCreate);
try
if Length(Data) > 0 then
FS.WriteBuffer(Data[0], Length(Data));
finally
FS.Free;
end;
end;
הוספת קבצים מצורפים וכתיבה בשני שלבים
יצירת קובץ מצורף דורשת שתי קריאות, לא אחת. הפונקציה CreateAttachment(Name) רושמת מקום חדש בעץ הקבצים המוטמעים ומחזירה True במקרה של הצלחה. מקום זה מתחיל כשהוא ריק. לאחר מכן אתם מקצים את נתוני הקובץ על ידי כתיבה ל-Attachment[AttachmentCount - 1], תוך פנייה לרשומה שנוצרה לאחרונה. אם CreateAttachment מחזירה False, המקום לא נוצר וההקצאה תשחית את הקובץ המצורף באינדקס שבמקרה הוא האחרון
לאחר שינוי רשימת הקבצים המצורפים, השינויים חיים בזיכרון בלבד. קראו ל-SaveAs כדי לכתוב קובץ חדש עם עץ הקבצים המוטמעים המעודכן. רכיב PDFium אינו תומך כרגע בשמירה חזרה לאותו קובץ שפתוח כעת, מכיוון שהמנוע מחזיק בידית קריאה למקור. התבנית הסטנדרטית לעדכון מקומי היא שמירה לנתיב זמני, סגירת המסמך, מחיקה או שינוי שם של המקור, ואז שינוי שם של הקובץ הזמני למקומו ופתיחתו מחדש
procedure AddFileAttachment(Pdf: TPdf; const FilePath: string);
var
FS: TFileStream;
Data: TBytes;
AttachName: string;
begin
if not Pdf.Active then
Exit;
FS := TFileStream.Create(FilePath, fmOpenRead or fmShareDenyWrite);
try
SetLength(Data, FS.Size);
if FS.Size > 0 then
FS.ReadBuffer(Data[0], FS.Size);
finally
FS.Free;
end;
AttachName := ExtractFileName(FilePath);
if Pdf.CreateAttachment(AttachName) then
Pdf.Attachment[Pdf.AttachmentCount - 1] := Data;
end;
מידע על סוג קובץ מצורף
מעבר לשם ולנתוני הבייטים, AttachmentType[Index] מחזיר את מחרוזת סוג ה-MIME השמורה במילון הקובץ המוטמע ב-PDF, אם נרשמה כזו כאשר הקובץ צורף במקור. מחוללים רבים משאירים שדה זה ריק או מגדירים אותו לערך כללי כמו application/octet-stream, כך שאינכם יכולים להסתמך עליו לצורך זיהוי פורמט בצינור הפקה. לצורך זיהוי אמין, קראו את הבייטים הראשונים של נתוני הקובץ ובדקו חתימות קבצים מוכרות: %PDF עבור PDF מקונן, כותרת קובץ מקומי של ZIP PK\x03\x04 עבור מסמכי Office Open XML, \xD0\xCF\x11\xE0 עבור קבצים בינאריים מורכבים ישנים. מידע על סוג מתוך המילון הוא בסדר להצגה בתווית ממשק משתמש, אך אינו אמור להניע החלטות עיבוד כאשר יש לכם את הבייטים בפועל זמינים
מחיקת קבצים מצורפים
הפונקציה DeleteAttachment(Index) מסירה את הרשומה באותו מיקום ומחזירה True במקרה של הצלחה. לאחר המחיקה, הרשומות הנותרות מסיטות מטה, כך שאם אתם מוחקים מספר קבצים מצורפים בלולאה עליכם לבצע את הלולאה מהאינדקס האחרון כלפי מטה, ולא קדימה, כדי להימנע מדילוג על רשומות לאחר כל הסטה. השינוי הוא בזיכרון עד שתקראו ל-SaveAs
תרחיש נפוץ בצינורות עיבוד מסמכים הוא הסרת כל הקבצים המצורפים מ-PDF נכנס לפני העברתו להמשך הטיפול, מסיבות אבטחה או גודל. ספרו פעם אחת לפני הלולאה ובצעו לולאה בסדר הפוך:
procedure StripAllAttachments(Pdf: TPdf);
var
I: Integer;
begin
for I := Pdf.AttachmentCount - 1 downto 0 do
Pdf.DeleteAttachment(I);
end;
היכן מופיעים קבצים מצורפים ל-PDF בפועל
ה-API של קבצים מצורפים עובד על כל PDF ש-PDFium יכולה לפתוח, אך המסמכים שבהם אתם נתקלים בפועל בקבצים מוטמעים מתרכזים סביב כמה מקרים ספציפיים. תקן PDF/A-3 (ISO 19005-3) מאפשר במפורש קבצים מוטמעים תואמים כמנגנון לאיגוד נתוני מקור לצד גרסת הארכיון; חשבוניות אלקטרוניות מסוג ZUGFeRD ו-Factur-X מסתמכות בדיוק על זה כדי להטמיע קובץ XML מובנה בתוך פריסת ה-PDF הקריאה לבני אדם. קובצי PDF שמקורם באימיילים נושאים לפעמים את קבצי המקור של האימייל שהועברו לתוך עץ הקבצים המוטמעים. תיעוד טכני שמקורו במערכות כתיבה מובנות מאגד לפעמים נכסי תמיכה באותו אופן
כאשר האפליקציה שלכם מעבדת קובצי PDF נכנסים מחוץ לארגון שלכם, בדיקת AttachmentCount כחלק מקליטת המסמך כדאית משתי סיבות עצמאיות. ראשית, קבצים מוטמעים עשויים לשאת נתונים שתרצו לחלץ ולעבד, כגון ה-XML בתוך PDF של חשבונית. שנית, קבצים מוטמעים יכולים לשאת תוכן הרצה שרירותי, כך שחשוב לדעת מה קיים אפילו כאשר אינכם מתכוונים לחלץ אותו. אף אחת מהסיבות אינה דורשת מכם לעשות דבר מורכב: קראו את המספר, בדקו את השמות, והחליטו מה לעשות עם הבייטים
מאפייני הקבצים המצורפים המוצגים כאן הם חלק מרכיב PDFium עבור Delphi ו-C++Builder