บล็อก

สร้างบาร์โค้ด GS1-128 ความแม่นยำ 0.1 mm จาก JSON

GS1-128 ดูเรียบง่ายจนกว่า scanner จะอ่านไม่ออกที่ 240 dpi คู่มือนี้อธิบายความยาวรวม, X-dimension, quiet zone และข้อจำกัดของ HTML/CSS.

ถ้าคุณส่งสินค้าจริง สุดท้ายคุณต้องพิมพ์ GS1-128 ที่เครื่องสแกนจริงในคลังสินค้าจริงอ่านได้ ภายใต้แสงและระยะจริง เรื่องนี้ดูเหมือนรายละเอียดเล็ก ๆ แต่ใน PDF generation มันเป็นหนึ่งในจุดล้มเหลวที่สร้างปัญหามากที่สุด

บทความนี้อธิบายว่า “ความแม่นยำ 0.1 mm” ของ GS1-128 หมายถึงอะไร ทำไม renderer ที่อิง HTML/CSS จึงรักษาเรขาคณิตนี้ได้ยาก และกฎใดช่วยลดการถูกปฏิเสธโดย scanner ของ DHL, FedEx, USPS และ Amazon inbound

Barcode precision หมายถึงอะไร

GS1-128 (เดิม UCC/EAN-128) เข้ารหัสข้อมูลด้วย ความกว้างของแท่งและช่องว่าง ในสัดส่วนที่แน่นอน หน่วยพื้นฐานคือ X-dimension หรือความกว้างของแท่ง/ช่องที่แคบที่สุด ความกว้างอื่นคือหลายเท่าของ X

Scanner วัดความกว้างสัมพัทธ์ ไม่ได้ดูแค่ว่าภาพคมชัดหรือไม่ ปัญหาที่พบใน production บ่อยที่สุดคือ:

  1. X-dimension ไม่สม่ำเสมอใน symbol เดียวกัน: renderer ทำ sub-pixel rounding ต่างกันระหว่างแท่งที่ติดกัน
  2. ความยาวรวมหรือ scaling ผิด: render symbol แล้วถูกย่อ/ขยาย ทำให้ X-dimension ต่ำกว่าค่า GS1 minimum ซึ่งโดยมากคือ 0.495 mm ที่ 1.0×

อาการมักหลอกตา: sample หนึ่งใบอ่านได้ แต่ batch จริงมี rejection 1 ใน 30 เครื่อง dev scanner มักให้อภัยมากกว่า scanner ในคลัง

กฎ 0.1 mm

precision ที่สำคัญคือ ความยาวรวมของ barcode ต้องอยู่ใน tolerance 0.1 mm จาก target ของ spec ไม่ได้หมายความว่าแต่ละแท่งกว้าง 0.1 mm; โดยทั่วไปแท่งกว้าง 0.495 mm หรือมากกว่า

สำหรับ GS1-128 ที่มีตัวเลข 18 หลัก:

  • Symbol มีแท่งและช่องว่างประมาณ 120 ส่วน
  • ความยาวรวมที่ 1.0× ประมาณ 58 mm
  • tolerance 0.1 mm เท่ากับความแม่นยำรวม ~0.17%
  • budget ต่อแท่งประมาณ 0.001 mm

ดังนั้นแท่งที่ควรเป็น 7.4 px แต่ถูกวาดเป็น 7 px อาจทำให้ scan fail ได้ เพราะ error สะสมตลอด symbol

ทำไม HTML/CSS ถึงยาก

วิธีที่พบบ่อยคือสร้าง SVG จากข้อมูล GS1-128, ฝังใน HTML แล้ว render PDF ด้วย Puppeteer หรือ Prince ทุกขั้นตอนมีโอกาสขยับ geometry

1. Browser rasterisation ทำ rounding

แม้แต่ SVG ใน HTML ก็ผ่าน painter ของ browser ต้องมี shape-rendering="crispEdges", boundary ที่ตรงกับ integer pixel และความสัมพันธ์ DPI กับ bar width ที่สะอาด

2. CSS scale ได้แบบเงียบ ๆ

transform: scale(0.95) ที่เคยเพิ่มเพื่อแก้ layout อื่น จะบิด barcode ทุกตัวบนหน้า PDF ดูปกติ แต่ scanner วัดไม่ตรง

3. PDF emitter quantize coordinates

บาง engine snap coordinates ไปยัง internal grid ตอนเขียน PDF ผลลัพธ์ดูเกือบถูก แต่ error สะสม

4. Font Code 128 เสี่ยงกว่า

Font เป็น vector ก็จริง แต่ font hinting ปรับความกว้างเล็ก ๆ เพื่อให้มนุษย์อ่านสบาย นั่นไม่ใช่สิ่งที่ scanner ต้องการ

