Technical Article

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

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

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

چرا بردار بهتر از یک بیت‌مپ قرار داده شده است

یک بارکد الگویی از میله‌ها و فاصله‌ها، یا در دو بعد شبکه‌ای از ماژول‌های تیره و روشن است. رمزگشا با اندازه‌گیری نسبت آن عرض‌ها کار می‌کند. هر چیزی که نسبت‌ها را مخدوش کند، نویزی است که بودجه خطای نماد را از بین می‌برد. یک تصویر بارکد شطرنجی‌شده (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) است. هر ردیف یک بارکد خطی کوتاه است و ردیف‌ها روی هم قرار می‌گیرند تا یک بلوک تشکیل دهند، به همین دلیل است که روی گواهینامه‌های رانندگی، کارت‌های پرواز و برچسب‌های حمل و نقل حامل ظاهر می‌شود، جایی که نوار وسیع‌تری از داده‌ها باید در یک فضای مستطیلی قرار گیرد. تصحیح خطای آن در مقیاس ۰ تا ۸ اجرا می‌شود. هر مرحله تقریباً تعداد کلمات کد تصحیح را دو برابر می‌کند، بنابراین سطح ۵ به قیمت کلمات کد بیشتر در صفحه، افزونگی بسیار بیشتری نسبت به سطح ۱ حمل می‌کند

شکل یک بلوک PDF417 قابل تنظیم است و این مهم است زیرا برچسب فضای ثابتی برای پر کردن دارد. متد DrawPDF417SymbolEx کنترل‌هایی را نشان می‌دهد که فراخوانی اصلی فاقد آن‌هاست. پارامترهای FixedColumns و FixedRows تعداد ستون‌ها و ردیف‌های داده را ثابت می‌کنند، که مقدار 0 به معنای واگذاری تصمیم‌گیری به رمزگذار است. ErrorLevel مقدار -1 برای حالت خودکار یا مقداری صریح از ۰ تا ۸ را می‌گیرد. 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 برای گام نقطه، یک Encoding با مقدار 1 برای ASCII، و یک SymbolSize که یا 0 برای حالت خودکار است یا یکی از ابعاد استاندارد مربع و مستطیل از 10x10 تا 132x132 است را می‌گیرد. پارامتر Options جهت‌گیری را با عرض منطقه آرام (Quiet-zone) ترکیب می‌کند، جایی که افزودن ۱۰۰ تا ۴۰۰ یک حاشیه سفید یک تا چهار ماژولی را تنظیم می‌نماید. منطقه آرام یک تزئین نیست. یک رمزگشا به آن حاشیه واضح نیاز دارد تا الگوی یابنده نماد را پیدا کند، و نمادی که به جوهرهای دیگر چسبیده باشد، نمادی است که خوانده نمی‌شود

// 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

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

نمادهای دو بعدی مورد توجه قرار می‌گیرند، اما بارکدهای خطی همچنان بخش‌های بزرگی از خرده‌فروشی و لجستیک را در اختیار دارند و دلیل آن اسکنرهای لیزری مستقر است که با یک حرکت می‌خوانند. بارکد Code128 ابزار اصلی برای داده‌های حروف و اعداد است و کارایی آن از سه مجموعه نویسه حاصل می‌شود. مجموعه A نویسه‌های کنترلی و حروف بزرگ را پوشش می‌دهد، مجموعه B کل محدوده قابل چاپ ASCII را پوشش می‌دهد و مجموعه C موردی است که برای اعداد اهمیت دارد. زیرمجموعه C یک جفت رقم را در یک نویسه نماد واحد رمزگذاری می‌کند، بنابراین اجرای داده‌های عددی نصف نویسه‌های نمادی را که در مجموعه A یا B نیاز بود، مصرف می‌کند. این فشرده‌ترین راه برای قرار دادن یک بارکد عددی طولانی است و پیاده‌سازی Code128 در PDFlibPas مجموعه‌های 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 Intelligent Mail که OneCode نیز نامیده می‌شود، داده‌های مسیریابی و ردیابی را در یک بارکد مدوله شده با ارتفاع برای اتوماسیون پستی رمزگذاری می‌کند. متد DrawIntelligentMailBarcode هندسه صریحی برای عرض میله، ارتفاع کامل میله، ارتفاع ردیاب و عرض فاصله می‌گیرد، در حالی که داده‌ها به صورت یک رشته عددی ۲۰، ۲۵، ۲۹ یا ۳۱ رقمی ارائه می‌شوند. ارتفاع صریح میله و ردیاب به این دلیل وجود دارد که نماد حاوی اطلاعاتی در مورد این است که آیا هر میله یک میله کامل است، یا بالارونده (Ascender) یا پایین‌رونده (Descender)، و خواننده پستی به رعایت مشخصات این ارتفاع‌ها وابسته است

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

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

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

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