JSZipというクライアントサイドでzipファイルを作成するプラグインと、作成したファイルのダウンロードを行うFileSaverというプラグインの動作検証を行いました。
その他、作成の過程でサムネイル画像を選択するのにimage-pickerというjQueryプラグインを使用しました。
- GitHub – Stuk/jszip: Create, read and edit .zip files with Javascript
- GitHub – eligrey/FileSaver.js: An HTML5 saveAs() FileSaver implementation
- GitHub – rvera/image-picker
今回は、画面表示されている10枚のサムネイル画像のうち選択した画像のオリジナル画像をダウンロードし、zipで圧縮したものをダウンロードするサンプルを作成しました。
デモは以下↓
クライアントサイドでzipファイルを生成して、ダウンロードするサンプル
http://etc.imo-tikuwa.com/create-zip-on-client-side/
やってること
- ユーザーがダウンロードしたい画像を1件以上選択してダウンロードボタンをクリック
- XMLHttpRequestで1件ずつ順番に画像をダウンロードし、レスポンスデータをzipアーカイブに追加
- 画像のダウンロードが全て完了したらzipファイルに圧縮し、ダウンロードダイアログ表示
画像素材は以下のサイトのものを使っています。
Kaboompics – Free High Quality Photos
プログレスバーの動作確認に大きいサイズの画像が必要だったため、上記サイトから適当に10ファイル使わせていただきました。
選択した画像をダウンロードして、zipファイルを生成して、ダウンロードするスクリプト
[js]
// bootstrapっぽいプログレスバーのテンプレート
var progressTemplate = "<div class=\"list-group-item\"><div class=\"progress progress-striped active\"><div class=\"progress-bar progress-bar-info\" style=\"width: 0%;\"></div></div></div>";
var $images = $("select.select-image");
var $downloadBtn = $("#download");
var $progress = $("#progress-container");
var zip;
var deferreds;
$(function(){
// 画像を選択するプラグインimage-picker.jsのスクリプト
$images.imagepicker({
hide_select : true,
show_label : false
});
// ダウンロードしたい画像が1件以上選択されているとき、ダウンロードボタンをクリック可能にする
$images.on("change", _setSelectStatus);
_setSelectStatus();
// zipファイル生成&ダウンロード処理
$downloadBtn.on("click", _createAndDownloadZip);
});
/**
* ダウンロードボタンのクリック制御
*/
function _setSelectStatus() {
if ($images.val() && $images.val().length > 0) {
$downloadBtn.removeAttr("disabled");
} else {
$downloadBtn.attr("disabled", "disabled");
}
}
/**
* ZIPファイルを生成する
*/
function _createAndDownloadZip() {
// 初期化
$progress.empty().append(progressTemplate).show();
zip = new JSZip();
deferreds = $.Deferred();
var promise = deferreds;
// 選択した画像分ループ
$.map($images.val(), function(value, index){
var thumbUrl = $images.find("option[value=\"" + value + "\"]").data("img-src");
var originalUrl = thumbUrl.replace(/\/thumb\//, "/original/");
promise = promise.then(function() {
var newPromise = new $.Deferred();
// オリジナル画像を読み込む
var xhr = new XMLHttpRequest();
xhr.open(‘GET’, originalUrl, true);
xhr.responseType = ‘arraybuffer’;
xhr.addEventListener(‘load’, function() {
// zipにレスポンスデータを追加
zip.file(originalUrl.match(".+/(.+?)([\?#;].*)?$")[1], xhr.response);
newPromise.resolve();
});
xhr.send();
// プログレスバーを更新
$progress.find(".progress-bar").width((index + 1) / $images.val().length * 100 + "%");
return newPromise;
});
});
// 画像のダウンロードが完了した後でzipファイルを生成してsaveAsメソッドでダウンロード
promise.then(function(){
zip.generateAsync({type:"blob"}).then(function (content) {
saveAs(content, _formatDate(new Date(), "YYYYMMDD-hhmmss") + ".zip");
});
$progress.hide();
});
deferreds.resolve();
}
[/js]
メリット/デメリット
- サーバーサイドでzipファイルの生成を行う必要がないため、ディスク容量の圧迫や負荷が少ない。
- 1ファイルずつダウンロードしたあと、zipにまとめたものをダウンロードするので全体の転送量が約2倍になる?
その他
JSZipはfileメソッドでファイルを追加する他に、folderというメソッドでフォルダを作成することも可能なようです。
dhtmlxのようなウェブベースで動作するファイルエクスプローラと連携して、右クリック>zipで保存なんてできたら面白いかも。