PythonのFlaskで取得した画像データをHTMLのcanvas要素へ描写します。
やりたいこと
Google Cloud Storageに保存した画像データをCloud functionsで読み出して、手元のHTMLのcanvas要素に描写します。Cloud functionsでは画像イメージがまずはblob形式で読み出されます。これをpngやjpgに変換してflaskでreturnして、canvas要素で描写します。
Cloud functionsでStorageのファイルを読み込んでダウンロードする
ここは公式ドキュメントが充実しているので迷いませんでした。
from google.cloud import storage
def download_blob(bucket_name, source_blob_name, destination_file_name):
"""Downloads a blob from the bucket."""
# bucket_name = "your-bucket-name"
# source_blob_name = "storage-object-name"
# destination_file_name = "local/path/to/file"
storage_client = storage.Client()
bucket = storage_client.bucket(bucket_name)
#bucket_nameとは、Storageに作った格納先の名前。手動で設定したもの
blob = bucket.blob(source_blob_name)#要するにファイル名
blob.download_to_filename(destination_file_name)
print(
"Blob {} downloaded to {}.".format(
source_blob_name, destination_file_name
)
)
実行するとローカルにファイルがダウンロードされます。
単体ファイルとしてダウンロードさせるのではなく、flaskでjpgとしてreturnしてダウンロードする
この辺で詰まり始めた。要するに、blobをbytesで読んで、それにheaderなどをつけて画像としてreturnする。その際、Flaskのsend_fileというモジュールを使う。いや、これわからんでしょ。
なお、今回はホスティングはGCPのCloud functionsでやっているので、app.run()などはありません。ただこれをホスティングすると、あるURLを叩いたらdownload_blob()の関数が動きます。
from google.cloud import storage
import io
from flask import send_file
def download_blob(request):
"""Downloads a blob from the bucket."""
bucket_name = "your-bucket-name"
source_blob_name = "storage-object-name"
storage_client = storage.Client()
bucket = storage_client.bucket(bucket_name)
#bucket_nameとは、Storageに作った格納先の名前。手動で設定したもの
blob = bucket.blob(source_blob_name)#要するにファイル名
image_binary= blob.download_as_bytes()
return send_file(
io.BytesIO(image_binary),
mimetype='image/jpeg',
as_attachment=True,
attachment_filename='%s.jpg' % source_blob_name)
Cloud functionsでのデプロイは下記を参考に。
https://qiita.com/NP_Systems/items/f0f6de899a84431685ff
ライブラリなどインストールしていたら下記を打つだけで、ローカルでエミュレートします。
functions-framework --target=hello --port=8081
ホスティングしたURLを叩いたら、画像がダウンロードされます。でも単体ファイルとは違って、returnしています。これを使って、あとは受け取ったものをcanvasへ描写します
canvas要素への描写
ここもかなり詰まりました。こんなシンプルなことなのに。
このサイト本当に助かりました。
https://stackoverflow.com/questions/57014217/putting-an-image-from-flask-to-an-html5-canvas
phpですがhtmlでも同じようなものです。
<?php get_header(); ?>
<main>
<article>
<section>
<input type="button" value="Start" onclick="main();"/>
<canvas></canvas>
</section>
</article>
</main>
<script language="javascript" type="text/javascript">
function main(){
var canvas = document.getElementsByTagName('canvas');
var ctx = canvas[0].getContext('2d');
var img = new Image();
img.src = 'http://0.0.0.0:8081';//FlaskでホスティングしたURL
img.onload = function() {
img.style.display = 'none'; // ようわからん
console.log('WxH: ' + img.width + 'x' + img.height)
ctx.drawImage(img, 0, 0);
var imageData = ctx.getImageData(0, 0, img.width*2, img.height*2)
for(x = 0 ; x < 100 ; x += 10) {
for(y = 0 ; y < 100 ; y += 10) {
ctx.putImageData(imageData, x, y);
}
}
}; }
</script>
<?php get_footer(); ?>
感想
いや、こんなシンプルなことなのに詰まりまくった。blobやpngへの理解が浅い気がする。