مقاله فنی

تولید بارکدهای قابل اسکن در PDF با HotPDF در دلفی

یک بارکد تصویری نیست که با آن سندی را تزئین کنید. بارکد یک اندازه‌گیری است، و اسکنر ابزاری است که آن را می‌خواند. این تغییر چارچوب ذهنی تقریباً همه چیز را در مورد نحوه رسم یک بارکد در یک PDF تعیین می‌کند. میله‌ها (bars) با سیاهی خود اطلاعاتی حمل نمی‌کنند؛ اطلاعات در نسبت عرض میله‌ها به عرض فضاها نهفته است، و یک دستگاه خواننده (reader) هنگام عبور لیزر یا سنسور از روی آنها با زمان‌سنجی انتقال‌ها، این اطلاعات را بازیابی می‌کند. اگر این هندسه را فشرده کنید، آن را تار کنید، یا حاشیه‌های آن را شلوغ کنید، چیزی تولید می‌کنید که دقیقاً شبیه یک بارکد به نظر می‌رسد اما مانند یک لکه کثیف اسکن می‌شود. HotPDF دو راه برای قرار دادن یک بارکد در صفحه به شما ارائه می‌دهد، و تفاوت بین آنها دقیقاً تفاوت بین کنترل آن هندسه و تسلیم کردن آن است

یک صفحه PDF که شبکه‌ای از بارکدهای خطی در نمادگذاری‌های مختلف را نشان می‌دهد که توسط HotPDF در دلفی رسم شده‌اند
نمادگذاری‌های بارکد خطی که با HotPDF در یک سند PDF واحد رسم شده‌اند

آنچه HotPDF می‌تواند رمزگذاری کند

کامپوننت HotPDF نمادگذاری‌های خطی (یک‌بعدی) را رسم می‌کند، و این مجموعه گسترده‌تر از آن چیزی است که اکثر پروژه‌ها نیاز دارند. شمارش THPDFBarcodeType شامل خانواده Code 2 of 5 در اشکال interleaved (درهم‌تنیده)، صنعتی (industrial)، و ماتریسی؛ Code 39 و نوع گسترش‌یافته آن؛ سه زیرمجموعه A، B، و C از Code 128؛ Code 93 ساده و گسترش‌یافته؛ MSI؛ PostNet؛ Codabar؛ گروه خرده‌فروشی UPC و EAN، یعنی EAN-8، EAN-13، UPC-A، مدل‌های فشرده UPC-E0 و UPC-E1، و افزودنی‌های تکمیلی 2 و 5 رقمی UPC؛ و زیرمجموعه‌های GS1-128 (EAN-128) را پوشش می‌دهد. این مقدار برای پوشش برچسب‌های زنجیره تأمین، نقاط فروش خرده‌فروشی، و کدهای صنعتی قدیمی‌تر که هنوز در انبارها زنده هستند، کافی است

چیزی که رسم نمی‌کند خانواده دوبعدی است. در اینجا هیچ QR، Data Matrix، یا PDF417 وجود ندارد. این نوع بارکدها بایت‌ها را در شبکه‌ای با محاسبات تصحیح خطای خودشان رمزگذاری می‌کنند، و اگر نیازی یکی از آنها را نام می‌برد، این ابزار اشتباهی است و شما باید این را قبل از شروع ساختن در اطراف آن بدانید، نه بعد از آن. برای کدهای یک‌بعدی سؤال عملی محدودتر است: کدام سیستم نمادگذاری (symbology) داده‌هایی را که شما واقعاً در اختیار دارید می‌پذیرد، زیرا رمزگذاری‌ها قابل تعویض نیستند

محدودیت‌های داده واقعی هستند و در زمان تولید خود را نشان می‌دهند. انواع Code 2 of 5 و MSI فقط ارقام را می‌پذیرند. Code 39 حروف بزرگ، ارقام، و تعداد انگشت‌شماری از علائم نگارشی را حمل می‌کند؛ اگر به حروف کوچک یا محدوده کامل ASCII نیاز دارید، باید از Code 39 Extended یا یک زیرمجموعه Code 128 استفاده کنید. Code 128C برای تراکم بیشتر، دو رقم را در هر نماد بسته‌بندی می‌کند، بنابراین به یک رشته عددی با طول زوج و هیچ چیز دیگری نیاز دارد. EAN-13 انتظار دوازده رقم را دارد و سیزدهمی را به عنوان یک چک (check digit) محاسبه می‌کند؛ EAN-8 هفت رقم را انتظار دارد و هشتمی را محاسبه می‌کند؛ UPC-A دوازده رقم می‌پذیرد. اگر به یک سیستم نمادگذاری داده‌ای بدهید که نمی‌تواند آن را نمایش دهد، یک استثنای (exception) مفید دریافت نمی‌کنید، بلکه یک بارکد دریافت می‌کنید که زباله را رمزگذاری می‌کند، که این بدتر است، زیرا تا زمانی که کسی آن را در یک صندوق اسکن نکند، خوب به نظر می‌رسد

