مقاله فنی

بارکدها در PDF با Delphi: QR، PDF417، DataMatrix

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

جایگزین این است که نماد را به عنوان محتوای برداری (vector)، مستقیماً در صفحه رسم کنید. PDFlibPas خانواده‌ای از فراخوانی‌های ترسیم را دقیقاً برای همین منظور ارائه می‌دهد، که نمادهای ماتریس دوبعدی QR، PDF417 و DataMatrix، خانواده‌های خطی از طریق Code128 و GS1-128، و پست هوشمند USPS (USPS Intelligent Mail) را برای اتوماسیون پستی پوشش می‌دهد. دلیل استفاده از وکتور زیبایی‌شناختی نیست. این موضوع به این برمی‌گردد که آیا میله‌ها در جایی که اسکنر انتظار دارد قرار می‌گیرند یا خیر

چرا وکتور بر تصویر بیتی قرار داده شده برتری دارد

بارکد الگویی از میله‌ها و فضاها، یا در دو بعد شبکه‌ای از ماژول‌های تاریک و روشن است. رمزگشا (decoder) با اندازه‌گیری نسبت آن عرض‌ها کار می‌کند. هر چیزی که این نسبت‌ها را مخدوش کند، نویزی است که بودجه خطای نماد را می‌بلعد. یک تصویر بارکد شطرنجی (rasterized) دارای پیکسل‌های ثابت است. هنگامی که PDF به چاپگری ارسال می‌شود که نقاط آن به طور مساوی در شبکه تصویر تقسیم نمی‌شوند، رسترایزر باید دوباره نمونه‌برداری کند، و لبه‌های ماژول که باید واضح باشند در دو پیکسل دستگاه پخش می‌شوند. یک نوار باریک می‌تواند ضخیم شود، یک فضای مجاور می‌تواند نازک شود، و نسبت عرضی که رمزگشا به آن متکی است منحرف می‌شود

هنگامی که به عنوان محتوای برداری ترسیم می‌شود، همان نماد مجموعه‌ای از مستطیل‌های پر شده است که در مختصات فضای کاربری PDF توصیف شده‌اند. هیچ شبکه پیکسلی ثابتی برای مبارزه وجود ندارد. در زمان چاپ، دستگاه هر مستطیل را با رزولوشنی که در واقع دارد رندر می‌کند، بنابراین هر لبه ماژول در هر مقیاس و هر اندازه چاپی تا آنجا که سخت‌افزار اجازه می‌دهد واضح است. یک نماد برداری را برای برچسب پالت بزرگ کنید یا آن را برای یک بسته کوچک کنید و هندسه دقیق باقی می‌ماند. این دقت همان چیزی است که نرخ خواندن در اولین عبور را بالا نگه می‌دارد، که کل هدف قرار دادن بارکد روی صفحه است

کدهای QR و چهار سطح تصحیح

QR یک نماد ماتریس دوبعدی است که در هر دو محور به طور همزمان خوانده می‌شود، به همین دلیل است که داده‌های زیادی را در یک مربع کوچک جای می‌دهد. تحمل آسیب آن ناشی از تصحیح خطای Reed-Solomon است که در چهار سطح ارائه می‌شود. سطح L تقریباً ۷ درصد از کلمات رمز را بازیابی می‌کند، M حدود ۱۵ درصد، Q حدود ۲۵ درصد و H حدود ۳۰ درصد. تصحیح بالاتر رایگان نیست. کلمات رمز بازیابی ظرفیت ماژول را اشغال می‌کنند، بنابراین برای مقدار ثابتی از داده، سطح بالاتر نمادی متراکم‌تر یا از نظر فیزیکی بزرگ‌تر را تحمیل می‌کند

این مبادله سوالی درباره محیطی است که نماد در آن زندگی خواهد کرد. یک سند دیجیتالی تمیز که فقط از روی صفحه نمایش اسکن می‌شود می‌تواند در سطح L بماند و فشرده بماند. برچسبی که چاپ می‌شود، جابجا می‌شود، خراشیده می‌شود و احتمالاً تا حدی با چسب پوشانده می‌شود، نیازمند Q یا H است، زیرا این افزونگی اضافی است که به رمزگشا اجازه می‌دهد تا بارکد را از نمادی که دیگر دست‌نخورده نیست بازسازی کند. DrawQRCode موقعیت و SymbolSize را می‌گیرد که عرض و ارتفاع ترسیم شده را ثابت می‌کند، به علاوه یک مقدار EncodeOptions که حالت داده (0 برای خودکار، یا عددی، الفبایی، انواع ISO-8859-1 و UTF-8) و مقدار DrawOptions را برای جهت‌گیری انتخاب می‌کند

