Skip to content

Instantly share code, notes, and snippets.

@yne
Created July 6, 2025 21:32
Show Gist options
  • Select an option

  • Save yne/6e83bcaac2a1e9b56b7e503870c56cfd to your computer and use it in GitHub Desktop.

Select an option

Save yne/6e83bcaac2a1e9b56b7e503870c56cfd to your computer and use it in GitHub Desktop.
image to ansi code graphic
<!DOCTYPE html>
<html lang="en">
<style>
:root{--size:1}
output{font-family:monospace;font-size:14px;padding: 1em;display:grid;grid-template-columns: repeat(var(--size), 10px);}
b{font-size:0px;}
</style>
<script>$=function(query,e){return (e||document).querySelector(query)};
$css=document.documentElement.style;
function asciicode8(r1,g1,b1,a1, r2,g2,b2,a2) {//8^3 colorspace
if(!a1&&!a2)return ['\u0020', ];
if(!a1&& a2)return ['\u2584',49, 38,2,r2,g2,b2];
if( a1&&!a2)return ['\u2580',38,2,r1,g1,b1,49, ];
if( a1&& a2)return ['\u2580',38,2,r1,g1,b1,48,2,r2,g2,b2];
}
function asciicode6(r1,g1,b1,a1, r2,g2,b2,a2) {//6^3 colorspace
var c1=16+((r1/43|0)*36)+((g1/43|0)*6)+(b1/43|0);
var c2=16+((r2/43|0)*36)+((g2/43|0)*6)+(b2/43|0);
if(!a1&&!a2)return ['\u0020', ];
if(!a1&& a2)return ['\u2584',49, 38,5,c2];
if( a1&&!a2)return ['\u2580',38,5,c1,49, ];
if( a1&& a2)return ['\u2580',38,5,c1,48,5,c2];
}
function inflate(c){
const b = (c%6)*51;
const g = ((c/6)%6)*51;
const r = ((c/36)%6)*51;
return `rgb(${r},${g},${b})`
}
var last=['\u0020'];
function compress(c){
if(JSON.stringify(c)==JSON.stringify(last))
return c[0];
last=c;
return '\u001b['+c.slice(1).join(';')+'m'+c[0];
}
function toascii(img,use8b){
var asciicode=use8b?asciicode8:asciicode6;
var ascii="",w=img.width*4,d=img.data;
for(var y=0;y<img.height;y+=2){//skip half lines
for(var x=0,i=y*img.width*4;x<img.width;x++,i+=4){
ascii+=compress(asciicode(d[i],d[i+1],d[i+2],d[i+3],d[w+i],d[w+i+1],d[w+i+2],d[w+i+3]));
}
ascii+=(last.length>1?"\u001b[m":"")+"\n"
}
return ascii;
}
function code2css(text) {
const codes = text.slice(2,-1).split(';').map(e=>+e);
let result = {}
while(codes.length) {
switch(codes.shift()){
case 0: result.bg='black';result.fg="transparent";break;
case 39: result.bg='black';break;
case 38: switch(codes.shift()){
case 2:result.bg = `rgb(${codes.shift()},${codes.shift()},${codes.shift()})`;break;
case 5:result.bg = inflate(codes.shift()-16);break;
default: console.log("unk colorspace")
}break;
case 49: result.fg = 'transparent';break;
case 48: switch(codes.shift()){
case 2:result.fg = `rgb(${codes.shift()},${codes.shift()},${codes.shift()})`;break;
case 5:result.fg = inflate(codes.shift()-16);break;
default: console.log("unk colorspace")
}break;
default: console.log("unk CSI command",text)
}
}
return result;
}
function toHTML(ascii) {
let state = {bg:"transparent",fg:"transparent"};
return ascii.replace(/(\u001b\[.*?m)?[^\u001b]/g, tuple => {
let text = tuple.substr(-1), csi=tuple.substr(0,tuple.length-1);
if(text==' ')text='&nbsp;'
if(text=='\n')return ''
if(tuple[0]=='\u001b')Object.assign(state,code2css(csi))
else{csi=''}
return `<a style="background:${state.fg};color:${state.bg}"><b>${csi}</b>${text}</a>`
})
}
</script>
</head>
<body>
<form style="position:absolute;top:0;right:0;z-index:999" onsubmit="var fr=new FileReader();fr.onload=function(){$('img').src=fr.result;};fr.readAsDataURL($('[type=file]').files[0]);return false;">
<img onload="$css.setProperty('--size', this.width);var canvas=document.createElement('canvas');canvas.getContext('2d').drawImage(this,0,0,canvas.width=this.width,canvas.height=this.height);$('output').innerHTML=toHTML($('textarea').innerHTML=toascii(canvas.getContext('2d').getImageData(0,0,canvas.width,canvas.height),$('[type=checkbox]').checked))" hidden/>
<input onchange="this.form.onsubmit()" type="file"/>
<input onchange="this.form.onsubmit()" type="checkbox"/>8bit
<input type=color value=#FFFFFF onchange="$('output').style.background=this.value">
</form>
<div style="display:flex;justify-content:center;"><output></output></div>
<form method="POST" action="http://ix.io/" enctype="text/plain">
<textarea name="f:1"></textarea>
</form>
</body>
<script>
</script>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment