Exploiting JavaScript To Create ASCII ART


Welcome to this JavaScript ASCII art creation tutorial! ASCII art is a fascinating form of visual expression that uses characters and symbols to create images. ASCII art holds a special place in the digital world, offering a creative outlet for expression and showcasing the artistic potential of programming languages like JavaScript. By the end of this tutorial, you’ll have the skills to create stunning ASCII art using JavaScript code.

Prerequisites

Before we get started, make sure you have a basic understanding of HTML, CSS, and JavaScript.

  • Basic Understanding of HTML, CSS, and JavaScript: Familiarity with the fundamental concepts of HTML for structuring web pages, CSS for styling, and JavaScript for adding interactivity is essential. This tutorial assumes a basic knowledge of these languages.
  • Web Browser: Use a modern web browser like Google Chrome, Mozilla Firefox, or Microsoft Edge.

For the purpose of this tutorial, you can download the source files for the ASCII art generator to help you follow along:

Note: As you test the source files, ensure that you load them within a suitable environment such that all the files are loaded. For offline use, we recommend that you use Live Server and vscode to load the files. Simply open the files in Vscode and run “index.html” using Live Server.

Demo

Here is what we are going to create.

Setting Up the Project

Let’s start by setting up the basic HTML structure for our project. Create an HTML called “index.html”, with a basic HTML web format, and add some adds for canvas element, input tag to select a file and button to execute the convert to ASCII command.

Also, add some tags for the css in the header (link tag) , and a script tag for our javascript code.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" type="text/css" href="web.css">
    <title>ASCII TEXT IMAGE CONVERTOR </title>
</head>
<body>
    <div class="main">
    <canvas id="canvas"></canvas>
    <span>
       <input type="file" placeholder="Browse Image" oninput="loadImage(this);"></input>
       <button onclick="convertImage()">Convert</button>
    </span>
    </div>
    <script type="text/javascript" src="app.js"></script>
</body>
</html>

Now create a css file called “web.css”, to add some basic CSS styles as shown below.

.main{
    display: flex;
    flex-direction: column;
    flex-wrap: nowrap;
}
#canvas{
    background: black;
    max-width: 500px;
    max-height: 500px;
}
.main>span{
    display: flex;
    flex-direction: row;
    flex-wrap: nowrap;
}

JavaScript Code

Now, let’s dive into the JavaScript code to create our ASCII art. We’ll break down the code into several sections:

1. Setting The Project Constants

As shown below, the code begins with the initialization of several constants essential for subsequent operations. These constants include densityString, which represents different levels of density, pixelSize to define the size of each pixel in the output, plotColor to specify the colour used for plotting characters, and fontFamily to set the font family for the plotted characters. These constants provide the foundational parameters required for processing and displaying images on the canvas.

const densityString ="@++---**^^```.....   ";
//sample with random pixel size
const pixelSize=10;
const plotColor="white";
const fontFamily="Consola"

2. Clearing the Screen

The clear() function below is responsible for clearing the canvas. It retrieves the canvas element and its context, sets the canvas dimensions to 500×500 pixels, and fills it with a black color, effectively clearing any previous content.

//function to clear the screen
function clear(){
       var canvas=document.getElementById("canvas");
       var ctx=canvas.getContext("2d");

       canvas.width=500;
       canvas.height=500;
       ctx.fillStyle="black";
       ctx.fillRect(0,0,canvas.width,canvas.height)
}

3. The Image Function

This function draws an image onto the canvas. It takes an image object as input and draws it starting from the top-left corner of the canvas, stretching it to fit the canvas dimensions. This is the function used to load the image when a photo is selected.

//function to draw an image on the canvas
function drawImage(img){
    var canvas=document.getElementById("canvas");
    var ctx=canvas.getContext("2d");
    ctx.drawImage(img,0,0,canvas.width,canvas.height)
}

4. Loading the Image

