はじめに
ページ中の複数の画像を zip に圧縮してローカルにダウンロードする方法を整理した。
※JavaScript で画像をローカルにダウンロード の続き
TL;DR
目次
- はじめに
- TL;DR
- 環境・条件
- 詳細
- 完成形
- 解説
- jszip を CDN から読み込み: loadJSZipFromCDN
- ボタン追加: addImageDownloadButton
- 画像リクエスト: downloadImages
- zip 生成: generateImagesZip
- まとめ
- その他・メモ
- 参考文献
環境・条件
- Google Chrome バージョン: 79.0.3945.88(Official Build) (64 ビット)
- jszip v3.2.1 (CDN)
詳細
「いらすとや トップページの『〇〇のイラスト』の画像をまとめてダウンロード」を例にダウンロードボタンを作る。

完成形
前回 と同様に、先に完成形。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
| function loadJSZipFromCDN() { let script = document.createElement("script"); script.src = "https://cdn.jsdelivr.net/npm/jszip@3.2.1/dist/jszip.js"; document.head.append(script); } loadJSZipFromCDN();
function addImageDownloadButton() { document.body.insertAdjacentHTML( "afterBegin", `<button id="download">画像一括ダウンロード</button>` ); document.getElementById("download").addEventListener("click", downloadImages); }
async function downloadImages() { const sources = [].slice.call( document.querySelectorAll("#section_banner img") ).map(img => img.getAttribute("src"));
const imagePromises = sources.map( (src, i) => new Promise((resolve, reject) => { let xhr = new XMLHttpRequest(); xhr.open('GET', src, true); xhr.responseType = "blob"; xhr.onload = function() { const fileName = src.slice(src.lastIndexOf("/") + 1); resolve({ data: this.response, fileName: fileName }); }; xhr.onerror = () => resolve({ data: null }); xhr.onabort = () => resolve({ data: null }); xhr.ontimeout = () => resolve({ data: null }); xhr.send(); }) );
const images = await Promise.all(imagePromises); generateImagesZip(images); }
function generateImagesZip(images) { let zip = new JSZip();
const folderName = "いらすとや バナー"; let folder = zip.folder(folderName);
images.forEach(image => { if (image.data && image.fileName) { folder.file(image.fileName, image.data) } });
zip.generateAsync({ type: "blob" }).then(blob => {
let dlLink = document.createElement("a");
const dataUrl = URL.createObjectURL(blob); dlLink.href = dataUrl; dlLink.download = `${folderName}.zip`;
document.body.insertAdjacentElement("beforeEnd", dlLink); dlLink.click(); dlLink.remove();
setTimeout(function() { window.URL.revokeObjectURL(dataUrl); }, 1000); }); }
addImageDownloadButton();
|
上記スクリプトを Dev tools のコンソールで実行すると、トップにボタンが配置される。

このボタンをクリックすると、 いらすとや バナー.zip
がダウンロードされるはず。
展開すると下記のような感じ。

解説
関数単位で簡単に解説。
jszip を CDN から読み込み: loadJSZipFromCDN
1 2 3 4 5 6 7 8
| function loadJSZipFromCDN() { let script = document.createElement("script"); script.src = "https://cdn.jsdelivr.net/npm/jszip@3.2.1/dist/jszip.js"; document.head.append(script); } loadJSZipFromCDN();
|
head
に jszip 読み込みの script
タグを追加
1 2 3 4 5 6 7 8
| function addImageDownloadButton() { document.body.insertAdjacentHTML( "afterBegin", `<button id="download">画像一括ダウンロード</button>` ); document.getElementById("download").addEventListener("click", downloadImages); }
|
画像リクエスト: downloadImages
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| async function downloadImages() { const sources = [].slice.call( document.querySelectorAll("#section_banner img") ).map(img => img.getAttribute("src"));
const imagePromises = sources.map( (src, i) => new Promise((resolve, reject) => { let xhr = new XMLHttpRequest(); xhr.open('GET', src, true); xhr.responseType = "blob"; xhr.onload = function() { const fileName = src.slice(src.lastIndexOf("/") + 1); resolve({ data: this.response, fileName: fileName }); }; xhr.onerror = () => resolve({ data: null }); xhr.onabort = () => resolve({ data: null }); xhr.ontimeout = () => resolve({ data: null }); xhr.send(); }) );
const images = await Promise.all(imagePromises); generateImagesZip(images); }
|
- バナー画像には
"#section_banner img"
でアクセス可能
- 「画像がすべて取得できたら zip 生成」としたいので、リクエスト処理を
new Promise
で wrap
await Promise.all()
ですべての非同期リクエストが完了するのを待つ
zip 生成: generateImagesZip
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| function generateImagesZip(images) { let zip = new JSZip();
const folderName = "いらすとや バナー"; let folder = zip.folder(folderName);
images.forEach(image => { if (image.data && image.fileName) { folder.file(image.fileName, image.data) } });
zip.generateAsync({ type: "blob" }).then(blob => {
let dlLink = document.createElement("a");
const dataUrl = URL.createObjectURL(blob); dlLink.href = dataUrl; dlLink.download = `${folderName}.zip`;
document.body.insertAdjacentElement("beforeEnd", dlLink); dlLink.click(); dlLink.remove();
setTimeout(function() { window.URL.revokeObjectURL(dataUrl); }, 1000); }); }
|
folder()
で、フォルダの生成
folder.file()
で、フォルダ下にファイルを配置(生成)
- 対応フォーマットは下記
- String
- ArrayBuffer
- Uint8Array
- Buffer
- Blob
- Promise
- Nodejs stream
generateAsync()
で、zip ファイルの生成
type
を blob
で生成することで、あとの処理は前回 と同じ流れ
createObjectURL
→ <a href="..." download="xxxx.zip">
→ クリック&削除
まとめ
その他・メモ
参考文献
関連記事