バーコードから機材を知る

# バーコードから機材を知る

このページを見ている多くの人はバーコードと聞けば QR コードを想像していることでしょう。QR コードからデータを得るにはスマホのカメラなんかを使うでしょうか。

QR コードのような二次元バーコードと違い、オープンロジの物流現場ではスケールメリットを活かした一次元バーコードを使っています。
物流現場では大人数、または多くの荷物にバーコードという形でデータをばら撒きます。そのような状況ではバーコードスキャナを人数分確保するなどを理由に二次元バーコードを読めない機器を使う場合があります。それにバーコードに持たせるデータも数文字程度の識別子で十分であることが多いです。よって一次元バーコードの使用が多くなります。

今回の記事では一次元バーコードの性質の一つである、構造の簡単さに着目します。一次元バーコードを自分の目で見て読んでみましょう。

過去の記事では具体的なラベルプリンタを使ってページ記述言語を 1 バイトずつ繋げていってラベルを印刷してみました。

- [WebUSB でバーコードラベルを印刷しよう - Qiita](https://qiita.com/karronoli/items/49eb179b9be6d5268950)

対比関係にある記事なので合わせて読んでみてください。また次回ではこれらの記事を元にして、白黒の模様からデータを読み取る簡単なアプリケーションを作る予定です。

続編の記事ができました。

- [バーコードを読み取る - Qiita](https://qiita.com/karronoli/items/975b05578c234442221c)

## 手元にある白黒の模様を調べる

バーコードはデータが得られるものでなければいけません。データが得られるバーコードかどうか、これはプリンタやスキャナ、ラベル等の特性によって決定されます。
とはいえ手元にバーコードが印字されたラベルだけがある。プリンタもスキャナもない。バーコードの仕様を調べるためのインターネットできる端末がある。
そんな状態でバーコードを調べる方法を検討してみましょう。

題材に KALDI で買い物したときのレシートを取りあげてみます。

![5fba7b00db79260051986427.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4162/65254c48-c2b1-568a-13db-e5ad252efb74.png)

## バーコードの種類を調べる

レシートを見てみると、白黒の縦線で書かれた模様のバーコード、その下にバーコードのデータを表す説明文字があります。どうやらデータは始まりが a、数字 16 桁、最後に a で終わることを表したいようです。
ここからバーコードの種類を調べてみましょう。

スマホアプリでスキャンしてみるとバーコードの種類や中身のデータを教えてくれますが、今回は見た目の雰囲気から既存のバーコードと比較します。バーコードの種類は [バーコードの種類 | バーコード講座 | キーエンス](https://www.keyence.co.jp/ss/products/autoid/codereader/basic-types.jsp) を参考に自分なりの解釈を挙げてみました。

| 種類       | 特徴（の一部）      | 使われる場所（の一部） |
| --- | --- | --- |
| JAN コード | 13 桁か 8 桁の数字 | 個別の商品 |
| ITF    |  数字のみの偶数桁       | 箱買いの商品の箱 |
| CODE39    | 先頭と末尾に「\*」を付けて印字されがち | 図書館の利用カード |
| NW-7(Codabar)    | 先頭と末尾に「A」を付けて印字されがち | 図書館の利用カード |
| CODE128    | 英数字を混ぜて印字されがち  | Amazon で買い物したときの箱 |

かなり偏りのある解釈のせいか判断が付きませんね。今度はカメラやスキャナなどで画像として取り込んで拡大してみましょう。

![5fba5e5bdb79260051986420.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4162/9bbe9234-e8b7-2c79-c38a-e58a8c781edb.png)

この画像から線幅が何ピクセルあるかを測ることができます。取り込んだ際に線が傾いてしまいましたが、細い黒線の幅は約 12 ピクセル、太い黒線の幅は約 24 ピクセルありました。白線も同じようです。線幅は 2 種類しかないようです。これをバイナリレベルのバーコードと呼びます。言い換えるとマルチレベルのバーコードではありません。

バイナリレベルやマルチレベルについてはこちらを参照してください。

- [バーコードのしくみ | バーコード講座 | キーエンス](https://www.keyence.co.jp/ss/products/autoid/codereader/basic_mechanism.jsp)

これで候補からマルチレベルのバーコードである JAN コードと CODE128 が消えました。残るは CODE39 か NW-7 か ITF ということになったんですが、判断するには線の本数を数える必要があります。ちょっと面倒ですね。

今分かっていることをおさらいします。

- 説明文字の最初と最後に「a」がある
- それ以外の説明文字は数字のみ
- バイナリレベル

これらの情報からバーコードの種類は NW-7 と仮定してみます。説明文字「a」はスタートキャラクタ「A」を表したいんだろうと考えるとどうでしょう。

バーコードの線幅で細線を「1」、太線を「2」として書き加えてみましょう。

![5fba7b00db79260051986428.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4162/f1636f74-7f41-f779-2ade-69ebf4e9391b.png)

線 7 本を 1 つの塊として数えると「1122 121」は NW-7 における「A」、「1111 122」は「0」のパターンと一致しました。目スキャン成功です。このまま 7 本ずつ数えていけば、説明文字と一致します。パターンの詳細は JISX0506 の「NW-7 のバーコードキャラクタの構成」などで確認できます。
ということでこのバーコードは NW-7 と判断できました。

## 線の幅

線の幅がスキャナの分解能よりも細いようならバーコードはスキャンできません。では細い線の幅を調べてみましょう。

先ほど使った画像をパソコンなどの画面上で細い線が 1 mm くらいになるように拡大します。このとき画面上では左端の黒線から右端の黒線までの幅は約 176 mm でした。同様に実物のバーコードでは 45 mm でした。
これらの関係から実際の細い線の幅が比で計算できます。

実物のバーコードの幅 : 実物のバーコードの細線の幅 = 画面上のバーコードの幅 : 画面上のバーコードの細線の幅

```math
45 ： x = 176 : 1 \\
x = 45 \div 176 \fallingdotseq 0.255 (mm)
```

印刷関係ではインチ表記を良く使います。では実際の細線の幅 0.255 (mm) を mil で換算しましょう。mil というのは 1 / 1000 inch のことです。

- [サウ - Wikipedia](https://ja.wikipedia.org/wiki/%E3%82%B5%E3%82%A6)

```math
0.255 (mm) \div 25.4 (mm / inch) \times 1000 \fallingdotseq 10 (mil)
```

ここで Amazon で売ってるバーコードスキャナを例に読み取れるか考察してみます。

- [Eyoyo EY-H2 Handheld USB 2D Barcode Scanner QR PDF417 Data Matrix 1D Bar Code Scanner Wired Barcode Reader with USB Cable for Mobile Payment, Convenie](https://eyoyousa.com/eyoyo-ey-h2-handheld-usb-2d-barcode-scanner-qr-pdf417-data-matrix-1d-bar-code-scanner-wired-barcode-reader-with-usb-cable-for-mobile-payment-convenience-store-supermarket-warehouse-p00240p1.html)

このバーコードスキャナのマニュアルには読み込み深さという項目がバーコードごとに書いてあります。

- EAN13: 40-200mm (13mil)
- Code128: 45-250mm (20mil)
- Code39: 45-95mm (5mil)

数値の意味がマニュアルでは解説されていませんでしたが、以下のように解釈できます。

- かっこ内の数値はそのバーコードにおける分解能を表す。
- 読み取れるバーコードの幅にはバーコードの種類ごとに許容範囲がある。
- EAN13（≒ JAN コード） は 13 mil の分解能でスキャンできる。
- Code128 は 20 mil の分解能でスキャンできる。
- Code39 は 5 mil の分解能でスキャンできる。
- スペックの誤差について示されていない。
    - 境界値近辺のスペックは疑ったほうが良さそう。

NW-7 について記載はないですが、スキャンできるということは明記されています。ではどのようなスペックでスキャナできるかはバーコードの種類から検討します。
EAN13 は固定長でマルチレベルのバーコード、Code128 は可変長でマルチレベルのバーコードなので NW-7 とは特性が異なります。
この中で NW-7 と特性が違いのは Code39 です。可変長でバイナリレベルのバーコードつながりです。
よってこのスキャナでは Code39 と同程度のスペックでバーコードを読める可能性が高いです。

### 番外編

上記推測をしましたが、実際にこのスキャナで読めました。その事実からの推測です。

## プリンタの解像度

約 0.255 mm の線をプリンタは何個のドットを使って印字しているでしょう？プリンタが等間隔に N 個のドットを打ち込めるとした場合、1 ドットの 1 辺の長さとその逆数を計算してみましょう。

| N (個) | 1 ドットの 1 辺の長さ (mm / 個) | 1 mm 当たりのドットの個数 (個 / mm) |
| --- | --- | --- |
| 1      | $0.255 \div 1 = 0.255$          | $1 \div 0.255 \fallingdotseq 4$ |
| 2      | $0.255 \div 2 ≒ 0.127$          | $1 \div 0.127 \fallingdotseq 8$ |
| 3      | $0.255 \div 3 ≒ 0.085$          | $1 \div 0.085 \fallingdotseq 12$ |
| 4      | $0.255 \div 4 ≒ 0.063$          | $1 \div 0.063 \fallingdotseq 16$ |

1 mm 当たりのドットの個数をインチ表記に直せばプリンタの解像度を DPI (= Dot Per Inch) で表記できます。

| 1 mm 当たりのドットの個数 (個 / mm) | DPI (dpi)            |
| ----------------------------------- | --------------- |
| 4                                   | $4 \times 25.4 \fallingdotseq 102$  |
| 8                                   | $8 \times 25.4 \fallingdotseq 204$  |
| 12                                  | $12 \times 25.4 \fallingdotseq 305$ |
| 16                                  |  $16 \times 25.4 \fallingdotseq 407$ |

※ 1 inch = 25.4 mm 

小数点の計算がいい加減ですがプリンタの解像度がいくつか推測できました。ここでバーコード以外の文字を見てプリンタの解像度を絞り込みましょう。

![5fba8295db79260051986428.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4162/aedd9aa4-b47a-91c8-1523-d554027c6a40.png)

良く見ると消費税等の「等」の文字で土と寸の間に白い領域が見えます。それでいてバーコードの細線よりも細いですね。「費」の文字はもっと小さい白い領域がありますが潰れ気味です。ちなみにこの画像はスキャナで 600 dpi の解像度でスキャンして作ったものです。

「等」の文字の白い領域はバーコードの細線の半分か 1 / 3 程度でしょうか。そうだとすればバーコードの細線は 2 ドットか 3 ドットで印字されていると言えます。もし細線を 4 ドットで印字できていたとしたら細線よりも細かい「費」の文字はこれほど潰れずに印字できていたでしょう。
以上から細線が 2 ドットで印字されていればプリンタの解像度は 204 dpi、3 ドットなら 305 dpi だと推測することができます。

### 番外編

仕様の分かっているラベルと比較しましょう。斜線のジャギーからプリンタの解像度が分かります。ルーペを持っておくと便利です。
上記の計算上では 204 dpi とか 305 dpi といった数値が出てきましたが、203 dpi の解像度で印字されているはずです。

## クワイエットゾーン

バーコード全体とはどこからどこのことでしょうか？左端の黒線から右端の黒線まででしょうか？それは違います。黒線よりも外側の白い領域があることで、黒線を意味のある線として認識することができます。この左右両端にある白い領域をクワイエットゾーンと呼びます。これがないとスキャンできないバーコードを作ることになります。

この黒線の左側の余白がクワイエットゾーンです。右側も同じようにあります。
![5fba7b00db79260051986426.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4162/fbd3ad06-effc-db40-bbf7-5ca0c0fcf63d.png)

では JIS 規格の記述を元に計算してみましょう。JISX0506 の 4.5.4 クワイエットゾーンの幅によると、このようになっていました。

> 左右のクワイエットゾーンの幅、各々スタートキャラクタ及びストップキャラクタの幅以上とする。

スタートキャラクタ及びストップキャラクタは細線の本数に換算すると 10 本分の幅があります。細線の幅は 0.255 mm です。よってクワイエットゾーンは最低でも $0.255 \times 10 = 2.55 (mm)$ が左右それぞれに必要です。
実物のラベルでは左右それぞれに約 6 mm のクワイエットゾーンがありました。これなら印字位置が左右どちらかにブレたとしてもクワイエットゾーンを安定して確保できそうですね。

# まとめ

その辺のレシートのバーコードからいくつかの仕様を垣間見ることができました。

- バーコードの種類は NW-7
- バーコードの細線の幅は約 0.255 mm
- 読み取るのに使うスキャナで必要とする分解能は最低でも 10 mil
- 印刷に使ったプリンタの解像度は 204 dpi か 305 dpi
- 印字ブレに耐えられる程度に十分なクワイエットゾーンが確保されている

次回の記事では NW-7 を読み取る基本的なアプリケーションを作ります。