str = `
⠀⠀⠀⠀⠀⠀⠀⣤⣤⣤⣤⣤⣤⡄⠀⠀⣀⣤⣤⣤⣤⡄⠀⠀⠀⣀⣤⣤⣤⣤⡀⠀⠀⠀⣀⣤⣤⣤⣤⡀⠀⠀⣀⡀⠀⣠⣶⠆⣴⡖⠀⣀⡀⠀⣀⣤⣤⣤⣤⣤⣤⣤⣤⣤⣤⡄
⠀⠀⠀⠀⠀⣀⣼⡿⠉⠉⠉⠉⠉⠀⣠⣾⡿⠋⠉⠙⣿⡿⠀⣠⣾⠟⠋⠉⢹⣿⡗⠀⣠⣾⠟⠋⠉⢹⣿⡇⠀⠀⣿⣷⣠⣿⠃⣼⣟⣤⡾⠟⠁⣀⣾⡟⠉⠉⣹⡿⠉⠉⢉⣿⠏⠀
⠀⠀⠀⠀⣠⣾⣿⣶⣶⣶⣦⠀⠀⣴⣿⠋⠀⠀⠀⣸⣿⢇⣼⡿⠃⠀⠀⠀⣼⣿⢃⣾⡿⠁⠀⠀⠀⣾⣿⠁⠀⠀⠛⣩⣿⢃⣾⣟⣝⠋⠀⠀⣀⣾⣟⣀⣀⣴⣿⣁⣀⣠⣿⠏⠀⠀
⠀⠀⠀⠀⠛⠋⠁⠀⠀⣿⡿⠀⣼⣿⠃⠀⠀⣀⣼⣿⠋⣾⣿⠁⠀⠀⣀⣼⡿⢃⣾⡿⠁⠀⠀⣀⣾⡿⠁⣴⣶⠾⣿⡿⢃⣾⡟⠙⣿⣷⠄⣀⣾⠟⠛⠛⠛⠛⠛⠛⢻⣿⠏⠀⠀⠀
⠀⠀⣰⣶⣆⣀⣀⣤⣾⠟⠁⣰⣿⣯⣀⣀⣤⣾⠟⠁⣸⣿⣧⣀⣀⣴⣿⠟⠁⣸⣿⣇⣀⣀⣴⣿⠟⠀⡈⣁⣤⣾⠟⣀⣾⠏⠀⣀⣾⠄⣠⣾⠏⠀⠀⠀⠀⠀⠀⣠⣿⠏⠀⠀⠀⠀
⠀⠀⡈⠛⠿⠿⠛⠋⠁⠀⠀⠀⠛⠿⠿⠛⠋⠁⠀⠀⡈⠛⠿⠟⠛⠋⠀⠀⠀⡈⠛⠿⠟⠛⠉⠀⠀⣶⡿⠟⠋⠀⠀⠾⢿⣷⠾⠿⠋⣠⣿⠏⠀⠀⠀⠀⡸⠿⠶⠿⠋⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣴⣤⢤⣄⠀⣠⣶⠦⠀⠀⠀⠀⠀⡰⣦⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣤⣤⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⡴⢟⣯⣄⣸⣿⣷⠿⠥⣴⣾⠄⠀⠀⠀⣴⡿⠋⠀⠀⠀⠀⠀⠀⠀⣀⣿⡆⠀⠀⠀⠀⢄⡀⠀⠀⠀⠀⠀⠀⠀⠀⣼⡿⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢉⣴⠿⠛⣷⡴⢋⣿⠟⠞⠋⠀⠀⠀⣀⣼⠟⠀⠀⠀⠀⠀⠀⠀⠀⣀⣾⠟⠀⡀⠀⠀⠀⣈⣿⡀⠀⠀⠀⠀⠀⠀⣰⡟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡠⢶⣿⠓⣶⣾⠛⣡⣿⡟⠀⠀⠀⠀⠀⣀⣾⠋⠀⠀⠀⠀⠀⡀⠀⠀⠀⣾⠏⣠⠞⠀⠀⣀⣠⣼⡿⠀⠀⠀⠀⠀⠀⣠⠏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣿⠃⣰⡿⣁⣾⠟⣰⣷⡀⠀⠀⠀⠀⣾⡇⠀⣀⣀⣤⡶⠋⠀⠀⠀⡸⣿⣿⠁⠀⠀⠀⠀⠙⠉⠀⠀⠀⠀⠀⣀⣤⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡰⠿⠋⢉⡿⠟⠋⠀⠀⣸⠟⠋⠀⠀⠀⠀⠻⠿⠿⠛⠋⠁⠀⠀⠀⠀⠀⠀⠉⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡘⠛⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
`
console.log(str)
JavaScript(ES2015)で点字を扱う方法についてのメモ。
点字は見た目からして2進数と親和性が高い。
ビット演算を学ぶのにいいかも?
Canvasについては説明なし。
点字の読み方も説明なし。
点字の種類
「6点点字(2×3)」と「8点点字(2×4)」の2種類がある。
6点点字
UnicodeのU+2800
〜U+283F
の64文字。
サイコロの6の目のような2×3の点が並ぶ。
点字の各点にはそれぞれ左上から順番に番号が振られている。
①④
②⑤
③⑥
Unicodeの点字はその番号をn桁目とする2進数の順番に並んでいる。
①③⑤に点を打つなら010101
で21番目。
Unicodeの文字の名称もBRAILLE PATTERN DOTS-135
等そのまま。
var dots135 = 0b010101 + 0x2800; //0bXXは2進数リテラル
String.fromCodePoint(dots135);
//=> ⠕
var dots246 = 0b101010 + 0x2800;
String.fromCodePoint(dots246);
//=> ⠪
全て取得するとこう。
var all = "";
for(var i = 0; i <= 0x3F; i++)
all += String.fromCodePoint(i + 0x2800);
⠀⠁⠂⠃⠄⠅⠆⠇⠈⠉⠊⠋⠌⠍⠎⠏⠐⠑⠒⠓⠔⠕⠖⠗⠘⠙⠚⠛⠜⠝⠞⠟⠠⠡⠢⠣⠤⠥⠦⠧⠨⠩⠪⠫⠬⠭⠮⠯⠰⠱⠲⠳⠴⠵⠶⠷⠸⠹⠺⠻⠼⠽⠾⠿
8点点字
UnicodeのU+2800
〜U+28FF
の256文字。
世界で使われている点字はほぼ全て6点点字。
8点点字は漢字等にしか使われない。Wikipedia: 8-dot braille scripts
この記事ではもちろん8点点字を使う。
点の番号は6点点字の下に点⑦⑧が後付けされる形。
①④
②⑤
③⑥
⑦⑧
このままでは2進数そのままの順番で扱えず都合が悪い。⑦の位置に④が来ないと困る。
2進数そのままの順番で点字を得られる関数を作っておく。
function numToBrailleLetter(n){
var flags = 0;
flags += (n & 0b00001000) << 3; //⑦を左シフト
flags += (n & 0b01110000) >> 1; //④⑤⑥を右シフト
flags += (n & 0b10000111); //①②③⑧はそのまま
return String.fromCodePoint(flags + 0x2800);
}
// 使用例:
var n = 0b11110000;//右1列の点
console.log(numToBrailleLetter(n));
//=> ⢸
ついでに逆も作る。使う予定は無し。
function brailleLetterToNum(c){
var u = c.codePointAt(0);
var flags = 0;
flags += (u & 0b01000000) >> 3;
flags += (u & 0b00111000) << 1;
flags += (u & 0b10000111);
return flags;
}
// 使用例:
var n = brailleLetterToNum("⢸");
console.log(n.toString(2));
//=> 11110000
全て取得するとこんな感じ。
var all = "";
for (var i = 0; i <= 0xFF; i++)
all += numToBrailleLetter(i);
⠀⠁⠂⠃⠄⠅⠆⠇⡀⡁⡂⡃⡄⡅⡆⡇⠈⠉⠊⠋⠌⠍⠎⠏⡈⡉⡊⡋⡌⡍⡎⡏
⠐⠑⠒⠓⠔⠕⠖⠗⡐⡑⡒⡓⡔⡕⡖⡗⠘⠙⠚⠛⠜⠝⠞⠟⡘⡙⡚⡛⡜⡝⡞⡟
⠠⠡⠢⠣⠤⠥⠦⠧⡠⡡⡢⡣⡤⡥⡦⡧⠨⠩⠪⠫⠬⠭⠮⠯⡨⡩⡪⡫⡬⡭⡮⡯
⠰⠱⠲⠳⠴⠵⠶⠷⡰⡱⡲⡳⡴⡵⡶⡷⠸⠹⠺⠻⠼⠽⠾⠿⡸⡹⡺⡻⡼⡽⡾⡿
⢀⢁⢂⢃⢄⢅⢆⢇⣀⣁⣂⣃⣄⣅⣆⣇⢈⢉⢊⢋⢌⢍⢎⢏⣈⣉⣊⣋⣌⣍⣎⣏
⢐⢑⢒⢓⢔⢕⢖⢗⣐⣑⣒⣓⣔⣕⣖⣗⢘⢙⢚⢛⢜⢝⢞⢟⣘⣙⣚⣛⣜⣝⣞⣟
⢠⢡⢢⢣⢤⢥⢦⢧⣠⣡⣢⣣⣤⣥⣦⣧⢨⢩⢪⢫⢬⢭⢮⢯⣨⣩⣪⣫⣬⣭⣮⣯
⢰⢱⢲⢳⢴⢵⢶⢷⣰⣱⣲⣳⣴⣵⣶⣷⢸⢹⢺⢻⢼⢽⢾⢿⣸⣹⣺⣻⣼⣽⣾⣿
↑これそのままソースに書き込んで使うなら上の変換関数は不要
Booleanの配列から点字にする
var ary = [
[true, false],
[false, true],
[true, false],
[false, true]
];
上の配列を⢕
に変換したい。
左上から順番に$2^n$をかけて足せばOK。
var flags = 0;
flags += ary[0][0] * 0b00000001; // 0x01 (1)
flags += ary[1][0] * 0b00000010; // 0x02 (2)
flags += ary[2][0] * 0b00000100; // 0x04 (4)
flags += ary[3][0] * 0b00001000; // 0x08 (8)
flags += ary[0][1] * 0b00010000; // 0x10 (16)
flags += ary[1][1] * 0b00100000; // 0x20 (32)
flags += ary[2][1] * 0b01000000; // 0x40 (64)
flags += ary[3][1] * 0b10000000; // 0x80 (128)
var letter = numToBrailleLetter(flags);
//=> ⢕
連番にするために論理和の代入とビットシフトに書き換えて..
var flags = 0;
flags |= ary[0][0] << 0;
flags |= ary[1][0] << 1;
flags |= ary[2][0] << 2;
flags |= ary[3][0] << 3;
flags |= ary[0][1] << 4;
flags |= ary[1][1] << 5;
flags |= ary[2][1] << 6;
flags |= ary[3][1] << 7;
var letter = numToBrailleLetter(flags);
//=> ⢕
ループにすればすっきり。
var flags = 0;
for (var r = 0; r < 4; r++)
for (var c = 0; c < 2; c++)
flags |= ary[r][c] << r + c * 4;
var letter = numToBrailleLetter(flags);
//=> ⢕
関数
上のを元にして作った、配列が何行*何列でも点字に変換する関数。
function boolAryToBrailleLetters(ary){
var flagsAry = [];
for (var r = 0; r < ary.length; r++){
if (r % 4 == 0) flagsAry.push([]);
for (var c = 0; c < ary[r].length; c++){
flagsAry[r / 4 | 0][c / 2 | 0] |= ary[r][c] << r % 4 + c % 2 * 4;)
}
}
return flagsAry.map(a=>a.map(n=>numToBrailleLetter(n)).join("")).join("\r\n");
}
var ary = [
[true, true, true],
[true, true, true],
[true, true, true],
[true, true, true],
[true, true, true]
];
console.log(boolAryToBrailleLetters(ary));
// ⣿⡇
// ⠉⠁
var ary = [[true]];
console.log(boolAryToBrailleLetters(ary));
// ⠁
あとはCanvasとかから画像のRGBデータを受け取って、RGBの平均とって白黒(true/false)の2値化してこの関数に渡すだけ。
動作例:http://jsdo.it/zakuroishikuro/MNbhM
おわり。
ズレ問題
点字は全て同じ幅なので、他の文字で作ったAAと違ってズレないはず。
そう思っていた時期が私にもありました。
- Mac・iPhoneでは完璧
- Windowsではズレる
- Androidではフォントが間違ってるので乱れる
結局フォントによるんだけど、点字を収録しているフォントなんてそうないし、フォントごとの個性を出しちゃいけない文字だと思うし、個人差無しのデフォのままで考えていいと思う。
Mac・iPhone
表示フォント: 「Apple Braille」 (Apple Symbolsにも一応入ってる)
Macには点字専用フォントが用意されている。
全くズレずに完璧に表示される。
iPhoneのフォント事情は知らないけどズレなかったのでMacと同じなのでは。
Windows
表示フォント: 「Segoe UI Symbol」
点字用の空白U+2800
の文字幅が他の点字と違うのでズレる。無意味。
本来の実用上は問題ないのかもしれないけど、なぜ同じ幅にしてくれなかった...。
対策:U+2800
をなるべく目立たなそうな⡀
で置換
Android
表示フォント:「Noto Sans Symbols」 (コメントで教えていただきました)
フォント内の一部の点字が間違っている。GitHubにIssueあり
右側にしか点が無いものが全て左寄りになってる。
つまり⠈⠐⠘⠠⠨⠰⠸⢀⢈⢐⢘⢠⢨⢰⢸
が⠁⠂⠃⠄⠅⠆⠇⡀⡁⡂⡃⡄⡅⡆⡇
と同じになってる。
対策:左下に点をつけて置換
⠈⠐⠘⠠⠨⠰⠸⢀⢈⢐⢘⢠⢨⢰⢸
→⡀⡈⡐⡘⡠⡨⡰⡸⣀⣈⣐⣘⣠⣨⣰⣸
Linux
分かりません。教えてください。
参考
点字で画像を表現するライブラリ (この記事書いたあとに見つけた)
mapscii
drawille
ちなみに@nullkal氏のトゥートで思いついた