App StoreやGoogle Playに誘導する際に、中央にロゴ付きのQRコードを使いたい場合がありますが、PythonのQRコード生成ライブラリと(qrcode)と、画像処理のライブラリ(Pillow)を使うと比較的かんたんにできたので備忘録を兼ねて情報を共有します。
ちなみに、ロゴ入りのQRコードですが、QRコードの仕様にロゴの部分を避けるような仕組みがあるのではなく、エラー訂正機能によりロゴで隠れている部分は補正してしまうという少々強引な感のあるハックで実現されていて大変興味深いです。誰が最初に始めたのでしょう?
実装例
こんな感じの実装になります:
def encode_qr_with_logo(body, logo_filename, output_filename, transparent=False, size=0, version=None, logo_bg='white'):
qr = qrcode.QRCode(
version=version,
error_correction=qrcode.constants.ERROR_CORRECT_Q)
qr.add_data(body)
qr.make()
qr_image = qr.make_image().convert('RGB')
if size == 0:
MARGIN_WIDTH = 40 # 4 modules
size = (qr_image.width - (MARGIN_WIDTH * 2)) // 4
logo = Image.open(logo_filename).convert('RGBA')
logo = logo.resize((size,size), resample=Image.LANCZOS)
pos = ((qr_image.size[0] - logo.size[0]) // 2, (qr_image.size[1] - logo.size[1]) // 2)
if transparent:
qr_image.paste(logo, pos, logo)
else:
logo_bg = Image.new('RGB', logo.size, logo_bg)
logo_bg.paste(logo, mask=logo)
qr_image.paste(logo_bg, pos)
qr_image.save(output_filename)
-
body
— QRコードに変換する文字列 -
logo_filename
— ロゴの元データのファイル名 -
output_filename
— 生成したQRコードを保存するファイル名 -
transparent
— 透過PNGの処理をするかのフラグ(Bool値) -
size
— ロゴのサイズ(px) -
version
— QRコードのバージョン(ほぼサイズと同じと考えて良い)
出力はこんな感じ:
ポイント
- Error Correction を
ERROR_CORRECT_Q
に設定し、QRコードを生成します(通常の誤り補正レベルです)。- QRコードの 仕様 によれば、この場合の誤り訂正能力は約25%となります。
- これにより、画像がQRコードの上に重なっていても補正により情報が伝達できます。たとえばQRコードの幅の25%程度の幅でロゴを描画しても問題なく認識できます(ロゴで隠れる大きさは6.25%未満となるため)。
- 上の例ではロゴは正方形であることを想定しています。これをリサイズして利用します。
- リサイズした画像を、最初のステップで生成したQRコードの画像の上に貼り付けます。
- この際、重ねるアイコンが透過PNGの場合、
paste()
の引数として自分自身をマスクに設定してあげればPNGの透明部分を透過して貼り付けることが可能です。 - 逆に透過させたくない場合、背景色の箱を作ってその上にロゴを貼り付けたもの(上記コードだと
logo_bg
)をQRコードの画像上に貼るという処理にすると透過部分の色のコントロールができます。
- この際、重ねるアイコンが透過PNGの場合、
- ロゴのサイズを計算により算出する場合は、以下を考慮すると良いでしょう:
-
qrcode
モジュールでは特に指定しない場合、QRコードの1セルの大きさは10pxで描画されます。 - 仕様 に従い、特に指定しない場合、QRコードには4セル分のマージンがつきます。
-
成果物
pip でインストールできる形にしてあるので、比較的簡単にインストールできるはずです。
確認した環境
$ uname -a
Darwin wlc-lap-114.local 21.3.0 Darwin Kernel Version 21.3.0: Wed Jan 5 21:37:58 PST 2022; root:xnu-8019.80.24~20/RELEASE_ARM64_T8101 x86_64
$ python --version
Python 3.7.9
$ pip list | grep -i -e 'pillow' -e 'qrcode'
Pillow 9.0.1
qrcode 7.3.1