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!