מאמר טכני

ייבוא וייצוא של הערות (Annotations) ב-PDF כ-XFDF בדלפי

HotPDF מייצאת ומייבאת הערות (annotations) של PDF כ-XFDF באמצעות שתי פונקציות הפועלות על המסמך הטעון כעת, ExportLoadedAnnotationsToXFDF ו-ImportLoadedAnnotationsFromXFDF.‏ XFDF הוא פורמט XML להחלפת הערות המתוקנן כ-ISO 19444-1, וצמד זה מאפשר לתוכנית דלפי או C++Builder למסור את הערותיה ל-Acrobat או לכלי סקירה של צד שלישי ולקבל את התוצאות המסומנות בחזרה, כל זאת מבלי לכתוב מחדש את תוכן העמוד שבו יושבות ההערות

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

מה ההבדל בין FDF ל-XFDF?

FDF ו-XFDF נושאים את אותו מטען נתונים בשני תחבירים שונים, וההבחנה חשובה ברגע שאתה מחליט איזה קובץ למסור לכלי אחר. FDF הוא פורמט Forms Data Format הישן יותר המוגדר בתוך מפרט ה-PDF עצמו: הוא משתמש בתחביר אובייקטים של PDF, ולכן קובץ FDF נראה כמו PDF מופשט וזקוק למנתח המכיר PDF כדי לקרוא אותו. XFDF הוא ייצוג ה-XML של אותם נתונים, המתוקנן באופן עצמאי כ-ISO 19444-1, מה שאומר שכל ספריית XML בכל פלטפורמה יכולה לפתוח אותו, להשוות אותו (diff) או לייצר אותו. שני הפורמטים יכולים לשאת ערכי שדות טפסים בעץ <fields>, שעליו שולט סעיף 6.3 של ISO 19444-1, והערות בעץ <annots>;‏ HotPDF מפצלת את האחריות הזו, ומנתבת את נתוני הטפסים דרך ExportLoadedFormToXFDF ושומרת את ExportLoadedAnnotationsToXFDF עבור צד ה-<annots>. כאשר אתה מחליף הערות עם שירות אינטרנט, שרת סקירה של Java או תסריט (script),‏ XFDF הוא הפורמט שאינו מאלץ את הצד השני להטמיע מנתח PDF

כיצד מייצאים הערות PDF כ-XFDF בדלפי?

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

var
  Pdf: THotPDF;
  Written: Integer;
begin
  Pdf := THotPDF.Create(nil);
  try
    if Pdf.LoadFromFile('report-reviewed.pdf', '') > 0 then
    begin
      // Write one XFDF element per supported annotation on every page
      Written := Pdf.ExportLoadedAnnotationsToXFDF('comments.xfdf');
      if Written <= 0 then
        ShowMessage('No supported annotations were found');
    end;
  finally
    Pdf.Free;
  end;
end;

ה-XFDF שמתקבל הוא XML פשוט וקריא. HotPDF כותבת שורש <xfdf> במרחב השמות ISO 19444-1, מיכל <annots>, ובן אחד לכל הערה עם אינדקס העמוד מבוסס 0 שלה, צבע וגיאומטריה כמאפיינים או כאלמנטים בנים. קו עם מילוי צהוב וראש חץ פתוח, היושב לצד פוליגון מלא, עובר סריאליזציה כך

<?xml version="1.0" encoding="UTF-8"?>
<xfdf xmlns="http://ns.adobe.com/xfdf/">
  <annots>
    <line page="0" start="72,700" end="220,700"
          color="#FF0000" interior-color="#FFFF00"
          head="OpenArrow" tail="None">
      <contents-richtext>Baseline looks off</contents-richtext>
    </line>
    <polygon page="0" color="#0000FF" interior-color="#CCE5FF">
      <vertices>72,120;180,120;180,200;72,200</vertices>
    </polygon>
  </annots>
</xfdf>

כיצד תת-סוגי הערות ממופים לאלמנטים של XFDF

כל תת-סוג הערה ממופה לאלמנט ספציפי של ISO 19444-1 עם מוסכמת גיאומטריה משלו, ו-HotPDF עוקבת אחר מבנים אלה במקום להמציא משלה. הערות קו נושאות מאפייני start ו-end המחזיקים את שני זוגות קואורדינטות הקצה, שנלקחו ישירות ממערך L של ההערה, בעוד סגנונות קצוות הקו LE הופכים למאפייני head ו-tail. הערות פוליגון ופולי-קו מעבירות את רשימת הנקודות שלהן לתוך אלמנט בן <vertices> כזוגות x,y מופרדים בנקודה-פסיק, ולא כמאפיין, מכיוון שקורא המצפה לאלמנט הבן ישמיט בשקט נקודות המסתתרות בכל מקום אחר. הערות דיו, שיכולות להחזיק מספר משיכות נפרדות, מקננות אלמנט <inklist> עם בן <gesture> אחד לכל משיכה, כך שחתימה מרובת משיכות שורדת את המסלול כמחוות נפרדות ולא כגוש ממוזג אחד

