Code to Convert Image to Ascii Art with JavaScript
This tutorial explains how to write a JavaScript code that takes image as input and outputs a ascii art. source code link
Index.html
<html lang="en">
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Ascii Art</title>
<link href="https://fonts.googleapis.com/css?family=VT323" rel="stylesheet">
<link rel="stylesheet" href="src/style.css" />
</head>
<body>
<h1>CODENAP</h1>
<h3>Ascii Art </h3>
<input type="file" name="picture" />
<canvas id="preview" style="display: none;"></canvas>
<pre id="ascii"></pre>
<script src="src/index.js"></script>
</body>
</html>
Index.js
const canvas = document.getElementById('preview');
const fileInput = document.querySelector('input[type="file"');
const asciiImage = document.getElementById('ascii');
const context = canvas.getContext('2d');
const toGrayScale = (r, g, b) => 0.21 * r + 0.72 * g + 0.07 * b;
const getFontRatio = () => {
const pre = document.createElement('pre');
pre.style.display = 'inline';
pre.textContent = ' ';
document.body.appendChild(pre);
const { width, height } = pre.getBoundingClientRect();
document.body.removeChild(pre);
return height / width;
};
const fontRatio = getFontRatio();
const convertToGrayScales = (context, width, height) => {
const imageData = context.getImageData(0, 0, width, height);
const grayScales = [];
for (let i = 0 ; i < imageData.data.length ; i += 4) {
const r = imageData.data[i];
const g = imageData.data[i + 1];
const b = imageData.data[i + 2];
const grayScale = toGrayScale(r, g, b);
imageData.data[i] = imageData.data[i + 1] = imageData.data[i + 2] = grayScale;
grayScales.push(grayScale);
}
context.putImageData(imageData, 0, 0);
return grayScales;
};
const MAXIMUM_WIDTH = 80;
const MAXIMUM_HEIGHT = 80;
const clampDimensions = (width, height) => {
const rectifiedWidth = Math.floor(getFontRatio() * width);
if (height > MAXIMUM_HEIGHT) {
const reducedWidth = Math.floor(rectifiedWidth * MAXIMUM_HEIGHT / height);
return [reducedWidth, MAXIMUM_HEIGHT];
}
if (width > MAXIMUM_WIDTH) {
const reducedHeight = Math.floor(height * MAXIMUM_WIDTH / rectifiedWidth);
return [MAXIMUM_WIDTH, reducedHeight];
}
return [rectifiedWidth, height];
};
fileInput.onchange = (e) => {
const file = e.target.files[0];
const reader = new FileReader();
reader.onload = (event) => {
const image = new Image();
image.onload = () => {
const [width, height] = clampDimensions(image.width, image.height);
canvas.width = width;
canvas.height = height;
context.drawImage(image, 0, 0, width, height);
const grayScales = convertToGrayScales(context, width, height);
fileInput.style.display = 'none';
drawAscii(grayScales, width);
}
image.src = event.target.result;
};
reader.readAsDataURL(file);
};
const grayRamp = '010101 ';
//const grayRamp = '$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/|()1{}[]?-_+~<>i!lI;:,"^`\'. ';
const rampLength = grayRamp.length;
const getCharacterForGrayScale = grayScale => grayRamp[Math.ceil((rampLength - 1) * grayScale / 255)];
const drawAscii = (grayScales, width) => {
const ascii = grayScales.reduce((asciiImage, grayScale, index) => {
let nextChars = getCharacterForGrayScale(grayScale);
if ((index + 1) % width === 0) {
nextChars += '\n';
}
return asciiImage + nextChars;
}, '');
asciiImage.textContent = ascii;
};
style.css
* {
margin: 0;
}
body {
padding: 2rem 3rem;
font-family: 'VT323', monospace;
line-height: 1.5rem;
font-size: 18px;
}
header {
display: flex;
align-items: baseline;
font-size: 18px;
}
header h1 {
margin-right: 1.5rem;
}
input {
margin-top: 2rem;
font-size: 18px;
}
pre {
font-family: 'Courier New', 'monospace';
margin: 1rem auto;
font-size: 8px;
line-height: 1;
}
footer {
position: absolute;
bottom: 1rem;
}