47歳でやむなくセミリタイア

病気のためセミリタイアをすることに。現在は週20時間程度のバイトをしています。その他、雑多なことを記録として書いています。

技術メモ: html上のcanvasの画像をzipで固めてサーバに送信する

今日は暑い…。5分くらい外を歩くだけで汗が噴き出します。今日は夜中でも気温が下がらないかもしれませんね。クーラー漬けになりそう。

さて、とある必要に駆られ、html上に複数の画像を表示し、その画像をzipで固めてサーバに送信する方法を調べたので、メモを残します。

準備

JavaScriptのzipライブラリをインストール

JavaScriptのzipライブラリとしては、zlib.jsとjszipの二つが有名どころみたいです。 どちらでもいいのですが、jszipの方が最近までメンテナンスされているっぽいのでjszipを選びました。

stuk.github.io

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