[69-4] canvasに画像を描画しよう(トリミングやクリッピングも)

今回は、<canvas>に画像(写真)を描画してみますよ。
トリミングや、クリッピング(切り抜き)もやってみます。

今回のサンプルはこちら。
クリックで別ウィンドウで開きます。

本日のINDEX
  1. 画像を原寸で描画する(drawImage(image, dx, dy);)
    * drawImage() メソッドについて
  2. 画像をサイズ指定して描画する(drawImage(image, dx, dy, dw, dh);)
  3. 画像をトリミングして描画する(drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh);)
  4. 画像をクリッピングする(clip(); と drawImage(); )
  5. クリッピングを複数並べる
  6. 別に作ったキャンバスを drawImage(); で描画して、クリッピングを横に並べる

今回使用した画像は 素材辞典(株式会社データクラフト)から使用しています。著作権は株式会社データクラフトにあります。

画像を原寸で描画する(drawImage(image, dx, dy);)

画像を原寸で描画するときは「drawImage(image, dx, dy);」で描きます。
()内の最初の「image」は変数名です。自分で好きにつけた変数名を書きます。
dx, dy は、描画先のキャンバス(Destination Canvas)の x, y 座標。
(描画先のキャンバスはDestination Canvasなので、頭文字の「d」がついてます)
この座標を左上の頂点とした位置に、画像を描画します。

サンプル1を見てみましょう。
<canvas>サイズは 500×300px、画像サイズは 280×370px。わかりやすいように<canvas>にはベージュの背景色をつけています。
<canvas>の左上(x=0, y=0 の地点)から、原寸で描画しているので、 キャンバスのサイズに収まらない部分(画像の下部70pxの高さ分)はカットされています。

● drawImage() メソッドについて

drawImage() メソッドは、<img>要素、<video>要素、<canvas>要素をオブジェクトとして扱うことができます。

● drawImage() メソッドの注意点

<img>要素、<video>要素を描画する時、
それらの要素が「読み込まれた後でないと、drawImage() を呼び出せない」んだって。要注意です。

なので、<img>要素なら loadイベント、<video>要素なら loadeddataイベントを使って、
そのイベント内で描き出しをします。

サンプル1のソースを見てみましょう。

function image1() {	
    var cnvs = document.getElementById('canvas1');
    var ctx = cnvs.getContext('2d');
/* 新しいImageオブジェクトを生成 */
    var img = new Image();
/* 画像が読み込まれてからcanvasへ書き出す */
    img.onload = function() {
    ctx.drawImage(img, 0, 0);
  };
/* 画像URLを指定して、画像のロードを開始する */
  img.src = "img/family.jpg";
}

「new Image();」で新しく<img>要素を作って(5行目)、
その loadイベントで、指定したキャンバスへの描画の指定までした後で(7,8,9行)、
最後に画像のURLを指定して、画像をロードしています(11行目)。

このようにしなければ、最初は<canvas>上に何も表示されず、
更新ボタンなどでリロードすれば、やっと表示される....なんてことになっちゃいます。

画像をサイズ指定して描画する(drawImage(image, dx, dy, dw, dh);)

次は、画像を縮小して<canvas>要素の中にピッタリ収まるようにしてみます。
画像をサイズ指定して描画するときは「drawImage(image, dx, dy, dw, dh);」で描きます。
dx, dy は、描画先のキャンバスでの描画の左上の x, y 座標。
dw, dh は、描画先のキャンバスでの描画の幅と高さです。
(描画先のキャンバスはDestination Canvasなので、頭文字の「d」がついてます)

サンプル2を見てみましょう。
<canvas>のサイズは、500×300pxですので、
画像サイズ(原寸280×370px)を、高さ300pxに縮小します。
横サイズは、280×(300÷370)=227.027なので、227pxにしましたよ。

function image2() {	
    var cnvs2 = document.getElementById('canvas2');
    var ctx2 = cnvs2.getContext('2d');
    var img2 = new Image();
    img2.onload = function() {
    ctx2.drawImage(img2, 0, 0, 227, 300);
  };
  img2.src = "img/family.jpg";
}

画像をトリミングして描画する
 (drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh);)

画像全体ではなく、1部をトリミングすることもできます。
画像をトリミングして描画するときは「drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh);」で描きます。
sx, sy は、元のイメージ(Source Image)でトリミングした左上の x, y 座標。
sw, sh は、元のイメージのトリミングしたの幅と高さです。
(元のイメージはSource Imageなので、頭文字の「s」がついてます)