The loadImage(input) function facilitates the dynamic loading of an image file selected by the user via an input element. Upon selection, it initializes an Image object and assigns it the URL of the selected file using window.URL.createObjectURL(input.files[0]). Once the image is fully loaded, it updates the currentImage variable with the loaded image object and calls the drawImage(img) function to render the image on the canvas. This function streamlines the process of integrating user-selected images into the canvas display, enhancing the interactivity and customization of the application.

//function to load the image
function loadImage(input){
    var img=new Image()
    var src=''
    if(input.value!=''){
        src= window.URL.createObjectURL(input.files[0]);
    }
    img.src=src;
img.onload=function(){{
    currentImage=img;
    drawImage(img);
}}

}

5. Plotting Actual Pixel for Debugging

The pt() function is used for debugging purposes to plot an actual pixel. It fills a small rectangle at coordinates (x, y) with a specified color on the canvas context ctx.

//function to plot actual pixel for debugging
function pt(ctx,x,y,px,color="blue"){
      var w=5;
      var h=5;
      ctx.fillStyle=color
      ctx.fillRect(x+px/2-w/2,y+px/2-h/2,w,h);
}

6.Computing Density String

The computeDensityString(value, limit) function calculates a character representing the density of a pixel’s color value relative to a specified limit. It first computes the index within the densityString array based on the ratio of the provided value to the limit. This index is then adjusted to ensure it falls within the bounds of the densityString. If the computed index exceeds the array length, it is capped at the maximum index. Finally, the character corresponding to the adjusted index is returned, providing a visual representation of the pixel’s color density. This function is crucial for converting color values into characters that represent their density, contributing to the visual rendering process.

function computeDensityString(value,limit=255){
  
    var densityIndex=parseInt((value/limit)*densityString.length);
    densityIndex=densityString.length-densityIndex;
   if(densityIndex>=densityString.length){
    densityIndex=densityString.length-1;  
   }
    return densityString[densityIndex];
}

7. Getting the Pixel Data

The getPixelData(data, index) function retrieves the color data of a pixel from the provided image data array (data) at the specified index. It extracts the red, green, blue, and alpha values of the pixel located at the given index within the array. These color components are then encapsulated within an object and returned, enabling easy access to individual color channels. This function facilitates the extraction of pixel color information, which is essential for subsequent processing and rendering tasks, such as determining color density or performing image manipulations.

function getPixelData(data,index){
    var red=data[index];
    var green=data[index+1];
    var blue=data[index+2];
    var alpha=data[index+3];
    return {
        "red":red,
        "green":green,
        "blue":blue,
        "alpha":alpha
    }
}

8. Computing the Average Color Intensity

The averagePixels(array) function calculates the average color intensity across an array of pixel color objects. It iterates through each pixel color object in the array, summing the red, green, and blue color values. By dividing the total sum by the total number of color channels (3 times the array length), it computes the average color intensity. This function is crucial for determining the overall color intensity of a group of pixels, which can be useful in various image processing tasks such as contrast adjustment or color balancing.

function averagePixels(array){
    var total=0;
    for(let i=0;i<array.length;i++){
        color=array[i];
        total+=color.red+color.green+color.blue;

    }
    var average=total/(array.length*3);
    return average;
}

9. Computing the Pixel Sample Position

The computeCenterPixel function calculates the index of the center pixel within a pixel box given the index of a corner pixel, the offset within that box, the pixel size, and the dimensions of the canvas. It first determines the midpoint of the pixel size to locate the center of the box. Then, it computes the index of the center pixel by adjusting the corner pixel index based on the offset and the dimensions of the canvas. This function is essential for sampling the correct position of the center pixel within each pixel box.

