קורא עם לקות ראייה אינו יכול לקרוא טקסט שחור על דף לבן בניגוד ברירת מחדל, לכן הוא מבקש מצב כהה. התשובה התמימה היא להפוך כל פיקסל של הדף המעובד. זה מגיע תוך שבוע ונשבר למחרת: תצלומים סרוקים חוזרים כנראים כנגטיבים של סרט, סמני ההדגשה הצהובים של הקורא הופכים לכתם כחול בלתי קריא, ומישהו שואל מדוע התדפיס יצא שחור מוצק. התכונה שווה באמת לבנות וקל באמת לקבל אותה חצי נכון, והפער בין שתי התוצאות הוא רעיון אחד: כל החלטת צבע שייכת לנקודה ספציפית בצינור העיבוד, והיפוך הוא הכלי הלא נכון המיושם בשלב הלא נכון. הקוד כאן משתמש ב-PDFium Component, המציג מבוסס PDFium עבור Delphi, C++Builder ו-Lazarus, שממשק ה-API של העיבוד שלו חושף את השלבים הללו בנפרד
מסננים הם מצב תצוגה, לא מצב מסמך
כלל אחד מונע את קטגוריית הבאגים הגרועה ביותר כאן: מצב קריאה משנה את אופן ייצור הביטמאפ או עיבודו לאחר מעשה, ולא יותר מזה. בייטי ה-PDF נשארים ללא שינוי, כל מצב ניתן להיפוך על ידי עיבוד מחדש, ו"שמור" לעולם לא כותב מראה מסוננת חזרה לקובץ. זה נשמע ברור עד שסוקר משפטי מדפיס חוזה תחת מסנן פעיל ומגיש את הגרסה ההפוכה. בנקודה זו השאלה "האם ההדפסה משתמשת במראה המסמך עצמו או במסך" מסתבר שהיא ראויה לתשובה מפורשת במפרט, לא לתאונה של נתיב קוד. שמור את הגדרת המסנן במצב המציג, החל אותו בזמן עיבוד, וגרום לכל נתיב ייצוא להצהיר באיזה מראה הוא משתמש
הכלל משלם על עצמו פעמיים. הפיכות מגיעה בחינם, כי החלפת מצבים מעבדת מחדש מהמקור שלא שונה: אין stack undo לתחזק ואין דרך שריצה של שינויי מצב תדרדר את הדף. תרחישי ריבוי-חלונות נשארים קוהרנטיים מאותה סיבה. שתי תצוגות של מסמך אחד יכולות להריץ מצבים שונים, מכיוון שכל תצוגה מחזיקה במצב התצוגה שלה בזמן שאובייקט המסמך נשאר משותף
עבד תחילה, שנה לאחר מכן
הדפוס הנתמך הוא עיבוד ביטמאפ לאחר עיבוד: RenderPage מייצר את ה-raster של הדף, ואז מעבר שינוי מתאם אותו. הרכיב מגיע עם שלושה שינויים כפעולות ביטמאפ במקום, InvertPdfBitmap, DuotonePdfBitmap ו-GrayscalePdfBitmap, מה שהופך את החלפת המצב לפונקציה דו-שלבית נקייה:
function TViewerForm.RenderWithMode(W, H: Integer): TBitmap;
begin
Result := Pdf.RenderPage(0, 0, W, H, ro0, [reAnnotations]);
case FReadingMode of
rmInverted: InvertPdfBitmap(Result);
rmHighContrast: DuotonePdfBitmap(Result, clBlack, $0000C8FF); // dark bg, amber text
rmGrayscale: GrayscalePdfBitmap(Result);
end;
// rmNormal falls through: the document keeps its own colors
end;
שתי דברים נובעים מהעיצוב הזה. ראשית, עלות השינוי פרופורציונלית לגודל הביטמאפ, כך שהעבודה שייכת לאן שתוצאות העיבוד שלך נשמרות: סנן את הביטמאפ הנשמר פעם אחת, לא בכל ציור. שנית, מכיוון שהשינוי רץ על ה-raster הגמור, הוא פוגע בטקסט, אמנות וקטורית, תמונות ומראות הערות באותה דרך. אחידות זו היא בדיוק מה שהיפוך רגיל מקבל לא נכון עבור תצלומים. זו הסיבה שהשינוי duotone מהווה ברירת מחדל טובה יותר למסמכים עתירי טקסט, כי הוא ממפה לומינוסיות על רמפת צבעים כהה-לבהיר שנבחרה במקום לשלול גוונים; היפוך נשאר זמין כבחירה מפורשת עבור קוראים שרוצים אותו. קצוות גליפים חדים הם מנוף נפרד. אפשרות העיבוד reNoSmoothText כובה את anti-aliasing הטקסט בזמן עיבוד ומשתלבת היטב עם מצב ניגוד גבוה בזום גדול
שני גווני אפור שלא מסכימים
אפשרויות העיבוד כוללות reGrayscale, שנראה כקיצור דרך מעבר לשלב העיבוד שלאחר מעשה. זו אינה אותה פעולה:
// Engine-level: grayscale applied during rasterization
GrayA := Pdf.RenderPage(0, 0, W, H, ro0, [reGrayscale]);
// Post-process: render in color, convert the finished bitmap
GrayB := Pdf.RenderPage(0, 0, W, H);
GrayscalePdfBitmap(GrayB);
האפשרות ברמת המנוע חלה על פלט ה-raster של תוכן תמונות אך אינה מגיעה למילויים וקטוריים או צבעי טקסט, כך שדף עם כותרות צבעוניות יכול לחזור עם תצלומים אפורים וכותרות כחולות עקשניות. GrayscalePdfBitmap על הביטמאפ הגמור ממיר הכל, ללא תנאי. אפשרות העיבוד עדיין מרוויחה את מקומה כשאתה רוצה שתמונות יבוטלו הרוות בזמן שמשאיר את צבע הטקסט כאות, מה שחלק מקוראי לקות ראייה מעדיפים ספציפית. אך אם הדרישה קוראת "דף גווני אפור", עיבוד לאחר מעשה הוא הגרסה שמספקת אותה. בכל נתיב שתבחר, זכור את שני עומסי-היתר של RenderPage. הגרסה בסגנון פונקציה מחזירה ביטמאפ שהקורא מחזיק בבעלותו ועליו לשחרר, וזה חשוב ברגע שמסננים מכפילים את מספר הביטמאפים המעובדים בתעופה
רקעים, סמני בחירה ומלכוד PageColor
לא כל התאמת נוחות היא שינוי. החלפת רקע הדף הלבן בגוון חם מספיקה לעיתים קרובות בפני עצמה עבור קוראים רגישים לבוהק, ויש לה מאפיין ייעודי. המאפיין נושא כלל היקף שתופס אנשים:
// Affects the on-screen view only
PdfView.PageColor := $00D9EDF2; // warm paper tone behind page content
// RenderPage output ignores PageColor; pass the color explicitly
Bmp := Pdf.RenderPage(0, 0, W, H, ro0, [], $00D9EDF2);
PageColor משנה את מה ש-TPdfView מציג, אך ביטמאפים שנוצרו דרך RenderPage שומרים על לבן ברירת המחדל אלא אם הפרמטר Color אומר אחרת. הסימפטום אמין: המסך מראה את הדף הצבעוני, המשתמש מייצא או מדפיס, והפלט חוזר ללבן. תייק זאת תחת אותה החלטת מדיניות ייצוא מהסעיף הראשון
מאפייני הצבע הנותרים מגדירים סמני שכבת-על: HighlightColor ללחצי חיפוש, SelectionColor לבחירת טקסט של המשתמש, ReadingWordColor לסמן מילה מדוברת. כל אחד מהם חייב להיבדק מחדש תחת כל מסנן שאתה מציע. סמן קריאה ענבר שעובד על לבן נעלם לאחר היפוך; בחירה כחולה חיוורת נעלמת לתוך רקע ניגוד גבוה. שמור פלטות שכבת-על לכל מצב ולא קבוצה גלובלית אחת, ובדוק את השילובים בכוונה. מסננים בשילוב עם המרת טקסט לדיבור היא תצורה רגילה עבור הקוראים שהתכונה הזו משרתת, לא מקרה קצה. מנגנון שכבת-העל עצמו מכוסה במאמר הקורא הנגיש
מספרים, אימות ושאלת ההדפסה
WCAG 2.1 הופכת תכונה זו למשהו שניתן למדוד. קריטריון הצלחה 1.4.3 מבקש יחס ניגוד של 4.5:1 לטקסט גוף, ו-1.4.6 מעלה אותו ל-7:1 לניגוד משופר. בדוק את מצב הניגוד הגבוה שלך מול היחסים הללו עם מנתח ניגוד המריץ על פלט עיבוד בפועל. טקסט על תמונות וטקסט בשדות טופס הם המקומות שבהם היחסים נכשלים בשקט אפילו כשטקסט הגוף עובר
הדפסה ראויה להחלטה משלה, וברירת המחדל הגנתית היא מראה המסמך עצמו, כש"הדפס כפי שמוצג" מוצע כבחירה מפורשת של המשתמש. דף מודפס הוא ראיה ביותר זרימות עבודה ממה שמחברי מציגים נוטים לצפות, ותדפיס הפוך של חוזה הוא אירוע תמיכה עם מרכיב משפטי. עוד צימוד אחד חשוב לביצועים: עיבוד עם מסנן מכפיל את עבודת הביטמאפ בכל החלפת מצב, אז אל תחיל שינוי בכל הודעת ציור. שמור את הביטמאפ המסונן והרץ מחדש את השינוי רק כשהדף, ה-zoom או המצב משתנים בפועל. אסטרטגיית השמירה שהופכת זאת לזול חיה במאמר cache העיבוד וביצועי ה-zoom
דבר אחד להסדיר בממשק המשתמש שלך ולא בקוד: איזה מצב הוא ברירת המחדל הנכונה. אין תשובה יחידה, לכן הצע את הקבוצה ואפשר לקורא לבחור. ניגוד גבוה מתאים לרוב הקריאה עתירת טקסט, היפוך מתאים לקוראים שרוצים ספציפית אור על כהה, גווני אפור מפחית רעש צבע, וגוון רקע מטפל ברגישות לבוהק. שמור את הבחירה לכל משתמש, שחזר אותה בהפעלה, ושמור נתיב חד-מקש לנורמלי, מכיוון שקורא שנוחת במצב שהוא אינו יכול לקרוא צריך יציאה מהירה
אפשרויות העיבוד, שינויי הביטמאפ ומאפייני צבע התצוגה המשמשים כאן מגיעים עם PDFium Component עבור Delphi, C++Builder ו-Lazarus/FPC, עם קוד מקור מלא כדי שניתן יהיה לבקר או להרחיב את יישומי השינוי