Created
July 6, 2025 21:32
-
-
Save yne/6e83bcaac2a1e9b56b7e503870c56cfd to your computer and use it in GitHub Desktop.
image to ansi code graphic
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 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=' ' | |
| 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