var
  Pdf: TPDFlib;
begin
  Pdf := TPDFlib.Create(nil);
  try
    Pdf.NewDocument;
    Pdf.SetPageSize('A4');
    Pdf.SetMeasurementUnits(1);   // 1 = millimetres
    Pdf.NewPage;

    // 30 mm square QR, automatic encoding, normal orientation
    Pdf.DrawQRCode(20, 20, 30, 'https://www.loslab.com/', 0, 0);

    Pdf.SaveToFile('Label_QR.pdf');
  finally
    Pdf.Free;
  end;
end;

سطح تصحیح به خودی خود توسط رمزگذار انتخاب می‌شود تا داده‌ها را در نمادی که درخواست کرده‌اید قرار دهد. اگر برای یک محیط خشن به سطح بالایی تضمین شده نیاز دارید، اندازه نماد را سخاوتمندانه در نظر بگیرید تا رمزگذار بودجه ماژول برای صرف افزونگی را داشته باشد به جای اینکه مجبور شود برای جا دادن فشرده شود

PDF417 برای شناسه‌ها و برچسب‌های حمل و نقل

PDF417 یک نماد خطی روی هم چیده شده (stacked linear) است. هر ردیف یک بارکد خطی کوتاه است و ردیف‌ها روی هم قرار می‌گیرند تا یک بلوک را تشکیل دهند، به همین دلیل است که روی گواهینامه‌های رانندگی، کارت‌های پرواز و برچسب‌های حمل و نقل شرکت‌های حمل و نقل ظاهر می‌شود، جایی که یک نوار عریض‌تر از داده‌ها باید در یک ردپای مستطیل شکل قرار گیرد. تصحیح خطای آن در مقیاس 0 تا 8 اجرا می‌شود. هر مرحله تقریباً تعداد کلمات رمز تصحیح را دو برابر می‌کند، بنابراین سطح 5 در ازای کلمات رمز بیشتر روی صفحه، افزونگی بسیار بیشتری نسبت به سطح 1 دارد

شکل یک بلوک PDF417 قابل تنظیم است، و این مهم است زیرا برچسب دارای یک منطقه ثابت برای پر کردن است. DrawPDF417SymbolEx کنترل‌هایی را که فراخوانی اصلی ارائه نمی‌دهد، در معرض دید قرار می‌دهد. FixedColumns و FixedRows تعداد ستون‌ها و ردیف‌های داده را ثابت می‌کنند، که 0 به معنای واگذاری تصمیم به رمزگذار است. ErrorLevel عدد -1 را برای حالت خودکار یا صراحتاً 0 تا 8 می‌پذیرد. ModuleSize عرض باریک‌ترین عنصر در واحد اندازه‌گیری فعلی است، و HeightWidthRatio تعیین می‌کند که هر ماژول نسبت به عرض آن چقدر بلند است، که این روشی است برای ساختن بلوک کوتاه و عریض یا بلند و باریک تا با فضای شما مطابقت داشته باشد

// Fixed 10 data columns, automatic rows, error level 5,
// module 0.30 mm wide, rows three times the module width tall
Pdf.DrawPDF417SymbolEx(20, 60, 'PDF417 PAYLOAD 0123456789',
  0,        // Options: 0 = normal orientation
  10,       // FixedColumns
  0,        // FixedRows: 0 = automatic
  5,        // ErrorLevel: 0 to 8
  0.30,     // ModuleSize, in the current measurement unit
  3.0);     // HeightWidthRatio

ثابت کردن ستون‌ها اهرم معمول در یک قالب برچسب است. تعداد ستون ثابت به بلوک یک عرض قابل پیش‌بینی می‌دهد، بنابراین با تغییر طول داده‌های رمزگذاری شده از یک سند به سند دیگر، چیدمان اطراف تغییر نمی‌کند، در حالی که رمزگذار برای جذب این تفاوت، ردیف‌هایی را به سمت پایین اضافه می‌کند

