チャーハンノート

チャーハンの作り方に関する覚書

PythonでQRコードを生成する

夏目漱石の「坊っちゃん」をQRコードに限界まで埋め込もうとした図。勘太郎どうなった。 f:id:friedrice_mushroom:20210328143510p:plain

ふと、PCで作った簡単なテキストをQRコード経由でスマホに取り込みたいと思った。
Python(Jupyter Notebook)でのQRコードの使い方について調べた記録。

QRコードとは

QRコードとは・・・などといまさら説明する必要がないほど普及しまくっている、いわゆるマトリックス2次元コードのひとつ。
キャッシュレス決済やLineの連絡先交換、街中の広告、雑誌、Webサイトなど、それを目にする機会を挙げればキリがない。
そんなQRコードの便利なところは、スマホのカメラモードでQRコードをかざすと即座に認識され、それがURLであればブラウザで即座にアクセスできるところ。スマホさえあれば専用のアプリも必要ない。

このQRコードを開発したのはデンソーだそう(今はデンソーウェーブ)。特許は取得しているがオープンにしていて、だれでも無償でつかうことができる。とても懐が深い。
ウィキペディアの記事を見てるだけで面白い。
QRコード - Wikipedia

そんなQRコードPythonで気軽に使う方法について調べることにした。

環境

今回、PythonQRコードを扱うにあたっての環境と使用したライブラリは下記の通り。

Pythonのバージョン : 3.8.5

PythonQRコードを生成する場合のライブラリ 「qrcode」
GitHub - lincolnloop/python-qrcode: Python QR Code image generator

クリップボードに取り込んだテキストをPythonで扱うライブラリ「pyperclip」
GitHub - asweigart/pyperclip: Python module for cross-platform clipboard functions.
このpyperclipについては、自宅のMacBookではpip3でインストールすることができたのだが、職場のWinPCではコマンドプロンプトからpip3でインストールすることができなかった。そのときは下記リンク先の手動インストール方法で解決できた。
要は、githubからライブラリを圧縮形式でダウンロードし、それをローカルでインストールする手順。
https://gammasoft.jp/blog/pip-install-from-local-archives-by-manually/

なお、以下のコードはすべてJupyter Notebookでの作業・表示に最適化している。

お試しコード

まずPythonQRコードを扱うとはどういうことなのかを確認する。

ライブラリ「qrcode」のテスト

まずは任意のテキスト“hogehoge”をQRコードで表示してみる。

import qrcode
im = qrcode.make('hogehoge') #QRコードの生成
im.show()

実行した結果、Macだと↓のプレビューウインドウが現れた。
iPhoneのカメラで読み込んだところ”hogehoge”と表示されることを確認。成功したようだ。
f:id:friedrice_mushroom:20210328143308p:plain

ライブラリ「pyperclip」のテスト

次に、クリップボードに取り込んだテキストがpythonで読み込めるかどうか確認する。

pyperclipをインポートする。
あらかじめ“hogehoge”というテキストをコピーしておき、↓のコードを実行する。

import pyperclip
text_target=pyperclip.paste() #クリップボードに取り込んだテキストを表示
print(text_target) #実行結果にクリップボードのテキストを表示

実行した結果。コピーしたテキストがきちんと表示された。
f:id:friedrice_mushroom:20210328222207p:plain

「qrcoode」「pyperclip」を組み合わせる

qrcode, pyperclipのどちらも問題なく使えることがわかった。今度はこれらを組み合わせてみる。

import qrcode
import pyperclip
text_target=pyperclip.paste()
im = qrcode.make(text_target)
im.show()

実行した結果。生成したQRコードのプレビューウインドウが現れる。
iPhoneのカメラで読み込んだところ”hogehoge”と表示されたので、うまくいった。
f:id:friedrice_mushroom:20210328143419p:plain
ひとまず、クリップボードにとりこんだテキストをQRコード生成することは成功。

QRコードの制限

ちなみに、QRコードに格納できるテキストの文字数はどれくらいなのだろうか?
Wikipediaによれば、

数字のみ 最大7,089文字
英数 (US-ASCII) 最大4,296文字
バイナリ(8ビット) 最大2,953バイト
漢字・かな(Shift_JIS) 最大1,817文字
QRコード - Wikipedia