Structured rendering approach

gPdf คำนวณ pattern ของแท่งและช่องว่างจาก GS1-128 specification แล้วเขียน PDF vector primitives โดยตรง: ไม่มี HTML, ไม่มี SVG translation, ไม่มี font hinting

{
  "pages": [{
    "size": "label_100_150",
    "elements": [
      {
        "type": "barcode",
        "format": "gs1128",
        "content": "(00)123456789012345678",
        "x": 4,
        "y": 8,
        "width": 58.0,
        "height": 18.0,
        "barcode_text": { "enabled": true, "position": "bottom" }
      }
    ]
  }]
}

ใน element barcode, width คือ ความยาวรวมของ symbol หน่วย mm ซึ่งวัดได้ด้วย caliper บน label ที่พิมพ์แล้ว เมื่อใช้ width: 58.0:

  • Renderer คำนวณ X-dimension จาก target length และจำนวน bar
  • ทุก bar ถูกวาดด้วย X-dimension เดียวกัน
  • ความกว้างถูกเขียนลง PDF เป็น floating-point coordinates
  • ไม่มี CSS pixel rounding, layout scaling หรือ font hinting

ถ้า printer ไม่เพิ่ม scaling เอง ความยาวรวมจะอยู่ภายใน 0.1 mm จาก target

ควรพิมพ์อย่างไร

กฎ 1: ระบุความยาวรวม

width คือ control ที่ถูกต้องเพราะวัดได้ หากระบุแค่ X-dimension ความยาว symbol จะเปลี่ยนตามข้อมูลที่ encode

  • Shipping label 4×6 in: กว้าง 100 mm; GS1-128 มักอยู่ที่ ~58–72 mm
  • Compliance label 4×4 in: ~45–58 mm
  • Carton label 2×1 in (Amazon UPC): ไม่ใช่ GS1-128; ใช้ UPC-A

กฎ 2: ต้องมี quiet zones

GS1-128 ต้องการ quiet zones ≥ 10X ทั้งสองด้าน ที่ 1.0× (X = 0.495 mm) คือพื้นที่ขาวอย่างน้อย 4.95 mm การวาง barcode ที่ x: 0 อาจทำให้ scanner หา edge เริ่มต้นไม่เจอ gPdf reserve พื้นที่นี้อัตโนมัติ

กฎ 3: ทดสอบกับ scanner เป้าหมาย

กล้องมือถือให้อภัยมากกว่า Honeywell หรือ Zebra industrial scanner พิมพ์ 50 labels ด้วย production printer ที่ความเร็วจริง แล้ว scan ด้วยอุปกรณ์จริง ถ้า read rate ต่ำกว่า 99% ให้ตรวจ X-dimension consistency

ความจริงของหลาย format

Label มักไม่ได้มีแค่ GS1-128:

Symbol ใช้สำหรับ Spec source
GS1-128 Logistics units, GTIN + serial + lot GS1 General Specifications
QR with FNC1 Ecommerce ที่สแกนด้วย mobile ISO/IEC 18004
Data Matrix Pharmaceutical (DSCSA / EU FMD) ISO/IEC 16022
PDF417 Drivers’ licences, boarding passes ISO/IEC 15438
Aztec Transport tickets ISO/IEC 24778
MaxiCode UPS specifically ISO/IEC 16023

Renderer ที่รองรับแค่ GS1-128 จะทำให้ต้องใช้ tool ที่สองในภายหลัง Workflow ด้าน logistics มักต้องใช้มากกว่าหนึ่ง format

ตรวจ scanner rejection ใน production

  1. เก็บ label ที่ fail จริง ไม่ใช่ดูแค่ metric
  2. วัดด้วย caliper ทั้งความยาวรวมและ X-dimension
  3. ตรวจ human-readable text ใต้ barcode
  4. วัด quiet zones ทั้งสองด้าน
  5. ลอง scanner model อื่น
  6. เทียบกับ known-good reference label

TL;DR

GS1-128 precision ไม่ใช่การพิมพ์แท่งให้บางที่สุด แต่คือการรักษา X-dimension ให้สม่ำเสมอตลอด symbol HTML/CSS เพิ่ม sub-pixel drift หลายจุด ส่วน renderer ที่เขียน PDF vector primitives โดยตรงจะเลี่ยงแหล่ง drift เหล่านี้

ถ้า PDF stack ปัจจุบันมี scanner rejection 1–5% ให้เริ่มตรวจที่นี่ Playground สามารถ render GS1-128 ด้วย width ตาม label spec ของคุณ แล้วนำไปพิมพ์และวัดด้วย caliper