記事の概要
Pythonのqrcodeを用いてQRコードを自動生成します。
QRコードに識別番号も同時に記載したいので、pillowやその他のツールも用いて文字も挿入します。
(追記)
@konikoni428 さんのご指摘により、画像をグレースケールに変換することで、文字が荒くなるのを回避できることが分かり、「画像の拡大・縮小処理」が不要になりました。(追記終わり)
(追記)
日本語の文字を表示させるためには、fontを日本語に対応したもの変更しないといけないようです。
詳細は以下の記事をご参照ください。
(追記終わり)
ツールのインストール
QRコードの生成にはqrcodeを使用します。
qrcodeをインストールしてください。
pip install qrcode
画像の加工にはpillowをします。
pillowをインストールしてください。
pip install Pillow
QRコードの生成
import qrcode
from PIL import Image
img = qrcode.make("Hello World!")
img.save('test.png')
img.show()
生成されたQRコードが正しく読み取れるかは、http://qrcode.red/ で読み込んで確認できます。
QRコードの生成(詳細設定)
詳細な設定を行うこともできます。
import qrcode
from PIL import Image
qr = qrcode.QRCode(
version=3,
error_correction=qrcode.constants.ERROR_CORRECT_L,
box_size=10,
border=2,
)
qr.add_data('Hello World!')
qr.make(fit=True)
img = qr.make_image(fill_color="black", back_color="white").convert('L')
img.save('test.png')
img.show()
- version
- セル数を決めるパラメータで、1から40の値に設定できます。
- 1で21セルx21セル、2で25セルx25セル、40で177セルx177セルです
- 以下参照
- error_correction
- 誤り訂正レベルで以下のパラメータから選択します
- ERROR_CORRECT_L
- 7%以下のエラーを修正
- ERROR_CORRECT_M
- 初期設定値
- 15%以下のエラーを修正
- ERROR_CORRECT_Q
- 20%以下のエラーを修正
- ERROR_CORRECT_H
- 30%以下のエラーを修正
- ERROR_CORRECT_L
- 誤り訂正レベルで以下のパラメータから選択します
- box_size
- ボックスのピクセル数
- border
- 境界線の太さ
- 初期値4(最小設定値)
(追記)
@konikoni428 さんのご指摘を受けて、QRコードをグレースケールに変換しています。
img = qr.make_image(fill_color="black", back_color="white").convert('L')
もしデータサイズをなるべく小さくしたいなどの理由で白黒2階調にしたい場合は、グレースケール変換を省略ください
img = qr.make_image(fill_color="black", back_color="white")
(追記終わり)
余白の追加
画像に余白を追加、削除するにはnote.nkmk.meにて公開されている関数add_marginが便利です。
Python, Pillowで画像の上下左右に余白を追加しサイズ変更
関数の詳細は上記ブログを参照してください。
今回はQRコードの下に文字を表示する余白を作りたいので、下方向にサイズを追加します。
背景色は白(#ffffff)にしています。
from PIL import Image
img = Image.open('test.png') #先ほどに保存した画像を読み込む
img_new = add_margin(img, 0, 0, 100, 0, '#ffffff')
img_new.show()
この関数はマイナスの数値を入力すれば、サイズを縮小できるので、画像サイズの調整に便利です。
画像サイズの変更
後で使用するので、画像サイズの拡大縮小方法を紹介します。
resizeにより画像を拡大縮小できます。
from PIL import Image, ImageDraw, ImageFont
img = Image.open('test.png') #画像の読み込み
img_resize = img.resize((int(img .width / 2), int(img .height / 2)), Image.LANCZOS)
img_resize.show()
'Image.LANCZOS' は圧縮フィルタを指定するパラメータです。
以下から選択します。一般的に下の方が圧縮率が低くなる代わりに、画像はキレイになります。
このパラメータは省略可能で、省略すると自動的にNEARESTが適用されます。
- NEAREST
- 何も指定しなければ、これが選択される
- BOX
- BILINEAR
- HAMMING
- BICUBIC
- LANCZOS
文字の挿入
Pythonで一気に画像編集できるPillowを使った画像処理のチートシートにて紹介されていた方法で、文字を挿入してみました。
from PIL import Image, ImageDraw, ImageFont
img = Image.open('test.png')
img_new = add_margin(img, 0, 0, 100, 0, '#ffffff')
draw = ImageDraw.Draw(img_new)
font = ImageFont.truetype("./fonts/arial.ttf", 55)
draw.text((20, 320), 'Hello! 12345', font=font, fill='#000000')
img_new.save('test.png')
img_new.show()
フォントの種類は変更できます。
以下を参照して選択ください。
https://helpx.adobe.com/jp/x-productkb/global/cq08041028.html
文字の画像解像度が荒い場合
(追記)
画像をグレースケールに変換している場合は、文字画像は荒くなりません。
以下は参考用に残しますが、必要のない処理になります。
(追記終わり)
小さなサイズのQRコードに対しては、上記の方法で挿入した文字は荒いという欠点があります。
そこでresizeで拡大した解像度の高い画像を保存し、それを画像サイズを縮小するツールで適切なサイズにします。
まずは余白を入れた画像を10倍に拡大し、そこに大きめの文字を挿入します。
from PIL import Image, ImageDraw, ImageFont
img = Image.open('test.png')
img_add = add_margin(img, 0, 0, 100, 0, '#ffffff')
img_resized = img_add.resize((int(img_add.width*10), int(img_add.height*10)), resample=Image.LANCZOS)
draw = ImageDraw.Draw(img_resized)
font = ImageFont.truetype("./fonts/arial.ttf", 530)
draw.text((190, 3200), 'Hello! 12345', font=font, fill='#000000')
img_resized.save('test.png')
img_resized.show()
画像の縮小には、フリーソフトの 藤 -Resizer- を使用しました。
何百枚の画像でも、アイコンにドラッグ&ドロップすれば一括で縮小してくれます。
文字がキレイに表示されています。
画像編集ソフトで確認すると、印刷しても問題ない解像度であることが分かります。
大量生成
今までのコードを関数化すれば、連番のQRコードを大量生成できます。
フォルダの自動作成は以下の記事をマネしました。
Python フォルダの作成 既存かチェックあり
import os
import qrcode
from PIL import Image, ImageDraw, ImageFont
def add_margin(pil_img, top, right, bottom, left, color):
#先ほどに紹介した記事のコードをコピペしてください。
return result
def qr_generator(number):
qr = qrcode.QRCode(
version=2,
error_correction=qrcode.constants.ERROR_CORRECT_L,
box_size=9,
border=4,
)
qr.add_data('Hello!' + number)
qr.make(fit=True)
img = qr.make_image(fill_color="black", back_color="white").convert('L')
img_add = add_margin(img, -15, -15, 45, -15, '#ffffff')
# (追記)画像拡大・縮小工程が必要だった時の設定
# img_resized = img_add.resize((int(img_add.width*10), int(img_add.height*10)), resample=Image.LANCZOS)
draw = ImageDraw.Draw(img_add)
font = ImageFont.truetype("./fonts/arialbd", 45)
num = number
# (追記)画像拡大・縮小工程が必要だった時の設定
#draw.text((200, 2550), 'Hello!' + num, font=font, fill='#000000')
#img_resized.save('./my_qr_code/' + number + '.png', quality=95)
draw.text((15, 250), 'Hello! ' + num, font=font, fill='#000000')
img_add.save('./my_qr_code/' + number + '.png', quality=95)
#img_add.show()
def main(total_num):
new_path = "my_qr_code"#フォルダ名
if not os.path.exists(new_path):#ディレクトリ有無確認
os.mkdir(new_path)
for number in range(total_num):
qr_generator(str(1000+number))
main(100)
以上で作成した画像を藤 -Resizer- で一括縮小すれば完成です。
(追記:画像拡大・縮小が不要になったので、必要のない処理になりました)