LoginSignup
30
13

More than 5 years have passed since last update.

Unicodeの点字でお絵かき

Last updated at Posted at 2017-09-18
5000000000000000yen.js
str = `

⠀⠀⠀⠀⠀⠀⠀⣤⣤⣤⣤⣤⣤⡄⠀⠀⣀⣤⣤⣤⣤⡄⠀⠀⠀⣀⣤⣤⣤⣤⡀⠀⠀⠀⣀⣤⣤⣤⣤⡀⠀⠀⣀⡀⠀⣠⣶⠆⣴⡖⠀⣀⡀⠀⣀⣤⣤⣤⣤⣤⣤⣤⣤⣤⣤⡄
⠀⠀⠀⠀⠀⣀⣼⡿⠉⠉⠉⠉⠉⠀⣠⣾⡿⠋⠉⠙⣿⡿⠀⣠⣾⠟⠋⠉⢹⣿⡗⠀⣠⣾⠟⠋⠉⢹⣿⡇⠀⠀⣿⣷⣠⣿⠃⣼⣟⣤⡾⠟⠁⣀⣾⡟⠉⠉⣹⡿⠉⠉⢉⣿⠏⠀
⠀⠀⠀⠀⣠⣾⣿⣶⣶⣶⣦⠀⠀⣴⣿⠋⠀⠀⠀⣸⣿⢇⣼⡿⠃⠀⠀⠀⣼⣿⢃⣾⡿⠁⠀⠀⠀⣾⣿⠁⠀⠀⠛⣩⣿⢃⣾⣟⣝⠋⠀⠀⣀⣾⣟⣀⣀⣴⣿⣁⣀⣠⣿⠏⠀⠀
⠀⠀⠀⠀⠛⠋⠁⠀⠀⣿⡿⠀⣼⣿⠃⠀⠀⣀⣼⣿⠋⣾⣿⠁⠀⠀⣀⣼⡿⢃⣾⡿⠁⠀⠀⣀⣾⡿⠁⣴⣶⠾⣿⡿⢃⣾⡟⠙⣿⣷⠄⣀⣾⠟⠛⠛⠛⠛⠛⠛⢻⣿⠏⠀⠀⠀
⠀⠀⣰⣶⣆⣀⣀⣤⣾⠟⠁⣰⣿⣯⣀⣀⣤⣾⠟⠁⣸⣿⣧⣀⣀⣴⣿⠟⠁⣸⣿⣇⣀⣀⣴⣿⠟⠀⡈⣁⣤⣾⠟⣀⣾⠏⠀⣀⣾⠄⣠⣾⠏⠀⠀⠀⠀⠀⠀⣠⣿⠏⠀⠀⠀⠀
⠀⠀⡈⠛⠿⠿⠛⠋⠁⠀⠀⠀⠛⠿⠿⠛⠋⠁⠀⠀⡈⠛⠿⠟⠛⠋⠀⠀⠀⡈⠛⠿⠟⠛⠉⠀⠀⣶⡿⠟⠋⠀⠀⠾⢿⣷⠾⠿⠋⣠⣿⠏⠀⠀⠀⠀⡸⠿⠶⠿⠋⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣴⣤⢤⣄⠀⣠⣶⠦⠀⠀⠀⠀⠀⡰⣦⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣤⣤⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⡴⢟⣯⣄⣸⣿⣷⠿⠥⣴⣾⠄⠀⠀⠀⣴⡿⠋⠀⠀⠀⠀⠀⠀⠀⣀⣿⡆⠀⠀⠀⠀⢄⡀⠀⠀⠀⠀⠀⠀⠀⠀⣼⡿⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢉⣴⠿⠛⣷⡴⢋⣿⠟⠞⠋⠀⠀⠀⣀⣼⠟⠀⠀⠀⠀⠀⠀⠀⠀⣀⣾⠟⠀⡀⠀⠀⠀⣈⣿⡀⠀⠀⠀⠀⠀⠀⣰⡟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡠⢶⣿⠓⣶⣾⠛⣡⣿⡟⠀⠀⠀⠀⠀⣀⣾⠋⠀⠀⠀⠀⠀⡀⠀⠀⠀⣾⠏⣠⠞⠀⠀⣀⣠⣼⡿⠀⠀⠀⠀⠀⠀⣠⠏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣿⠃⣰⡿⣁⣾⠟⣰⣷⡀⠀⠀⠀⠀⣾⡇⠀⣀⣀⣤⡶⠋⠀⠀⠀⡸⣿⣿⠁⠀⠀⠀⠀⠙⠉⠀⠀⠀⠀⠀⣀⣤⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡰⠿⠋⢉⡿⠟⠋⠀⠀⣸⠟⠋⠀⠀⠀⠀⠻⠿⠿⠛⠋⠁⠀⠀⠀⠀⠀⠀⠉⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡘⠛⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
`
console.log(str)

点文字ジェネレータ (jsdo.it)

JavaScript(ES2015)で点字を扱う方法についてのメモ。
点字は見た目からして2進数と親和性が高い。
ビット演算を学ぶのにいいかも?

Canvasについては説明なし。
点字の読み方も説明なし。

点字の種類

「6点点字(2×3)」と「8点点字(2×4)」の2種類がある。

6点点字

UnicodeのU+2800U+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+2800U+28FFの256文字。

世界で使われている点字はほぼ全て6点点字。
8点点字は漢字等にしか使われない。Wikipedia: 8-dot braille scripts
この記事ではもちろん8点点字を使う。

点の番号は6点点字の下に点⑦⑧が後付けされる形。

①④
②⑤
③⑥
⑦⑧

このままでは2進数そのままの順番で扱えず都合が悪い。⑦の位置に④が来ないと困る。
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));
//=> ⢸

ついでに逆も作る。使う予定は無し。

点字から2進数へ
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);
//=> ⢕

関数

上のを元にして作った、配列が何行*何列でも点字に変換する関数。

Booleanの配列から点字の文字列にする関数
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

分かりません。教えてください。

参考

Wikipedia - Braille Patterns

点字で画像を表現するライブラリ (この記事書いたあとに見つけた)
mapscii
drawille

ちなみに@nullkal氏のトゥートで思いついた

30
13
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
30
13