今回は画像編集を可能にするfabric.jsを使って画像を編集する方法を記事にまとめました。
デモはこちら。
この記事では以下5つを紹介します。
① 任意の画像をcanvasに読み込む
② 画像上に四角形 / 円形 / 文字を挿入する
③ 「②」の要素を削除する
④ 「②」の要素のプロパティを更新する(カラー変更・透明度・borderの太さ など)
⑤ 読み込み画像と共に新規でデータをダウンロードする
それ以外の詳しい処理やプロパティの操作は下記の公式Docsを読んでみてください。
http://fabricjs.com/docs/fabric.Canvas.html
開発環境
・Javascript
・Vue.js 2系
fabric.js インストール方法
$ npm i fabric
① 任意の画像をcanvasに読み込む
画像を読み込むには画像パスが必要です。
fabric.jsではfabric.Image.fromURL
で画像パスからデータを読み込むことができます。
今回は画像を編集したいので、描画される画像をbackgroundとして使います。
その場合、setBackgroundImage
で描画できます。
<template>
<div class="hello">
<canvas id="canvas"></canvas>
</div>
</template>
<script>
import { fabric } from 'fabric';
export default {
name: 'HelloWorld',
props: {
},
data:() => {
return {
}
},
methods:{
// 初回マウント
init(){
const canvas = new fabric.Canvas('canvas');
canvas.selection = true;
// 画像読込み
const img_path = 'https://vuejs.org/images/logo.png';
fabric.Image.fromURL(img_path,(img) => {
canvas.setDimensions({
width: img.width,
height: img.height
});
canvas.setBackgroundImage(img,() => {
canvas.requestRenderAll();
});
})
console.log(canvas);
}
},
mounted(){
this.init();
}
}
</script>
画像のwidth やheightはsetDimensions
で定義します。
② 画像上に四角形 / 円形 / 文字を挿入する
fabric.jsでは図形と文字を以下のように定義します。
// オブジェクトの定義
let newRect = fabric.Rect; // 四角形
let newCircle = fabric.Circle; // 円形
let newText = fabric.Text; // 文字
読み込んだ画像上に図形や文字を挿入する時はまずfabric.jsのイベント処理とoptionsを理解する必要があります。
イベント処理
fabric.jsではユーザーアクションに応じて処理を定義できます。
たとえば、マウスクリック / クリックしたまま動かす / クリックを外す / 二重クリック などです。
マウスクリック = canvas.on('mouse:down'() => {});
クリックしたまま動かす = canvas.on('mouse:move',() => {});
クリックを外す = canvas.on('mouse:up',() => {});
ダブルクリック = canvas.on('mouse:dblclick',() => {});
こんな感じでイベント処理が用意されています。
options
optionsはユーザーが行ったイベントの情報を持っています。
たとえば、クリック位置はoptions.pointer
で、クリックした場所にオブジェクトがあるかどうかはoptions.target
などで取得できます。
この2つを使うことでどの位置にどんな図形や文字を挿入するかを定義することができます。
たとえば赤枠の四角形を挿入したい時は
canvas.on('mouse:down',(options) => {
if (!options.pointer) return
if (options.target == null) {
newRect = new fabric.Rect({
left: options.pointer.x,
top: options.pointer.y,
width: 0,
height: 0,
fill: 'white',
opacity: 0.5,
stroke: 'red',
strokeWidth: 2,
strokeUniform: true,
});
}
});
canvas.on('mouse:move', (options) => {
if (!options.pointer) return;
if (newRect && newRect.left && newRect.top) {
newRect.width = Math.max(options.pointer.x - newRect.left, 0)
newRect.height = Math.max(options.pointer.y - newRect.top, 0)
canvas.requestRenderAll();
}
});
canvas.on('mouse:up', (options) => {
if (!options.pointer) return;
if (newRect && newRect.width != 0 && newRect.height != 0) {
canvas.add(newRect);
}
// 初期化
newRect = undefined;
});
図形をadd()
した後はオブジェクトの初期化を忘れずに。
newRect = undefined;
とすると、2個目のオブジェクトを生成できます。
円形や文字も同じです。参考パターンはデモを見てください。
③ 「②」の要素を削除する
要素を削除するにはremove()
メソッドを使います。
オブジェクトの取得
ユーザーがどの図形や文字をクリックしたか、を取得するにはcanvas.getActiveObject()
を使います。console.log()
で確認するといろんな情報が取得できます。
※ たとえば、クリックしたオブジェクトの図形タイプを取得したい場合canvas.getActiveObject().type
で取得できます。これを利用すると各オブジェクトに応じて必要な処理を分岐できます。
以下では、特定の要素をクリック後deleteキーをタイプしたときに削除が実行されます。
// 特定要素の削除
document.addEventListener("keyup", function (e) {
if (e.keyCode == 8 | e.keyCode == 46) { // delete と backspaceに対応
canvas.remove(canvas.getActiveObject());
}
});
remove()
にまるっと選択オブジェクトを入れることで削除が実行されます。
④ 「②」の要素のプロパティを更新する(カラー変更・透明度・borderの太さ など)
オブジェクトプロパティを更新するにはset()
メソッドとrenderAll()
を使います。
②で紹介した図形のプロパティはそれぞれ定義するものが違います。
たとえばプロパティにfill
があり、図形だと「塗りつぶし」にあたりますが文字だとtext-colorになります。詳しい内容は公式Docsを読んでみてください。
今回カラーピッカーはHTMLの <input type="color">
、オパシティの透明度は <input type="range">
を使うことにします。
下記では四角形の塗りつぶしfill
と透明度opacity
を変更してみます。
<template>
<div class="hello">
<input id="defined_color" type="color">
<input id="defined_opacity" type="range">
<canvas id="canvas"></canvas>
</div>
</template>
上記のinputのvalueは.value
で取得できます。以下は値変更時の例です。
const defined_color = document.getElementById('defined_color');
var d_color;
defined_color.addEventListener('change',(e) => {
d_color = defined_color.value;
});
const defined_opacity = document.getElementById('defined_opacity');
var d_opacity;
defined_opacity.addEventListener('change',(e) => {
if(defined_opacity.value != 0){
d_opacity = Math.floor(defined_opacity.value) / 100;
console.log(d_opacity);
} else {
d_opacity = 0;
}
});
プロパティ変更はダブルクリックとしてみます。
canvas.on('mouse:dblclick',(options) => {
canvas.getActiveObject().set("fill", d_color);
canvas.getActiveObject().set("opacity",d_opacity);
canvas.renderAll();
});
これで特定のオブジェクトのプロパティを変更できます。
borderの太さはstrokeWidth
を、borderカラーはstroke
プロパティを調整すると変えられます。
⑤ 読み込み画像と共に新規でデータをダウンロードする
読み込んだ画像を編集して新しい画像として保存したい時はtoDataURL()
を使います。
通常downnload機能を実装するには<a href="example.gif" download="デモファイル">ダウンロード</a>
という形で実装しますね。今回は画像をデータをhrefに、downloadには画像名をセットします。
以下ローカルサーバー上の挙動です。サーバーを立ち上げていないと
Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.
とCrossOriginで弾かれるので注意してください。
<template>
<div class="hello">
<input id="defined_color" type="color">
<input id="defined_opacity" type="range">
<canvas id="canvas"></canvas>
<a id="download">Download</a> //こいつを追加
</div>
</template>
<script>
.
.
.
methods:{
// 画像読込み
init(){
const canvas = new fabric.Canvas('canvas');
canvas.selection = true;
// ダウンロードボタン
let download_btn = document.getElementById('download'); // 追加
.
.
.
// ダウンロード
download_btn.addEventListener('click',() => {
if (!canvas) return
canvas.selection = true;
console.log(canvas.toJSON());
const image = canvas.toDataURL({ format: 'png' }).replace('image/png', 'image/octet-stream');
download_btn.setAttribute('href',image);
download_btn.setAttribute('download','sample.png');
});
.
.
.
</script>
download_btn
がクリックされたときにtoDatURL({ format: 'png' })
とし、replace()で置き換えています。
こうすることでaタグのhrefにセットしたのちにダウンロードできます。今回はファイル名を'sample.png'としていますが、webアプリケーション上であればDBのデータ名をそのままセットすることもできます。
# まとめ
今回はfabric.jsを使って画像編集を紹介しました。
オブジェクトを取得するだけでfabricを使って多彩な機能で編集できるので極めると面白そうですね。
暇があればごりごりの編集アプリでも作ってみようと思います。