[69-11] Canvasでビットマップを操作しよう(ビットマップの明度や色調の変更)

最終更新日:2019年02月06日  (初回投稿日:2015年03月11日)

Canvasはビットマップ画像のピクセル情報を数値として扱えます。
それによって、例えばカラーの画像をグレーにしたり...など、いろんなことができます。
画像を2つ用意せずに、カラー画像をグレースケールに変化させたりできます。使えますね♪

それをやるにはまず ImageData の概念を理解して、ImageDataの中の「data」の構造を知る必要がありました。順番に見ていきましょう。

本日のINDEX
  1. ImageDataのメソッド(createImageData, getImageData, putImageData)
  2. 各ピクセル情報の取り出し方(Canvas Pixel Array)
    1. data の構造
    2. canvasの幅と高さが必要な場合の x,y を使った dataの取り出し方
    3. lengthプロパティを使った dataの取り出し方
  3. Canvasに createImageData でグラデーションを描く
  4. Canvas上のグラフィックの一部を変更する
  5. Canvasに描画した写真をグレースケールにする
  6. img要素の画像をCanvasにゲットしてセピア調にする

今回のサンプルです。


サンプル1

Canvasに createImageData でグラデーションを描く。


サンプル2

Canvas上のグラフィックの一部を変更する。


サンプル3

Canvasに描画した写真をグレースケールにする。


サンプル4

img要素の画像を Canvasにゲットしてセピア調にする。

ImageDataのメソッド
 (createImageData, getImageData, putImageData)

Canvasでピクセルデータをいじるために ImageData というオブジェクトがあります。
ImageData はビットマップ。ピクセルの集合体なんです。
ImageData には以下のメソッドが用意されています。

  • createImageData(width, height) 幅と高さのあるImageDataを作る
  • createImageData(imagedata) ImageDataと同じサイズのImageDataを作る
  • getImageData(x, y, width, height) Canvas上のモノをImageDataにする
  • putImageData(imagedata, x, y) ImageDataをCanvasに書き出す

createImageData は、何もネタが無いところでImageDataを作るためのもの。最初は高さと幅だけがある透明なImageDataができます。これを編集して、createImageData(imagedata) に渡すと別編集ができるというわけ。

getImageData は、今Canvasにあるグラフィックをゲット(get)します。
x,y で左上の始点を、width, height で幅と高さを指定してゲット。それを編集するわけです。

createImageDatagetImageData で取り込んだ ImageData は、各ピクセルデータを編集できるようになっています。詳細はこのあと説明します。

で、編集し終わった ImageData は、まだ宙に浮いた状態ってかんじ。この時点ではブラウザ上で見えません。
そこで putImageData で Canvasに戻して(put)やる必要があるんです。

putImageDataは、詳しくは下記のような引数を持っていて、dirtyX以降の引数は省略可能です。
putImageData(imagedata, x, y, dirtyX, dirtyY, dirtyWidth, dirtyHeight)
引数 imagedataは編集し終わった ImageData、x,y は Canvas上の描き出しの始点です。
dirtyX, dirtyY は ImageData上での切り出す始点、dirtyWidth, dirtyHeight はその始点からの幅と高さです。作った ImageDataをトリミングできるんですね。
(でもなんでダーティなんですかね? 闇の中にいるイメージでしょうか?)

各ピクセル情報の取り出し方(Canvas Pixel Array)

create か get した ImageData は、3つのプロパティを使うことで、いろいろ操作できます。

  • width ImageData の幅
  • height ImageData の高さ
  • data ImageData の各ピクセルのrgba。このすぐあと↓詳細。

data の構造

ImageData はビットマップ。なので各ピクセルが集まって画像を作っているのですが、
この「data」は1ピクセルごとにさらに細かく「rgba」の4つの情報に分かれています。
rgba とはご存知の、赤・緑・青・透明度(アルファ)の情報で 0〜255の256段階で表現されます。
(ってことは、Canvas の ImageData は256階調ってことですね)
data は1つ1つのピクセルの rgba情報 というわけです。