サンプル3を見てみましょう。
画像を200×270pxにトリミングして、キャンバスの中央に描画しました。

サンプルのソースはこのようになっています。

function image3() {	
    var cnvs3 = document.getElementById('canvas3');
    var ctx3 = cnvs3.getContext('2d');
    var img3 = new Image();
    img3.onload = function() {
    ctx3.drawImage(img3, 20, 45, 200, 270, 150, 15, 200, 270);
    };
    img3.src = "img/family.jpg";
}

sx, sy, sw, sh と dx, dy, dw, dh の関係を図説するとこんなかんじ。

ここでは、トリミングしたサイズのままキャンバスに貼っていますが、
トリミング後、拡大や縮小もできる(dw, dhで)わけです。

画像をクリッピングする(clip(); と drawImage(); )

画像を図形で切り抜く(クリッピングする)こともできます。
図形の描画の時に、塗りを色指定する「 fill() 」、線の色指定の「stroke()」をやりましたが、
もうひとつ「 clip() 」っていうのがあるんだそうです。
これは図形の内部をクリッピング領域にする指定です。
「 clip() 」の後に「 drawImage() 」で描画すると、画像がパスで切り抜かれます。

サンプル4を見てみましょう。
90×90px(半径45px)の正円を描いて「 clip() 」を指定し、その後にトリミングした男の子の画像を置いたので、丸くクリッピングされました。

function image4() {	
    var cnvs4 = document.getElementById('canvas4');
    var ctx4 = cnvs4.getContext('2d');
/* 円を指定 */
    ctx4.beginPath();
    ctx4.arc(65, 65, 45, 0, Math.PI*2, false);
    ctx4.clip();
/* 画像を指定 */
    var img4 = new Image();
    img4.onload = function() {
    ctx4.drawImage(img4, 98, 187, 90, 90, 20, 20, 90, 90);
    };
    img4.src = "img/family.jpg";
}

円は「中心点のx,y座標」、画像は「左上のx,y座標」が基準になるのがややこしいところ。
円の指定(6行目)では、カンバスの左から20px上からも20pxのところに半径45pxの正円を描きたいので、中心点のx,y座標を「65,65」と指定しています。
(このカンバスのサイズは130×130pxです)
画像では(11行目)、男の子の顔を90px角で切り抜いて、カンバスの、円を描いた場所にジャストミートするように貼るのですが、こっちは左上が基準なので「20,20」。 慣れないとややこしいね。

クリッピングを複数並べる

切り抜いた画像を、複数並べてみます。
コツは、画像のための onloadファンクションの中で、クリッピング用のパスをまとめて書く。
切り抜かれる画像も、複数まとめて書き、最後に画像をロードします。
切り抜かれたくない画像は、クリッピングパスより前に指定するのが鉄則です。

サンプル5を見てみましょう。
まず集合写真をトリミングして配置し、
その横にファミリーの顔をクリッピングして並べています。

function image5() {	
    var cnvs5 = document.getElementById('canvas5');
    var ctx5 = cnvs5.getContext('2d');
/* 画像のための onloadファンクション */
    var img5 = new Image();
    img5.onload = function() {
    /* まずトリミングした画像を描画(clip() より前に指定) */
    ctx5.drawImage(img5, 20, 45, 200, 270, 0, 0, 200, 270);	
    /* 円を指定 */
    ctx5.beginPath();
    ctx5.arc(255, 135, 45, 0, Math.PI*2, false);
    ctx5.arc(350, 135, 45, 0, Math.PI*2, false);
    ctx5.arc(445, 135, 45, 0, Math.PI*2, false);
    ctx5.clip();
    /* クリッピング用の画像を描画 */
    ctx5.drawImage(img5, 37, 40, 90, 90, 210, 90, 90, 90); /*父*/
    ctx5.drawImage(img5, 98, 187, 90, 90, 305, 90, 90, 90); /*息子*/
    ctx5.drawImage(img5, 135, 90, 90, 90, 400, 90, 90, 90); /*母*/
    };
    img5.src = "img/family.jpg";
}

クリッピング用の画像の座標は、
こういうことです。

別に作ったキャンバスを drawImage(); で描画し、クリッピングを横に並べる

drawImage() メソッドは、<img>要素、<video>要素、<canvas>要素をオブジェクトとして扱うことができる。ということなので、
3つのクリッピング画像を、90px角の<canvas>要素として作って並べる手を考えてみました。

サンプル6を見てみましょう。
サンプル5と見た目は同じですが、
「createElement('canvas');」で、
90px角のキャンバスを、3人分作り、それをHTML上のキャンバスに描画する手法で作っています。

