Created
February 8, 2019 17:31
-
-
Save aqua-lzma/3e74763c615b5efaef2c48ffc244b759 to your computer and use it in GitHub Desktop.
Ascii art with xterm colours, but it takes forever
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<style> | |
canvas { | |
max-height: 50px; | |
/* image-rendering: optimizespeed; */ | |
padding: 5px; | |
} | |
</style> | |
<script> | |
let xterm = ['#000000','#00005f','#000087','#0000af','#0000d7','#0000ff','#005f00','#005f5f','#005f87','#005faf','#005fd7','#005fff','#008700','#00875f','#008787','#0087af','#0087d7','#0087ff','#00af00','#00af5f','#00af87','#00afaf','#00afd7','#00afff','#00d700','#00d75f','#00d787','#00d7af','#00d7d7','#00d7ff','#00ff00','#00ff5f','#00ff87','#00ffaf','#00ffd7','#00ffff','#5f0000','#5f005f','#5f0087','#5f00af','#5f00d7','#5f00ff','#5f5f00','#5f5f5f','#5f5f87','#5f5faf','#5f5fd7','#5f5fff','#5f8700','#5f875f','#5f8787','#5f87af','#5f87d7','#5f87ff','#5faf00','#5faf5f','#5faf87','#5fafaf','#5fafd7','#5fafff','#5fd700','#5fd75f','#5fd787','#5fd7af','#5fd7d7','#5fd7ff','#5fff00','#5fff5f','#5fff87','#5fffaf','#5fffd7','#5fffff','#870000','#87005f','#870087','#8700af','#8700d7','#8700ff','#875f00','#875f5f','#875f87','#875faf','#875fd7','#875fff','#878700','#87875f','#878787','#8787af','#8787d7','#8787ff','#87af00','#87af5f','#87af87','#87afaf','#87afd7','#87afff','#87d700','#87d75f','#87d787','#87d7af','#87d7d7','#87d7ff','#87ff00','#87ff5f','#87ff87','#87ffaf','#87ffd7','#87ffff','#af0000','#af005f','#af0087','#af00af','#af00d7','#af00ff','#af5f00','#af5f5f','#af5f87','#af5faf','#af5fd7','#af5fff','#af8700','#af875f','#af8787','#af87af','#af87d7','#af87ff','#afaf00','#afaf5f','#afaf87','#afafaf','#afafd7','#afafff','#afd700','#afd75f','#afd787','#afd7af','#afd7d7','#afd7ff','#afff00','#afff5f','#afff87','#afffaf','#afffd7','#afffff','#d70000','#d7005f','#d70087','#d700af','#d700d7','#d700ff','#d75f00','#d75f5f','#d75f87','#d75faf','#d75fd7','#d75fff','#d78700','#d7875f','#d78787','#d787af','#d787d7','#d787ff','#d7af00','#d7af5f','#d7af87','#d7afaf','#d7afd7','#d7afff','#d7d700','#d7d75f','#d7d787','#d7d7af','#d7d7d7','#d7d7ff','#d7ff00','#d7ff5f','#d7ff87','#d7ffaf','#d7ffd7','#d7ffff','#ff0000','#ff005f','#ff0087','#ff00af','#ff00d7','#ff00ff','#ff5f00','#ff5f5f','#ff5f87','#ff5faf','#ff5fd7','#ff5fff','#ff8700','#ff875f','#ff8787','#ff87af','#ff87d7','#ff87ff','#ffaf00','#ffaf5f','#ffaf87','#ffafaf','#ffafd7','#ffafff','#ffd700','#ffd75f','#ffd787','#ffd7af','#ffd7d7','#ffd7ff','#ffff00','#ffff5f','#ffff87','#ffffaf','#ffffd7','#ffffff','#080808','#121212','#1c1c1c','#262626','#303030','#3a3a3a','#444444','#4e4e4e','#585858','#626262','#6c6c6c','#767676','#808080','#8a8a8a','#949494','#9e9e9e','#a8a8a8','#b2b2b2','#bcbcbc','#c6c6c6','#d0d0d0','#dadada','#e4e4e4','#eeeeee'] | |
function getColours (blob) { | |
let set = new Set() | |
for (let i = 0; i < blob.data.length; i += 4) { | |
set.add(`${blob.data[i].toString(16).padStart(2, '0')}${blob.data[i + 1].toString(16).padStart(2, '0')}${blob.data[i + 2].toString(16).padStart(2, '0')}`) | |
} | |
let out = new Set() | |
for (let i of [...set]) { | |
let best = Infinity | |
let bC | |
for (let col of xterm) { | |
let dif = Math.abs(Number.parseInt(col.slice(1, 3), 16) - Number.parseInt(i.slice(0, 2), 16)) + Math.abs(Number.parseInt(col.slice(3, 5), 16) - Number.parseInt(i.slice(2, 4), 16)) + Math.abs(Number.parseInt(col.slice(5, 7), 16) - Number.parseInt(i.slice(4, 6), 16)) | |
if (dif < best) { | |
best = dif | |
bC = col | |
} | |
if (dif === 0) break | |
} | |
out.add(bC) | |
} | |
return ['#00000000', ...out] | |
} | |
function drawImage() { | |
let img = document.createElement('img') | |
img.src = document.querySelector('#fileName').value | |
img.style.display = 'none' | |
document.body.appendChild(img) | |
img.onload = () => { | |
let canvas = document.createElement('canvas') | |
let charWidth = Number(document.querySelector('#charWidth').value) | |
let charHeight = Number(document.querySelector('#charHeight').value) | |
let fontHeight = Number(document.querySelector('#fontHeight').value) | |
let xChars = Math.ceil(img.width / charWidth) | |
let yChars = Math.ceil(img.height / charHeight) | |
canvas.width = img.width | |
canvas.height = img.height | |
document.body.appendChild(canvas) | |
let ctx = canvas.getContext('2d') | |
ctx.drawImage(img, 0, 0) | |
let spaced = document.createElement('canvas') | |
spaced.width = img.width + xChars + 1 | |
spaced.height = img.height + yChars + 1 | |
document.body.appendChild(spaced) | |
let nctx = spaced.getContext('2d') | |
nctx.fillStyle = 'red' | |
nctx.fillRect(0, 0, spaced.width, spaced.height) | |
for (let yi = 0; yi < yChars; yi++) { | |
for (let xi = 0; xi < xChars; xi++) { | |
// nctx.fillRect(xi * (charWidth + 1), yi * (charHeight + 1), charWidth, charHeight) | |
let blob = ctx.getImageData(xi * charWidth, yi * charHeight, charWidth, charHeight) | |
nctx.putImageData(blob, xi * (charWidth + 1), yi * (charHeight + 1)) | |
} | |
} | |
document.body.appendChild(document.createElement('br')) | |
let test = document.createElement('canvas') | |
let best = document.createElement('canvas') | |
let out = document.createElement('canvas') | |
test.width = charWidth | |
best.width = charWidth | |
out.width = img.width | |
test.height = charHeight | |
best.height = charHeight | |
out.height = img.height | |
document.body.appendChild(out) | |
let tctx = test.getContext('2d') | |
let bctx = best.getContext('2d') | |
let octx = out.getContext('2d') | |
tctx.font = document.querySelector('#font').value | |
bctx.font = document.querySelector('#font').value | |
for (let yi = 0; yi < yChars; yi++) { | |
document.querySelector('textarea').textContent += 'echo -e "' | |
for (let xi = 0; xi < xChars; xi++) { | |
let blob = ctx.getImageData(xi * charWidth, yi * charHeight, charWidth, charHeight) | |
let bestVal = Infinity | |
let bestData = '' | |
let cols = getColours(blob) | |
for (let bgCol of cols) { | |
for (let fgCol of cols) { | |
for (let cCode = 32; cCode < 127; cCode++) { | |
tctx.clearRect(0, 0, charWidth, charHeight) | |
tctx.fillStyle = bgCol | |
tctx.fillRect(0, 0, charWidth, charHeight) | |
tctx.fillStyle = fgCol | |
tctx.fillText(String.fromCharCode(cCode), 0, fontHeight) | |
let tBlob = tctx.getImageData(0, 0, charWidth, charHeight) | |
let curBest = 0 | |
for (let i = 0; i < charWidth * charHeight * 4; i++) { | |
curBest += Math.abs(blob.data[i] - tBlob.data[i]) | |
if (curBest > bestVal) break | |
} | |
if (curBest < bestVal) { | |
bestVal = curBest | |
let bgCode = '' | |
if (bgCol !== '#00000000') bgCode = `\\e[48;5;${xterm.indexOf(bgCol) + 16}m` | |
let fgCode = '' | |
if (fgCol !== '#00000000') fgCode = `\\e[38;5;${xterm.indexOf(fgCol) + 16}m` | |
let char = String.fromCharCode(cCode) | |
if (char === '"') char = '\\"' | |
if (char === '`') char = '\\`' | |
bestData = `${bgCode}${fgCode}${char}\\e[0m` | |
bctx.putImageData(tBlob, 0, 0) | |
} | |
if (bestVal === 0) break | |
} | |
if (bestVal === 0) break | |
} | |
if (bestVal === 0) break | |
} | |
let bBlob = bctx.getImageData(0, 0, charWidth, charHeight) | |
octx.putImageData(bBlob, xi * charWidth, yi * charHeight) | |
document.querySelector('textarea').textContent += bestData | |
} | |
document.querySelector('textarea').textContent += '"\n' | |
alert() | |
} | |
} | |
} | |
</script> | |
</head> | |
<body style="background-color: grey"> | |
<table> | |
<tbody> | |
<tr> | |
<td>Char width</td> | |
<td><input id="charWidth"></td> | |
</tr> | |
<tr> | |
<td>Char height</td> | |
<td><input id="charHeight"></td> | |
</tr> | |
<tr> | |
<td>Font height</td> | |
<td><input id="fontHeight"></td> | |
</tr> | |
<tr> | |
<td>Font</td> | |
<td><input id="font"></td> | |
</tr> | |
<tr> | |
<td>File Name</td> | |
<td><input id="fileName"></td> | |
<td><button onclick="drawImage()">Load</button></td> | |
</tr> | |
</tbody> | |
</table> | |
<script> | |
</script> | |
<textarea></textarea> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment