絵や写真を文字だけで描いてみよう

0

画像ファイルをアスキーアートに変換してみる

アスキーアートに使用する主なメソッド

drawImage(image,x,y,width,height)
#キャンバスの指定された短形に画像を描画する

getImageData(x,y,width,height)
#キャンバスの指定された短形内にある画像データをImageDataオブジェクトとして返す

ImageDataオブジェクト.data
#imageDataオブジェクトに格納されているピクセルデータの配列。1ピクセルにつき4つの要素(RGBA)の値(0~255)が順に格納されている

putimageData(ImageDataオブジェクト,x,y)
#キャンバスに指定された位置にImageDataオブジェクトを描画する

font
#描画するテキストのスタイルを指定するプロパティ
#CSSフォントを指定。初期値は「10px sans-serif」

fillText(文字列,x,y)
#指定された位置に文字列を塗りつぶして描写する。

String.fromCharCode(num1[,....[numN]])
#指定されたユニコードの文字列を返す。ここでは32~126の値を指定し半角スペースから「~」までの文字を取得している
<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<title>アスキーアートに変換まん</title>
	<script>
		let canvas,context; //キャンバス
		let textCanvas,textContext;	//テキスト用キャンバス
		const image = new Image();	//画像

		const init = () => {
			//キャンバスの取得
			canvas = document.getElementById("image");
			context = canvas.getContext("2d");
			textCanvas = document.getElementById("text");
			textContext = textCanvas.getContext("2d");
		}

		const loadImage = files => {
			//画像の読み込み
			image.src = URL.createObjectURL(files[0]);
			image.onload = () => {
				//画像の描画+2値化
				drawImage();
			}
		}

		const drawImage = () => {
			//画像を描画
			context.fillStyle = "#FFFFFF";
			context.fillRect(0,0,canvas.width,canvas.height);
			let sx,sy,sw,sh;
			if (image.width > image.height) {
				[sw,sh] = [image.width,image.width];
				[sx,sy] = [0,image.height/2 - sh/2];
			} else {
				[sw,sh] = [image.height, image.height];
				[sx,sy] = [image.width/2 - sw/2,0];
			}
			context.drawImage(image,sx,sy,sw,sh,0,0,canvas.width,canvas.height);
			//閾値の取得
			const t = document.getElementById("t").value;
			document.getElementById("tText").innerText = t;
			//画像の2値化
			const imageData = context.getImageData(0,0,canvas.width,canvas.height);
			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];
				let mono = 0.299 * r + 0.587 * g + 0.114 * b;
				if (mono > t) {
					mono = 255;
				}	else {
					mono = 0;
				}
				imageData.data[i] = mono;
				imageData.data[i+1] = mono;
				imageData.data[i+2] = mono;
			}
			context.putImageData(imageData,0,0);
		}

		const makeAA = () => {
			//解像度を取得
			const level = document.getElementById("level").value;
			const w = (4 - level) * 5
			//テキストデータを取得
			const textImageData = new Array();
			textContext.font = `${w*2}px monospace`;
			textContext.textAlign = "left";
			textContext.textBaseline = "top";
			for (let i = 32; i<= 126; i++)	{
				//テキストの描画
				textContext.fillStyle = "#FFFFFF";
				textContext.fillRect(0,0,w,w*2);
				textContext.fillStyle = "#000000"
				textContext.fillText(String.fromCharCode(i),0,0);
				//2値化
				textImageData[i-32] = textContext.getImageData(0,0,w,w*2);
				for (let j=0; j<textImageData[i-32].data.length; j+=4)	{
					const r = textImageData[i-32].data[j];
					const g = textImageData[i-32].data[j+1];
					const b = textImageData[i-32].data[j+2];
					let mono = 0.299 * r + 0.587 * g + 0.114 * b;
					if (mono > 100)	{
						mono = 255;
					} else {
						mono = 0;
					}
					textImageData[i-32].data[j] = mono;
					textImageData[i-32].data[j+1] = mono;
					textImageData[i-32].data[j+2] = mono;
				}
			}
			//画像データを取得
			const imageData = new Array();
			for (let y=0; y<canvas.height; y+=w*2)	{
				for (let x=0; x<canvas.width; x+=w)	{
					imageData.push(context.getImageData(x,y,w,w*2));
				}
			}
			//アスキーアートの作成
			if (level == 3)	{
				document.getElementById("aa").style.fontSize = "10px";
			} else {
				document.getElementById("aa").style.fontSize = "20px";
			}
			document.getElementById("aa").innerText = "";
			for (let i=0; i<imageData.length; i++)	{
				let maxScore = 0;
				let text = " ";
				for (let j=32; j<=126; j++)	{
					let score=0;
					for (let k=0; k<imageData[i].data.length; k+=4)	{
						const iColor = imageData[i].data[k];
						const tColor = textImageData[j-32].data[k];
						if (iColor == tColor) score++;
					}
					if (score > maxScore)	{
						maxScore = score;
						text = String.fromCharCode(j);
					}
				}
				document.getElementById("aa").innerText += text;
				//改行
				if (i%(canvas.width/w)	== canvas.width/w -1)	{
					document.getElementById("aa").innerText += "\n";
				}
			}
		}
		</script>
		<style>	
			#text {display: none;}
			#image {
				margin-right: 10px;
				float: left;
				border: thin solid #000000;
			}
			#aa {
				font-family: monospace;
				margin: 0px;
			}
		</style>
	</head>
	<body onload="init()">
		<p>アスキーアート変換まん</p>
		<input type="file" accept="image/*" onchange="loadImage(this.files)">
		<hr>
		閾値:<input type="range" id="t" value="100" min="1" max="255"
		onchange="drawImage()">[<span id="tText">100</span>]
		解像度:<input type="range" id="level" value="2" min="1" max="3">
		<input type="button" value="変換" onclick="makeAA()">
		</hr>
		<canvas id="text" width="15" height="30"></canvas>
		<canvas id="image" width="600" height="600"></canvas>
		<pre id="aa"></pre>		
	</body>
</html>

返事を書く

Please enter your comment!
Please enter your name here

CAPTCHA