ブラウザ上での画像変換で扱うオブジェクトとその変換(TypeScript)
はじめに
ブラウザ上で画像を扱う際に、扱うオブジェクトが複数あり、その全体を把握・整理するためのドキュメントです。
何ができるようになる?
- ブラウザ上での画像変換用に扱うオブジェクトの概要
- それぞれのオブジェクトの生成方法
- 画像形式の変換
- jpeg→png / gif→png など
- 画像のリサイズ
本記事での対象としないこと
- PDFファイルの扱い
ブラウザでの画像変換で扱うオブジェクト一覧
- File
- ObjectURL
- DataURL
- HTMLImageElement
- canvas/drawImage
- 画像をリサイズ・クリップ可能
まずは、それぞれ簡単に解説していきます
扱うオブジェクトの紹介
File
- 通常、HTMLのinput要素を経由して、ファイルを選択した結果として返されます。
- 画像とは限りません。
- インスタンスメソッドにより、最終更新日/ファイル名/MIMEタイプ/サイズ(byte)を読み取れます。
MIMEタイプとは
MDN: https://developer.mozilla.org/ja/docs/Web/HTTP/Basics_of_HTTP/MIME_types によると
文書、ファイル、またはバイト列の性質や形式を示す標準
一般的には、ファイルの拡張子に対応する。
ObjectURL
- Fileオブジェクトを識別できるURLのことです
Fileオブジェクトがブラウザに保存されていて、それを参照できるURL=ObjectURLです
const objectURL = URL.createObjectURL(file); // fileはFileオブジェクト
とすることでObjectURLを作成できます。
DataURL
data:[<mediatype>][;base64],<data>
の形式で、小さなファイルをインラインで文書に埋め込むことができ、ObjectURLとは異なり、そのURL自体で、ファイルを表現できます。
例えば、以下のDataURLをブラウザで表示できる
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAYAAAA7MK6iAAAABmJLR0QA/wD/AP+gvaeTAAAA1klEQVRIie2WsQ3CMBBFXxBjJKPQE9GxDCWhZCCgpmKPJD0jhAJFODaOHdsHjb90zTm69/9FsgxZWT/QDuiBQag6oP4G7gShY7UjrFDAw8INhaoAWAkNvwAlUAE318cpV1oqcyvtDLAnPnkmSyLdVUN44ivTVRuJ58AAhwi4rbzANvgxwpQ3GKZrf1j6ImAdcnbAmxlTi8Eq5Dlj6u4wFQQG2AObQFNR4BBTxmzbXa32U8iYLXVXO/U38NrSj/nPXlIT99Iw3o8NQzWyr5AW2AoFysr66AWhSOt0gsDT9AAAAABJRU5ErkJggg==
HTMLImageElement
HTMLの<img>
に等しい。
JavaScript上では、document.createElement('img')
またはnew Image()
でオブジェクトを生成できます。
画像変換においては主にsrc属性
とonload
イベントリスナーを用います。
画像変換においては、HTMLImageElementをブラウザに表示する必要はなく、処理の過程のみで使うことが可能です。
canvas/drawImage
canvasはブラウザ上でグラフィックを描画できます。
HTMLImageElementをcanvasでdrawImageでき、このときに画像のリサイズやクリップも可能です。
drawImageした後、toDataURL
というメソッドを使うことで、DataURLを取得できます。
画像変換においては、canvasをブラウザに表示する必要はなく、処理の過程のみで使うことが可能です。
関係性
関係性は以下のようになっています。
それぞれの変換関数の実装は次項です。
それぞれの変換関数の実装
TypeScriptで実装しています。
1. URL.createObjectURL
const objectURL = URL.createObjectURL(file); // fileはFileオブジェクト
2. cvtObjURL2Image
async関数にです。
Promiseを用いて、画像がロード終了後のHTMLImageElementを取得します。
async function cvtObjURLToImage(
objURL: ReturnType<typeof URL.createObjectURL>
) {
return new Promise<HTMLImageElement>((resolve, reject) => {
const img = new Image();
img.onerror = (e) => {
console.error("failed to load image from objUrl");
reject(e);
};
img.onload = () => {
resolve(img);
};
img.src = objURL;
});
}
3. cvtHTMLImageElement2Canvas
下記の例では、widthとheightを指定することで、画像のリサイズが可能です。
function cvtHTMLImageElement2Canvas(
img: HTMLImageElement,
width: number,
height: number,
) {
const canvas = document.createElement("canvas");
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext("2d");
if (!ctx) {
throw new Error("failed to getContext from canvas");
}
ctx.drawImage(img, 0, 0, width, height);
return canvas
}
4. canvas.toDataURL
3. cvtHTMLImageElement2Canvas
の返り値に対してtoDataURLを実行するだけ。MIMEタイプを指定できます。
const dataURL = canvas.toDataURL("image/png");
5. cvtDataURL2File
ファイル名を指定する必要があります。
dataURLをfetch後、blobに変換し、Fileオブジェクトを生成します。
async関数です。
async function cvtDataURL2File(
dataURL: string,
filename: string
): Promise<File> {
const blob = await (await fetch(dataURL)).blob();
return new File([blob], filename);
}
まとめ
前項の関数を組み合わせることで、HTMLのinput要素から入力されたFileオブジェクトを変換し、リサイズして、新たにFileオブジェクトを生成することができます。
前項で触れていませんが、dataURLをHTMLImageElementに変換することも可能です。
ブラウザでの画像変換は、様々なオブジェクトを経由するので、全体を理解していないと、複雑なコードになったり、余計な処理を挟んでしまいがちかと思います。
最小の手数で画像を変換できるように、これらのオブジェクトの関係性を把握しておきましょう。
Discussion