DataMatrix برای نشانه‌های کوچک

DataMatrix نمادی است که وقتی نشانه باید کوچک باشد به سراغ آن می‌روید. این یک شبکه دوبعدی فشرده است که از ECC 200، طرح مدرن Reed-Solomon استفاده می‌کند، و در اندازه‌هایی که یک نماد QR با همان داده‌ها نامناسب خواهد بود، خوانا باقی می‌ماند. این امر آن را به انتخاب استانداردی برای علامت‌گذاری مستقیم قطعات، قطعات الکترونیکی کوچک و برچسب‌های تدارکات متراکم تبدیل می‌کند

DrawDataMatrixSymbol پارامتر ModuleSize را برای گام نقطه (dot pitch)، یک Encoding برابر 1 برای ASCII، و SymbolSize که یا 0 برای خودکار یا یکی از ابعاد استاندارد مربع و مستطیل، از 10x10 تا 132x132 است را دریافت می‌کند. پارامتر Options جهت‌گیری را با عرض منطقه آرام (quiet-zone) ترکیب می‌کند، جایی که اضافه کردن 100 تا 400 یک حاشیه سفید یک تا چهار ماژولی را تنظیم می‌کند. منطقه آرام تزئینی نیست. یک رمزگشا برای یافتن الگوی یابنده نماد به آن حاشیه واضح نیاز دارد، و نمادی که در مقابل جوهرهای دیگر فشرده شده است، نمادی است که در خواندن شکست می‌خورد

// Auto-sized ASCII DataMatrix, 0.5 mm module, normal orientation
// with a one-module quiet zone (Options 0 + 100)
Pdf.DrawDataMatrixSymbol(20, 110, 0.5, 'DMX-SN-4408812',
  1,        // Encoding: 1 = ASCII
  0,        // SymbolSize: 0 = automatic
  100);     // Options: normal + one-module quiet zone

جایی که بارکدهای یک‌بعدی هنوز حاکم هستند

نمادهای دوبعدی توجه‌ها را به خود جلب می‌کنند، اما بارکدهای خطی هنوز بخش‌های بزرگی از خرده‌فروشی و تدارکات را در اختیار دارند، و دلیل آن پایگاه نصب شده اسکنرهای لیزری است که با یک حرکت رفت و برگشت می‌خوانند. Code128 اسب کاری برای داده‌های الفبایی-عددی است، و کارایی آن از سه مجموعه کاراکتر ناشی می‌شود. مجموعه A کاراکترهای کنترلی و حروف بزرگ را پوشش می‌دهد، مجموعه B محدوده کامل ASCII قابل چاپ را پوشش می‌دهد، و مجموعه C موردی است که برای اعداد اهمیت دارد. زیرمجموعه C یک جفت رقم را در یک کاراکتر نماد منفرد رمزگذاری می‌کند، بنابراین یک سری از داده‌های عددی نیمی از کاراکترهای نمادی را که در مجموعه A یا B نیاز داشت مصرف می‌کند. این فشرده‌ترین راه برای قرار دادن یک بارکد عددی طولانی است و پیاده‌سازی PDFlibPas برای Code128 مجموعه‌های B و C را به طور خودکار برای رسیدن به آن ترکیب می‌کند

GS1-128، استانداردی که قبلاً EAN-128 نامیده می‌شد، با حمل شناسه‌های کاربردی (Application Identifiers) که پیشوندهای داخل پرانتز هستند، بر روی Code128 ساخته شده است، و به سیستم دریافت‌کننده می‌گوید که آیا ارقام بعدی یک شماره سریال، کد دسته، یا تاریخ انقضا هستند. این ساختار با FNC1، یک کاراکتر ویژه غیرداده‌ای مشخص می‌شود که نماد را به عنوان رمزگذاری شده با GS1 پرچم‌گذاری می‌کند و فیلدهای با طول متغیر را جدا می‌کند. در PDFlibPas شما یک نماد GS1-128 را با DrawBarcode با استفاده از نوع Code128 و نشانگر تحت‌اللفظی [FNC1] قرار داده شده در رشته داده در جایی که هر شناسه برنامه آغاز می‌شود، رسم می‌کنید

