Skip to content

JavaScriptで画像を読み込んでcanvasからjpeg変換したりするまでのアレやコレや

一番カンタンにダウンロードを実装する方法

HTMLでファイルや画像をdownloadする為の単純な実装はこんな感じだとおもいます。
<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インスタンスを作成します。
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行を追加することで回避することができます。
image.crossOrigin = "anonymous";

canvasにdrawImageしてjpegに変換してbase64にする

状況によっては png ではなく jpeg が必要だったりするかもしれません。その場合 canvas を使って jpeg に変換します。また、後述する FileSaverBlob にする必要があるので base64 に変換しておきます。
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でもファイルをダウンロードさせることができます。 FileSaverbase64 から Blob に変換してから使用します。
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);

Be First to Comment

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です