孅いエンジニアブログ

画像のダウンロード時に拡張子(フォーマット)を指定できる拡張機能作ってみた

作った。

いつもイラスト描いてくれてる友達に、Chrome拡張機能作成にハマってる俺が無理に要望を引き出したところ出てきた機能。画像をウェブ上でダウンロードする際にWebPとかでダウンロードされるのが意外とうざいらしい話。言われてみると確かに。。。

実装

変換時に外部のライブラリを使おうかと界王拳2倍くらいの気力で頑張ってみたけどなんか難しくて(あとめんどくさくて)諦めました。

なので、ブラウザ上でなんとかしてみた。

やり方は単純、画像をcanvasに描画してダウンロードするというもの。

const res = await fetch(location.href);
const blob = await res.blob();
const img = new Image();
img.src = URL.createObjectURL(blob);
img.onload = async () => {
	const width = img.width;
	const height = img.height;

	const canvas = document.createElement("canvas");
	canvas.width = width;
	canvas.height = height;
	try {
		const ctx = canvas.getContext("2d");
		ctx!.drawImage(img, 0, 0, width, height);
		const dataURL = canvas.toDataURL("image/png");
		const blob = await (await fetch(dataURL)).blob();
		const link = document.createElement("a");
		link.href = URL.createObjectURL(blob);
		link.download = "image.png";
		link.click();
	} catch (e) {
		/* empty */
	}
};

コードの全貌はこちらから

fetchで開いているページのURLを取得して、こねこねしてcanvasにぶち込んでcanvas.toDataURL("image/png")でなんとかかんとか。

try catchしているのは、svgで実行された時対策です。svgはちとめんどそう、未来の自分に期待。

現在変換可能な拡張子は、PNG, JPEG, WebPの3つ。これ以外の拡張子はChromeでは変換不可能なので、現在は未対応。FireFoxはBMPもいけるらしい。FireFox用は作ってないですが。

他の拡張子はサーバーに送ってこねこねくねくねしないとだめなのかな。サーバーで動かすとなると金かかるので、考えもの。

再変換はしないはず

そもそも変換が必要ない場合はそのままダウンロードするようにしています。

例えばJPGのものをJPGとしてダウンロードすることで画像が劣化するみたいなことは防げてるはずです。

const byteArray = new Uint8Array(await res.clone().arrayBuffer());

let currentImageType = "unknown";
if (byteArray[0] === 255 && byteArray[1] === 216) {
	currentImageType = "image/jpeg";
} else if (byteArray[0] === 137 && byteArray[1] === 80 && byteArray[2] === 78 && byteArray[3] === 71) {
	currentImageType = "image/png";
} else if (
	byteArray[0] === 82 &&
	byteArray[1] === 73 &&
	byteArray[2] === 70 &&
	byteArray[3] === 70 &&
	byteArray[8] === 87 &&
	byteArray[9] === 69 &&
	byteArray[10] === 66 &&
	byteArray[11] === 80
) {
	currentImageType = "image/webp";
}

こんな感じでファイル名とかではなく中身で判断してるので、正しいはず...正しいよね...?

良ければ使ってみてください。