今回はネット上に多数ある情報かもしれませんが、HTML5で導入されたCanvasを使った簡単な画像処理です。
現在の仕事でReactクライアント(ブラウザー上)で選択した画像の大きさ等を調整してサーバーに送る必要があります。ブラウザー上で画像処理ができるnpm(JavaScript)ライブラリーもありますが、今回はCanvasを使い簡単な画像処理を行うコードを書いてみました。
Bing Image Creatorが生成した画像です
サンプルプログラム
今回のプログラムの画面は以下のようになります。
- 最初に、ファイル選択ボタンで画像ファイルを選択します
- その画像がファイル選択ボタンの下に表示されます
- 次に、Zoomボタンを押すと
- Zoomボタンの下に拡大縮小された画像が表示されます
- ここでは幅が0.5倍、高さが2倍になっています
サンプルプログラムのコード
import React, { useState } from "react";
export default const App = () => {
const [srcImage, setSrcImage] = useState<string|null>(null); // ← ①
const [zoomedImage, setZoomedImage] = useState<string|null>(null); // ← ②
const loadImage = (e: React.ChangeEvent<HTMLInputElement>) => { // ← ③
const files = e.target.files; // ← ④
if (!files || !files[0]) return;
const reader = new FileReader();
reader.readAsDataURL(files[0]); // ← ⑤
reader.onload = () => {
setSrcImage(reader.result as string); // ← ⑥
};
}
- ① 選択された元画像データが入るステート
- 画像データはデータURL 形式の文字列です(base64エンコードされています)
- ② 拡大縮小された画像データが入るステート
- ③ 画像読み込み関数
- ④
<input type="file" />
のイベントデータには選択されたファイルの情報が入っています - ⑤ ファイルの内容をFileReader.readAsDataURL()を使い読み込みます
- ⑥ 読み込みが完了したら、画像データ(データURL形式)をステートに格納
const zoomImage = async (xRate: number, yRate: number) => { // ← ⑦
if (!srcImage) return;
const image = new Image();
image.src = srcImage;
await image.decode(); // ← ⑧
const canvas = document.createElement('canvas'); // ← ⑨
const ctx = canvas.getContext('2d'); // ← ⑩
if (!ctx) return;
canvas.width = image.width * xRate; // ← ⑪
canvas.height = image.height * yRate;
ctx.scale(xRate, yRate); // ← ⑫
ctx.drawImage(image, 0, 0); // ← ⑬
const [, mimeType] = srcImage.match(/^data:(.*?);/) ??
['', 'image/png']; // ← ⑭
setZoomedImage(canvas.toDataURL(mimeType)); // ← ⑮
}
- ⑦ 画像拡大縮小の関数
- 引数
xRate
:幅の拡大率、yRate
:高さの拡大率
- 引数
- ⑧ 画像オブジェクトを作成し、元画像データを読み込みます
await image.decode()
で画像読み込みの完了を待ちます
- ⑨ Canvasを作成
- ⑩ 2次元描画コンテキスト(画像処理の各種パラメーターの格納されたオブジェクト)を取得
- ⑪ Canvasの幅・高さを拡大縮小後の画像サイズに設定
image.width
には元画像の幅です、image.height
は高さ
- ⑫ scale()で次で描画する画像のスケール(拡大率)を設定
- ⑬ 元画像オブジェクトをCanvasに描画
- ここで拡大縮小された画像がCanvasに書かれます
- ⑭ 元画像のmime-typeを取得
- データURLの先頭には
data:image/png';
のように画像の形式が書かれています match()
関数は正規表現にマッチしないとnullを戻すので、その場合はimage/png
を設定します
- データURLの先頭には
- ⑮ Canvasの内容をデータURL形式に変換し、拡大縮小された画像をzoomedImageステートの格納します
return (
<div>
<input type="file" onChange={loadImage} /> {# ← ⑯ }
<hr /> {# ↓ ⑰ }
{srcImage && <img src={srcImage} alt="source image" style={{border: 'solid 1px blue'}} />}
<hr />
<button onClick={_ => zoomImage(0.5, 2.0)}>Zoom</button> {# ← ⑱ }
<hr /> {# ↓ ⑲ }
{zoomedImage && <img src={zoomedImage} alt="zoomed image" style={{border: 'solid 1px blue'}}/>}
</div>
);
}
- ⑯ ファイル選択ボタン、選択されたら
loadImage()
関数が呼び出されます - ⑰ 選択された元(srcImage)画像の表示用
img
タグ - ⑱ Zoomボタンを押すと、拡大縮小関数
zoomImage(0.5, 2.0)
が呼び出されます - ⑲ 拡大縮小された(zoomedImage)画像の表示用
img
タグ
まとめ
このようにCanvasを使った画像処理は、CanvasRenderingContext2Dが提供している関数で処理できる範囲で、かつ何らかの汎用的な画像処理ライブラリーを使った事のある方なら、難しくないと思います。