PythonでQRコードを作る・読む
PythonにはQRコードを扱う便利なライブラリがいくつかあります。ここでは、その中でも代表的なQRコードライブラリ
qrcode、pyqrcode、pyzbar
を使ったQRコードの作成・読み取りを行う簡単な実装方法を紹介します。
それぞれのライブラリは次のようにインストールします。
qrcode
|
$ pip install qrcode
$ pip install pillow
|
pyqrcode
|
$ pip install pyqrcode
$ pip install pypng
※pypngはpng画像処理のために必要。
|
pyzbar
|
$ pip install pyzbar
$ pip install pillow
Linuxの場合はlibzbarが必要(Windowsは標準で用意されている)。
sudo apt install libzbar
|
それぞれ別途画像処理用のライブラリを利用するので、あわせてインストールしてください。
qrcodeモジュール
qrcodeモジュールを使ったQRコードを生成する最も簡単な例です。
qrcode_enc01.py
import qrcode
img = qrcode.make('QR code Test')
img.save("qrcode_enc01.png")
$ python3 qrcode_enc01.py
「QR code Test」を格納するQRコードのpng画像ファイルが出力されます。デフォルトは1セルあたり10ピクセルで、適切なバージョンが自動選択され(ギリギリではなく少し余裕をもって選択されるようだ)、誤り訂正は最低レベルで作成されます。
make()メソッドには、次のオプションを与えることができます。
box_size
|
1セルのサイズ(ピクセル)(デフォルト10)
|
borde
|
QRコードの周囲余白セル数(デフォルト4)
|
version
|
バージョン(1〜40)
|
error_correction
|
qrcode.constants.ERROR_CORRECT_L(最低)
qrcode.constants.ERROR_CORRECT_M
qrcode.constants.ERROR_CORRECT_Q
qrcode.constants.ERROR_CORRECT_H(最高)
|
次の例は、セルのサイズを30ピクセル、外側の余白を2セルとしてオプション指定しています。make()メソッドが返すオブジェクト(image.pil.PilImage)のsave()メソッドにより画像ファイルが保存されます。
qrcode_enc02.py
import qrcode
img = qrcode.make('QR code Test', box_size=30, border=2)
img.save("qrcode_enc02.png")
make()メソッドは、内部的に次の手続きを一括で実行しています。
qr = QRCode()
|
QRCodeオブジェクトを作成する。
box_sizeやborderのオプションを指定できる。
|
qr.add_data()
|
データを与える。
|
qr.make()
|
QRコードをエンコードする。
|
qr.make_image()
|
QR画像を出力する。
|
この手続きで実装すると次のようになります。上の例に加えてバージョンと誤り訂正レベルをオプション指定します。
qrcode_enc03.py
import qrcode
qr = qrcode.QRCode(
version=3,
error_correction=qrcode.constants.ERROR_CORRECT_M,
box_size=20,
border=3
)
qr.add_data('QR code Test')
qr.make()
img = qr.make_image()
img.save("qrcode_enc03.png")
バイナリデータを格納する場合は、add_data()メソッドにバイト列を指定します。
qrcode_enc04.py
import qrcode
qr = qrcode.QRCode()
qr.add_data(b'\x21\x22\x0a\x00\x30\x31')
qr.make()
img = qr.make_image()
img.save("qrcode_enc04.png")
日本語の文字列の場合は、文字列をencode()メソッドでバイト列に変換してadd_data()に与えます。このとき文字コードはシフトJISを指定します。QRコードの日本語文字コードはシフトJISを使うよう定められています。
qrcode_enc05.py
import qrcode
qr = qrcode.QRCode()
qr.add_data("日本語ABC012".encode('shift_jis'))
qr.make()
img = qr.make_image()
img.save("qrcode_enc05.png")
make_image()のかわりにprint_ascii()メソッドを使うと、画像ではなく四角と空白のキャラクターでQRコードを出力します。
qrcode_enc06.py
import qrcode
qr = qrcode.QRCode()
qr.add_data("QR code Test")
qr.print_ascii()
四角が全角文字なので、空白とフォント幅が表示上一致しない限りきちんとQRコードには見えません。
█▀▀▀▀▀█ ▄ ▀▄█ █▀▀▀▀▀█
█ ███ █ █▄▀▀ █ ███ █
█ ▀▀▀ █ ▀▄ █▀ █ ▀▀▀ █
▀▀▀▀▀▀▀ ▀ █ ▀ ▀▀▀▀▀▀▀
█ ▀ ▀ ▀ ▄ ▀▄▀▄ ▄█▄ ▀
▄███▀▀▀ ▄ █▄ ▀ ▀▄ ▀▀
▀ ▀▀ ▀ ▄▄██ ▀▀██▄ ▀
█▀▀▀▀▀█ ▀▄▄▀ ▀█▀ ▀█▀
█ ███ █ ▀ █▀█ ██▄ █
█ ▀▀▀ █ ▀█▀▀█▀▀▀█▀ ▄▀
▀▀▀▀▀▀▀ ▀ ▀▀ ▀ ▀▀
get_matrix()メソッドにより、QRコードを配列として取得できます。次の例は、get_matrixが返す配列を参照して「*(四角)」と「_(空白)」でQRコードのパターンを表示しています。
qrcode_enc07.py
import qrcode
qr = qrcode.QRCode()
qr.add_data("QR code Test")
arr = qr.get_matrix()
for ln in arr:
for c in ln:
if c:
print("*", end="")
else:
print("_", end="")
print()
この配列には外枠の空白は含みません。
_____________________________
_____________________________
_____________________________
_____________________________
____*******___*_*_*******____
____*_____*_*__**_*_____*____
____*_***_*__*_**_*_***_*____
____*_***_*__**___*_***_*____
____*_***_*_*__**_*_***_*____
____*_____*__*_*__*_____*____
____*******_*_*_*_*******____
______________*______________
____*_*_*_*___*_*___*__*_____
____*_______*__*_*_***_______
_____******____*__*_*__**____
____****____*__**____*_______
_____*_**_*___**_****___*____
____________****___***_______
____*******__*__*_***_***____
____*_____*___**___*___*_____
____*_***_*_*_***__**__*_____
____*_***_*___*_*__***_*_____
____*_***_*_**********__*____
____*_____*__*__*___*__*_____
____*******_*___**_*___**____
_____________________________
_____________________________
_____________________________
_____________________________
pyqrcodeモジュール
pyqrcodeモジュールを使ったQRコードを作成する例です。
qrcode_enc08.py
import pyqrcode
qr = pyqrcode.create("PyQRcode QR code", version=2, error='M')
qr.png("qrcode_enc08.png", scale=10)
qr.svg("qrcode_enc08.svg", scale=10)
create()メソッドにデータとオプションを指定すると、生成したQRコードのオブジェクトを返します。QRコードオブジェクトのpng()メソッドにファイル名を指定することで、png画像ファイルとして保存できます。また、svg()メソッドによりSVG文書として出力できます。
png()メソッドやsvg()メソッドのscaleオプションには、セルサイズ(ピクセル)を指定します。
qrcode_enc08.svg
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" height="330" width="
330" class="pyqrcode"><path transform="scale(10)" stroke="#0
00" class="pyqrline" d="M4 4.5h7m3 0h1m1 0h4m2 0h7m-25 1h1m5
0h1m1 0h2m1 0h1m3 0h1m2 0h1m5 0h1m-25 1h1m1 0h3m1 0h1m1 0h2m
...
1m2 0h1m2 0h1m-25 1h7m1 0h1m1 0h4m2 0h3m1 0h2m2 0h1"/></svg>
create()メソッドには、次のオプションを与えることができます。
version
|
バージョン(1〜40)
|
error
|
誤り訂正レベル
L(最低)、M、 Q、H(最高)
|
mode
|
kanji: 日本語
binary: バイナリ
|
バイナリデータの場合は、バイト列をデータに指定し、modeに「binary」を指定します。
qrcode_enc09.py
import pyqrcode
qr = pyqrcode.create(b'\x21\x22\x0a\x30\x31', mode='binary')
qr.png("qrcode_enc09.png", scale=10)
modeに「kanji」を指定すれば日本語をデータにできますが、半角文字を含めるとうまくいかないようです。バイナリデータとして格納した方が使いやすいようです。
qr = pyqrcode.create("日本語", mode='kanji')
pyzbarパッケージ
pyzbarパッケージを使ったQRコード画像の読み取りの例です。
qrcode_enc10.py
import pyzbar.pyzbar
from PIL import Image
qr = pyzbar.pyzbar.decode(Image.open('qrcode_enc01.png'))
print(qr)
print(qr[0].data.decode())
画像処理に利用するpillowをインポートします。pyzbar.pyzbarモジュールのdecode()メソッドへ画像ファイルをPILのImageで開いて与えると、画像の読み取り結果をDecodedクラスのリストで返します。
[
Decoded(
data=b'QR code Test',
type='QRCODE',
rect=Rect(left=40, top=40, width=210, height=210),
polygon=[Point(x=40, y=40), Point(x=40, y=250), Point(x=250, y=250), Point(x=250, y=40)],
quality=1,
orientation='UP'
)
]
QR code Test
データは、data属性からバイト列として参照できます。バイト列はdecode()メソッドで文字列に変換します。
日本語がシフトJISで格納されている場合は、data属性のバイト列をencode()メソッドでUTF-8に変換して読み取ることができます。
qrcode_enc11.py
import pyzbar.pyzbar
from PIL import Image
qr = pyzbar.pyzbar.decode(Image.open('qrcode_enc05.png'))
print(qr[0])
print(qr[0].data.decode())
Decoded(
data=b'\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9eABC012',
type='QRCODE',
rect=Rect(left=40, top=40, width=210, height=210),
polygon=[Point(x=40, y=40), Point(x=40, y=250), Point(x=250, y=250), Point(x=250, y=40)],
quality=1,
orientation='UP'
)
日本語ABC012
画像の中にQRコードが複数ある場合は、それらのオブジェクトがリストの要素として得られます。
qrcode_enc12.py
import pyzbar.pyzbar
from PIL import Image
qr = pyzbar.pyzbar.decode(Image.open('qrcode2.png'))
for dec in qr:
print(dec)
Decoded(
data=b'QR code Test',
type='QRCODE',
rect=Rect(left=58, top=58, width=583, height=583),
polygon=[Point(x=58, y=58), Point(x=58, y=641), Point(x=641, y=641), Point(x=641, y=58)],
quality=1,
orientation='UP'
)
Decoded(
data=b'\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9eABC012',
type='QRCODE',
rect=Rect(left=40, top=40, width=210, height=210),
polygon=[Point(x=40, y=40), Point(x=40, y=250), Point(x=250, y=250), Point(x=250, y=40)],
quality=1,
orientation='UP'
)