FabricJS

【JavaScript】【Fabric.js】回転させた画像をキャンバスの背景画像に設定する

MAX

JPEG画像は画像の回転角度(元の画像から何度回転したか)をEXIF情報内のOrientationに保持している。

この回転角度を意識せずにWEBアプリでアップロードする画像の描画等を行うと、想定とは異なる向きの画像が表示されたりする。

今回は、キャンバスの背景画像に回転させた画像を設定していく。

html上のimgタグで回転表示させるだけであれば、transformに適切な角度を設定するだけで上手く表示できるが、キャンバス上の場合、それだけでは上手く表示ができない。

適切な個所に表示させるためには、回転角度に応じて、originの設定を変更してから回転させる必要がある。

 

スポンサーリンク

HTML(画像読込フォーム)

画像ファイルはフォームから読み込んだものを設定する。

1<form>
2  <!-- 画像読込フォーム -->
3  <input type="file" id="selectImage" name="selectImage" accept="image/*" >
4</form>
5
6<!-- キャンバス -->
7<canvas class="imageCanvas" id="imageCanvas"></canvas>

JavaScript部分は以下の通り。

画像読込開始時の処理

1/*
2 * ボタンからの画像ファイルの読込
3 */
4document.getElementById('selectImage')
5        .addEventListener('change',async function (e) {
6
7    //画像ファイル用変数
8    let imgFile = e.target.files[0];
9
10    //画像ファイル選択判定
11    if (imgFile != null ) {
12        drawBackgroundImage(imgFile);
13    }else {
14});

画像選択時に実行される処理。メイン処理と分けたのは、ネストが深くなるのを避けるため。

キャンバス描画メイン処理

1/*
2 * drawBackgroundImage()
3 * キャンバスの背景に画像を描画する。
4 */
5async function drawBackgroundImage(imgFile) {
6    //フォームから読み込んだ画像データをキャンバスの背景に描画する。
7
8    //exif情報の取得
9    let orientation = await getOrientation(imgFile);
10    console.log("orientation:", orientation);
11
12    //回転角度の設定
13    let imgAngle = setAngle(orientation);
14
15    //画像からblobUrlを作成し、背景画像として表示する。
16    let blobUrl = window.URL.createObjectURL(imgFile);
17
18    //blobURLから画像データ読込
19    let imgElement = await loadImage(blobUrl).catch(e => {
20        console.log("onload error", e);
21    });
22
23    //画像の縦横サイズ取得
24    let imgSize = {
25            "imgHeight": 0,    //初期化
26            "imgWidth": 0      //初期化
27    }
28    imgSize = getImgSize(imgElement, imgAngle);
29
30    //キャンバスのサイズを画像のサイズに変更する。
31    canvas.setWidth(imgSize.imgWidth);
32    canvas.setHeight(imgSize.imgHeight);
33
34    //画像の原点の設定
35    let imgOrigin = {
36            "imgOriginX": "",     //初期化
37            "imgOriginY": ""      //初期化
38    }
39    imgOrigin = getImgOrigin(imgAngle);
40
41    //キャンバスの背景に画像描画
42    canvas.setBackgroundImage(blobUrl, canvas.renderAll.bind(canvas), {
43        backgroundImageOpacity: 0,
44        backgroundImageStretch: false,
45        originX: imgOrigin.imgOriginX,
46        originY: imgOrigin.imgOriginY,
47        angle: imgAngle
48    });
49    console.log("drawBackgroundImage end");
50}

EXIF情報の取得、回転角度の設定、画像データの読込、画像に合わせたキャンバスサイズの設定、背景画像の原点設定、キャンバスに背景描画と処理を行っていく。

フォームからの画像読込やexif情報の取得は非同期で行われるため、Promiseとasync/awaitを使う。

EXIF情報の取得

1/*
2 * getOrientation
3 * 戻り値
4 *   resolve: exifdata.Orientationを返す
5 *   reject: なし
6 */
7function getOrientation(imgFile){
8    return new Promise( (resolve, reject) => {
9        EXIF.getData(imgFile, function() {
10            console.log(imgFile.exifdata);
11            resolve(imgFile.exifdata.Orientation);
12        });
13        //EXIFデータの取得完了時以外は何も返さない。
14    });
15}

回転角度の設定

1/*
2 * setAngle
3 * orientationの値に応じて回転角度を返却する。
4 * 引数
5 *   orientation: exif.Orientation
6 * 戻り値
7 *   imgAngle: 正しい向きに戻すための回転角度(時計回り)
8 */
9function setAngle(orientation){
10    // orientationの値に応じて回転角度を返却する。
11    switch(orientation){
12    case 1:        //回転なし
13        imgAngle = 0;
14        break;
15    case 3:        //元画像を180度回転している。
16        imgAngle = 180;
17        break;
18    case 6:        //元画像を270度回転している。
19        imgAngle = 90;
20        break;
21    case 8:        //元画像を90度回転している。
22        imgAngle = 270;
23        break;
24    default:
25        imgAngle = 0;
26        break;
27    }
28    return imgAngle;
29}

orientationの値に応じて、回転させる角度を返す。

画像データ読込

1/*
2 * 画像読込時用のPromiseを返す関数
3 * 戻り値
4 *   resolve:画像データ
5 *   reject :error情報
6 */
7function loadImage(blobImg){
8    return new Promise((resolve, reject) => {
9        const img = new Image();
10        img.onload = () => resolve(img);
11        img.onerror = (e) => reject(e);
12        img.src = blobImg;
13    });
14}

画像を読み込むと、画像サイズを取得できるため、キャンバスサイズを設定していく。

画像サイズの取得

1/*
2 * 画像のサイズを取得する。
3 */
4function getImgSize(imgElement, imgAngle){
5    //変数宣言と初期化
6    let imgSize = {
7            "imgHeight": 0,
8            "imgWidth": 0
9    }
10
11    //画像の回転角度に合わせて、画像の縦横を取得する。
12    if ((imgAngle === 90) || (imgAngle === 270)) {
13        console.log("convert height and width");
14        imgSize.imgHeight = imgElement.naturalWidth;
15        imgSize.imgWidth = imgElement.naturalHeight;
16    } else {
17        imgSize.imgHeight = imgElement.naturalHeight;
18        imgSize.imgWidth = imgElement.naturalWidth;
19    }
20    return imgSize;
21}

回転角度が90度、270度の場合、回転後に縦と横が入れ替わるので、それを考慮してキャンバスサイズを設定する。

背景画像の原点設定

1/*
2 * 画像の回転角度に合わせてOriginX、OriginYを設定する。
3 */
4function getImgOrigin(imgAngle){
5    //変数宣言と初期化
6    let imgOrigin = {
7            "imgOriginX": "",
8            "imgOriginY": ""
9    }
10
11    //回転角度に応じてOriginを設定する。
12    switch(imgAngle){
13    case 0:
14        imgOrigin.imgOriginX = "left";
15        imgOrigin.imgOriginY = "top";
16        break;
17    case 90:    //左下を起点に回転させる
18        imgOrigin.imgOriginX = "left";
19        imgOrigin.imgOriginY = "bottom";
20        break;
21    case 180:    //右下を起点に回転させる
22        imgOrigin.imgOriginX = "right";
23        imgOrigin.imgOriginY = "bottom";
24        break;
25    case 270:    //右上を起点に回転させる
26        imgOrigin.imgOriginX = "right";
27        imgOrigin.imgOriginY = "top";
28        break;
29    default:
30        imgOrigin.imgOriginX = "left";
31        imgOrigin.imgOriginY = "top";
32        break;
33    }
34    return imgOrigin;
35}

imgタグだとこんなことを考慮しなくて良いのだが、キャンバスの場合、考慮する必要がある。

WEBサーバにアップロードしてから画面に表示でもOKな場合、サーバ側で回転させて、キャンバス上は普通に表示するのが楽だと思う。

そもそも、画像を色々加工して表示したいとか、理由がない限り、画像描画にキャンバスは使う必要がない。というか、面倒なだけw

スポンサーリンク
ABOUT ME
MAX
MAX
ITエンジニア、データサイエンティスト
新卒でSIerに入社し、フリーランスになってWEB系へ転向。
その後AIの世界へ足を踏み入れ、正社員に戻る。 テーブルデータの分析がメイン。
スポンサーリンク
記事URLをコピーしました