BarCode 製作與辨識

本篇使用 python-barcode 套件製作條碼,再使用 pyzbar 套件辨識條碼。請注意,安裝 python-barcode 時,還要手動安裝 Pillow,否則 python-barcode 會發生例外。

BarCode 格式

BarCode 有一維條碼及二維條碼,

一維條碼如下圖:

二維條碼如下圖

EAN13

EAN13 是市面上商品的條碼格式,格式為 “國碼+公司碼+流水號”,共有12碼,而且只能是數字。但仔細算一下條碼上的文字卻有 13 碼,因為最後一碼是檢查號碼。

code128

code128 沒有碼數限制,可以是英文字母或數字。

安裝套件

在 python 中製作條碼最方便的套件為 python-barcode。

本例需安裝套件

pip install python-barcode matplotlib pandas pyside6 matplotlib pillow mysql-connector-python

製作條碼

barcode 提供 barcode.get() 製作條碼圖像,再用 code.render 轉成 Pillow 格式。

import pylab as plt
import barcode
from barcode.writer import ImageWriter
n="123456789012"
code=barcode.get('EAN13', '4713268582114', writer=ImageWriter())
#bar.save("barcode")
opts={
    "module_width":0.2,#預設為 0.2
    "module_height":10,
    "text_distance":4,
    "font_size":9
}
img=code.render(writer_options=opts)
img.save("barcode.jpg")
plt.imshow(img)
plt.show()

輸出 Pillow 選項

code.render 轉成 Pillow 格式,writer_options 參數可以設定輸出選項,常用參數如下。

"module_width" : 每個條碼寬度,單位為毫米,預設為0.2
"module_height" : 條碼高度,單位為毫米,預設為15.0
"quiet_zone" : 兩端空白寬度,單位為毫米,預設為 6.5
"font_size" : 字体大小,單位為磅,預設為 10
"text_distance": 本文和條碼之間的距離,單位為毫米,預設為5
"background": 背景色,預設為白色
"foreground": 前景色,預設為黑色
"write_text": 是否顯示本文,預設為 True
"center_text" : 本文是否置中, 預設為 True
"format" : 圖片格式,預設為 'PNG'
"dpi" : 圖片分辨率,預設 300 dpi (ImageWriter 時才有效)

module_width 盡可能不要改變,不然顯示出來的圖片 BarCode 機器不易掃瞄,甚至掃瞄不正確。

Pillow 轉 QPixmap

經由 barcode 取得的 Pillow 圖像,若要置入 Pyside6 的 QLabel 中,請先了解如下順序

Pillow.ImageQt(pil) => QImage => QPixmap => QLabel

先使用Pillow 的 ImageQt.toqimage(pil) 轉成 QImage 格式,再轉成 QPixmap,最後餵給 QLabel ,完整代碼如下。

no="123456789012"
code = barcode.get('EAN13', no, writer=ImageWriter())
opts = {
    "module_width": 0.1,  # 預設為 0.2
    "module_height": 2,
    "write_text":''
}
pil = code.render(writer_options=opts)
pix = QPixmap(ImageQt.toqimage(pil))
self.lblBarcode.setPixmap(pix)

pyzbar 辨識 BarCode

可以辨識 barcode  圖片的套件蠻多的,比如 cv2 。但 cv2 只能辨識 EAN13 格式,對於 code128 就沒轍。

pyzbar 經本人測試認為是最方便且準確的套件,本例以此進行說明。

本例需安裝套件

pip install opencv-python pyzbar

首先由 cv2 讀入圖片,再將 numpy 格式的圖片傳入 pyzbar 進行辨識

import numpy as np
import cv2
from pyzbar import pyzbar
img=cv2.imdecode(
    np.fromfile("19690507.jpg", dtype=np.uint8),
    cv2.IMREAD_UNCHANGED
)
codes=pyzbar.decode(img)
for code in codes:
    data=code.data.decode("utf-8")
    type=code.type
    print(f"BarCode資料 : {data}")
    print(F"BarCode格式 : {type}")
結果:
BarCode資料 : 4713268582114
BarCode格式 : CODE128

barcode 深入研究

1. 首先指定條碼的格式

import barcode
format=barcode.get_barcode_class("code128")

2. 將條碼資料傳入 format 中.產生 barcode 格式的圖像。format 中的 writer = ImageWriter(format=”jpeg”) 是指定要轉換成那一種圖像格式,所以當使用 save 儲存檔案時不需指定副檔名。圖像格式跟 Pillow 完全一樣,可以是 “png”,”jpeg” 等, 但就是沒有 “jpg”

import barcode
format=barcode.get_barcode_class("code128")
from barcode.writer import ImageWriter
img=format("123456", writer=ImageWriter(format="png"))
img.save("a")

3. save 時的 options 參數可以設定前景色、間距(module_width)、高度(module_height)。間距預設為 0.2

import barcode
format=barcode.get_barcode_class("code128")
from barcode.writer import ImageWriter
img=format("123456", writer=ImageWriter(format="png"))
opts={
    "foreground":"red",
    "module_width":0.1,#預設為 0.2
    "module_height":10
}
img.save("a", options=opts)

4. 使用 render 轉成 Pillow 格式,將 options 傳入,最後使用 Pillow 的 save 即可轉成 “.jpg” 格式

import barcode
format=barcode.get_barcode_class("code128")
from barcode.writer import ImageWriter
import pylab as plt
img=format("123456", writer=ImageWriter(format="png"))
opts={
    "foreground":"red",
    "module_width":0.1,#預設為 0.2
    "module_height":10
}
img.save("a", options=opts)

pil=img.render(writer_options=opts)
pil.save("b.jpg")
plt.imshow(pil)
plt.show()

5. 結果 :  format=”png” 其實可以省略,因為最後都是由 Pillow 輸出存檔。

barcode.generate

barcode 套件也可以使用 barcode.generate 產生檔案格式,再由 image.imread 讀取轉成 Pillow 格式。但這種作法比是何用意,本人也不太清楚,所以僅作記錄用。

from barcode import EAN13
import pylab as plt
import barcode
from barcode.writer import ImageWriter
from matplotlib import image
n="123456789012"
bar=barcode.generate(
    "code128",
    n, 
    writer=ImageWriter(), 
    output="barcode_png"
)
img=image.imread(bar)
plt.imshow(img)
plt.show()

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *