本ページはプロモーションが含まれています


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ピクセルで、適切なバージョンが自動選択され(ギリギリではなく少し余裕をもって選択されるようだ)、誤り訂正は最低レベルで作成されます。

Picture

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")

Picture

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")

Picture

バイナリデータを格納する場合は、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")

Picture

日本語の文字列の場合は、文字列を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")

Picture

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オプションには、セルサイズ(ピクセル)を指定します。

Picture

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)

Picture

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)

Picture

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'
)