タイトルわかりにく!! グリッチっぽいあれです。

元の画像
サンプル1: 赤を→2
サンプル2: 緑を←2, ↑2
サンプル3: 青を←4, ↓3

加工の流れは次の通りです。

  1. 全ピクセル (ImageData.data) をスキャンして、各座標の指定チャンネルの値を取得したあと、現在の値をゼロにします。
  2. ふたたび全ピクセルをスキャンして、移動先座標の指定チャンネルに、取得しておいた値を加算します。

移動先座標を算出するので、2回目のスキャンはxyでやってます。xyの座標は、(y * 幅 + x) * 4ImageData.data のインデックスに変換できます。

/**
 * 指定チャンネルの描画位置をずらす
 * @param {HTMLCanvasElement} canvas - canvas要素
 * @param {Number} channel - 0: 赤, 1: 緑, 2: 青
 * @param {Number} shiftX - 右方向移動量 (px)
 * @param {Number} shiftY - 下方向移動量 (px)
 */
function shiftRGB(canvas, channel, shiftX, shiftY) {
	var ctx = canvas.getContext('2d');
	var w = canvas.width;
	var h = canvas.height;
	var tmp = [];
	var imageData = ctx.getImageData(0, 0, w, h);
	for (var i = 0, len = imageData.data.length; i < len; i += 4) {
		tmp[i] = imageData.data[i + channel];
		imageData.data[i + channel] = 0;
	}
	for (var y = 0; y < h; ++y) {
		for (var x = 0; x < w; ++x) {
			var dstX = x + shiftX;
			var dstY = y + shiftY;
			if (0 <= dstX && dstX < w && 0 <= dstY && dstY < h) {
				var i = (y * w + x) * 4;
				var dstI = (dstY * w + dstX) * 4;
				imageData.data[dstI + channel] = imageData.data[dstI + channel] + tmp[i];
			}
		}
	}
	ctx.putImageData(imageData, 0, 0);
}

以下、ページ上部でやってるサンプルの例です。

/**
 * Canvasに元画像をコピーして返却
 * @param {HTMLCanvasElement} canvas - コピー先のcanvas要素
 * @return {HTMLCanvasElement} コピー済みcanvas
 */
function copyOrgTo(canvas) {
	var org = document.getElementById('exsample-org'); // 元画像要素のid
	canvas.width = org.width;
	canvas.height = org.height;
	var ctx = canvas.getContext('2d');
	ctx.drawImage(org, 0, 0, canvas.width, canvas.height);
	return canvas;
}

var sample1 = copyOrgTo(document.getElementById('exsample-1')); // 描画先canvasのid
var sample2 = copyOrgTo(document.getElementById('exsample-2'));
var sample3 = copyOrgTo(document.getElementById('exsample-3'));

// サンプル1: 赤を→2
shiftRGB(sample1, 0, 2, 0); 

// サンプル2: 緑を←2, ↑2
shiftRGB(sample2, 1, -2, -2); 

// サンプル3: 青を←4, ↓3
shiftRGB(sample3, 2, -4, 3);