DEV Community

Cover image for How to Add Pixel Filter?
Vinit Gupta
Vinit Gupta

Posted on

How to Add Pixel Filter?

Until now, I had only talked about the simple color to grayscale conversion.
Now it's time for the real stuff.

This is going to be about how I have converted an actual image to a text based filtered image.

Well, the first thing was to to load the image into a canvas element. This had to be followed by converting to grayscale image.

I have discussed this in my previous post, which you can checkout here 👉Adding Grayscale Filter or you can access it at the top of this page.

Now, let's move on to the Pixel value to text conversion.

Step 1 : Selecting the right characters

This is an important step. When you use characters to represent pixel brightness, you have to be really careful.

If you choose the wrong character or the wrong size your image may end up looking distorted.

There are multiple sources that suggest different set of characters for different range of brightness. But after some testing I found out the optimal character set as follows :

convertToSymbol(g){
        if(g> 245) return 'G';
        else if(g > 225) return 'H';
        else if(g > 200) return '&';
        else if(g > 185) return 'S';
        else if(g > 165) return '%';
        else if(g > 145) return 'W';
        else if(g > 120) return '+';
        else if(g > 100) return '=';
        else if(g > 80) return '-';
        else if(g > 60) return ':';
        else if(g > 45) return '.';
        else return ' ';

    }
// here 'g' is the brightness value of a particular pixel
Enter fullscreen mode Exit fullscreen mode

Once this is done, one more important thing is to set the font-size of each of these characters.
You can select 10px or any other size that you prefer.
We also have to use a monospace font for the characters so that the pixels are not distorted.

Step 2 : Replacing the image data for the pixels

Now that we have the brightness values for each pixel, we can start assigning the characters.
I started by making a different class for this process called AsciiEffect.
You can check it out below :

class AsciiEffect {
    #imageCellArray = [];
    #pixels = [];
    #ctx;
    #width;
    #height;
    constructor(ctx, width, height, image){
        this.#ctx = ctx;
        this.#width = width;
        this.#height = height;
        this.#ctx.drawImage(image, 0, 0, this.#width, this.#height);
        this.#pixels = this.#ctx.getImageData(0, 0, this.#width, this.#height);
    }
    #convertToSymbol(g){
        if(g> 245) return 'G';
        else if(g > 225) return 'H';
        else if(g > 200) return '&';
        else if(g > 185) return 'S';
        else if(g > 165) return '%';
        else if(g > 145) return 'W';
        else if(g > 120) return '+';
        else if(g > 100) return '=';
        else if(g > 80) return '-';
        else if(g > 60) return ':';
        else if(g > 45) return '.';
        else return ' ';

    }
    #scanImage(cellSize, color){
        this.#imageCellArray = [];
        for(let y  = 0; y < this.#pixels.height; y += cellSize){
            for(let x = 0; x < this.#pixels.width; x += cellSize){
                let posX = (x*4), posY = y*4;
                const pos = (posY*this.#pixels.width) + posX;
                if(this.#pixels.data[pos+3]>120){
                    let total = this.#pixels.data[pos]+this.#pixels.data[pos+1]+this.#pixels.data[pos+2];
                    const avgColorValue = total/3;
                    const symbol = this.#convertToSymbol(avgColorValue);
                    this.#imageCellArray.push(new Cell(x,y, symbol, color));
                }
            }
        }
        console.log(this.#imageCellArray);
    }
    #drawAscii(){
        this.#ctx.fillStyle = "#000000"
        this.#ctx.fillRect(0,0, this.#width, this.#height);
        for(let i=0;i<this.#imageCellArray.length;i++){
            this.#imageCellArray[i].draw(this.#ctx);
        }
    }
    draw(cellSize, color){
        this.#scanImage(cellSize, color);
        this.#drawAscii();
    }
}

Enter fullscreen mode Exit fullscreen mode

Step 3 : Replacing The Canvas Data

After the above returns the image data, we have to replace the canvas data with the new data. This is really simple :

ctx.font = '7px Fira Code';
effect.draw(7,"#ffffff");
Enter fullscreen mode Exit fullscreen mode

Now , I am working on the front end and will be released soon!

Top comments (2)

Collapse
 
haimantika profile image
haimantika mitra

Love it! 🤩

P.S: We have a lot of interesting things happening in our Appwrite discord, we would love to see you there!

discord.gg/KKZprAnX

Collapse
 
thevinitgupta profile image
Vinit Gupta

Thanks.
I would love to join the community!!