ほんっとにはじめてのHTML5とCSS3
<canvas>サンプル10

canvasでビットマップを操作

●createImageData()、getImageData()、putImageData()

サンプル1_CanvasにImageDataでグラデーションを描く

createImageData() で CanvasサイズのImageDataを作ります。このImageDataのピクセルを操作してグラデーションを作り、putImageData() で Canvasに描画します。

お使いのブラウザはcanvas要素に対応していないので描画できませんでした

function Draw1() {
  var ctx1 = document.getElementById('canvas1').getContext('2d');
  // canvasのサイズでImageDataを作る
  var imageData = ctx1.createImageData(canvas1.width, canvas1.height);
  // ImageDataの操作
  var width = imageData.width, height = imageData.height; /*ImageDataの幅と高さを定義*/
  var imgd = imageData.data;
  for (var y = 0; y < height; ++y) { /*yが0から高さの数まで1ずつ増えるあいだで*/
    for (var x = 0; x < width; ++x) { /*xが0から幅の数まで1ずつ増えるあいだに*/
    var base = (x+y*width)*4; /*ImageDataのrgbaのうちrをゲットしといて*/
    // redは横方向に0から255、greenは縦方向に0から255、blueは斜めに255から0でちょこっと、透明度はマックスに
    imgd[base+0] = 255*x/width;
    imgd[base+1] = 255*y/height;
    imgd[base+2] = Math.max(255-x-y,0);
    imgd[base+3] = 255;
    }
  }
  // 制作したImageDataをcanvasに描く
  ctx1.putImageData(imageData, 0, 0);
};

Canvasの幅と高さが必要なため、for文が入れ子になっています。

サンプル2_canvasに既にあるグラフィックの一部を変更する

まず最初に Canvasに四角形を描画。getImageData() で Canvasの真ん中の小さい四角形だけピクセル情報をゲットし、透明度を変更にしてから putImageData() で Canvasに戻しています。

お使いのブラウザはcanvas要素に対応していないので描画できませんでした

function Draw2() {
  var ctx2 = document.getElementById('canvas2').getContext('2d');
  // まずCanvasの真ん中に200*200pxの赤い四角形を描く
  var center = {x:canvas2.width * 0.5, y:canvas2.height * 0.5};
  ctx2.translate(center.x, center.y);
  ctx2.fillStyle = 'rgb(255, 0, 0)';
  ctx2.fillRect(-100, -100, 200, 200);
  // 中央の100*100の四角部分のImageDataを取得
  var imageData = ctx2.getImageData(center.x - 50, center.y - 50, 100, 100);
  // ImageDataの操作
  var imgd = imageData.data;
  // length でImageDataのデータ総数をゲット。4で割ると総ピクセル数(そしてrの情報ね)
  var len = imgd.length/4;
  for (var i = 0; i < len; ++i) { /*変数i だけ使ったfor文なのでシンプルに*/
  // 透明度だけ2分の1にした(rgbのソース3行は不要だけど、一応書いときました)
  imgd[i*4+0] = imgd[i*4+0];
  imgd[i*4+1] = imgd[i*4+1];
  imgd[i*4+2] = imgd[i*4+2];
  imgd[i*4+3] = 255/2;
  }
  // 変更した内容をcanvasの真ん中に戻す
  ctx2.putImageData(imageData, center.x - 50, center.y - 50);
};

ImageData.data の操作だけで Canvas のサイズは関係ないので「length(dataの長さ=総数)」を使用。
サンプル1よりfor文がシンプルになりました。

サンプル3_グラフィックをグレースケールにする

Canvasに描画した写真のピクセル情報をゲットして、グレースケールに調整してからCanvasに戻します。

お使いのブラウザはcanvas要素に対応していないので描画できませんでした

function Draw3() {
  var ctx3 = document.getElementById('canvas3').getContext('2d');
  // 画像をcanvasの左側に描画
  var img = new Image();
  img.src = "img/img1peach.jpg";
  img.onload = function() {
    ctx3.drawImage(img, 0, 0);
    // この画像のImageDataをゲットしてグレーにします
    var imageData = ctx3.getImageData(0,0,300,300);
    var imgd = imageData.data;
    var len = imgd.length/4;
    for (var i = 0; i < len; ++i) {
		var gray = (imgd[i*4] + imgd[i*4+1] + imgd[i*4+2])/3;
		/*var gray = parseInt(imgd[i*4]*0.3 + imgd[i*4+1]*0.59 + imgd[i*4+2]*0.11);という方法も*/
		imgd[i*4] = imgd[i*4+1] = imgd[i*4+2] = gray;
		imgd[i*4+3] = 255;
    }
    // 変更した内容をcanvasの右側に戻す
    ctx3.putImageData(imageData, 320, 0);
  };
};

グレイスケールの計算は、rgbの情報を足して3で割る(平均化する)という方法でやってます。
画像処理アルゴリズムってやつを使った「r×0.3 + g×0.59 + b×0.11」という方法もあるらしい。(解像度が高い時はこっちのほうがキレイ)

サンプル4_グラフィックをセピア調にする

サンプル3のグレースケールの要領で画像をセピアにしてみました。
img要素で先に画像を表示し、その画像をCanvasにゲットし、セピアにして戻しています。
CanvasはCSSで img要素の真上に乗っけて、マウスオーバーすると下のimg要素が見えるようにしています。

画像にマウスオーバーしてください。
(セピア画像のフェイドイン・フェイドアウトはCSSを使った演出。Canvasとは無関係です。)

お使いのブラウザはcanvas要素に対応していないので描画できませんでした

サンプル4のJavascriptです。

function Draw4() {
  var ctx4 = document.getElementById('canvas4').getContext('2d');
  // img要素の画像を取り込む(roseはimg要素のidです)
  var getimg = document.getElementById('rose');
  // 取り込んだ画像をcanvas上に描画
  ctx4.drawImage(getimg, 0, 0);
  // この画像のImageDataをゲットしてセピアにします
  var imageData = ctx4.getImageData(0,0,300,300);
  var imgd = imageData.data;
  var len = imgd.length/4;
  for (var i = 0; i < len; ++i) {
    var gray = (imgd[i*4] + imgd[i*4+1] + imgd[i*4+2])/3;
    imgd[i*4] = parseInt((gray/255)*240);
	imgd[i*4+1] = parseInt((gray/255)*200);
	imgd[i*4+2] = parseInt((gray/255)*145);
    imgd[i*4+3] = 255;
    }
  // 変更した内容をcanvasに戻す
  ctx4.putImageData(imageData, 0, 0);
};

サンプル4のHTMLです。

<div id="photos">
  <img src="img/img2rose.jpg" id="rose">
  <canvas id="canvas4" width="300" height="300">
    <p>お使いのブラウザはcanvas要素に対応していないので描画できませんでした</p>
  </canvas>
</div>

img要素と canvas要素を div#photosで囲み、このdivに対して canvas要素を position:absolute で img要素の上にかぶせています。canvas要素はマウスオーバー時に opacity(透明度)が0になるように指定。
このサンプル4のCSSはこちら

div#photos {
	position:relative; 
	width:300px; 
	height:300px}
div#photos #canvas4 {
	position:absolute;
	top:0;
	left:0;
	opacity: 1;
	-webkit-transition: opacity 1s .2s;
	-moz-transition: opacity 1s .2s;
	-o-transition: opacity 1s .2s;
	transition: opacity 1s .2s}
div#photos:hover #canvas4 {
	opacity: 0;
	cursor: pointer}