商品を物理的に出荷するなら、いつか必ず GS1-128 バーコードを印刷することになります。しかもそのバーコードは、実際の倉庫の照明、実際の距離、実際のハンドヘルドスキャナで読めなければなりません。地味な話に見えますが、PDF 生成ではかなり厄介な失敗パターンの 1 つです。
この記事では、GS1-128 バーコードにおける「0.1 mm 精度」が実際に何を意味するのか、HTML/CSS ベースのレンダラーがなぜそこで苦戦するのか、そして DHL、FedEx、USPS、Amazon の受け入れ側スキャナでも最初から正しく印刷するための設計ルールを整理します。
「バーコード精度」とは実際に何か
GS1-128(旧 UCC/EAN-128)は、厳密な比率を持つバー幅とギャップ幅でデータを符号化します。最小単位は X 寸法、つまり最も細いバーまたはギャップの幅です。それ以外の幅は X の倍数です(Code 128 の内部パターンでは 1X、2X、3X、4X)。
スキャナは相対幅を測って復号します。印刷された幅がずれると、復号は失敗します。
本番で最もよくある失敗モードは 2 つです。
- シンボル内で X 寸法が一貫しない —— レンダラーが隣り合うバーを別々にサブピクセル丸めしている。最初の 3 本は 8 px なのに、途中で 7 px のバーが出る。スキャナには一貫性のないパターンに見えます。
- 全長または拡大縮小が間違う —— 描画後にシンボルが拡大縮小され、X 寸法が GS1 の最小値(1.0× 倍率では通常 0.495 mm)を下回る。
どちらも症状は似ています。単発サンプルではスキャナが 1 回鳴るのに、本番バッチでは 30 枚に 1 枚落ちる。開発用スキャナは倉庫のスキャナより寛容なので、QA では見つかりません。
0.1 mm ルール
ここで重要な精度は、仕様上の目標に対してバーコード全体の長さが 0.1 mm 以内に収まることです。「各バーが 0.1 mm 幅」という意味ではありません。バーは通常 0.495 mm 以上です。0.1 mm の制約は、シンボル全体の累積寸法精度に対するものです。
18 桁の数字を持つ典型的な GS1-128 では、次のようになります。
- シンボルには約 120 個のバーとギャップが含まれる。
- 1.0× 倍率で全長は約 58 mm。
- 全長 0.1 mm の許容差は、全体で約 0.17% の精度。
- 1 本あたりに換算すると、整合性の予算は約 0.001 mm。単一バーの幅よりはるかに小さい。
だからこそ、「7.4 px になるべきバーをレンダラーが 7 px として置く」だけで致命的になります。サブピクセル丸めは 120 本のバー全体で累積し、バー 50 から 80 の間あたりで 0.1 mm の許容差を超えてしまいます。
HTML/CSS がここで苦戦する理由
多くのチームがたどる経路はこうです。GS1-128 データを文字列へ符号化し、SVG(さらに悪い場合は個別の <div> バー)を生成し、HTML に埋め込み、Puppeteer や Prince で PDF にします。
このチェーンの各段階で、ずれが入ります。
1. ブラウザのラスタライズが丸める
HTML 内の SVG であっても、shape-rendering="crispEdges" が設定され、かつ周囲のコンテナが整数ピクセル境界に乗り、かつ PDF の DPI がバー幅へきれいに対応していない限り、ブラウザのペインターでサブピクセル丸めが発生します。3 つの制約があり、どれも偶然破れやすいです。
2. CSS レイアウトがずらす
6 か月前に別のレイアウト問題を直すためにスタイルシートへ入った transform: scale(0.95) が、ページ上のすべてのバーコードを静かに歪めます。警告はありません。PDF は問題なく見えます。スキャナはそう判断しません。
3. PDF エミッター自身の量子化
ブラウザが PDF へシリアライズするとき、描画済みの結果を PDF 描画演算子へ変換します。一部のエミッター、特に Chromium のものは、固定された PDF 内部グリッドへスナップします。そのグリッドに合わない座標へ SVG バーコードを置くと、ほぼ正しいが誤差を蓄積する出力になります。
4. フォントベースの符号化はさらに悪い
Code 128 フォントを使うチームもあります({ font: "Code128" } としてデータを入力し、うまくいくことを祈る方式です)。フォントはベクターで理論上は拡大縮小できますが、小さいサイズでのフォントヒンティングは人間に読みやすく見せるために幅を動かします。これは、スキャナに必要なものとは正反対です。
構造化レンダリングの考え方
gPdf はデータを受け取り、GS1-128 仕様からバーとギャップのパターンを計算し、PDF ベクタープリミティブを直接出力します。HTML も、SVG 変換も、フォントヒンティングもありません。
{
"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" }
}
]
}]
}
barcode 要素では、width は シンボル全体の長さ(mm 単位)です。印刷したラベル上でノギスを当てて測る値です。ここを指定するのが正しい調整箇所であり、width: 58.0 が保証するのは次です。
- レンダラーは、目標長をシンボルのバー数で割って X 寸法を計算する。バー数はデータによって完全に決まる。
- すべてのバーをまったく同じ X 寸法で描く。
- それらの幅を PDF の浮動小数点座標として書き込む(PDF unit = 1/72 inch で、スキャン解像度には十分以上に細かい)。
- フォントヒンティング、CSS ピクセル丸め、レイアウト処理による歪みが入らない。
結果として、プリンタ側が独自のスケーリングを追加しない限り、全長は指定した目標から 0.1 mm 以内に収まります。ほとんどのプリンタは、デフォルトでは追加スケーリングしません。
実際に何を印刷すべきか
本番のスキャナ失敗の 95% を防ぐ 3 つのルールがあります。
ルール 1: X 寸法ではなく全長を指定する
width フィールドが正しい調整箇所なのは、それが測定可能だからです。印刷したラベルにノギスを当てれば直接確認できます。X 寸法を指定する方式だと、シンボル長が符号化されるデータ長に依存するため、ラベル QA が難しくなります(SKU が違えばバーコード幅も変わります)。
多くのラベルサイズでは、目安は次のとおりです。
- 4×6 inch の配送ラベル: 幅 100 mm、GS1-128 はおよそ 58〜72 mm。
- 4×4 inch のコンプライアンスラベル: およそ 45〜58 mm。
- 2×1 inch のカートンラベル(Amazon UPC): GS1-128 の領域ではありません。UPC-A を使います。
ルール 2: クワイエットゾーンは必ず確保する
GS1-128 には両側に 10X 以上のクワイエットゾーンが必要です。スキャナがシンボルの端を見つけるための空白です。1.0× 倍率(X = 0.495 mm)では、4.95 mm 以上の白地が必要です。
典型的な失敗は、他のラベル要素の横に収めるために開発者がバーコードを x: 0 に置き、スキャナが開始位置を見つけられなくなることです。レンダラーはクワイエットゾーンを自動で確保すべきです(gPdf はそうします)。自分のレンダラーも確認してください。
ルール 3: 開発用ではなく実際の対象スキャナでテストする
スマートフォンのカメラスキャナは、Honeywell や Zebra の産業用スキャナより寛容です。標準的な QA 手順は次です。
- 実際の本番プリンタで、本番速度のまま 50 枚のラベルを印刷する。
- 実際のスキャナ機種で、実際の搬送速度のまま通す。
- 読取率が 99% 未満なら、何かがずれています。多くの場合は X 寸法の一貫性です。
「自分の MacBook のカメラでは読めた」を根拠に、物流パートナーへ出荷してはいけません。
複数フォーマットが現実
ラベルに必要なのは、おそらく GS1-128 だけではありません。よくある組み合わせは次のとおりです。
| シンボル | 用途 | 仕様の出典 |
|---|---|---|
| GS1-128 | 物流単位、GTIN + シリアル + ロット | GS1 General Specifications |
| QR with FNC1 | モバイルで読み取れる EC | ISO/IEC 18004 |
| Data Matrix | 医薬品 (DSCSA / EU FMD) | ISO/IEC 16022 |
| PDF417 | 運転免許証、搭乗券 | ISO/IEC 15438 |
| Aztec | 交通チケット | ISO/IEC 24778 |
| MaxiCode | UPS 専用 | ISO/IEC 16023 |
GS1-128 だけを扱うレンダラーでは、いずれ 2 つ目のツールが必要になります。gPdf が 6 形式すべてを 1 つのレンダラーに含めているのは、配送・物流ワークフローでは、ほぼ必ず少なくとも 2 種類のコードが必要になるからです。
本番でスキャナ拒否が出たときの扱い
すでに本番でスキャナ拒否の問題が出ているなら、診断の順序は次です。
- 失敗したラベルをサンプルとして確保する —— 集計メトリクスに頼らないでください。実際に失敗した物理ラベルを入手します。
- ノギスで測る —— 全長と X 寸法を測ります。仕様の許容差に入っていなければ、それがバグです。
- 下の可読テキストを確認する —— バーの読み取りに失敗したスキャナは、しばしば OCR による読み取りへ切り替えようとします。両方失敗するなら、シンボルが本当に不正です。
- クワイエットゾーンを確認する —— 両側の白地を測ります。ロゴ、区切り線、別のバーコードなど、何かが近すぎる位置に印刷されているなら、それが問題です。
- 別のスキャナモデルで試す —— スキャナによってはファームウェア上の癖があります。モデル A は読めてモデル B は読めないなら、問題はレンダラーだけではなく相互運用性です。
- 既知の良品リファレンスラベルと比較する —— ベンダーは正確な仕様の参照画像を公開しています。自分のラベルが視覚的に一致しないなら、その差から逆算します。
TL;DR
GS1-128 の精度は、どれだけ細いバーを印刷できるかではありません。シンボル全体で X 寸法がミリメートルのわずかな範囲内に一貫して保たれるかです。HTML/CSS ベースのレンダラーは、処理の複数段階でサブピクセルのずれを持ち込みます。PDF ベクタープリミティブを直接出力する構造化レンダラーは、そのずれの発生源を丸ごと避けます。
現在の PDF 生成基盤で 1〜5% のスキャナ拒否率が出ているなら、それが疑うべきサインです。Playground では、width フィールドをラベル仕様に合わせた GS1-128 サンプルを生成できます。印刷した出力をノギスで測り、比較してください。