1
3

More than 3 years have passed since last update.

SpreadSheetを方眼にしてQRコードをプロットする

Last updated at Posted at 2020-03-07

以前仕事で、SpreadSheetでQRコードを管理したいという要望があったのだが、SpreadSheetに画像ってどうやってアップロードするんだ?GASでやればいいのか?わからん!とかいろいろ悩んでいるうちに我を忘れて、SpreadSheetを方眼にしてそこにQRコードをプロットするという、明日から使える無駄技術を身につけてしまったのでここに書いておく。

SpreadSheetを外部から操作するための準備

SpreadSheetをgspreadで操作するためにはGoogleCloudのコンソールからAPIを有効にして、jsonキーをダウンロードしないといけない。ここが一番めんどくさかった。
以下が参考になります。
[参考]
【もう迷わない】Pythonでスプレッドシートに読み書きする初期設定まとめ
pythonでGoogle Spread Sheetをいじる(OAuth)

QRのデータなんてどうせどっかに二次元配列でおいてるだろ

ってことでpythonのqrcodeモジュールのコードサンプルを見てみた。使い方は要約すると以下のような感じ。

import qrcode

img = qrcode.make('hogehoge')
img.save('qrcode.png')

なかった。。。
まぁそんな使い方する人はいないので、考えてみれば当たり前である。

qrcodeモジュールの中身を見てみる

いやいや内部的にはどっかにあるでしょ!
というわけでqrcodeモジュールの中身を見てみる。

import inspect
import qrcode
print(inspect.getfile(qrcode))

たったこれだけのコードでモジュールの__init__.pyの場所がわかるので、そこから探すとよいです。
該当のmain.pyの中身を見てみると、どうやらQRCode().modulesに二次元配列でそれっぽいものが入っているので、これを使うことにした。

>>> import qrcode
>>> qr = qrcode.QRCode()
>>> qr.add_data('hoge')
>>> qr.make()
>>> qr.modules
[[True, True, True, True, True, True, True, False, False, True, False, False, False, False, True, True, True, True, True, True, True], [True, False, False, False, False, False, True, False, False, True, False, True, False, False, True, False, False, False, False, False, True], [True, False, True, True, True, False, True, False, True, True, False, True, False, False, True, False, True, True, True, False, True], [True, False, True, True, True, False, True, False, True, True, True, True, False, False, True, False, True, True, True, False, True], [True, False, True, True, True, False, True, False, True, True, False, True, True, False, True, False, True, True, True, False, True], [True, False, False, False, False, False, True, False, True, True, False, False, True, False, True, False, False, False, False, False, True], [True, True, True, True, True, True, True, False, True, False, True, False, True, False, True, True, True, True, True, True, True], [False, False, False, False, False, False, False, False, True, False, False, True, True, False, False, False, False, False, False, False, False], [True, False, True, True, True, True, True, False, False, True, False, False, True, False, True, True, True, True, True, False, False], [True, False, False, False, True, True, False, False, False, False, True, False, True, False, False, True, False, True, False, False, True], [True, True, True, False, False, True, True, False, False, True, False, True, False, True, False, False, True, True, False, True, False], [False, False, False, True, False, False, False, True, True, True, True, False, False, False, False, True, True, True, True, False, False], [False, True, True, True, True, True, True, True, True, False, False, True, False, True, False, False, True, False, False, False, True], [False, False, False, False, False, False, False, False, True, False, True, True, True, True, True, False, False, True, True, False, True], [True, True, True, True, True, True, True, False, False, False, False, False, True, False, True, True, False, True, False, True, False], [True, False, False, False, False, False, True, False, True, True, False, True, True, True, True, False, False, True, True, False, False], [True, False, True, True, True, False, True, False, True, True, True, False, True, False, False, True, False, False, False, True, False], [True, False, True, True, True, False, True, False, True, True, False, False, True, False, False, True, False, True, True, False, False], [True, False, True, True, True, False, True, False, True, False, True, True, False, True, False, False, True, True, True, False, False], [True, False, False, False, False, False, True, False, False, False, False, False, False, False, False, True, True, False, True, False, False], [True, True, True, True, True, True, True, False, True, True, False, True, False, True, False, False, True, False, True, True, False]]

あった!

ソースコード

import qrcode
import gspread
from oauth2client.service_account import ServiceAccountCredentials
from gspread_formatting import *
import time

scope = ['https://spreadsheets.google.com/feeds','https://www.googleapis.com/auth/drive']
credentials = ServiceAccountCredentials.from_json_keyfile_name('XXXXXXXXXXXXXXXXXXXXXXX.json', scope)
gc = gspread.authorize(credentials)
SPREADSHEET_KEY = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
workbook = gc.open_by_key(SPREADSHEET_KEY)

text = input("Please input =>")
qr = qrcode.QRCode()
qr.add_data(text)
qr.make()

body = {
    "requests": [
        {
            "updateDimensionProperties": {
                "range": {
                    "dimension": "COLUMNS",
                    "startIndex": 1,
                    "endIndex": len(qr.modules)+1
                },
                "properties": {
                    "pixelSize": 25
                },
                "fields": "pixelSize"
            }
        }
    ]
}
res = workbook.batch_update(body)

body = {
    "requests": [
        {
            "updateDimensionProperties": {
                "range": {
                    "dimension": "ROWS",
                    "startIndex": 1,
                    "endIndex": len(qr.modules)+1
                },
                "properties": {
                    "pixelSize": 25


     },
                "fields": "pixelSize"
            }
        }
    ]
}
res = workbook.batch_update(body)

fmt = cellFormat(
    backgroundColor=color(255, 255, 255)
    )

for ii, l in enumerate(qr.modules):
    for jj, b in enumerate(l):
        if b:
            format_cell_range(workbook.sheet1, f'{chr(65+ii+1)}{jj+2}', fmt)
        time.sleep(0.2)


img = qr.make_image()
img.save('qr_image.png')

今回gspread_formattingというモジュールを使ったが、少し癖が強かった。
セルの指定が"A1"の形式でしかできない(?)ようなので、chr()で無理やり変換している。よって"AA"以降の列には対応していないので、長い文字列だとQRコードの右側が切れる。
また、もう少しまとめて一度に書きこめればいいのだが、現状1セルずつ塗っているので処理がめちゃ遅い。
sleepを0.2入れてるのは、普通に回すと以下のGoogle Sheets APIの規約に引っかかるため。

This version of the Google Sheets API has a limit of 500 requests per 100 seconds per project, and 100 requests per 100 seconds per user.

こちらが実行中の動画。
10倍速でもこの速度である。
Hello world!はダサいのでHello hello, how low?(かっこいい)を合成している。

1
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
3