מאמר טכני

הערות PDF ב-Delphi עם HotPDF: סוגים ומלבנים

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

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

עמוד PDF שהופק על ידי HotPDF המציג סמלי הערות טקסט, תיבות טקסט חופשי, סימוני ריבוע וקווים, וחותמות אישור הממוקמים ברחבי העמוד
עמוד אחד הנושא מספר תתי-סוגים של הערות בו-זמנית: הערות טקסט, טקסט חופשי, סימונים גיאומטריים, וחותמות

המלבן הוא ההערה, לא הטקסט

כל קריאת הערה מקבלת TRect, ומלבן זה אומר משהו שונה מהקואורדינטות שאתה מעביר ל-TextOut. עבור הערת טקסט זהו האזור החם (hotspot) הלחיץ, האזור הקטן שבו יושב סמל ההערה ושבו לחיצה פותחת את התגובה. עבור ריבוע או תיבת טקסט חופשי זהו ההיקף הגלוי של הסימון. עבור חותמת זו התיבה שאליה מאוירת אמנות החותמת. המספרים הם נקודות במרחב משתמש של PDF, נמדדים מהפינה השמאלית-תחתונה של העמוד עם Y עולה כלפי מעלה, אותה מוסכמה ששאר חלקי HotPDF משתמשים בה

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

Pdf.CurrentPage.AddTextAnnotation(
  'Reviewer: confirm the totals on this line before sign-off.',
  Rect(120, 700, 140, 720),   // icon hotspot, ~20pt square
  False,                      // closed until the reader clicks it
  taComment,                  // bubble icon
  clBlue);

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

שם הסמל מגיע מ-THPDFTextAnnotationType, הממפה לסמלי ההערות הסטנדרטיים: taComment, taKey, taNote, taHelp, taParagraph, taNewParagraph, ו-taInsert. הסמל הוא הדבר היחיד שהסוג משנה. הוא אינו משנה את ההתנהגות, ושווה לדעת שלא כל צופה מצייר את כל השבעה; הבטוחים מבין הקוראים הישנים והחדשים הם taComment, taNote, ו-taHelp

טקסט חופשי נכתב על העמוד, אך נשאר הערה

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

Pdf.CurrentPage.AddFreeTextAnnotation(
  'DRAFT - not for distribution',
  Rect(200, 210, 400, 235),   // the box the text is laid into
  ftCenter,                   // ftLeftJust / ftCenter / ftRightJust
  clRed);

כאן המלבן חשוב יותר מאשר עבור הערת טקסט, מכיוון שהטקסט עוטף ומיושר בתוכו. עשה את התיבה קצרה מדי והטקסט ייחתך בקצה התחתון; צרה מדי והוא ייעטף במקומות שלא התכוונת אליהם. היישור מגיע מ-THPDFFreeTextAnnotationJust ויש לו רק את שלושת הערכים. מכיוון שטקסט חופשי הוא הערת סימון (markup), קורא שפותח את הקובץ בעורך יכול לבחור אותו, להזיז אותו או למחוק אותו כיחידה אחת, וזהו ההבדל שמחליט האם אתה מושיט יד לטקסט חופשי או פשוט מצייר את המילים עם TextOut. אם התווית חייבת להיות קבועה, צייר אותה. אם היא למטרות עריכה ואמורה לרדת, הפוך אותה להערה

סימונים גיאומטריים וקווים להצבעה על דברים

ריבועים, עיגולים וקווים הם הסימון שבו אתה משתמש כדי להצביע על אזור במקום לתאר אותו במילים. AddCircleSquareAnnotation מכסה את שתי צורות התיבה דרך THPDFCSAnnotationType של csCircle או csSquare, כאשר המלבן מספק את גבולות הצורה

// A box drawn around a figure that needs attention
Pdf.CurrentPage.AddCircleSquareAnnotation(
  'Check this region against the source data',
  Rect(50, 300, 120, 360),
  csSquare,
  clGreen);

// A line, given two points rather than a rectangle
var
  StartPt, EndPt: THPDFCurrPoint;
begin
  StartPt.X := 130; StartPt.Y := 360;
  EndPt.X   := 250; EndPt.Y   := 320;
  Pdf.CurrentPage.AddLineAnnotation(
    'Points from the note to the figure',
    StartPt, EndPt,
    clBlue);
end;