とのこと。
「最大容量はバージョンを最大 (40)、誤り訂正レベルを最低 (L) にした場合の値」との表記もあるが、このバージョンというのは生成するQRコードの四辺のドットの数のこと。
githubのコメントをみると、自動的に調整するにはQRCodeクラスのなかで指定する必要があるとのことだった。 指定しなくても自動で調整されているっぽいが・・・。
念の為、以下の応用編ではそれらを反映したコードを作成する。

応用編

これまでのおためしプログラムを応用し、より実用的な形に作り変える。
盛り込みたかったのは下記の内容。

クリップボードのテキストを表示する(プレビュー)
・テキストの文字数とバイト数を表示する
・matplotlibを使い、実行結果のなかでQRコードを表示する(ポップアップ表示させない)
・matplotlibの体裁をととのえるためFigureサイズを調整する

そして作成したのが下記のコード。
今回、サンプルテキストとしてクリップボードにコピーしたのは夏目漱石の「坊っちゃん」。
青空文庫からダウンロードし、改行を削除するなどの前処理を行ったもの。

#Jupyter Notebook上でグラフを表示するための儀式
%matplotlib inline

import qrcode
import matplotlib.pyplot as plt
import pyperclip

#QRコード仕様の定義
qr = qrcode.QRCode(
    version=None, #QRコードのサイズ(1〜40の整数)
    error_correction=qrcode.constants.ERROR_CORRECT_L, #エラー訂正レベル(L,M,Q,H)
    box_size=3, #ドットのピクセルサイズ
    border=2  #QRコードを囲う余白のサイズ(Boxサイズ N個分)
)

# QRコードを生成させる文字列の読み込み
text_target=pyperclip.paste()

#コマンドライン上に読み込んだ文字列、文字数を表示する(表示しなくてもよい)
print(text_target)
print()
print("Text length",len(text_target)) #文字数
print("(",len(text_target.encode('UTF-8')),"byte)") #バイト数

#QRコードの生成
qr.add_data(text_target)
qr.make(fit=True) #クリップボードのデータサイズに応じて自動的にバージョン(1〜40)を調整

# QRコードの表示(Matplotlibを使用)
fig=plt.figure(figsize=(8,8)) #Figureサイズ調整
img = qr.make_image(fill_color="Black", back_color="White")
plt.imshow(img,cmap="gray")

plt.axis("off")
plt.show()

実行結果

f:id:friedrice_mushroom:20210328143510p:plain

ひとまずうまくできた。スマホでもきちんと読み込むことができた。
ちなみに上記の結果で埋め込まれている文字数は全角カナで984文字。何通りか試したのだがこれが最大だった。これより1文字でも多いとオーバーフローとなり失敗してしまう。

QRコードに埋め込む事ができる最大文字数は、全角かなだと1817文字までだった(Wikipedia)。しかし今回の結果は984文字(2952バイト)だったので、半分程度ということになる。
なぜそうなったのかはわからないが、QRコードに埋め込めるバイナリは2953バイトまでということから、それに関係するのだと思われる。

ちなみに、数字のみのデータだと7080文字(桁?)まで埋め込めることができた。QRコードに埋め込めるとされる7089ではなかった。
この微妙なギャップがなぜ生じているのかは謎。(調べようとしない)

(↓実行結果。円周率が埋め込まれている)
f:id:friedrice_mushroom:20210328143549p:plain

ちなみに、クリップボードの文字数があまりに大きすぎるとJupyter Notebookでは実行結果の縦幅が狭くなり、シークバーが追加されてしまう。
そして、QRコード全体がみえなくなってしまうのだった。
このような状態に陥った場合は、プレビュー用の行を適宜コメントアウトするなどして対処が必要。(プレビューしなければよいのでは)

# print(text_target)

QRコードが全部みえない!!

f:id:friedrice_mushroom:20210328143700p:plain

まとめ

ひとまずPython(Jupyter Notebook)をつかってクリップボードのテキストをQRコードに埋め込む手順がわかった。
今後やってみたいのは、もっと大容量のデータをQRコード経由でとりこむというもの。ファイルを分割してQRコードを生成する側(PC)と、QRコードをひたすら読み込んで結合する側(スマホ)の双方が用意できれば可能。ただ、実際それを使いたい場面などはなく、ただの興味なので作ることはなさそう。というか誰かすでにやってそう。(調べようとしない)

悪用は厳禁。 以上です。