canvasでビットマップを操作
●createImageData()、getImageData()、putImageData()
createImageData() で CanvasサイズのImageDataを作ります。このImageDataのピクセルを操作してグラデーションを作り、putImageData() で 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文が入れ子になっています。
まず最初に Canvasに四角形を描画。getImageData() で Canvasの真ん中の小さい四角形だけピクセル情報をゲットし、透明度を変更にしてから putImageData() で 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文がシンプルになりました。
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」という方法もあるらしい。(解像度が高い時はこっちのほうがキレイ)
サンプル3のグレースケールの要領で画像をセピアにしてみました。
img要素で先に画像を表示し、その画像をCanvasにゲットし、セピアにして戻しています。
CanvasはCSSで img要素の真上に乗っけて、マウスオーバーすると下のimg要素が見えるようにしています。
画像にマウスオーバーしてください。
(セピア画像のフェイドイン・フェイドアウトはCSSを使った演出。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}