מאמר טכני

יצירת ברקודים הניתנים לסריקה ב-PDF עם HotPDF ב-Delphi

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

עמוד PDF המציג רשת של ברקודים ליניאריים בסימבולוגיות שונות שצוירו על ידי HotPDF ב-Delphi
סימבולוגיות ברקוד ליניארי שצוירו לתוך PDF יחיד עם HotPDF

מה HotPDF יכול לקודד

HotPDF מצייר סימבולוגיות ליניאריות (חד-ממדיות), והסט רחב יותר ממה שרוב הפרויקטים צריכים. ספירת THPDFBarcodeType מכסה את משפחת Code 2 of 5 בצורות משולבות (interleaved), תעשייתיות (industrial) ומטריצות (matrix); Code 39 והגרסה המורחבת שלו; שלוש תת-הקבוצות A, B ו-C של Code 128; Code 93 רגיל ומורחב; MSI; PostNet; Codabar; קבוצת הקמעונאות UPC ו-EAN, דהיינו EAN-8, EAN-13, UPC-A, ה-UPC-E0 ו-UPC-E1 הדחוסים, והתוספות (add-ons) המשלימות של 2 ו-5 ספרות של UPC; ותת-הקבוצות GS1-128 (EAN-128). זה מספיק כדי לכסות תוויות שרשרת אספקה, נקודות מכירה קמעונאיות, והקודים התעשייתיים הישנים שעדיין חיים במחסנים

מה שהוא לא מצייר הוא המשפחה הדו-ממדית. אין כאן QR, Data Matrix, או PDF417. אלו מקודדים בתים ברשת (grid) עם מתמטיקה משלהם לתיקון שגיאות, ואם דרישה מציינת אחד מהם, זהו הכלי הלא נכון וכדאי שתדע זאת לפני שתבנה סביבו ולא אחרי. עבור קודים חד-ממדיים השאלה המעשית צרה יותר: איזו סימבולוגיה מקבלת את הנתונים שיש לך בפועל, מכיוון שהקידודים אינם ניתנים להחלפה זה בזה

אילוצי הנתונים הם אמיתיים והם נושכים בזמן היצירה (generation time). הגרסאות של Code 2 of 5 ו-MSI מקבלות ספרות בלבד. Code 39 נושא אותיות רישיות (uppercase), ספרות וקומץ סימני פיסוק; אם אתה צריך אותיות קטנות (lowercase) או את כל טווח ה-ASCII, זהו Code 39 Extended או תת-קבוצה של Code 128. ה-Code 128C אורז שתי ספרות לכל סמל לצורך צפיפות, ולכן הוא דורש מחרוזת מספרית באורך זוגי ולא שום דבר אחר. EAN-13 מצפה לשתים עשרה ספרות ומחשב את השלוש עשרה כביקורת (check); EAN-8 מצפה לשבע ומחשב את השמינית; UPC-A מקבל שתים עשרה. מסור לסימבולוגיה נתונים שהיא אינה יכולה לייצג ולא תקבל חריגה (exception) מועילה, תקבל ברקוד שמקודד זבל, וזה גרוע יותר, כי הוא נראה בסדר עד שמישהו סורק אותו בקופה

שני נתיבי ציור, שתי רמות שליטה

המתודה שיש לשלוח אליה יד בייצור היא DrawBarcode, על אובייקט העמוד. היא מקבלת את הסימבולוגיה, מיקום, גובה, ופרמטר אחד שחשוב יותר מהשאר: MUnit, רוחב המודול. המודול הוא הרוחב של הפס הצר ביותר, האטום שכל מידה אחרת בקוד היא כפולה שלו, והוא מבוטא כאן בנקודות (points). כל מה שקשור לשאלה האם התוצאה המודפסת תיסרק חוזר לאותו מספר שלם (integer) יחיד

var
  Pdf: THotPDF;
begin
  Pdf := THotPDF.Create(nil);
  try
    Pdf.FileName := 'label.pdf';
    Pdf.BeginDoc;

    // BCType, X, Y, Height, MUnit (module width in points), angle,
    // data, UseCheckSum, bar color, background color.
    Pdf.CurrentPage.DrawBarcode(
      bcCodeEAN13,           // symbology
      72, 680,               // X, Y in points from the bottom-left
      60,                    // bar height
      1,                     // MUnit: 1pt narrowest bar
      0,                     // no rotation
      '123456789012',        // 12 digits; the 13th is the check
      True,                  // append the modulo-10 check digit
      clBlack, clWhite);     // bars black, background white

    Pdf.EndDoc;
  finally
    Pdf.Free;
  end;
end;

שני ארגומנטים ראויים למבט מקרוב. UseCheckSum מוסיף את ספרת הביקורת בשיטת מודולו-10 שהסימבולוגיה מצפה לה, ועבור קודי הקמעונאות אתה כמעט תמיד רוצה שזה יהיה True; כבה זאת רק כאשר הנתונים שלך כבר נושאים ביקורת מחושבת מראש, או שתקבל ספרה כפולה. צבעי הפס והרקע הם שני הפרמטר האחרונים, והפיתוי להיות יצירתי שם הוא מלכודת הנידונה בהמשך. שים לב גם למקור הקואורדינטות: כמו כל קריאת ציור אחרת ב-HotPDF, ציר ה-X וה-Y מודדים מהפינה השמאלית-תחתונה של העמוד בנקודות, כשציר Y גדל כלפי מעלה, אותה מוסכמה שדוגמת Hello World עוברת דרכה