function image6() {	
    var cnvs6 = document.getElementById('canvas6');
    var ctx6 = cnvs6.getContext('2d');
/* 別に作った3つのキャンバスを描画する */
	ctx6.drawImage(clp1, 20, 20);
	ctx6.drawImage(clp2, 130, 20);
	ctx6.drawImage(clp3, 240, 20);
}
// 「クリッピング1-父」のキャンバスを作成
    var clp1 = document.createElement('canvas');
    clp1.width = 90;
    clp1.height = 90;
    var cCtx1 = clp1.getContext('2d');	
    /* 円を指定 */
    cCtx1.beginPath();
    cCtx1.arc(45, 45, 45, 0, Math.PI*2, false);
    cCtx1.clip();
    /*画像を指定 */
    var image = new Image();
    image.onload = function() {
    cCtx1.drawImage(image, 37, 40, 90, 90, 0, 0, 90, 90);
    };
    image.src = "img/family.jpg";
// 「クリッピング2-息子」のキャンバスを作成
    var clp2 = document.createElement('canvas');
    clp2.width = 90;
    clp2.height = 90;
    var cCtx2 = clp2.getContext('2d');	
    /* 円を指定 */
    cCtx2.beginPath();
    cCtx2.arc(45, 45, 45, 0, Math.PI*2, false);
    cCtx2.clip();
    /*画像を指定 */
    var image = new Image();
    image.onload = function() {
    cCtx2.drawImage(image, 98, 187, 90, 90, 0, 0, 90, 90);
    };
    image.src = "img/family.jpg";
// 「クリッピング3-母」のキャンバスを作成
    var clp3 = document.createElement('canvas');
    clp3.width = 90;
    clp3.height = 90;
    var cCtx3 = clp3.getContext('2d');	
    /* 円を指定 */
    cCtx3.beginPath();
    cCtx3.arc(45, 45, 45, 0, Math.PI*2, false);
    cCtx3.clip();
    /*画像を指定 */
    var image = new Image();
    image.onload = function() {
    cCtx3.drawImage(image, 135, 90, 90, 90, 0, 0, 90, 90);
    };
    image.src = "img/family.jpg";

これ、スクリプトは長くなったんですが、
1個のキャンバス内で、クリッピングを済ませるので、描画するキャンバス上での座標指定がカンタン。
clip() が他に与える影響も考えなくて済むし。1話完結オムニバス形式で、扱いやすいです。

あと、スクリプト内で「キャンバスを作る」という不思議な感覚も味わえました(笑)
「createElement('canvas');」で作ったキャンバスは、存在するけど見えない。描画するまでは。
いろいろ使える手法だと思いました。

次回予告

次回は、図形の塗りや線に、グラデーションを指定してみます。
線形グラデーション、円形(放射)グラデーション、両方とも使えます。
それから、図形にシャドウをつけることもできますので、こちらもやってみます。

関連記事
この記事をはてなブックマークに追加

やる気を保つためにランキングに参加しています。
応援してくださると すっごいやる気を出します! (笑)

初心者にも使いやすい(と思う)レンタルサーバー

最近よく「レンタルサーバーはどこがいい?」とご質問が来ます。
自分でも使っていてオススメなのはミニバード。管理画面がわかりやすくていい感じす。
仕事で使ってるロリポップもわかりやすい管理画面で、初めてでもすんなり使えると思います。
両方とも、なんといっても料金が安いです。初めてだとなるべく安いほうがイイですからね。

それよりちょっと料金は高いけど、高スペックでコスパが良く、信頼性も高いサーバといえば、やはりさくらのレンタルサーバと、XSERVER(エックスサーバー)だと思う。この2つは老舗でユーザーも多いので、質問する場がたくさんあり、初心者の方でもイケるだろうと思います。

レンタルサーバーは、たくさんあり過ぎて迷いますよね。近いうちに、初心者にも良さげなサーバーについて記事にまとめます。*記事をアップしたらココにもリンクを貼ります。

スポンサーリンク

コメントの投稿

スポンサーリンク
最新記事
Category
オススメの本
Links
Calendar
05 | 2017/06 | 07
- - - - 1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 -
Archive
RSS Link
Profile

yuki★hata

Author : yuki★hata
せめて月1回の更新をめざします~。

メールフォームはこちら

スポンサーリンク
スポンサーリンク
Copyright © ほんっとにはじめてのHTML5とCSS3 All Rights Reserved.