Skip to content

Commit 424dfff

Browse files
committed
Merge branch 'feat/3'. Closes #3
2 parents 3d601bf + a9b4000 commit 424dfff

File tree

8 files changed

+208
-31
lines changed

8 files changed

+208
-31
lines changed

build/bitmap.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -641,7 +641,12 @@ define(["require", "exports", "./histogram", "./transform", "./filter"], functio
641641
console.log(this._bitmap.current);
642642
};
643643
Bitmap.prototype.kernel = function (width, height, customKernel) {
644-
this._filter.setKernel(width, height);
644+
if (customKernel) {
645+
this._filter.setKernel(width, height, customKernel);
646+
}
647+
else {
648+
this._filter.setKernel(width, height);
649+
}
645650
};
646651
Bitmap.prototype.blur = function (type) {
647652
if (type === "box") {
@@ -659,6 +664,9 @@ define(["require", "exports", "./histogram", "./transform", "./filter"], functio
659664
this._bitmap.current.data = this._filter.edge(1, this._bitmap.current.data, this._bitmap.current.width, this._bitmap.current.height);
660665
}
661666
};
667+
Bitmap.prototype.customFilter = function () {
668+
this._bitmap.current.data = this._filter.custom(this._bitmap.current.data, this._bitmap.current.width, this._bitmap.current.height);
669+
};
662670
Bitmap.prototype.drawProperties = function (properties) {
663671
properties[0].innerHTML = this._bitmap.infoHeader.width;
664672
properties[1].innerHTML = this._bitmap.infoHeader.height;

build/filter.js

Lines changed: 37 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,29 @@ define(["require", "exports"], function (require, exports) {
161161
}
162162
return data;
163163
};
164+
Filter.prototype.custom = function (image, width, height) {
165+
var data = new Uint8ClampedArray(width * height * 4);
166+
for (var y = 0; y < height; y++) {
167+
for (var x = 0; x < width; x++) {
168+
var location_5 = y * width * 4 + x * 4;
169+
var neighbors = this.getNeighbors(image, width, height, [x, y]);
170+
var total = new RGB();
171+
for (var i = 0; i < this.kernel.width * this.kernel.height; i++) {
172+
total.r += this.kernel.matrix[i] * neighbors[i].r;
173+
total.g += this.kernel.matrix[i] * neighbors[i].g;
174+
total.b += this.kernel.matrix[i] * neighbors[i].b;
175+
}
176+
total.r = this.truncate(total.r);
177+
total.g = this.truncate(total.g);
178+
total.b = this.truncate(total.b);
179+
data[location_5] = total.r;
180+
data[location_5 + 1] = total.g;
181+
data[location_5 + 2] = total.b;
182+
data[location_5 + 3] = 0xFF;
183+
}
184+
}
185+
return data;
186+
};
164187
Filter.prototype.truncate = function (value) {
165188
if (value < 0)
166189
value = 0;
@@ -177,41 +200,41 @@ define(["require", "exports"], function (require, exports) {
177200
var neighbor = new Array(4);
178201
var pixel = new RGB();
179202
if (x === 0 && y === 0) {
180-
var location_5 = index[1] * width * 4 + index[0] * 4;
181-
neighbor[0] = new RGB(image[location_5], image[location_5 + 1], image[location_5 + 2]);
203+
var location_6 = index[1] * width * 4 + index[0] * 4;
204+
neighbor[0] = new RGB(image[location_6], image[location_6 + 1], image[location_6 + 2]);
182205
matrix[halfh * this.kernel.width + halfw] = neighbor[0];
183206
}
184207
else {
185208
if (index[1] - y < 0 || index[0] - x < 0) {
186209
neighbor[0] = new RGB();
187210
}
188211
else {
189-
var location_6 = (index[1] - y) * width * 4 + (index[0] - x) * 4;
190-
neighbor[0] = new RGB(image[location_6], image[location_6 + 1], image[location_6 + 2]);
212+
var location_7 = (index[1] - y) * width * 4 + (index[0] - x) * 4;
213+
neighbor[0] = new RGB(image[location_7], image[location_7 + 1], image[location_7 + 2]);
191214
}
192215
matrix[(halfh - y) * this.kernel.width + (halfw - x)] = neighbor[0];
193216
if (index[1] - y < 0 || index[0] + x >= width) {
194217
neighbor[1] = new RGB();
195218
}
196219
else {
197-
var location_7 = (index[1] - y) * width * 4 + (index[0] + x) * 4;
198-
neighbor[1] = new RGB(image[location_7], image[location_7 + 1], image[location_7 + 2]);
220+
var location_8 = (index[1] - y) * width * 4 + (index[0] + x) * 4;
221+
neighbor[1] = new RGB(image[location_8], image[location_8 + 1], image[location_8 + 2]);
199222
}
200223
matrix[(halfh - y) * this.kernel.width + (halfw + x)] = neighbor[1];
201224
if (index[1] + y >= height || index[0] - x < 0) {
202225
neighbor[2] = new RGB();
203226
}
204227
else {
205-
var location_8 = (index[1] + y) * width * 4 + (index[0] - x) * 4;
206-
neighbor[2] = new RGB(image[location_8], image[location_8 + 1], image[location_8 + 2]);
228+
var location_9 = (index[1] + y) * width * 4 + (index[0] - x) * 4;
229+
neighbor[2] = new RGB(image[location_9], image[location_9 + 1], image[location_9 + 2]);
207230
}
208231
matrix[(halfh + y) * this.kernel.width + (halfw - x)] = neighbor[2];
209232
if (index[1] + y >= height || index[0] + x >= width) {
210233
neighbor[3] = new RGB();
211234
}
212235
else {
213-
var location_9 = (index[1] + y) * width * 4 + (index[0] + x) * 4;
214-
neighbor[3] = new RGB(image[location_9], image[location_9 + 1], image[location_9 + 2]);
236+
var location_10 = (index[1] + y) * width * 4 + (index[0] + x) * 4;
237+
neighbor[3] = new RGB(image[location_10], image[location_10 + 1], image[location_10 + 2]);
215238
}
216239
matrix[(halfh + y) * this.kernel.width + (halfw + x)] = neighbor[3];
217240
}
@@ -220,12 +243,11 @@ define(["require", "exports"], function (require, exports) {
220243
return matrix;
221244
};
222245
Filter.prototype.setKernel = function (width, height, customKernel) {
246+
this.kernel.height = height;
247+
this.kernel.width = width;
248+
this.kernel.matrix = new Array(height * width);
223249
if (customKernel) {
224-
}
225-
else {
226-
this.kernel.height = height;
227-
this.kernel.width = width;
228-
this.kernel.matrix = new Array(height * width);
250+
this.kernel.matrix = customKernel;
229251
}
230252
};
231253
return Filter;

build/main.js

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,23 +135,57 @@ define(["require", "exports", "./bitmap"], function (require, exports, bitmap_1)
135135
bmp.drawOnCanvas(canvas);
136136
});
137137
document.getElementById("boxBlur").addEventListener("click", function () {
138-
bmp.kernel(3, 3);
138+
var input = +document.getElementById("inputKernel").value;
139+
bmp.kernel(input, input);
139140
bmp.blur("box");
140141
bmp.drawOnCanvas(canvas);
141142
});
142143
document.getElementById("gaussBlur").addEventListener("click", function () {
143-
bmp.kernel(3, 3);
144+
var input = +document.getElementById("inputKernel").value;
145+
bmp.kernel(input, input);
144146
bmp.blur("gauss");
145147
bmp.drawOnCanvas(canvas);
146148
});
147149
document.getElementById("prewittEdge").addEventListener("click", function () {
150+
var input = +document.getElementById("inputKernel").value;
148151
bmp.kernel(3, 3);
149152
bmp.edge("prewitt");
150153
bmp.drawOnCanvas(canvas);
151154
});
152155
document.getElementById("sobelEdge").addEventListener("click", function () {
156+
var input = +document.getElementById("inputKernel").value;
153157
bmp.kernel(3, 3);
154158
bmp.edge("sobel");
155159
bmp.drawOnCanvas(canvas);
156160
});
161+
document.getElementById("customFilter").addEventListener("click", function () {
162+
var input = +document.getElementById("inputKernel").value;
163+
var matrix = document.querySelector("#kernelMatrix");
164+
matrix.innerHTML = "";
165+
for (var y = 0; y < input; y++) {
166+
var row = "";
167+
for (var x = 0; x < input; x++) {
168+
row += "<th><input type='number' id='matrix" + (y * input + x) + "' value=1></th>";
169+
}
170+
var tr = document.createElement("tr");
171+
tr.innerHTML = row;
172+
matrix.appendChild(tr);
173+
}
174+
document.getElementById("custom").style.display = "block";
175+
document.getElementsByClassName("close")[1].addEventListener("click", function () {
176+
document.getElementById("custom").style.display = "none";
177+
});
178+
document.getElementById("btnCustom").addEventListener("click", function () {
179+
var custom = new Array(input * input);
180+
for (var y = 0; y < input; y++) {
181+
for (var x = 0; x < input; x++) {
182+
custom[y * input + x] = +document.getElementById("matrix" + (y * input + x)).value;
183+
}
184+
}
185+
document.getElementById("custom").style.display = "none";
186+
bmp.kernel(input, input, custom);
187+
bmp.customFilter();
188+
bmp.drawOnCanvas(canvas);
189+
});
190+
});
157191
});

src/bitmap.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -720,7 +720,12 @@ export class Bitmap {
720720

721721
// set kernel
722722
public kernel(width: number, height: number, customKernel?: number []) {
723-
this._filter.setKernel(width, height);
723+
if (customKernel) {
724+
this._filter.setKernel(width, height, customKernel);
725+
} else {
726+
this._filter.setKernel(width, height);
727+
}
728+
724729
}
725730

726731
public blur(type: string) {
@@ -741,6 +746,10 @@ export class Bitmap {
741746
}
742747
}
743748

749+
public customFilter() {
750+
this._bitmap.current.data = this._filter.custom(this._bitmap.current.data, this._bitmap.current.width, this._bitmap.current.height);
751+
}
752+
744753
public drawProperties(properties: [HTMLElement, HTMLElement, HTMLElement, HTMLElement]) {
745754
properties[0].innerHTML = this._bitmap.infoHeader.width;
746755
properties[1].innerHTML = this._bitmap.infoHeader.height;

src/filter.ts

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,32 @@ export class Filter {
178178
return data;
179179
}
180180

181+
public custom(image: Uint8ClampedArray, width: number, height: number): Uint8ClampedArray {
182+
let data: any = new Uint8ClampedArray(width * height * 4);
183+
for (let y: number = 0; y < height; y++) {
184+
for (let x: number = 0; x < width; x++) {
185+
let location: number = y * width * 4 + x * 4;
186+
let neighbors: RGB [] = this.getNeighbors(image, width, height, [x, y]);
187+
// do multiplication!
188+
let total: RGB = new RGB();
189+
for (let i: number = 0; i < this.kernel.width * this.kernel.height; i++) {
190+
total.r += this.kernel.matrix[i] * neighbors[i].r;
191+
total.g += this.kernel.matrix[i] * neighbors[i].g;
192+
total.b += this.kernel.matrix[i] * neighbors[i].b;
193+
}
194+
total.r = this.truncate(total.r);
195+
total.g = this.truncate(total.g);
196+
total.b = this.truncate(total.b);
197+
198+
data[location] = total.r;
199+
data[location + 1] = total.g;
200+
data[location + 2] = total.b;
201+
data[location + 3] = 0xFF;
202+
}
203+
}
204+
return data;
205+
}
206+
181207
private truncate(value: number): number {
182208
if (value < 0) value = 0;
183209
if (value > 255) value = 255;
@@ -425,12 +451,11 @@ export class Filter {
425451
return matrix;
426452
}
427453
public setKernel (width: number, height: number, customKernel?: number []) {
454+
this.kernel.height = height;
455+
this.kernel.width = width;
456+
this.kernel.matrix = new Array<number>(height * width);
428457
if (customKernel) {
429-
// load custom kernel
430-
} else {
431-
this.kernel.height = height;
432-
this.kernel.width = width;
433-
this.kernel.matrix = new Array<number>(height * width);
458+
this.kernel.matrix = customKernel;
434459
}
435460
}
436461
}

src/main.ts

Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -171,36 +171,72 @@ document.getElementById("rotateBtn").addEventListener("click", () => {
171171

172172
// box blurring
173173
document.getElementById("boxBlur").addEventListener("click", () => {
174-
// let kernel: number = + (<HTMLInputElement>document.getElementById("rotateAngle")).value;
174+
let input: number = +(<HTMLInputElement>document.getElementById("inputKernel")).value;
175175

176-
bmp.kernel(3, 3);
176+
bmp.kernel(input, input);
177177
bmp.blur("box");
178178
bmp.drawOnCanvas(canvas);
179179
});
180180

181181
// gauss blurring
182182
document.getElementById("gaussBlur").addEventListener("click", () => {
183-
// let kernel: number = + (<HTMLInputElement>document.getElementById("rotateAngle")).value;
183+
let input: number = +(<HTMLInputElement>document.getElementById("inputKernel")).value;
184184

185-
bmp.kernel(3, 3);
185+
bmp.kernel(input, input);
186186
bmp.blur("gauss");
187187
bmp.drawOnCanvas(canvas);
188188
});
189189

190190
// prewitt edge
191191
document.getElementById("prewittEdge").addEventListener("click", () => {
192-
// let kernel: number = + (<HTMLInputElement>document.getElementById("rotateAngle")).value;
192+
let input: number = +(<HTMLInputElement>document.getElementById("inputKernel")).value;
193193

194194
bmp.kernel(3, 3);
195195
bmp.edge("prewitt");
196196
bmp.drawOnCanvas(canvas);
197197
});
198198

199-
// prewitt edge
199+
// sobel edge
200200
document.getElementById("sobelEdge").addEventListener("click", () => {
201-
// let kernel: number = + (<HTMLInputElement>document.getElementById("rotateAngle")).value;
201+
let input: number = +(<HTMLInputElement>document.getElementById("inputKernel")).value;
202202

203203
bmp.kernel(3, 3);
204204
bmp.edge("sobel");
205205
bmp.drawOnCanvas(canvas);
206206
});
207+
208+
// custom filter
209+
document.getElementById("customFilter").addEventListener("click", () => {
210+
211+
let input: number = +(<HTMLInputElement>document.getElementById("inputKernel")).value;
212+
let matrix: HTMLElement = <HTMLElement>document.querySelector("#kernelMatrix");
213+
matrix.innerHTML = "";
214+
for (let y: number = 0; y < input; y++) {
215+
let row: string = "";
216+
for (let x: number = 0; x < input; x++) {
217+
row += "<th><input type='number' id='matrix" + (y * input + x) + "' value=1></th>";
218+
}
219+
let tr: HTMLElement = document.createElement("tr");
220+
tr.innerHTML = row;
221+
matrix.appendChild(tr);
222+
}
223+
document.getElementById("custom").style.display = "block";
224+
// close
225+
document.getElementsByClassName("close")[1].addEventListener("click", () => {
226+
document.getElementById("custom").style.display = "none";
227+
});
228+
229+
// apply filter
230+
document.getElementById("btnCustom").addEventListener("click", () => {
231+
let custom: number[] = new Array<number>(input * input);
232+
for (let y: number = 0; y < input; y++) {
233+
for (let x: number = 0; x < input; x++) {
234+
custom[y * input + x] = +(<HTMLInputElement>document.getElementById("matrix" + (y * input + x))).value;
235+
}
236+
}
237+
document.getElementById("custom").style.display = "none";
238+
bmp.kernel(input, input, custom);
239+
bmp.customFilter();
240+
bmp.drawOnCanvas(canvas);
241+
});
242+
});

src/views/index.html

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
<link rel="stylesheet" type="text/css" href="style.css">
77
</head>
88
<body>
9+
<!-- ZOOM MODAL -->
910
<div id="myModal" class="modal">
1011

1112
<!-- Modal content -->
@@ -32,6 +33,21 @@
3233
</div>
3334

3435
</div>
36+
37+
<!-- CUSTOM FILTER MODAL -->
38+
<div id="custom" class="modal">
39+
40+
<!-- Modal content -->
41+
<div class="modal-content">
42+
<span class="close">×</span>
43+
<div style="overflow-x:auto">
44+
<table id="kernelMatrix">
45+
</table>
46+
</div>
47+
<button id="btnCustom">Apply</button>
48+
</div>
49+
</div>
50+
3551
<canvas id="canvas1" style="display:none;">
3652
</canvas>
3753
<div class="center">
@@ -95,13 +111,26 @@
95111
</div>
96112
<hr>
97113
<div>
114+
<label>Kernel: </label>
115+
<select id="inputKernel">
116+
<option value="3"> 3x3
117+
<option value="5"> 5x5
118+
<option value="7"> 7x7
119+
<option value="9"> 9x9
120+
<option value="11"> 11x11
121+
<option value="13"> 13x13
122+
<option value="15"> 15x15
123+
</select>
124+
&nbsp;&nbsp;||&nbsp;&nbsp;
98125
<label>Blur: </label>
99126
<button id="boxBlur">Box</button>
100127
<button id="gaussBlur">Gauss</button>
101128
&nbsp;|&nbsp;
102129
<label>Edge: </label>
103130
<button id="prewittEdge">Prewitt</button>
104131
<button id="sobelEdge">Sobel</button>
132+
&nbsp;|&nbsp;
133+
<button id="customFilter">Custom</button>
105134

106135
</div>
107136
<hr>

0 commit comments

Comments
 (0)