טקסט עשיר, צבע וסגנון גבול שורדים לצד הגיאומטריה. גוף הטקסט העשיר של הערה נכתב כאלמנט בן <contents-richtext>; המילוי הפנימי ש-PDF מאחסן במערך IC, הצבע בתוך עיגול, ריבוע, פוליגון או ראש חץ של קו והמילוי של תיבת השחרה, מגיע כמאפיין interior-color בצורת #RRGGBB; ורוחב הגבול, דפוס המקפים ואפקט גבול מעונן ממופים למאפייני width,‏ dashes,‏ style ו-intensity, כך שבלון הסבר עם קו מתאר מעונן עדיין נקרא כמעונן בצד השני. HotPDF משמרת גם את החלון הקופץ (popup) המחובר להערת סימון, מייבאת את גיאומטריית הבן הקופץ ומצב הפתיחה או הסגירה שלו לתוך מילון Popup של ההערה, והיא נושאת את מצבי הפתיחה והסקירה של הערת הטקסט, כך שמסמך שנסקר שומר לא רק על צורותיו אלא גם על מטא-נתוני זרימת העבודה שסוקרים מסתמכים עליהם

ייבוא XFDF בחזרה למסמך טעון

HotPDF מייבאת XFDF על ידי ניתוח ה-XML, יצירת הערה חדשה עבור כל אלמנט באמצעות NewLoadedAnnotation, חיבורה לעמוד שבו נקוב שם האלמנט, והחזרת מספר ההערות שהוסיפה. זרימת העבודה סימטרית לייצוא: טען את ה-PDF הבסיסי, קרא ל-ImportLoadedAnnotationsFromXFDF com עם קובץ הסוקר, ואז שמור את המסמך הטעון כדי לשמור את הסימונים החדשים. אם הקובץ חסר או שה-XML אינו ניתן לניתוח, הפונקציה מחזירה אפס והמסמך הטעון נותר ללא שינוי

var
  Pdf: THotPDF;
  Added: Integer;
begin
  Pdf := THotPDF.Create(nil);
  try
    if Pdf.LoadFromFile('report.pdf', '') > 0 then
    begin
      Added := Pdf.ImportLoadedAnnotationsFromXFDF('comments.xfdf');
      if Added > 0 then
        Pdf.SaveLoadedDocument('report-annotated.pdf');
    end;
  finally
    Pdf.Free;
  end;
end;

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

var
  Pdf: THotPDF;
  Total, I: Integer;
  Files: array[0..1] of string;
begin
  Files[0] := 'alice-comments.xfdf';
  Files[1] := 'bob-comments.xfdf';
  Pdf := THotPDF.Create(nil);
  try
    if Pdf.LoadFromFile('master.pdf', '') > 0 then
    begin
      Total := 0;
      for I := Low(Files) to High(Files) do
        Inc(Total, Pdf.ImportLoadedAnnotationsFromXFDF(Files[I]));
      if Total > 0 then
        Pdf.SaveLoadedDocument('master-merged.pdf');
    end;
  finally
    Pdf.Free;
  end;
end;

מה עובר סבב מלא בצורה נקייה, ומה לא

HotPDF מעבירה בסבב מלא את תת-סוגי ההערות ש-ISO 19444-1 מעניק להם בית, והיא מדלגת בכוונה על השאר במקום לפלוט משהו שקורא עלול לפרש בצורה שגויה. הסט הנתמך מקיף את סוגי הסימונים השולטים בעבודת סקירה אמיתית: הערות טקסט, טקסט חופשי, קו, ריבוע, עיגול, פוליגון, פולי-קו, ארבעת סוגי סימון הטקסט (הדגשה, קו תחתון, קו חוצה וקו גלי), חותמת, דיו וסימן כרש (caret), בתוספת קובץ מצורף, קול, השחרה וקישור, שמונה עשר תת-סוגים בסך הכל. הערה שתת-הסוג שלה נופל מחוץ לרשימה זו מדולגת בייצוא, ומכיוון שהיא מדולגת ולא נכתבת ריקה, היא אינה מנפחת את הספירה שהפונקציה מחזירה

טקסט עשיר הוא האזהרה הכנה. HotPDF משמרת את גוף ה-<contents-richtext> כך שהטקסט המעוצב והתוכן הפשוט עושים את המסלול, אך XFDF נושא את הטקסט של ההערה ואת סימון הסגנון שלו, ולא זרם מראה מרונדר, ולכן האפליקציה המקבלת מציירת מחדש את החלון הקופץ עם הגופנים והפריסה שלה במקום לשחזר את הפיקסלים המדויקים של HotPDF. התייחס לסבב המלא כנאמן לתוכן ולכוונה, ולא לרינדור על המסך ברמת הפיקסל. אם התוכן המעוצב שלך חי בנתוני טפסים של XFA ולא בזרמי הערות, הכללים שונים, ו-כיצד HotPDF מטפלת ב-exData, טקסט עשיר וקישורים של XFA מכסה נתיב נפרד זה

החלפת הערות היא חלק אחד ממה שממשק ה-API של מסמכים טעונים עושה, והיא משתלבת עם השאר: ייבוא XFDF של סוקר, התאמת העמודים או עריכת מטא-נתוני המסמך, השטחה או הרשאה מחדש של הקובץ, ואז ייצוא XFDF חדש לסבב הבא. כל זה מגיע ב-HotPDF Component הסטנדרטי עבור דלפי ו-C++Builder, שהרפרנס שלו מתעד את כיסוי תת-סוגי ההערות המלא ופונקציות ה-XFDF הנלוות לנתוני טפסים