みかづきブログ その3

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

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

kimizuka.hatenablog.com

前回 までのコードでは、

00 01 02 03 04
05 06 07 08 09
10 11 12 13 14
15 16 17 18 19
20 21 22 23 24

とピクセルがあったとき、自分の周りのピクセルの平均をとっていました。
例えば12番の値を出す際は 06 07 08 11 12 13 16 17 18 の平均です(LEVEL3の場合)。
しかし、例えば左端の 00 の値を出す際は 04 00 01 05 06 09 と右端の値まで含めて計算してしまっていました(上下は対策済み)。
今回は 00 の値は 00 01 05 06 で、05の値は 00 01 05 06 10 11 で計算するように改良をしてみました。

// forked from kimmy's "canvasで画像をぼかす" http://jsdo.it/kimmy/86vs
(function canvasBlur(win, doc, elm) {
    var body   = doc.body,
        img    = new Image(),
        canvas = doc.createElement("canvas"),
        ctx    = canvas.getContext("2d"),
        imgData, data;
    
    img.onload = function() {
        var ZOOM    = 1 / 4, // 縮小すると画質が落ち、スピードがあがる
            WIDTH   = this.width * ZOOM | 0,
            HEIGHT  = this.height * ZOOM | 0,
            LEVEL   = 3, // 自分を中心としたぼかす範囲の1辺の長さ(px)
            posList = [],
            r, g, b, count;
        
        canvas.width  = WIDTH;
        canvas.height = HEIGHT;
        
        ctx.drawImage(this, 0, 0, WIDTH, HEIGHT);
        
        imgData = ctx.getImageData(0, 0, WIDTH,  HEIGHT);
        data    = imgData.data;
        
        for (var i = 0, length = data.length; i < length; i += 4 | 0) {
            count   = 0;
            r       = 0;
            g       = 0;
            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);
            }
            
            _blur(posList, length);
        }
        
        ctx.putImageData(imgData, 0, 0);
        elm.style["background-image"] = "url(" + canvas.toDataURL("image/png") + ")";
        
        function _blur(arr, length) {
            if (LEVEL > 1) {
                _separateSide(arr);
            }
            
            for (var k = 0, kLength = arr.length; k < kLength; ++k | 0) {
                if (0 <= arr[k] && arr[k] < length) {                    
                    ++count;
                    
                    r += data[arr[k] + 0];
                    g += data[arr[k] + 1];
                    b += data[arr[k] + 2];
                }
            }
            
            data[i + 0] = r / count;
            data[i + 1] = g / count;
            data[i + 2] = b / count;
        }
        
        function _separateSide(arr) { // 左右を繋げない
            var centerIndex  = _getCenter(arr) / 4,
                levelLength  = (LEVEL - 1) / 2;
            
            (function _separateLeft() {
                for (var k = 0; k < levelLength; ++k) {
                    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) {
                    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 _getCenter(arr) {
            return arr[arr.length / 2 | 0];
        }
    };
    
    img.src = doc.defaultView.getComputedStyle(elm, null)["background-image"].replace(/^url\(/, "").replace(/\)$/, "").replace(/'|"/g, "");
    
})(this, document, document.body);

DEMO

jsdo.it



今回は以上です。