שים לב שהערת הקו שוברת את תבנית המלבן: היא לוקחת שתי רשומות THPDFCurrPoint, התחלה וסיום, מכיוון שקו מוגדר על ידי נקודות הקצה שלו, לא על ידי תיבה תוחמת (bounding box). הצבע קובע את הקו (stroke). אם אתה רוצה ראשי חץ, ל-HotPDF יש עומס (overloads) של AddLineAnnotation שמקבל סגנונות של סיום קו, אבל הצורה הפשוטה של שלושה ארגומנטים מציירת קו חשוף, שזה בדרך כלל מה שקריאה (callout) רוצה

תתי-סוגים של סימון טקסט עובדים על אזור שכבר פרסת. AddHighlightAnnotation מקבל מלבן, תוכן אופציונלי וצבע שברירת המחדל שלו היא צהוב, ומגוון את האזור כפי שהיה עושה עט הדגשה (highlighter). הוא נועד לשבת מעל טקסט אמיתי, כך שהמלבן צריך להתאים לגבולות של המילים שציירת, מה שאומר שבדרך כלל אתה מחשב אותו מאותן קואורדינטות שהעברת ל-TextOut במקום לנחש

חותמות תלויות בצופה שירנדר אותן

הערת חותמת היא זו שהכי סביר שתיראה שונה מקורא אחד למשנהו, והסיבה שווה הבנה. AddStampAnnotation נוקב בשם של חותמת סטנדרטית דרך THPDFStampAnnotationType, עם ערכים כמו satApproved, satConfidential, satFinal, satDraft, ו-satForComment

Pdf.CurrentPage.AddStampAnnotation(
  'Approved for release on review',
  Rect(50, 400, 200, 440),
  satApproved,
  clGreen);

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

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

כיצד הערות נבדלות משדות AcroForm

הבלבול שעולה הכי הרבה זמן הוא התייחסות להערה כאילו הייתה שדה טופס. שניהם מצורפים לעמוד דרך /Annots, ושדה טופס הוא למעשה תת-סוג הערה מיוחד (וידג'ט), וזו הסיבה שהם נראים קשורים. הם אינם ניתנים להחלפה זה בזה. שדה טופס מחזיק ערך, יש לו שם, משתתף בסדר הטאבים (tab order), וניתן להגיש אותו, לאפס אותו או להפעיל עליו סקריפטים; אתה יוצר אותם עם קריאות AddTextField, AddCheckBox, ו-AddPushButton, לא קריאות ההערה שבעמוד זה. הערת סימון מחזיקה הערה או צורה, אין לה שום ערך להגשה, והיא הכלי השגוי ברגע שאתה צריך לאסוף קלט

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

הרכבת העמוד

החלקים מרכיבים באותה דרך ששאר החלקים של HotPDF פועלים. הגדר מאפייני מסמך, קרא ל-BeginDoc, צייר כל תוכן עמוד שאתה צריך עם קריאות הטקסט והגרפיקה, הוסף הערות מלמעלה, וסגור עם EndDoc. הערות מתחברות ל-CurrentPage, כך שלאחר AddPage הן נוחתות על העמוד החדש, והערה שהתכוונת לעמוד הראשון תופיע בשקט בעמוד השני אם תוסיף אותה לאחר המעבר

Pdf := THotPDF.Create(nil);
try
  Pdf.FileName := 'annotated.pdf';
  Pdf.Compression := cmFlateDecode;
  Pdf.FontEmbedding := True;
  Pdf.BeginDoc;

  Pdf.CurrentPage.SetFont('Arial', [], 11);
  Pdf.CurrentPage.TextOut(50, 740, 0, 'Quarterly figures, draft for review');

  Pdf.CurrentPage.AddTextAnnotation(
    'Confirm the totals before sign-off.',
    Rect(50, 720, 70, 740), False, taComment, clBlue);
  Pdf.CurrentPage.AddFreeTextAnnotation(
    'DRAFT', Rect(450, 720, 540, 745), ftCenter, clRed);
  Pdf.CurrentPage.AddStampAnnotation(
    'For comment', Rect(50, 660, 180, 695), satForComment, clGreen);

  Pdf.EndDoc;
finally
  Pdf.Free;
end;

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

קריאות ההערות המוצגות כאן הן חלק מרכיב HotPDF עבור Delphi ו-C++Builder