今日は暑い…。5分くらい外を歩くだけで汗が噴き出します。今日は夜中でも気温が下がらないかもしれませんね。クーラー漬けになりそう。
さて、とある必要に駆られ、html上に複数の画像を表示し、その画像をzipで固めてサーバに送信する方法を調べたので、メモを残します。
準備
JavaScriptのzipライブラリをインストール
JavaScriptのzipライブラリとしては、zlib.jsとjszipの二つが有名どころみたいです。 どちらでもいいのですが、jszipの方が最近までメンテナンスされているっぽいのでjszipを選びました。
本家のgithubの、download JSZipのリンクからダウンロードして、展開したjszip.min.jsをサーバ(例: /js/jszip.min.js)に置きます。
canvas が配置されたhtmlを作成
canvas1とcanvas2のidを持つ以下のようなhtmlを作成しました。ここでjszipとjqueryを読み込ませています。
<html> <head> <meta charset="utf8"> <script type="text/javascript" src="https://code.jquery.com/jquery-3.0.0.min.js"></script> <script type="text/javascript" src="js/jszip.min.js"></script> <title>JSZip Test</title> </head> <body> <canvas id="canvas1" width="300" height="300"></canvas> <canvas id="canvas2" width="300" height="300"></canvas> <button id="upload">送信</button> </body> </html>
プログラム
ロード時にcanvasに画像を描画
canvasにサーバに送信したい画像を用意します。今回は手っ取り早く用意したpngを張り付けています。
<script type="text/javascript"> window.onload = () => { let draw = (id, src) => { const canvas = document.getElementById(id) const ctx = canvas.getContext("2d"); const img = new Image(); img.src = src; img.onload = () => { ctx.drawImage(img, 0, 0); } } draw('canvas1', '/img/image1.png'); draw('canvas2', '/img/image2.png'); }
送信ボタンでcanvasの画像をzipに変換してサーバに送信
canvas.toBlob()で、canvasをblobの形式に変換し、変換したblobをjszipで固め(zip.file()の部分)ます。 最後に固めたzipをblobに変換(zip.generateAsync()の部分)して、サーバに送信します。
気を付けないといけないのは、canvas.toBlob()とzip.generateAsync()が非同期関数なので、待ち合わせる必要があるという所です。 待ち合わせには、JavaScriptのPromiseを使用しています。
$(document).on('click', '#upload', () => { let addToZip = (target, id, filename) => { return new Promise((resolve, reject) => { const canvas = document.getElementById(id); canvas.toBlob(blob => { target.file(filename, blob); resolve(); }) }); } let zip = JSZip(); addToZip(zip, 'canvas1', 'canvas1.png') .then(() => addToZip(zip, 'canvas2', 'canvas2.png')) .then(() => zip.generateAsync({type: 'blob'}) .then(blob => { var fd = new FormData(); fd.append("data", blob); $.ajax({ url : "api/upload-file", type : "POST", data : fd, cache : false, contentType : false, processData : false, success : r => { alert("Success!"); }, error: response => { alert("failure!"); } }); })); }); </script>
最後に
JavaScriptは昔軽く勉強したことがあるのですが、Promiseとかアロー関数(=>)とか新しい機能が増えていて、ちょっと戸惑いました。
後は、技術的なメモを別の所に纏めようかなあと、少し調べては見ましたが、どこも50歩100歩のようです。技術メモブログの最大手はQiitaらしいですが、特出して優れているという訳でもなさそうです。という訳で、引き続きはてなブログに書くことにします。ネタにもなりますし。