2013/12/20更新

[jQuery] 画像の色を見て、ドミナントカラーを親要素の背景色に反映するプラグイン。色の抽出方法が気になったので調べてみた

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

こんにちは、@yoheiMuneです。
最近、GitHubで人気のリポジトリ25というGithubのまとめサイトを見つけて、色々と見てました。 言語別(CSSとかJavaScriptとかJavaとか)に、最近Hotなレポジトリが見れるのですが、いくつか気になったものがあったので、コードリーディング的になことをしてみました。

今日はその中で、jquery.adaptive-backgrounds.js@githubが面白そうだったので、今日はこれ取り上げたいと思います。

画像



jquery.adaptive-backgrounds.jsとは

jquery.adaptive-backgrounds.jsは、github上でStarが2,000個以上付いていて、ちょっと注目なやつっぽいです。
内容はというと、画像のドミナントカラーを抜き出して、親要素の背景に設定するという感じらしいです。

(サンプル)
画像
引用:https://github.com/briangonzalez/jquery.adaptive-backgrounds.js

他にも色々とデモページが用意されているので、試してみると良さげかも。


ドミナントカラーを抽出している仕組み

この点が気になったので、少し調べてみました。
色味を抽出する仕組みは、rgbaster.js@githubを使っているようです。
ではその中身をと思い、見てみました。 結論から言うと、HTML5 CanvasのimageDataを使って、各ピクセルの色を読み込んで(実際にはパフォーマンスを考慮して読み飛ばすピクセルもあるようです)、最終的に集計しているようです。
rgbaster.jsの実装は以下のコードです。
;(function(window, undefined){

  "use strict";

  // Helper functions.
  // Canvasの2dコンテキストを取得する
  var getContext = function(){
    return document.createElement("canvas").getContext('2d');
  };


  // 画像からイメージデータ(配列)を取得する
  var getImageData = function(img, loaded){

    var imgObj = new Image();
    imgObj.crossOrigin = "Anonymous";
    imgObj.src = img.src;

    imgObj.onload = function(){
      var context = getContext();
      context.drawImage(imgObj, 0, 0);

      var imageData = context.getImageData(0, 0, img.width, img.height);
      loaded && loaded(imageData.data);
    };

  };

  // css用の色指定を作成
  var makeRGB = function(name){
    return ['rgb(', name, ')'].join('');
  };

  var mapPalette = function(palette){
    return palette.map(function(c){ return makeRGB(c.name) })
  }

  /**
  *     RGBaster Object
  *
  *     @method colors
  *
  */
  var BLOCKSIZE = 5;
  var PALETTESIZE = 10;

  var RGBaster = {};

  RGBaster.colors = function(img, success, paletteSize){
    getImageData(img, function(data){

              var length        = data.length,
                  colorCounts   = {},
                  rgbString     = '',
                  rgb           = [],
                  colors        = {
                    dominant: { name: '', count: 0 },
                    palette:  Array.apply(null, Array(paletteSize || PALETTESIZE)).map(Boolean).map(function(a){ return { name: '0,0,0', count: 0 } })
                  };

              // Loop over all pixels, in BLOCKSIZE iterations.
              // BLOCKSIZEで間引いた感じで、全ピクセルの色を調べていく
              var i = 0;
              while ( i < length ) {
                rgb[0] = data[i];
                rgb[1] = data[i+1];
                rgb[2] = data[i+2];
                rgbString = rgb.join(",");

                // Keep track of counts.
                // 色数のインクリメント
                if ( rgbString in colorCounts ) {
                  colorCounts[rgbString] = colorCounts[rgbString] + 1;
                }
                else{
                  colorCounts[rgbString] = 1;
                }

                // Find dominant and palette, ignoring black/white pixels.
                // 色数が最大の場合にはドミナントカラーに(でも白と黒は除外)
                if ( rgbString !== "0,0,0" && rgbString !== "255,255,255" ) {
                  var colorCount = colorCounts[rgbString]
                  if ( colorCount > colors.dominant.count ){
                    colors.dominant.name = rgbString;
                    colors.dominant.count = colorCount;
                  } else {
                    colors.palette.some(function(c){
                      if ( colorCount > c.count ) {
                        c.name = rgbString;
                        c.count = colorCount;
                        return true;
                      }
                    });
                  }
                }

                // Increment!
                i += BLOCKSIZE * 4;
              }

              // コールバックあれば
              success && success({
                dominant: makeRGB(colors.dominant.name),
                palette:  mapPalette(colors.palette)
              });
    });
  }

  window.RGBaster = window.RGBaster || RGBaster;

})(window);
全部貼付けてしまった。でも100行ちょっとで色味の抽出が出来るのは便利ですね。



最後に

githubで気になったモジュールの実装内容を見てみる、という超雑多なブログでした。 でも気になった機能の実装を学んでいくのは意外と楽しくていい感じです。
また次も見つけたらブログに書きたいと思います。

最後までご覧頂きましてありがとうございました。





こんな記事もいかがですか?

RSS画像

もしご興味をお持ち頂けましたら、ぜひRSSへの登録をお願い致します。