دو مسیر رسم، دو سطح کنترل

متدی که برای تولید (production) باید به سراغ آن بروید DrawBarcode در شی صفحه (page object) است. این متد نمادگذاری، یک موقعیت، یک ارتفاع، و یک پارامتر که بیش از بقیه اهمیت دارد را دریافت می‌کند: MUnit، یعنی عرض ماژول. ماژول عرض باریک‌ترین میله است، همان اتمی که هر اندازه دیگری در کد مضربی از آن است، و در اینجا بر حسب نقاط (points) بیان می‌شود. همه چیز درباره اینکه آیا نتیجه چاپ‌شده اسکن می‌شود یا خیر، به همین عدد صحیح منفرد برمی‌گردد

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 رقم چک (check digit) ماژولو 10 را که سیستم نمادگذاری انتظار دارد ضمیمه می‌کند، و برای کدهای خرده‌فروشی شما تقریباً همیشه آن را برابر True می‌خواهید؛ آن را تنها زمانی خاموش کنید که داده‌های شما در حال حاضر یک رقم چک از پیش محاسبه‌شده را حمل می‌کنند، در غیر این صورت یک رقم دوبرابر شده (doubled digit) دریافت خواهید کرد. رنگ میله و پس‌زمینه دو پارامتر آخر هستند، و وسوسه خلاقیت به خرج دادن در آنجا تله‌ای است که در زیر در مورد آن بحث می‌شود. همچنین به مبدأ مختصات توجه کنید: مانند هر فراخوانی رسم دیگر در HotPDF، مقادیر X و Y از گوشه پایین سمت چپ صفحه بر حسب نقطه اندازه‌گیری می‌شوند، در حالی که Y به سمت بالا افزایش می‌یابد، همان قراردادی که در مثال Hello World نیز با آن کار کردیم

مسیر دوم DirectDrawBarcode است که داده‌ها و یک کادر مرزی (bounding box) به صورت X, Y, Width, Height را می‌گیرد و الگوی میله را برای پر کردن آن عرض مقیاس می‌دهد (scales). این برای چیدمان کدها روی یک شبکه راحت است زیرا شما ردپای فضایی (footprint) را نام می‌برید و این متد میله‌ها را با آن متناسب می‌کند. این راحتی در عین حال خطر آن نیز هست. هنگامی که شما یک عرض به آن می‌دهید، دیگر اندازه ماژول را تنظیم نمی‌کنید؛ این متد هر فضایی را که اجازه می‌دهید بین هر تعداد میله که داده‌ها نیاز دارند تقسیم می‌کند، و باریک‌ترین میله به هر چیزی تبدیل می‌شود که از آن تقسیم به دست می‌آید. اگر یک رشته Code 128 متراکم را در داخل جعبه‌ای بخواهید که خیلی باریک است، ماژول‌ها در سکوت به پایین‌تر از حدی که هر اسکنری می‌تواند تفکیک کند کوچک می‌شوند. برای هر چیزی که باید به طور قابل اعتمادی اسکن شود، DrawBarcode را ترجیح دهید و MUnit را به طور عمدی تنظیم کنید. از DirectDrawBarcode برای پیش‌نمایش‌ها و برای چیدمان‌هایی استفاده کنید که اندازه‌گیری کرده‌اید و مطمئنید میله‌های حاصل، خوانا باقی می‌مانند

عرض ماژول یک تصمیم در مورد وضوح تصویر (Resolution) است

