מאמר טכני

רינדור מעברי צבעים (Gradients) ב-PDF בדלפי: ציריים (Axial) ורדיאליים (Radial)

קובץ PDF שכותרתו נושאת רקע מעבר צבעים (gradient) בסגנון Word או Excel, כאשר הוא מרונדר לתמונה, נהג לחזור עם מלבן לבן ריק במקום שבו אמור להיות ערבוב הצבעים. מרנדר העמודים של HotPDF מכבד כעת את אופרטור ה-sh (הצללה - shading) של PDF עבור מעברי צבע ציריים (axial) מסוג 2 ורדיאליים (radial) מסוג 3: הוא מעריך את פונקציית ההצללה לאורך ציר מעבר הצבע ומצייר את הערבוב, בעוד גרסאות קודמות שמטו בשקט את האופרטור והותירו את האזור לבן-נייר. שני סוגי ההצללה המכסים כמעט כל מעבר צבע של מסמכי משרד כלולים; סוגי הרשת (mesh) אינם כלולים, ומאמר זה כנה לגבי היכן עובר הגבול הזה

מדוע מעבר צבע ב-PDF מרונדר כתיבה לבנה?

מעבר צבע ב-PDF הוא מבנה וקטורי, ולא מפת סיביות (bitmap) שהמרנדר יכול להעתיק ישירות. מילון הצללה (ISO 32000-1 §8.7.4.5) מתאר את הגיאומטריה — ציר או זוג עיגולים במערך Coords — בתוספת פונקציית צבע, ואופרטור ה-sh מצייר את ההצללה הזו על פני אזור הגזירה הנוכחי, אותו מודל גרפי ש-HotPDF חושפת כאשר אתה מצייר נתיבים ומילויים על קנבס של עמוד. מרנדר העמודים של HotPDF עובר על זרם התוכן אופרטור אחר אופרטור, וכל אופרטור שאין עבורו נתיב קוד מדולג כדי ששאר העמוד עדיין ירונדר. לפני גרסה 2.335.0,‏ sh שכן בקבוצה המדולגת הזו: כותרת או מעבר צבע של עמוד שלם לא תרמו דבר לפלט, ולכן הרקע הופיע כלבן. הקובץ מעולם לא היה פגום. למרנדר פשוט לא היה מטפל עבור אופרטור יחיד זה, ותיבה לבנה היא בדיוק מה שנראה כמו מטפל חסר

שרשרת הערכת הפונקציות שמאחורי ההצללה

לא ניתן לצבוע הצללה עד שהפונקציה שלה מוערכת, ולכן מנגנון זה היה חייב להגיע ראשון. הן הצללה צירית מסוג 2 והן הצללה רדיאלית מסוג 3 נושאות /Function הממפה מיקום פרמטרי לאורך מעבר הצבע לצבע (ISO 32000-1 §7.10), ומעריך הפונקציות של HotPDF פותר את ה-FunctionType ומנתב על פיו. אינטרפולציה אקספוננציאלית מסוג 2 (§7.10.3) מחשבת את C0 + t^N * (C1 - C0) עם הידוק (clamping) של Domain ו-Range; פונקציות דגומות מסוג 0 (§7.10.2) קוראות גריד של דגימות של 8,‏ 16 או 32 סיביות ובוחרות את הקרובה ביותר דרך מפת ה-Encode, המקרה המכוסה לעומק ב-מדריך שלנו לחיפושי צבע דגומים מסוג 0; פונקציות תפירה מסוג 3 (§7.10.4) בוחרות תת-פונקציה לפי מערך ה-Bounds ומבצעות רקורסיה לתוכה. פונקציות מחשבון PostScript מסוג 4 (§7.10.5) אינן מוערכות — הן נסוגות בחן להערכה שנכשלה במקום צבע שגוי, מה שמתאים למדיניות השמרנית ש-HotPDF נוקטת בה לאורך נתיב הרינדור. מעריך זה סופק בגרסה 2.334.0, מהדורה אחת לפני האופרטור עצמו, מכיוון שצבע ההצלחה טוב רק כמו הפונקציה שמתחתיו

כיצד HotPDF הופכת מעבר צבע רציף לפיקסלים?

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

// The shading discretizer uses up to 64 color bands along the gradient
// axis, but never more than the axis is long in device pixels. Rendering
// the same page at a higher DPI lengthens that axis, so a short gradient
// gains bands and the banding softens until the 64-band ceiling is hit.
Thumb := Pdf.RenderLoadedPageToBitmap(PageIndex, 96);   // coarser bands
Proof := Pdf.RenderLoadedPageToBitmap(PageIndex, 300);  // up to 64 bands

