In this article you will learn how to create image filters and apply them on any kind of image.
Canvas
First, you will need to create two canvas. one for the original image and the other for modified image. Also, you will need to create image class
const Img = new Image();
Img.src = "Images/Img.jpg";
const ImgCanvas = document.getElementById('Img');
const ImgContext = ImgCanvas.getContext('2d');
const MainCanvas = document.getElementById('MainCanvas');
const MainContext = MainCanvas.getContext('2d');
window.onload = () => {
ImgCanvas.width = Img.width;
ImgCanvas.height = Img.height;
MainCanvas.width = Img.width;
MainCanvas.height = Img.height;
ImgContext.drawImage(Img, 0, 0, ImgCanvas.width, ImgCanvas.height)
MainContext.drawImage(Img, 0, 0, MainCanvas.width, MainCanvas.height);
}
You can do it with one canvas and it will process faster, but doing it with 2 canvas helps you to visualize the difference. drawImage function is used inside window.onload function to draw
the image to the canvas after the image is fully loaded.
Filters
Then you will need to create some filters to test on our image. I will make few filters and you don't need to do all of them. you can just choose a couple.
Brightness
function SaturationFilter(imageData, Value){
const data = imageData.data;
for (let i = 0; i < data.length; i += 4) {
const red = data[i];
const green = data[i + 1];
const blue = data[i + 2];
// Calculate the grayscale value
const gray = 0.2126 * red + 0.7152 * green + 0.0722 * blue;
// Adjust the saturation based on the given percentage
const r = (1 - Value / 100) * red + Value / 100 * gray;
const g = (1 - Value / 100) * green + Value / 100 * gray;
const b = (1 - Value / 100) * blue + Value / 100 * gray;
data[i] = r;
data[i + 1] = g;
data[i + 2] = b;
}
MainContext.putImageData(imageData, 0, 0);
}
Contrast
function ContrastFilter(imageData, Value){
const data = imageData.data;
const factor = (259 * (Value + 255)) / (255 * (259 - Value));
for (let i = 0; i < data.length; i += 4) {
const red = data[i];
const green = data[i + 1];
const blue = data[i + 2];
// Adjust the contrast
data[i] = factor * (red - 128) + 128;
data[i + 1] = factor * (green - 128) + 128;
data[i + 2] = factor * (blue - 128) + 128;
}
MainContext.putImageData(imageData, 0, 0);
}
Saturation
function SaturationFilter(imageData, Value){
const data = imageData.data;
for (let i = 0; i < data.length; i += 4) {
const red = data[i];
const green = data[i + 1];
const blue = data[i + 2];
// Calculate the grayscale value
const gray = 0.2126 * red + 0.7152 * green + 0.0722 * blue;
// Adjust the saturation based on the given percentage
const r = (1 - Value / 100) * red + Value / 100 * gray;
const g = (1 - Value / 100) * green + Value / 100 * gray;
const b = (1 - Value / 100) * blue + Value / 100 * gray;
data[i] = r;
data[i + 1] = g;
data[i + 2] = b;
}
MainContext.putImageData(imageData, 0, 0);
}
Box Blur
function BoxBlurFilter(imageData, radius) {
var data = imageData.data;
// Define the box blur kernel
var kernelSize = radius * 2;
var kernel = new Array(kernelSize * kernelSize);
for (var i = 0; i < kernel.length; i++) {
kernel[i] = 1 / (kernel.length);
}
// Loop through each pixel and apply the box blur
for (var y = 0; y < imageData.height; y++) {
for (var x = 0; x < imageData.width; x++) {
var r = 0;
var g = 0;
var b = 0;
// Loop through the kernel and apply the blur
for (var ky = 0; ky < kernelSize; ky++) {
for (var kx = 0; kx < kernelSize; kx++) {
var cx = x + kx - radius;
var cy = y + ky - radius;
var idx = (cy * imageData.width + cx) * 4;
if (cx >= 0 && cx < imageData.width && cy >= 0 && cy < imageData.height) {
r += data[idx] * kernel[ky * kernelSize + kx];
g += data[idx + 1] * kernel[ky * kernelSize + kx];
b += data[idx + 2] * kernel[ky * kernelSize + kx];
}
}
}
// Set the new pixel value
var idx = (y * imageData.width + x) * 4;
data[idx] = r;
data[idx + 1] = g;
data[idx + 2] = b;
}
}
MainContext.putImageData(imageData, 0, 0);
}
Gaussian Blur
function GaussianBlur(imageData, radius) {
var data = imageData.data;
var side = radius * 2 + 1;
var matrix = [];
var sigma = radius / 3;
var sigma22 = 2 * sigma * sigma;
var sqrtPiSigma22 = Math.sqrt(Math.PI * sigma22);
for (var y = -radius; y <= radius; y++) {
for (var x = -radius; x <= radius; x++) {
var weight = Math.exp(-(x * x + y * y) / sigma22) / sqrtPiSigma22;
matrix.push(weight);
}
}
var weights = new Float32Array(matrix);
for (var i = 0; i < data.length; i += 4) {
var r = 0, g = 0, b = 0, a = 0;
for (var wy = -radius; wy <= radius; wy++) {
for (var wx = -radius; wx <= radius; wx++) {
var y = i / (imageData.width * 4) + wy;
var x = i / 4 - y * imageData.width + wx;
if (x >= 0 && x < imageData.width && y >= 0 && y < imageData.height) {
var index = (y * imageData.width + x) * 4;
var weight = weights[(wy + radius) * side + wx + radius];
r += data[index] * weight;
g += data[index + 1] * weight;
b += data[index + 2] * weight;
a += data[index + 3] * weight;
}
}
}
data[i] = r;
data[i + 1] = g;
data[i + 2] = b;
data[i + 3] = a;
}
MainContext.putImageData(imageData, 0, 0);
}
Sharpness
function SharpnessFilter(imageData, Value){
const data = imageData.data;
if(Value >= 1){
var matrix = [0, -1, 0, -1, Value + 4, -1, 0, -1, 0];
var divisor = Value + 4;
var bias = -Value / 4;
for (var y = 0; y < imageData.height; y++) {
for (var x = 0; x < imageData.width; x++) {
var pixelIndex = (y * imageData.width + x) * 4;
var r = 0, g = 0, b = 0;
for (var row = -1; row <= 1; row++) {
for (var col = -1; col <= 1; col++) {
var rowIndex = y + row;
var colIndex = x + col;
if (rowIndex >= 0 && colIndex >= 0 && rowIndex < imageData.height && colIndex < imageData.width) {
var index = (rowIndex * imageData.width + colIndex) * 4;
var weight = matrix[(row + 1) * 3 + col + 1];
r += data[index] * weight;
g += data[index + 1] * weight;
b += data[index + 2] * weight;
}
}
}
data[pixelIndex] = Math.min(255, Math.max(0, (r / divisor) + bias));
data[pixelIndex + 1] = Math.min(255, Math.max(0, (g / divisor) + bias));
data[pixelIndex + 2] = Math.min(255, Math.max(0, (b / divisor) + bias));
}
}
MainContext.putImageData(imageData, 0, 0);
}
}
Greyscale
function GreyScaleFilter(imageData, value){
const data = imageData.data;
for(let i = 0; i < data.length; i += 4){
const Total = data[i] + data[i+1] + data[i+2];
const Average = Total/2;
data[i] = Average + value;
data[i+1] = Average+ value;
data[i+2] = Average+ value;
}
MainContext.putImageData(imageData , 0, 0);
}
Filter Group
Now we will need to create some radio buttons to handle the change of the filter.
<!-- HTML -->
<input type="radio" name="Filters" id="saturation" value="Saturation">
<label class="icon_img icon-saturation" for="saturation">
<img src="Saturation.png">
<span class="tooltip">Saturation</span>
</label>
You will have to create radio button for each filter you have selected. Also, you will need to change the values of input id, input value and for value in label according to the selected filter.
Then add some javascript.
//JavaScript
var Filter;
const RadioButtons= document.querySelectorAll('input[name="Filters"]');
function handleClick(){
for (RB of RadioButtons) {
if (RB.checked) {
Filter = RB.value;
break;
}
}
}
Slider
You will need to create a slider to change the effect value of the filter that is applied to the image.
<!-- HTML -->
<div class="slidecontainer">
<input type="range" min="-50" max="50" value="0" class="slider" id="Range">
<output class="bubble" id="InputValue"></output>
</div>
Then add some javscript.
//JavaScript
const Slider = document.getElementById("Range");
const InputValue = document.getElementById("InputValue");
InputValue.innerHTML = Slider.value;
Slider.oninput = function() {
InputValue.innerHTML = this.value;
}
Slider.onchange = () => {
const imageData = ImgContext.getImageData(0, 0, ImgCanvas.width, ImgCanvas.height);
handleClick();
if(Filter === 'Brightness'){
MainContext.putImageData(BrightnessFilter(imageData, Number(Slider.value)), 0, 0);
}
else if(Filter === 'Saturation'){
MainContext.putImageData(SaturationFilter(imageData, Number(Slider.value)), 0, 0);
}
else if(Filter === 'BoxBlur'){
MainContext.putImageData(BoxBlurFilter(imageData, Number(Slider.value)), 0, 0);
}
else if(Filter === 'GaussianBlur'){
MainContext.putImageData(GaussianBlur(imageData, Number(Slider.value)), 0, 0);
}
else if(Filter === 'Sharp'){
MainContext.putImageData(SharpnessFilter(imageData, Number(Slider.value)), 0, 0);
}
else if(Filter === 'Contrast'){
MainContext.putImageData(ContrastFilter(imageData, Number(Slider.value)), 0, 0);
}
else if(Filter === 'Greyscale'){
MainContext.putImageData(GreyScaleFilter(imageData, Number(Slider.value)), 0, 0);
}
}
Buttons
Lastly, you will need to create two buttons. One for applying the filters on the image, and the other to download the image with filters applied on it.
<!-- HTML -->
<a>
<Button id="Btn" class="btn btn__secondary"><p>Apply</p></Button>
</a>
<a id="download" download="Image.png">
<Button id="DownloadBtn" class="btn btn__primary"><p>Download</p></Button>
</a>
Then add some javascript.
//JavaScript
const ApplyBtn = document.getElementById('ApplyBtn');
const DownloadBtn = document.getElementById('DownloadBtn');
ApplyBtn.onclick = () => {
const imageData = MainContext.getImageData(0, 0, MainCanvas.width, MainCanvas.height);
ImgContext.putImageData(imageData, 0, 0);
}
DownloadBtn.onclick = () => {
var download = document.getElementById("download");
var image = ImgCanvas.toDataURL("image/png");
download.setAttribute("href", image);
}
Result
CodePen: Image Processing (Filters)
Also Read
3D Product Card With ReactJS
Top comments (0)