今日は暑い…。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らしいですが、特出して優れているという訳でもなさそうです。という訳で、引き続きはてなブログに書くことにします。ネタにもなりますし。