-
Notifications
You must be signed in to change notification settings - Fork 6
/
index.js
137 lines (118 loc) · 2.56 KB
/
index.js
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
/**
* Expose `Filter`.
*/
module.exports = Filter;
/**
* Initialize a new `Filter` with the given `matrix`.
*
* @param {Array} matrix
* @api public
*/
function Filter(matrix) {
if (!(this instanceof Filter)) return new Filter(matrix);
if (!matrix) throw new TypeError('convolution matrix required');
this.matrix = matrix;
this.factor(1);
this.bias(0);
}
/**
* Set width.
*
* @param {Number} n
* @return {Filter}
* @api public
*/
Filter.prototype.width = function(n){
this.w = n;
return this;
};
/**
* Set height.
*
* @param {Number} n
* @return {Filter}
* @api public
*/
Filter.prototype.height = function(n){
this.h = n;
return this;
};
/**
* Set factor, this may be used to
* ensure that all matrix elements
* produce a sum of 1.
*
* @param {Number} n
* @return {Filter}
* @api public
*/
Filter.prototype.factor = function(n){
this._factor = n;
return this;
};
/**
* Set bias, this may be used to
* brighten or darken the result.
*
* @param {Number} n
* @return {Filter}
* @api public
*/
Filter.prototype.bias = function(n){
this._bias = n;
return this;
};
/**
* Apply the filter to `input` and populate `result`.
*
* @param {ImageData} input
* @param {ImageData} result
* @api public
*/
Filter.prototype.apply = function(input, result){
var data = input.data;
var out = result.data;
var width = this.w;
var height = this.h;
var matrix = this.matrix;
var w = matrix[0].length;
var h = matrix.length;
var half = Math.floor(h / 2);
var factor = this._factor;
var bias = this._bias;
for (var y = 0; y < height - 1; y++) {
for (var x = 0; x < width - 1; x++) {
var px = (y * width + x) * 4;
var r = 0, g = 0, b = 0;
for (var cy = 0; cy < w; ++cy) {
for (var cx = 0; cx < h; ++cx) {
var cpx = ((y + (cy - half)) * width + (x + (cx - half))) * 4;
r += data[cpx + 0] * matrix[cy][cx];
g += data[cpx + 1] * matrix[cy][cx];
b += data[cpx + 2] * matrix[cy][cx];
}
}
out[px + 0] = factor * r + bias;
out[px + 1] = factor * g + bias;
out[px + 2] = factor * b + bias;
out[px + 3] = data[px + 3];
}
}
};
/**
* Apply filter to the entire `canvas`.
*
* @param {Canvas} canvas
* @api public
*/
Filter.prototype.canvas = function(canvas){
var w = canvas.width;
var h = canvas.height;
var ctx = canvas.getContext('2d');
var data = ctx.getImageData(0, 0, w, h);
var result = ctx.createImageData(w, h);
this.width(w);
this.height(h);
this.apply(data, result);
ctx.putImageData(result, 0, 0);
};