در اینجا محاسباتی وجود دارد که تعیین می‌کند آیا برچسب شما کار می‌کند یا خیر. یک اسکنر لیزری و یک دوربین هر دو یک کوچک‌ترین ویژگی دارند که می‌توانند تشخیص دهند، و میله باریک پس از چاپ باید به راحتی بالاتر از آن قرار گیرد. کف تعیین‌شده و پرکاربرد برای کدهای خطی همه‌منظوره یک میله باریک 13 mil است، چیزی حدود 0.33 میلی‌متر، و بسیاری از راهنماهای خرده‌فروشی و صنعتی با این مقدار به عنوان حداقل رفتار می‌کنند تا یک هدف. این را به واحدهای PDF ترجمه کنید: یک نقطه (point) معادل 1/72 اینچ است، یعنی تقریباً 0.353 میلی‌متر، بنابراین یک تک نقطه از عرض ماژول دقیقاً روی همان کف قرار می‌گیرد. به همین دلیل است که MUnit := 1 کوچک‌ترین مقداری است که باید برای کدی که مقصد آن یک اسکنر واقعی است به آن اعتماد کنید، و به همین دلیل است که دو برابر کردن آن به 2، حاشیه‌ای را برای شما می‌خرد که در برچسبی با فضای خالی، تقریباً هیچ هزینه‌ای در بر ندارد

حالا این را به وضوح تصویر خروجی (output resolution) متصل کنید، زیرا ماژول باید از فرآیند چاپگر نیز جان سالم به در ببرد. روی یک چاپگر لیزری 300 DPI یک نقطه دستگاه (device dot) معادل 1/300 اینچ است، بنابراین یک ماژول یک-نقطه‌ای (one-point module) تقریباً چهار نقطه دستگاه عرض دارد. چهار نقطه به سختی برای رندر کردن یک لبه تمیز کافی است؛ پخش شدن تونر (toner spread) و خطای جزئی انطباق (registration error) این مقدار را می‌خورد، و میله‌ای که در PDF شما یک نقطه اندازه‌گیری شده است، در نهایت چاق‌تر یا لاغرتر از آن چیزی که مشخصات اجازه می‌دهد چاپ می‌شود. ماژول را به 2 نقطه ارتقا دهید و هشت نقطه دستگاه برای کار خواهید داشت، که آن نویز را جذب می‌کند. قاعده‌ای که ارزش درونی‌سازی دارد: عرض ماژولی که در PDF بر حسب نقاط تنظیم می‌کنید باید به یک عدد صحیح و راحت از نقاط دستگاه در وضوح واقعی چاپ شما نگاشت شود، نه وضوحی که آرزو داشتید داشته باشید. کدی که روی صفحه‌نمایش بدون نقص اسکن می‌شود و وقتی از چاپگر انبار بیرون می‌آید شکست می‌خورد، تقریباً همیشه در این بررسی شکست خورده است

منطقه آرام (Quiet Zone) بخشی از نماد است

رایج‌ترین دلیل برای اینکه یک بارکد درست کدگذاری شده اسکن نمی‌شود، منطقه آرام (quiet zone) است، یعنی حاشیه خالی در هر دو طرف میله‌ها. اسکنرها از این فضای خالی برای پیدا کردن نقطه شروع و پایان کد استفاده می‌کنند؛ بدون آن، خواننده نمی‌تواند میله اول را از هر چیزی که در صفحه در کنار آن قرار دارد تشخیص دهد. استانداردها مشخص هستند. اکثر سیستم‌های نمادگذاری خطی خواهان یک منطقه آرام حداقل ده برابر عرض ماژول در هر طرف هستند، و کدهای خرده‌فروشی UPC و EAN نیاز به نه ماژول در سمت چپ و هفت ماژول در سمت راست دارند. با یک ماژول یک-نقطه‌ای (one-point module) این مقدار تقریباً ده نقطه است، حدود یک هفتم یک اینچ فضای سفید تضمین‌شده که میله‌ها را در بر می‌گیرد

کامپوننت HotPDF میله‌ها و هیچ چیز دیگری را رسم نمی‌کند. این کامپوننت منطقه آرام را برای شما رزرو نمی‌کند، به این معنی که مسئولیت آن بر عهده شماست و فراموش کردن آن آسان است. حالت شکست ظریف و پنهان است: شما یک بارکد را دقیقاً هم‌تراز با لبه یک سلول جدول قرار می‌دهید، یا اجازه می‌دهید چیدمان صفحه یک لوگو را در کنار آن قرار دهد، و کدی که روی یک صفحه خالی هر تستی را با موفقیت پشت سر گذاشته بود، در لحظه‌ای که در یک سند واقعی ارسال می‌شود، از اسکن شدن باز می‌ماند. حاشیه را به صراحت در بودجه‌بندی فضای خود لحاظ کنید. قبل از اینکه DrawBarcode را فراخوانی کنید، حداقل فضایی خالی به اندازه ده عرض ماژول در هر دو طرف باقی بگذارید، و با هر گرافیک، خط‌کشی (rule) یا متنی که به این نوار وارد می‌شود به عنوان یک نقص رفتار کنید، نه یک انتخاب زیبایی‌شناختی