function computeCenterPixel(index,offset,pixelSize,width,height){
      var mid_point=Math.floor(pixelSize/2);

      var diff=(width-1)-offset;
   
    
      var newIndex=index+diff*4;

      //get to the vertical center of the pixel bound box assuming pixelsize is odd
      newIndex=newIndex+(mid_point-1)*width*4;
    
      //get to the center pixel
      newIndex=newIndex+offset*4+mid_point*4;
   
      return newIndex;

}

10. Drawing the ASCII Character for a single Pixel

The plotCharacter function is responsible for rendering each pixel on the canvas as a character. It sets the fill color, font size, and font family for the character. The font size is determined based on the size of the pixel. The function then centers the text horizontally and vertically within the pixel box. Finally, it draws the character at the specified coordinates (x, y) with the calculated font height. This function is crucial for visualizing the processed image data on the canvas, converting pixel values to ASCII characters according to their density.

//function to plot each pixel
function plotCharacter(ctx,x,y,w,h,char,font,color="white"){
    
    ctx.fillStyle=color;
 
    //set font size based on size of pixel
    size=Math.sqrt(w*w+h*h);
    ctx.font=size+"px "+font;
    
    //center the text
    ctx.textAlign="center"
    //get text metrics
    measure=ctx.measureText(char);
    font_height=measure.actualBoundingBoxAscent + measure.actualBoundingBoxDescent;
    //draw text
    ctx.fillText(char,x+w/2,y+font_height)
    
}

11. Finally The Entire Image As ASCII Art

The processImage function is the core of the image processing logic. It takes an image as input and renders it onto a canvas element. First, it creates a temporary canvas and context to manipulate the image data. It then retrieves the image data using getImageData. The function iterates through the image data, processing each pixel. For every pixel, it computes the center pixel, extracts its color data, calculates the density value based on its average color, and then plots the corresponding ASCII character on the canvas using the plotCharacter function. This process continues until all pixels are processed, resulting in an ASCII representation of the image on the canvas.

function processImage(image){
   
    var canvas=document.getElementById("canvas");
    var ctx=canvas.getContext("2d");
    var width=canvas.width;
    var height=canvas.height;
    //dump canvas
     var canvas_temp=document.createElement("canvas");
     canvas_temp.width=width;
     canvas_temp.height=height;
     var ctx_temp=canvas_temp.getContext("2d");
     //getting the image data
     ctx_temp.drawImage(image,0,0,canvas.width,canvas.height);
     var image_data=ctx_temp.getImageData(0,0,canvas.width,canvas.height);
     var data=image_data.data;
    
     //ctx.putImageData(image_data,0,0);
     var index=0;

     var pixel_count_x=parseInt(width/pixelSize);
     
     var offset_limit=pixelSize*pixel_count_x;
     var x=0;
     var y=0;
     var offset=index;
     while(index<data.length){
            //lets first get the center pixel based on pixel size
            var center=computeCenterPixel(index,offset,pixelSize,width,height);
      
            //lets the colors of the corner pixels
    
            var pixelColor=getPixelData(data,center);

            var colorValue=averagePixels([pixelColor]);

            var densityValue=computeDensityString(colorValue,255);

            
            //pt(ctx,x,y,pixelSize,"rgb("+pixelColor.red+","+pixelColor.green+","+pixelColor.blue+")");
          
            plotCharacter(ctx,x,y,pixelSize,pixelSize,densityValue,fontFamily,plotColor);
            x+=1*(pixelSize);
            if(x>=width){
                x=0;
                y+=1*(pixelSize);
            }
            index+=4*(pixelSize);  
            
            offset+=pixelSize;  
            if(offset>=offset_limit){
        
                index+=4*(pixelSize-1)*offset_limit;
                offset=0;
            } 

     }
   


}

Conclusion

With this JavaScript code, you can now create ASCII art from images using a web browser. Experiment with different images and ASCII character sets to create fascinating visual representations. ASCII art opens up a world of creativity, allowing you to express yourself uniquely through text-based visuals. Happy coding!

Leave a Reply

Your email address will not be published. Required fields are marked *