【JavaScript】 Canvasにサーバー上の画像を貼り付ける
更新日:2020/06/05
JavaScriptでサーバー上にある画像を読み込んで、Canvas要素上に貼り付ける方法をお伝えします。
画像の取り込み
まずは貼り付ける画像を、サーバー上からブラウザ内に取り込みます。
次の二つの方法があります。
imgタグで読み込む
HTML
<img id="image" src="https://xxxx.com/xxx.jpg">
JavaScript
window.addEventListener( "load" ,()=> {
const img = document.getElementById("image");
});
loadイベントは、画像を含めた全てのリソースが読み込みが終わった時点で発生します。
そのため、かなり遅いです。
そこでDOM構築後に発生するDOMContentLoadedイベントを使用します。
window.addEventListener( "DOMContentLoaded" , ()=> {
const img = document.getElementById("img");
if( !img.complete ){
img.onload = ()=>{
console.log( "読み込み完了" );
};
img.onerror = ()=>{
console.log( "読み込み失敗" );
};
}else{
console.log( ( img.naturalHeight === 0 && img.naturalWidth) ?
"読み込み失敗" : "読み込み完了" );
}
});
DOMContentLoadedイベント時点では、画像読み込み終了しているものもあれば、途中のものもある状態です。
そのため、画像が今どんな状態かを確認する必要があります。
complete プロパティがfalseなら読み込みが終了していないので、onloadおよびonerrorイベントをセットして読み込み完了を待ちます。
complete プロパティがtrueは、読み込み処理が完了している状態です。
読み込みが失敗していても完了していることになるので、値はtrueです。
読み込みが正常に行われたかどうかは、img要素の幅と高さを示すnaturalHeight とnaturalWidthが0より大きいかで判断します。
URLを動的に指定して読み込む
読み込み画像のURLをJavaScript上で指定することが可能なら、もっと簡単な方法があります。
次のように、Imageオブジェクトを使用する方法です。
window.addEventListener( "DOMContentLoaded" , ()=> {
const img = new Image( ); // Imageオブジェクトの作成
img.onload = function(){ }; // 読み込み成功
img.onerror = function(){ }; // 読み込み失敗
img.src = "https://xxxx.com/xxx.jpg"
});
上の例をそのまま使用してもらえれば問題ありませんが、次の記事に画像の動的に読みについて少し詳しく書いています。
参考記事:【JavaScript】 画像を動的に読み込んでhtml(DOM)やCanvasで使用する
Canvasで画像を処理する場合、こちらの方法をおススメします。
drawImageで貼り付け
Canvasへの画像貼り付けは、コンテキストが持っているdrawImage()メソッドを使用します。
drawImage()メソッドは、引数の数の違いで次の3つの機能を持っています。
- 引数3つ:Canvasの指定した位置に画像を描画(貼り付け)
- 引数5つ:Canvasの指定した位置に拡大・縮小して画像を描画(貼り付け)
- 引数7つ:元画像の一部をキャンバスの指定した位置に拡大・縮小して描画(貼り付け)
それぞれについて、簡単に解説します。
なおCanvasは、HTMLで次のように定義してあるとします。
HTML
<canvas id="canvas" width="500" height="500">
Canvasの指定した位置に画像を描画
drawImage()メソッドに3つの引数を与えると、Canvasの指定した位置に画像を描画します。
下の例は、前項のコード内のimg.onloadにセットした関数内の処理です。
img.onload内の処理
const canvas = document.getElementById("canvas");
const context = canvas.getContext("2d");
context.drawImage( img , 50 , 50 );
context.textBaseline = "top";
context.fillText( "0,0" , 0 , 0 );
drawImage( image sx , sy )
image: 貼り付けるイメージ
sx: 貼り付け先のキャンバス座標x
sy: 貼り付け先のキャンバス座標y
Canvasの指定した位置に拡大・縮小して画像を描画
drawImage()メソッドに5つの引数を与えると、Canvasの指定した位置に拡大・縮小して画像を描画します。
img.onload内の処理
const canvas = document.getElementById("canvas");
const context = canvas.getContext("2d");
context.drawImage( img , 50 , 50 );
// 横に2倍して表示
context.drawImage( img , 100 + img.naturalWidth , 50 , img.naturalWidth * 2 , img.naturalHeight );
context.textBaseline = "top";
context.fillText( "0,0" , 0 , 0 );
drawImage( image , sx , sy , sw , sh )
image: 貼り付けるイメージ
sx: 貼り付け先のキャンバス座標x
sy: 貼り付け先のキャンバス座標y
sw: 貼り付け先の幅
sh: 貼り付け先の高さ
貼り付け先の幅と高さは率ではなく、実際のピクセル数で指定します。
図形のサイズはnaturalWidthとnaturalHeightで取得できるので、例えば2倍したいときはそれぞれの値に2をかけてください。
元画像の一部をキャンバスの指定した位置に拡大・縮小して描画
drawImage()メソッドに7つの引数を与えると、元画像の一部をキャンバスの指定した位置に拡大・縮小して描画します。
img.onload内の処理
const canvas = document.getElementById("canvas");
const context = canvas.getContext("2d");
context.drawImage( image , 50 , 50 );
const [w,h] = [image.naturalWidth / 4 , image.naturalHeight/4];
context.strokeStyle = "blue";
context.strokeRect( 50 + w , 50 + h , w * 2 , h * 2 );
context.drawImage( image , w , h , w * 2 , h * 2 ,
100 + image.naturalWidth , 50 , image.naturalWidth , image.naturalHeight );
drawImage( image sx , sy , sw , sh , sx2 , sy2 , sw2 , sh2)
image: 貼り付けるイメージ
sx: 元画像の切り出し位置x
sy: 元画像の切り出し位置y
sw: 元画像の切り出し幅
sh: 元画像の切り出し高さ
sx2: 貼り付け先のキャンバス座標x
sy2: 貼り付け先のキャンバス座標y
sw2: 貼り付け先の幅
sh2: 貼り付け先の高さ
貼り付け先の幅と高さは率ではなく、実際のピクセル数で指定します。
画像を加工してから貼り付け
drawImage()メソッドは、キャンバスを元画像として指定することができます。
そのため、読み込んだ画像を一時的なキャンバス上で加工してから、目的のキャンバスに描画することができます。
// Path2Dオブジェクト作成(ハート形)</span>
const getHartPath =()=>{
const path = new Path2D();
path.moveTo( 0 , 43);
path.quadraticCurveTo(70 , 3, 70 , -37);
path.bezierCurveTo(70 , -77 , 20 , -77, 0 , -37);
path.bezierCurveTo(-20 , -77, -70 , -77, -70 , -37);
path.quadraticCurveTo(-70 , 3 , 0 , 43);
return path;
};
// 一時描画用キャンバス作成
const workCanvas = document.createElement("canvas");
// 一時描画用キャンバスの描画幅・高さセット
const [w,h] = [image.naturalWidth , image.naturalHeight];
workCanvas.setAttribute("width",w * 2);
workCanvas.setAttribute("height",h * 2);
const workContext = workCanvas.getContext("2d");
// 一時描画用キャンバスに画像を描画
workContext.drawImage( image , w /2 , h / 2 );
// 一時描画用キャンバスにハートを描画
workContext.fillStyle = "pink";
const hPath = getHartPath();
const hPathPos = [
[ 0.3,0.3 , 200,200 , 15 ],[ 0.3,0.2 , 400,600 , 60 ],[ 0.2,0.2 , 600,200 , 310 ]
];
hPathPos.forEach(
e =>{
workContext.save();
workContext.scale(e[0],e[1]);
workContext.translate(e[2],e[3]);
workContext.rotate( e[4] * Math.PI / 180)
workContext.fill(hPath);
workContext.restore();
}
);
// html上のキャンバスに、一時描画用キャンバスの内容を描画
const canvas = document.getElementById("canvas");
const context = canvas.getContext("2d");
context.drawImage( workCanvas , 50 , 50 );
context.drawImage( workCanvas , 100 + workCanvas.width , 50 , workCanvas.width / 2 , workCanvas.height );
上のコードは、一時描画用キャンバスに画像と3つのハートを描画しています。
その後、html上のキャンバスに、一時描画用キャンバス上の画像を2回描画しています。
更新日:2020/06/05
関連記事
スポンサーリンク
記事の内容について
こんにちはけーちゃんです。
説明するのって難しいですね。
「なんか言ってることおかしくない?」
たぶん、こんなご意見あると思います。
裏付けを取りながら記事を作成していますが、僕の勘違いだったり、そもそも情報源の内容が間違えていたりで、正確でないことが多いと思います。
そんなときは、ご意見もらえたら嬉しいです。
掲載コードについては事前に動作確認をしていますが、貼り付け後に体裁を整えるなどをした結果動作しないものになっていることがあります。
生暖かい視線でスルーするか、ご指摘ください。
ご意見、ご指摘はこちら。
https://note.affi-sapo-sv.com/info.php
このサイトは、リンクフリーです。大歓迎です。