みかづきブログ その3

3ヶ月つづけてみました。

Canvasをつかって画像をぼかす習作 #4

kimizuka.hatenablog.com

前回 からの改修点

  1. 実装をクラス風に改良しました。
  2. imageDataのコピーを取りました。(以前のものは右下ほどぼけてました)

JavaScript

(function(win, doc) {

  "use Strict";

  function Blur(elm) {
    var that = this;

    _init();

    function _init() {
      that.elm     = elm;
      that.img     = new Image();
      that.canvas  = doc.createElement("canvas");
      that.ctx     = that.canvas.getContext("2d");
      that.src     = doc.defaultView.getComputedStyle(elm, null)["background-image"].replace(/^url\(/, "").replace(/\)$/, "").replace(/'|"/g, "");
      that.imgData = null;
      that._temp   = {};

      that.img.onload = that._handleOnLoad.bind(that);
      that.draw();
    }
  }

  Blur.CONST = {
    ZOOM  : 1,
    LEVEL : 11
  };

  Blur.prototype._handleOnLoad   = _handleOnLoad;
  Blur.prototype._blur           = _blur;
  Blur.prototype._separateSide   = _separateSide;
  Blur.prototype._getCenterIndex = _getCenterIndex;
  Blur.prototype.draw            = draw;

  function _handleOnLoad() {
    var that      = this,
        startTime = Date.now(),
        zoom      = Blur.CONST.ZOOM,
        width     = that.img.width * zoom | 0,
        height    = that.img.height * zoom | 0,
        level     = Blur.CONST.LEVEL;
        posList   = [];

    that.canvas.width  = width;
    that.canvas.height = height;

    that.ctx.drawImage(that.img, 0, 0, width, height);
    that.imgData            = that.ctx.getImageData(0, 0, width, height);
    that._temp.data         = that.imgData.data;
    that._temp.originalData = [].slice.call(that._temp.data);

    for (var i = 0, length = that._temp.data.length; i < length; i += 4 | 0) {
      that._temp.count = 0;
      that._temp.r     = 0;
      that._temp.g     = 0;
      that._temp.b     = 0;

      for (var j = 0, jLength = level * level; j < jLength; ++j | 0) {
        posList[j] = i + (4 * ((j / level | 0) - (level / 2 | 0))) * width + (4 * (j % level) - (level - 1) * 2);
      }

      if (level > 1) {
        that._separateSide(posList, level, width, height);
      }

      that._blur(posList, length, i);
    }

    that.imgData.data = [];
    that.ctx.putImageData(that.imgData, 0, 0);
    that.elm.style["background-image"] = "url(" + that.canvas.toDataURL("image/png") + ")";
    that._temp = {};
  }

  function _blur(arr, dataLength, index) {
      var that = this;

      for (var i = 0, length = arr.length; i < length; ++i | 0) {
        if (0 <= arr[i] && arr[i] < dataLength) {
          ++that._temp.count;

          that._temp.r += that._temp.originalData[arr[i] + 0];
          that._temp.g += that._temp.originalData[arr[i] + 1];
          that._temp.b += that._temp.originalData[arr[i] + 2];
        }
      }

      that._temp.data[index + 0] = that._temp.r / that._temp.count;
      that._temp.data[index + 1] = that._temp.g / that._temp.count;
      that._temp.data[index + 2] = that._temp.b / that._temp.count;
  }

  function _separateSide(arr, level, width, height) {
    var that         = this,
        centerIndex  = that._getCenterIndex(arr) / 4,
        levelLength  = (level - 1) / 2;
    
    (function _separateLeft() {
      for (var k = 0; k < levelLength; ++k | 0) {
        if (centerIndex % width === k) {
          for (var i = 0; i < level; ++i | 0) {
            for (var j = 0; j < levelLength - k; ++j | 0) {
              arr[i * level + j] = -1;
            }
          }
        }
      }
    })();

    (function _separateRight() {
      for (var k = 0; k < levelLength; ++k | 0) {
        if ((centerIndex + 1 + k) % width === 0) {
          for (var i = 0; i < level; ++i | 0) {
            for (var j = 0; j < levelLength - k; ++j | 0) {
              arr[(level - 1) + level * i - j] = -1;
            }
          }
        }
      }
    })();
  }

  function _getCenterIndex(arr) {
    return arr[arr.length / 2 | 0];
  }

  function draw() {
    var that = this;

    that.img.src = that.src;
  }

  win.Blur = Blur;

})(this, document);

(function(win, doc) {
    
    "use strict";
    
    new Blur(doc.body);
    
})(this, document);

DEMO

jsdo.it