画像ファイルをアスキーアートに変換してみる
アスキーアートに使用する主なメソッド
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>
Apple Rooms laboratoryの運営者