にせねこメモ

はてなダイアリーがUTF-8じゃないので移ってきました。

Python 3 でQRコードを読み書き

QRコードを読む

バーコードをPythonから読めたらいいのでは、と思ったので。使ってるバージョンが Python 3 だったので結局は力技になってしまった。

Python でバーコードを読むには ZBar を使うといいらしい。
Pythonで画像ファイルからQRコードを読み込む (MacOS) - Qiita

QRコード読むのだと他にもパッケージあるっぽい。
How to decode a QR-code image in (preferably pure) Python? - Stack Overflow

環境

OS: Windows 7
Python: Python 3.5 (installed by Anaconda 64bit)

インストール

ZBar

公式サイトからインストーラをダウンロードしてきてインストールする。

あるいはCygwinなら、

  • zbar
  • libzbar-devel

をインストール。CygwinPythonを使うのであれば、Python bindings も

パッケージをインストールすればいけるかもしれない(2系用かな…)。

ZBar Python module

ZBar python モジュールがあったから何とか Python 3.5 にインストールしようとしたけどだめっぽい。
ZBar の python モジュールは Python 3 系に対応してないらしい。

探したら fork して python 3 対応してたものがあった…のだが、 Python 3.5.1 からコンパイルできず。
GitHub - Polyconseil/zbar: Fork of the zbar source code, adding Python3 compatibility.

駄目っぽいので諦める。

コマンドラインから使う

駄目っぽいからコマンドラインから使うことにする。

ZBar をコマンドラインから使う場合、 zbarimg というコマンドになるが、標準入力から入力を受け付ける場合には

zbarimg :-

とするといいらしい。

なので先日 potrace 向きに書いたコードをちょっと変えて zbar に画像データを渡す様にする。

#!/usr/bin/env/python3
# coding: utf-8

import numpy as np
import cv2
import subprocess

# zbar command
ZBARIMG = 'zbarimg'
    
def passzbar(image): 
    # convert to bmp binary so that zbar can handle it
    retval, buf = cv2.imencode('.bmp', image)
    if retval == False:
        raise ValueError('The Given image could not be converted to BMP binary data')
    # convert buf from numpy.ndarray to bytes
    binbmp = buf.tobytes()
    optionargs = []
    
    args = [
        ZBARIMG,
        ':-', '-q'
    ] + optionargs
    
    p = subprocess.Popen(
        args,
        stdin=subprocess.PIPE,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
        shell=False
        )
        
    stdout, stderr = p.communicate(input=binbmp)
    if len(stderr) == 0:
        bindata = stdout
    else:
        raise RuntimeError('ZBar threw error:\n' + stderr.decode('utf-8'))
        
    type, data = bindata.split(b":", 1)
    return type, data
    
def main():
    testpic = cv2.imread('test.png', cv2.IMREAD_GRAYSCALE)
    bartype, bardata = passzbar(testpic)
    print(bardata.decode('utf-8'))

if __name__ == '__main__':
    main()

Python bindings からサクっと使うはずだったのに完全に予定が狂ってしまった…。

QRコード生成

さて、生成する方はずっと楽。
python-qrcode パッケージをインストールする。
qrcode 5.2.2 : Python Package Index

pip install qrcode

上で挙げた pypi のサイトに解説がある通りだが、簡単には次のようにできる。

import qrcode
img = qrcode.make("ここにデータが入ります")
img.save("qr.png")

更に細かく設定することもできる。内部で PIL を利用してるらしく、 qrcode.make_image() の出力は PIL.Image のようである。 img.save() に io.BytesIO などを与えることもできるようだ。

import qrcode

qr = qrcode.QRCode(error_correction=qrcode.constants.ERROR_CORRECT_L)
qr.add_data("ここにデータが入ります")
qr.make(fit=True)
img = qr.make_image()
img.save("qr.png")