رنگ، تضاد (Contrast) و خط قابل خواندن توسط انسان

رنگ‌های میله و پس‌زمینه وجود دارند تا بتوانید آنها را با پالت رنگی یک برند مطابقت دهید، و آنها سریع‌ترین راه برای خراب کردن یک کد در حال کار هستند. اسکنرها تضاد (contrast) را می‌خوانند، به طور کلاسیک با نور قرمز، و آنها انتظار میله‌های تیره را در یک میدان روشن دارند. سیاه روی سفید تنها ترکیبی است که باید بدون آزمایش به سراغ آن بروید. آبی تیره یا سبز تیره روی سفید می‌تواند کار کند؛ هر چیزی با تضاد روشنایی (luminance contrast) پایین، و به ویژه میله‌های قرمز، که یک اسکنر نور قرمز آنها را به عنوان پس‌زمینه می‌بیند، کار نخواهد کرد. اگر یک طراح از شما کدهای میله‌ای رنگی بخواهد، پاسخ صادقانه این است که میله‌ها سیاه باقی می‌مانند و رنگ به جای دیگری روی برچسب می‌رود

مسیر DrawBarcode همچنین می‌تواند متن قابل خواندن توسط انسان در زیر میله‌ها را رندر کند، همان ارقامی که اگر اسکن ناموفق باشد، متصدی صندوق آنها را به صورت دستی وارد می‌کند. این متن یک راهکار پشتیبان (fallback) است، نه تزیینات، بنابراین وقتی عنوان (caption) خودتان را قرار می‌دهید، آن را از منطقه آرام دور نگه دارید؛ یک برچسب از سیستم نمادگذاری که به حاشیه کناری چپانده شده است، همان فضای خالی را که اسکنر به آن متکی است از بین می‌برد. فیلدهای موجود در مثال اینجا، از جمله TextOut برای هر برچسب احاطه‌کننده‌ای، همان فراخوانی‌های رسم هستند که در راهنمای خروجی گزارش پوشش داده شده‌اند، که آن راهنما دقیقاً مکانی است که وقتی بارکد یکی از عناصر در یک صفحه ترکیبی بزرگتر است باید به آن مراجعه کنید

یک عادت اعتبارسنجی کوتاه

میله‌های برداری (Vector bars) مزیتی هستند که ارزش نام بردن را دارند. از آنجایی که DrawBarcode کد را به صورت عملگرهای رسم PDF (drawing operators) به جای یک تصویر پیکسلی (rasterized image) می‌نویسد، میله‌ها در هر بزرگنمایی واضح باقی می‌مانند و فایل به تنهایی هیچ وضوح تصویری از خود حمل نمی‌کند؛ تنها وضوحی که اهمیت دارد وضوح چاپگر است. این موضوع شما را از آزمایش معاف نمی‌کند، بلکه فقط به این معناست که آزمایش باید روی کاغذ انجام شود. یک نمونه تولید کنید، آن را روی چاپگری با پایین‌ترین وضوحی که کدهای شما در واقعیت با آن روبرو خواهند شد چاپ کنید، و آن را با کلاسی از اسکنرها که کاربران شما در دست دارند اسکن نمایید، نه اسکنرهای تصویربردار پیشرفته‌ای (high-end imager) که روی میز خود دارید. مناطق آرام (quiet zones) را با یک خط‌کش روی خروجی چاپ شده بررسی کنید، تأیید کنید که عرض ماژول از سفر خود از نقطه (points) به نقاط چاپی (dots) جان سالم به در برده است، و بررسی کنید که مقدار رمزگشایی شده (decoded value) با آنچه رمزگذاری کرده‌اید مطابقت داشته باشد، از جمله رقم چک و تمام موارد. پنج دقیقه زمان گذاشتن با یک اسکنر واقعی، تک‌تک شکست‌هایی را که در بالا توضیح داده شد را می‌گیرد، و آنها را قبل از اینکه یک پالت از کالاهای با برچسب اشتباه شناسایی شوند، کشف می‌کند

توابع DrawBarcode و DirectDrawBarcode که در اینجا نشان داده شده‌اند، بخشی از کامپوننت HotPDF برای دلفی و C++Builder هستند