data はこの rgba の情報を 4つ一組で「配列」として持っているので javaScript で編集できるという画期的なものなんだそうです。
この配列のことを「Canvas Pixel Array」って言うそうですよ。

data について図解するとこんなかんじ。
1個1個のピクセルを、左上から始まって最後の右下のピクセルまで、下図のようにダ〜ッと読むんだそうです。

画像の1個1個のピクセルの中のrgba情報を data(ImageData.data)と呼ぶということね。
dataの幅は width(ImageData.width)、高さは height(ImageData.height)と呼びます。

さて、いよいよ各ピクセルデータを取り出す方法です。
r(赤の情報)なら r だけを取り出すことができてはじめていろんな加工ができるわけですから、これができなきゃ話になんない。

Canvasの幅と高さが必要な場合の x,y を使った dataの取り出し方

ImageData を「Canvas のサイズに合わせてグラデーションにしたい」など、幅や高さが必要な場合は、x,y座標を使います。
計算式に納得するために、4×3ピクセルのサイズの画像で考えてみました。
まずは下の図を見てください。
各ピクセルは、x0,y0 〜 x3,y2 まであります。
ピンクのピクセル(x2,y1)に注目して、このピクセルがスタートから何番目にいるか考えてみます。

今いる座標の横位置は簡単ですね。x座標のままでOK。
今いる行より前(上)のピクセル数は、自分の y座標 × width(幅)で出すことができます。ですので、それを足せばOK。
x + y * width
ピンクのピクセルに当てはめてみると、
2 + 1 * 4 = 6 アタリですね。
(1からでなく0からカウントしますよ。配列なので)

そして、各ピクセルに rgba4つの情報があるので、上の式に単純に4をかけます。
(x + y * width) * 4
これが各ピクセルの先頭の「r」の情報です。
例のピンクのピクセルに当てはめてみると、
(2 + 1 * 4) * 4 = 24 合ってますね。

x,y座標は、すべてのピクセルの座標を当てはめることができるのですから、
この式で、すべてのピクセルの「r」の情報をピックアップできるというわけです。

で、g、b、a は1つずつずれて配置されているわけですから、
r が、(x + y * width) * 4 なら、
g は、(x + y * width) * 4 + 1
b は、(x + y * width) * 4 + 2
a は、(x + y * width) * 4 + 3 で取り出せるというわけです。

この x,y座標を使う方法は、今回のサンプル1で使っています。
実際には下記のように for文を使ってrgbaをピックアップします。(詳細はサンプルで)

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をゲットしといて*/
    imgd[base+0] = /*ここに r の情報の操作を書きます*/ ;
    imgd[base+1] = /*ここに g の情報の操作を書きます*/ ;
    imgd[base+2] = /*ここに b の情報の操作を書きます*/ ;
    imgd[base+3] = /*ここに a の情報の操作を書きます*/ ;
    }
  }

lengthプロパティを使った dataの取り出し方

こっちのほうが使用頻度高いかも。(今回のサンプルでは、サンプル1 以外全部これを使ってます)

javaScriptのプロパティの length は、その名のとおり文字列の長さ(というか情報の総数)をゲットできます。
そうやってゲットした「data」の総数を4で割ったら「r」の情報というわけです。

実際には下記のように for文を使ってrgbaをピックアップします。(詳細はサンプルで)
r をピックアップしたら、後の gba は1ずつ足してピクアップできるというのは x,y 座標の考え方と同じです。

	var imgd = imageData.data;
    var len = imgd.length/4;
    for (var i = 0; i < len; ++i) {
        imgd[i*4] = /*ここに r の情報の操作を書きます*/ ;
        imgd[i*4+1] = /*ここに g の情報の操作を書きます*/ ;
        imgd[i*4+2] = /*ここに b の情報の操作を書きます*/ ;
        imgd[i*4+3] = /*ここに a の情報の操作を書きます*/ ;
    }

では、以上を踏まえて、実際に「data」を操作してみましょう。

Canvasに createImageData でグラデーションを描く

サンプル1は、Canvasに createImageData でグラデーションを描いています。
(クリックで別ウィンドウで開きます)

