一番カンタンにダウンロードを実装する方法
HTMLでファイルや画像をdownloadする為の単純な実装はこんな感じだとおもいます。
html1
| <a href="ダウンロードファイルのパス" download="ダウンロードした時のファイル名">click</a>
|
ただ、この実装では画像がクロスドメインの場合はダウンロードできません。また、safariでは別タブが開き右クリックで画像を保存しないとダウンロードできなかったりします。
やりたかったこと
HTMLのimgタグで表示している画像をクリックすると、画像をダウンロードさせる。という仕様を実装した時に色々苦労したのでメモしておきます。処理の順序としては以下の順番で説明します。またTypeScript用の型も指定しておきます。
- 画像URLからnew Image()する
- クロスドメインを回避する方法
- canvasにdrawImageしてjpegに変換してbase64にする
- base64からBlobに変換してFileSaverを使ってダウンロードさせる
- safariでダウンロードフォルダーに保存させるために使用
画像URLからnew Image()する
画像URLからHTMLImageElementインスタンスを作成します。
js1 2 3 4 5 6 7 8 9 10 11 12 13 14
| async load(imageURL) {
let imageSouce = await imageLoader(imageURL);
}
imageLoader(imageURL) {
return new Promise((resolve, reject) => {
let image= new Image();
image.crossOrigin = "anonymous";
image.src = imageURL;
image.onload = function(){
return resolve(image);
}
})
}
|
例えば画像URLがs3やakamaiサーバーにある場合、クロスドメインになると思います。それを回避するには下記の1行を追加することで回避することができます。
js1
| image.crossOrigin = "anonymous";
|
canvasにdrawImageしてjpegに変換してbase64にする
状況によっては png
ではなく jpeg
が必要だったりするかもしれません。その場合 canvas
を使って jpeg
に変換します。また、後述する FileSaver
は Blob
にする必要があるので base64
に変換しておきます。
js1 2 3 4 5 6 7 8 9 10 11
| let canvas:
HTMLCanvasElement = document.createElement("canvas");
let ctx: CanvasRenderingContext2D;
let dataURL: string; let base64: string;
canvas.width = imageSource.naturalWidth;
canvas.height = imageSource.naturalHeight;
ctx = canvas.getContext("2d");
ctx.drawImage(imageSource, 0, 0);
dataURL = canvas.toDataURL("image/jpeg");
base64 = dataURL.split(",")[1];
|
base64からBlobに変換してFileSaverを使ってダウンロードさせる
FileSaverを使うことによってsafariでもファイルをダウンロードさせることができます。 FileSaver
は base64
から Blob
に変換してから使用します。
js1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| base64ToBlob(base64) {
let blob;
let bin = atob(base64.replace(/^.\*,/, ""));
let buffer = new Uint8Array(bin.length);
for (let i = 0; i < bin.length; i++) {
buffer[i] = bin.charCodeAt(i);
}
// Blobを作成
try {
blob = new Blob([buffer.buffer], {
type: "image/jpeg"
});
} catch (e) {
return false;
}
return blob;
}
let blob = this.base64ToBlob(base64);
FileSaver.saveAs(blob, fileName);
|