רינדור עמוד מוצלל למפת סיביות (bitmap)

נקודת הכניסה הציבורית ללא שינוי: RenderLoadedPageToBitmap מקבלת אינדקס עמוד מבוסס 0 וערך DPI, מחזירה מפת סיביות של 24 סיביות בבעלות הפונה, ומחזירה nil במקרה של כשל במקום להעלות חריגה, כך שהתמיכה בהצללה שקופה לקוד שכבר יש לך. עמוד שנהג לרנדר את כותרת מעבר הצבע שלו ריקה מחזיר כעת את אותה מפת סיביות עם הערבוב צבוע בפנים, ואין צורך בשינוי API כדי לקבל זאת. הדבר היחיד שראוי לזכור הוא בעלות: הפונה משחרר את מפת הסיביות המוחזרת. צינור הרינדור המלא — פירוש זרם תוכן, גליפים מוטמעים ואיחסון עמודים במטמון — מכוסה ב-מדריך לרינדור עמודי PDF למפת סיביות בדלפי

var
  Pdf: THotPDF;
  Bmp: TBitmap;
begin
  Pdf := THotPDF.Create(nil);
  try
    if Pdf.LoadFromFile('quarterly-report.pdf') > 0 then
    begin
      // Page 1 (zero-based) at 150 DPI. A gradient-filled header that
      // used to come back blank now carries its color blend.
      Bmp := Pdf.RenderLoadedPageToBitmap(0, 150);
      if Assigned(Bmp) then
      try
        Bmp.SaveToFile('page1.bmp');
      finally
        Bmp.Free;
      end;
    end;
  finally
    Pdf.Free;
  end;
end;

הגנת נסיגה (regression guard) זולה נובעת מאותה קריאה. רנדר את העמוד, דגום פיקסל שבו נמצא פס מעבר הצבע, ואשר שהוא אינו לבן-הנייר שהמרנדר נהג לסגת אליו — בדיקה של שורה אחת התופסת חזרה שקטה להתנהגות הישנה של אי-ביצוע פעולה

Bmp := Pdf.RenderLoadedPageToBitmap(0, 150);
if Assigned(Bmp) then
try
  // True when the sh operator painted; False if the region fell back to white.
  HeaderPainted := Bmp.Canvas.Pixels[Bmp.Width div 2, 8] <> clWhite;
finally
  Bmp.Free;
end;

מה ש-HotPDF אינה מציירת: הצללות רשת (mesh) וקצוות גזירה

ארבעת סוגי הצללות הרשת (mesh) מחוץ לטווח, ומסמך צריך לדעת זאת מראש. רשתות משולשי Gouraud בצורה חופשית (סוג 4), רשתות Gouraud בצורת סריג (סוג 5), רשתות Coons patch (סוג 6), ורשתות tensor-product patch (סוג 7), המוגדרים לאורך ISO 32000-1 §8.7.4.5.5 עד §8.7.4.5.8, אינם מרונדרים; עמוד המשתמש באחד מהם עדיין מרונדר, אלא שרק האזור הזה נותר כפי שהוא. ראוי לציין בבירור שני קצוות נוספים. מלבני הפסים מכסים את רצועת ההצללה במקום להיגזר בדיוק לנתיב הגזירה הנוכחי, כך שמעבר צבע המוסתר לצורה מעוגלת או לא סדירה מצויר כרצועה החוסמת שלו עד להגעת גזירת אזור מדויקת בסבב מאוחר יותר. HotPDF מניחה גם שפלט הפונקציה הוא RGB או גווני אפור, כך שהצללה שנכתבה ב-CMYK או במרחב צבעים אקזוטי מיוצגת בקירוב ולא מנוהלת מבחינת צבע. עבור המסמכים שרוב צוותי דלפי ו-C++Builder מעבדים בפועל — דוחות, חשבוניות, הצהרות ומצגות המיוצאות ל-PDF — הצללות ציריות ורדיאליות מכסות למעשה כל מעבר צבע שתפגוש, וטיוטות עיצוב עתירות רשת הן המקרים שיש להתייחס אליהם כתצוגה מקדימה ולא כהוכחה סופית

מרנדר העמודים של HotPDF, התמיכה באופרטור sh המתוארת כאן, ומעריך הפונקציות מסוג 0/2/3 שמתחתיה מגיעים כחלק מ-HotPDF Component עבור דלפי ו-C++Builder — ספריית VCL מקורית ללא תלות ב-DLL חיצוני, המכסה יצירה, עריכה, חילוץ טקסט ורינדור עמודים של PDF בחבילה אחת