הנתיב השני הוא DirectDrawBarcode, המקבל את הנתונים ותיבה תוחמת (bounding box), X, Y, Width, Height, ומשנה את קנה המידה של תבנית הפסים כדי למלא רוחב זה. זה נוח לפריסת קודים על רשת (grid) מכיוון שאתה מציין את טביעת הרגל והמתודה מתאימה אליה את הפסים. נוחות זו היא גם הסכנה שלה. כאשר אתה נותן לה רוחב, אינך מגדיר יותר את גודל המודול; המתודה מחלקת כל שטח שתאפשר בין כל מספר הפסים שהנתונים דורשים, והפס הצר ביותר הופך להיות כל מה שנופל מאותה חלוקה. בקש מחרוזת Code 128 צפופה בתוך תיבה צרה מדי והמודולים יתכווצו מתחת למה שכל סורק יכול לפענח, בשקט. עבור כל דבר שחייב להיסרק באופן אמין, העדף את DrawBarcode והגדר MUnit במכוון. שים בצד את DirectDrawBarcode עבור תצוגות מקדימות ועבור סידורים שבהם מדדת שהפסים המתקבלים נשארים קריאים

רוחב מודול הוא החלטת רזולוציה

הנה האריתמטיקה שקובעת האם התווית שלך עובדת. לסורק לייזר ומצלמה יש תכונה קטנה ביותר שהם יכולים להבחין בה, והפס הצר צריך לנחות בנוחות מעליה לאחר ההדפסה. הרצפה המצוטטת באופן נרחב עבור קודים ליניאריים לשימוש כללי היא פס צר של 13 מיל (mil), כ-0.33 מ"מ, ומדריכים קמעונאיים ותעשייתיים רבים מתייחסים לכך כמינימום ולא כיעד. תרגם זאת ליחידות PDF: נקודה אחת היא 1/72 אינץ', בערך 0.353 מ"מ, כך שנקודה בודדת של רוחב מודול יושבת בדיוק ברצפה הזו. זו הסיבה ש-MUnit := 1 הוא הערך הקטן ביותר שעליך לסמוך עליו עבור קוד המיועד לסורק אמיתי, ומדוע הכפלתו ל-2 קונה מרווח ביטחון שכמעט לא עולה דבר על תווית עם מקום פנוי

כעת חבר זאת לרזולוציית הפלט, מכיוון שהמודול חייב גם לשרוד את המדפסת. במדפסת לייזר של 300 DPI, נקודת מכשיר (device dot) אחת היא 1/300 אינץ', כך שמודול של נקודה אחת הוא ברוחב של כארבע נקודות. ארבע נקודות זה בקושי מספיק כדי לרנדר קצה נקי; פיזור טונר ושגיאת רישום קלה נוגסים בזה, והפס שנמדד כנקודה אחת ב-PDF שלך יודפס שמן יותר או דק יותר ממה שהמפרט מאפשר. העלה את המודול ל-2 נקודות ויש לך שמונה נקודות לעבוד איתן, מה שסופג את הרעש הזה. הכלל ששווה להפנים: רוחב המודול שאתה קובע בנקודות חייב להיות ממופה למספר שלם ונוח של נקודות מכשיר ברזולוציית ההדפסה האמיתית שלך, לא הרזולוציה שהיית רוצה שתהיה לך. קוד שנסרק ללא דופי מהמסך ונכשל ממדפסת המחסן כמעט תמיד נכשל בבדיקה זו

האזור השקט הוא חלק מהסמל

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

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

צבע, ניגודיות ושורת ה-human-readable (הקריאה לבני אדם)

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

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

הרגל אימות קצר

פסי וקטור (Vector bars) הם יתרון ששווה לנקוב בשמו. מכיוון ש-DrawBarcode כותב את הקוד כאופרטורי ציור ב-PDF במקום כתמונת רסטר (rasterized image), הפסים נשארים חדים בכל רמת תקריב (zoom) והקובץ אינו נושא רזולוציה משלו; הרזולוציה היחידה שחשובה היא זו של המדפסת. זה לא פוטר אותך מבדיקה, זה רק אומר שהבדיקה חייבת לקרות על נייר. צור דוגמה, הדפס אותה במכשיר בעל הרזולוציה הנמוכה ביותר שהקודים שלך יפגשו בפועל, וסרוק אותה עם אותו סוג של קורא שהמשתמשים שלך מחזיקים בו, לא הסורק (imager) היוקרתי שעל שולחנך. בדוק את האזורים השקטים בעזרת סרגל על גבי התדפיס, ודא שרוחב המודול שרד את המסע מנקודות (points) לנקודות הדפסה (dots), ואמת שהערך המפוענח תואם את מה שקידדת, כולל ספרת הביקורת והכל. חמש דקות עם סורק אמיתי תופסות כל כשל המתואר לעיל, ותופסות אותם לפני שמשטח (pallet) של מלאי עם תווית שגויה עושה זאת

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