var
  W: Double;
begin
  // Code128, with FNC1 markers this becomes a GS1-128 symbol.
  // AI 21 (serial) = ABC123, AI 20 (variant) = 13
  Pdf.DrawBarcode(20, 150, 60, 18, '[FNC1]21ABC123[FNC1]2013',
    3,        // Barcode: 3 = Code128
    0);       // Options: 0 = default drawing

  // Measure the rendered width for a 0.30 mm narrow bar before laying out
  W := Pdf.GetBarcodeWidth(0.30, '[FNC1]21ABC123[FNC1]2013', 3);
end;

برای پست، پست هوشمند USPS که OneCode نیز نامیده می‌شود، داده‌های مسیریابی و ردیابی را در یک بارکد تک‌مدوله با ارتفاع برای اتوماسیون پستی رمزگذاری می‌کند. DrawIntelligentMailBarcode هندسه صریح برای عرض میله، ارتفاع کامل میله، ارتفاع ردیاب و عرض فضا را دریافت می‌کند، در حالی که داده‌ها به عنوان یک رشته 20، 25، 29 یا 31 رقمی فقط از ارقام ارائه می‌شوند. ارتفاع‌های صریح میله و ردیاب وجود دارند زیرا نماد اطلاعاتی را حمل می‌کند در مورد اینکه آیا هر میله یک میله کامل، بالارونده (ascender) یا پایین‌رونده (descender) است، و خواننده پستی به حفظ این ارتفاعات طبق مشخصات وابسته است

طراحی در صفحه و اندازه‌گیری برای چیدمان

هر فراخوانی نشان داده شده در اینجا در محتوای صفحه انتخاب شده فعلی ترسیم می‌شود، همان سطحی که متن و تصاویر شما را دریافت می‌کند، بنابراین بارکد به عنوان بخشی از تولید عادی سند به جای وارد شدن به عنوان یک دارایی جداگانه تولید می‌شود. از آنجا که نمادها محتوای برداری هستند، داده‌هایی که آنها رمزگذاری می‌کنند و هندسه‌ای که اشغال می‌کنند هر دو در زمان رسم شناخته شده‌اند، که همین امر به شما اجازه می‌دهد آنها را به طور قطعی قرار دهید

چیدمان برای خانواده‌های خطی از اندازه‌گیری اولیه سود می‌برد. GetBarcodeWidth کل عرض ترسیم شده یک بارکد را برای یک عرض نوار باریک داده شده و نوع بارکد برمی‌گرداند، بنابراین شما می‌توانید قبل از اینکه ترسیم را متعهد شوید، فضای افقی دقیق را رزرو کنید، به جای حدس زدن و کشف یک همپوشانی پس از ساخته شدن صفحه. قرار دادن نمادهای دوبعدی ساده‌تر است زیرا شما اندازه ترسیم شده آنها را مستقیماً از طریق SymbolSize یا ModuleSize تنظیم می‌کنید و نماد آن ردپا را پر می‌کند. در هر صورت انضباط یکسان است. اندازه فیزیکی را از محیط اسکن تصمیم بگیرید، تأیید کنید که نماد در شکافی که دارید قرار می‌گیرد، و اجازه دهید هندسه برداری هر لبه را از پیش‌نمایش صفحه نمایش تا چاپ نهایی تیز نگه دارد

برای گردش کار گسترده‌تر ساخت صفحه که این بارکدها در آن قرار می‌گیرند، تکنیک‌های موجود در مقاله ما در مورد استخراج متن، تصویر و فونت استخراج مجدد محتوا از یک PDF را پوشش می‌دهند، و راهنمای ادغام و تقسیم PDF بزرگ با دسترسی مستقیم نحوه مونتاژ اسناد با حجم بالا را به طور کارآمد نشان می‌دهد. هر دو به طور طبیعی با API ترسیم شرح داده شده در اینجا جفت می‌شوند، که به عنوان بخشی از کتابخانه PDF Delphi برای Delphi و C++Builder در کنار APIهای متن، گرافیک، فرم و امضا که در جاهای دیگر این وبلاگ پوشش داده شده‌اند، عرضه می‌شود