このカンバスは width="600" height="220" です。
r(red)は横方向に0 〜 255 まで増して行くようにしています。600ピクセルを256段階になるように設定します。
g(green)は縦方向に0 〜 255 まで増加。220ピクセルを256段階になるように設定します。
b(blue)は左上から斜め方向にに255 〜 0 にしています。これは256になった時点で終わります。
a(alpha value 透明度)はマックスの 255 にしています。

このグラデーション、CSSのグラデと違ってかなり複雑なことができるので、サイトの背景などに使えそうです。

Canvas上のグラフィックの一部を変更する

サンプル2は、Canvas上にまず赤い四角形を描画。
その真ん中を getImageData でゲットして、a(alpha value 透明度)だけ半調にして putImageData で Canvasに戻しています。
(クリックで別ウィンドウで開きます)

これは写真を使ったら、おもしろい表現ができそうですね。

Canvasに描画した写真をグレースケールにする

サンプル3は、グレースケールを試してみました。
まず Canvas上に写真を描画。(写真の描画は「[69-4] canvasに画像を描画しよう」に詳細)
それを getImageData でゲットして、グレースケールにしてから putImageData で隣りの Canvasに戻しています。
(クリックで別ウィンドウで開きます)

1つのカラー画像を用意するだけ、グレースケールの画像は不要なので、フォトギャラリーなどに利用すると便利ですね。

img要素の画像をCanvasにゲットしてセピア調にする

サンプル4は、グレースケールの応用で、セピア調にしています。
(クリックで別ウィンドウで開きます)

このサンプルでは img要素から画像を Canvasに取り込んでいます。
それを drawImage で Canvasに描画。これをさらに getImageData でゲットして、セピア調にしてから putImageData で Canvasに戻しています。

このサンプルは、マウスオーバーで元のカラー画像が現れるようにしていますが、これはCSSによる演出です。
CSSで img要素の上に canvas要素が乗っかるようにし、マウスオーバーで canvas要素の透明度が 0 になるようにしています。

フォトギャラリーを作る(外部参考サイト)

Canvasを使ったフォトギャラリーで、参考になるサイトを見つけました。
2012年の記事で、ちょっと古いですが、十分勉強になりました。

PEHAA BLOG
「Create your portfolio gallery using html5 canvas – tutorial」

こちらは、HTML上にCanvas要素は書かず、javaScriptでcanvas要素を imageの前に書き出すようにしています。
たくさんの写真のソースもシンプルにできています。
ソースの詳しい説明も載っていますよ。

次回予告

やっと Canvasっておもしろい!って思えるところまで来た感があります。
最初のころの四角とか線とか描いてたときは、けっこうつまんなかったですね(笑)

次回は、canvasをサイトの背景に使ってみます。

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

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

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

「初心者ですがレンタルサーバーはどこがいい?」というご質問をよくいただきます。
自由にファイルをアップロードできる自分のサーバがあると便利ですよね。ローカル環境じゃなくサーバ上で試してみたい時がありますからね。
私が使っているのは、 スターサーバーロリポップ!です。どちらも管理画面がわかりやすく、マニュアルも充実していて、料金も安い。どちらもライトプラン以上で WordPress が使えます。
初心者が始めやすいサーバだと思います。

ちょっと料金は高いけど、さくらのレンタルサーバや、エックスサーバー は、やはり老舗なのでおすすめです。
両方とも高スペックでコスパが良く、老舗でユーザーが多いので、質問する場がたくさんあります。初心者だけど仕事でサーバが欲しい場合は、安心なのではないかと思います。

スポンサーリンク

コメントの投稿

ご注意:メールアドレスは書かないで
「コメントを送信する」ボタンを押した後の「確認画面」で、メールアドレス・URL などを入力できるようになっており、メールアドレス・URL は、そのままオートリンクになる仕様です。
当方でメールアドレスだけ削除することも、メールアドレスを非公開にすることもできません
メールアドレスは書かないでください。詳しくはこちらにまとめましたのでご覧ください。

スポンサーリンク
最新記事
Category
オススメの本
Links
Calendar
11 | 2023/12 | 01
- - - - - 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
31 - - - - - -
Archive
Profile

yuki★hata

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

メールフォームはこちら

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