@danything/arib 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,314 @@
1
+ /**
2
+ * ARIB STD-B24 の8単位符号を読む。番組名・概要・局名はこの形式で流れてくる。
3
+ *
4
+ * ## 仕組み
5
+ *
6
+ * 符号表を4つ (G0〜G3) 持ち、**どの表を今使うか**を切り替えながら読む。
7
+ * 0x21〜0x7E は GL に、0xA1〜0xFE は GR に割り当てられた表で引く。
8
+ * SI の初期状態は G0=漢字 / G1=英数 / G2=ひらがな / G3=カタカナ、GL=G0・GR=G2。
9
+ *
10
+ * ## 英数の幅は文字の大きさで決まる
11
+ *
12
+ * 英数集合 (と空白) は**いまの文字の大きさ**で描く。SI の初期状態は標準 (NSZ) で、
13
+ * テレビはこれを全角で描く。半角にしたい局は中型 (MSZ) を挟んでくる (ARIB TR-B14)。
14
+ * 番組名の「Venue101」は英数集合を標準のまま送ったもの。**放送のとおりに出す** —
15
+ * 探すときや比べるときに半角へ寄せるのは使う側 (`fold.toHalfWidth` / `title.searchable`)。
16
+ * 全角は `toHalfWidth` でそのまま戻る字 (U+FF01〜U+FF5E) にする (0x5C は \、0x7E は ~)
17
+ *
18
+ * ## 漢字は EUC-JP に押し付ける
19
+ *
20
+ * 2バイトの漢字集合は JIS X 0208 そのもので、区点は (第1-0x20, 第2-0x20)。
21
+ * **各バイトの最上位を立てれば EUC-JP になる**ので、変換表を抱え込まずに
22
+ * `TextDecoder('euc-jp')` に渡せる。自前で持つのは規格の外にある外字だけ
23
+ * ([aribtext-gaiji.ts](aribtext-gaiji.ts))。
24
+ */
25
+ import { GAIJI } from "./aribtext-gaiji.js";
26
+ import { HIRAGANA as HIRAGANA_TABLE, JISX0201_HALF, KATAKANA as KATAKANA_TABLE, } from "./b24-tables.js";
27
+ const KANJI = { bytes: 2, kind: "kanji" };
28
+ const ALNUM = { bytes: 1, kind: "alnum" };
29
+ const HIRAGANA = { bytes: 1, kind: "hiragana" };
30
+ const KATAKANA = { bytes: 1, kind: "katakana" };
31
+ /** 図形にしかならない集合 (モザイク・DRCS)。字数だけ数えて中身は出さない */
32
+ const MOSAIC = { bytes: 1, kind: "blank" };
33
+ /**
34
+ * 終端バイト → 符号表。ESC の指示で使う。
35
+ *
36
+ * モザイク (0x32〜0x35) は図形なので読めるものが無い。**捨てずに空へ倒す**のは、
37
+ * 1バイト表として字数を数え続けないと以降がずれるため。
38
+ *
39
+ * **オブジェクトではなく Map。** 数値のキーは書式が10進に直されてしまい、
40
+ * 規格に載っている終端バイトと突き合わせられなくなる (この下も同じ)。
41
+ */
42
+ const CHARSETS = new Map([
43
+ [0x42, KANJI],
44
+ [0x39, KANJI], // JIS互換漢字1面
45
+ [0x3a, { bytes: 2, kind: "plane2" }], // JIS互換漢字2面
46
+ [0x3b, { bytes: 2, kind: "symbol" }], // 追加記号
47
+ [0x4a, ALNUM],
48
+ [0x30, HIRAGANA],
49
+ [0x31, KATAKANA],
50
+ [0x49, { bytes: 1, kind: "ank" }], // JIS X 0201 カタカナ (半角)
51
+ [0x36, ALNUM], // プロポーショナル英数
52
+ [0x37, HIRAGANA],
53
+ [0x38, KATAKANA],
54
+ [0x32, MOSAIC],
55
+ [0x33, MOSAIC],
56
+ [0x34, MOSAIC],
57
+ [0x35, MOSAIC],
58
+ ]);
59
+ /** 外字にも JIS にも無い文字を出すときの印。消すとタイトルから1文字黙って落ちる */
60
+ const UNKNOWN = "□";
61
+ /**
62
+ * 1バイトの集合は字幕と同じ表 ([b24-tables.ts](b24-tables.ts)) を引く。**番組表で違えるところ**:
63
+ *
64
+ * - ひらがなの 0x74〜0x76 は規格で空き。字幕は全角の空白で埋めるが、番組表では何も出さない
65
+ * - JIS X 0201 カタカナはいつも半角 (字幕は大きさで全角と半角を描き分ける)
66
+ * - 英数は大きさに従って全角か ASCII (字幕の半角の表は 0x5C が ¥、0x7E が ‾。番組表は検索で打つ字に合わせる)
67
+ * - 漢字は EUC-JP のまま読む (字幕は 1区33点の 〜・34点の ‖・61点の − などを差し替える。`KANJI_DIFF`)
68
+ */
69
+ const HIRA = [...HIRAGANA_TABLE];
70
+ const KATA = [...KATAKANA_TABLE];
71
+ const ANK = [...JISX0201_HALF];
72
+ const eucjp = new TextDecoder("euc-jp");
73
+ /**
74
+ * 2バイト文字の変換結果を覚えておく。
75
+ *
76
+ * 番組表は同じ字が何万回も出てくるので、1文字ごとに `TextDecoder` を
77
+ * 呼び直すと配列の確保だけで効いてくる。
78
+ */
79
+ const cache = new Map();
80
+ function twoByte(code, plane2) {
81
+ // 2面は同じ区点でも別の字。覚えるときも外字を引くときも1面と混ぜない
82
+ const key = plane2 ? code | 0x10000 : code;
83
+ const cached = cache.get(key);
84
+ if (cached !== undefined)
85
+ return cached;
86
+ const gaiji = plane2 ? undefined : GAIJI.get(code);
87
+ const high = code >> 8;
88
+ const low = code & 0xff;
89
+ // EUC-JP は最上位を立てたもの。2面は 0x8F を頭に付ける
90
+ const bytes = plane2
91
+ ? Uint8Array.of(0x8f, high | 0x80, low | 0x80)
92
+ : Uint8Array.of(high | 0x80, low | 0x80);
93
+ // 85区から先は外字の表だけで引く。EUC-JP に渡すと 89〜92区が IBM 拡張の漢字になる
94
+ const decoded = gaiji ?? (!plane2 && high >= 0x75 ? "" : eucjp.decode(bytes));
95
+ // 変換できないと置換文字が返る。そのまま出すとタイトルに「�」が並ぶ
96
+ const text = decoded === "" || decoded.includes("�") ? UNKNOWN : decoded;
97
+ cache.set(key, text);
98
+ return text;
99
+ }
100
+ /** C0 の制御符号が後ろに従える引数の数。ここを間違えると以降が全部ずれる */
101
+ const C0_PARAMS = new Map([
102
+ [0x16, 1], // PAPF
103
+ [0x1c, 2], // APS
104
+ ]);
105
+ /** 文字の大きさ (C1)。小型 SSZ と中型 MSZ は英数と空白を半角で描く */
106
+ const SSZ = 0x88;
107
+ const MSZ = 0x89;
108
+ const NSZ = 0x8a;
109
+ const SZX = 0x8b;
110
+ /** SZX の引数のうち半角にあたるもの (超小型 TSZ)。ほかは倍角・特殊で、幅は標準と同じに扱う */
111
+ const SZX_TINY = 0x60;
112
+ /** 標準の大きさの空白 (U+3000) */
113
+ const WIDE_SPACE = String.fromCharCode(0x3000);
114
+ /** C1 も同じ。COL/CDC は最初の引数が 0x20 のときだけもう1つ増える */
115
+ const C1_PARAMS = new Map([
116
+ [0x8b, 1], // SZX
117
+ [0x90, 1], // COL
118
+ [0x91, 1], // FLC
119
+ [0x92, 1], // CDC
120
+ [0x93, 1], // POL
121
+ [0x94, 1], // WMM
122
+ [0x97, 1], // HLC
123
+ [0x98, 1], // RPC
124
+ [0x9d, 2], // TIME
125
+ ]);
126
+ /**
127
+ * 8単位符号を読んで文字列にする。
128
+ *
129
+ * 壊れた並びで例外を投げない。放送波は落ちるもので、1つの記述子が読めなくても
130
+ * 番組表全体を落とすほうが害が大きい。**読めたところまで返す。**
131
+ */
132
+ export function decodeAribText(data) {
133
+ const g = [KANJI, ALNUM, HIRAGANA, KATAKANA];
134
+ let gl = 0;
135
+ let gr = 2;
136
+ /** 単発シフト (SS2/SS3)。1文字だけ別の表を使ったら元に戻す */
137
+ let single = null;
138
+ /** 英数と空白を半角で描く大きさか (MSZ/SSZ)。SI の初期状態は標準 (NSZ) で全角 */
139
+ let half = false;
140
+ let out = "";
141
+ let at = 0;
142
+ /** ESC の指示先。0x28〜0x2B が G0〜G3 */
143
+ const designate = (target, set) => {
144
+ if (set !== undefined && target >= 0 && target <= 3)
145
+ g[target] = set;
146
+ };
147
+ while (at < data.length) {
148
+ const byte = data[at];
149
+ // --- 制御符号 (C0) ------------------------------------------------
150
+ if (byte <= 0x20 || byte === 0x7f || byte === 0xa0 || byte === 0xff) {
151
+ at++;
152
+ switch (byte) {
153
+ case 0x0d: // APR。改行。直後の LF は同じ1回として畳む
154
+ out += "\n";
155
+ if (data[at] === 0x0a)
156
+ at++;
157
+ break;
158
+ case 0x0a: // APD。局によってはこちらで改行してくる
159
+ out += "\n";
160
+ break;
161
+ case 0x20: // SP。空白の幅も大きさに従う
162
+ case 0xa0:
163
+ out += half ? " " : WIDE_SPACE;
164
+ break;
165
+ case 0x0e: // LS1
166
+ gl = 1;
167
+ break;
168
+ case 0x0f: // LS0
169
+ gl = 0;
170
+ break;
171
+ case 0x19: // SS2
172
+ single = 2;
173
+ break;
174
+ case 0x1d: // SS3
175
+ single = 3;
176
+ break;
177
+ case 0x1b:
178
+ at = afterEscape(data, at, designate, (l, r) => {
179
+ if (l !== null)
180
+ gl = l;
181
+ if (r !== null)
182
+ gr = r;
183
+ });
184
+ break;
185
+ default:
186
+ at += C0_PARAMS.get(byte) ?? 0;
187
+ break;
188
+ }
189
+ continue;
190
+ }
191
+ // --- 制御符号 (C1) ------------------------------------------------
192
+ if (byte >= 0x80 && byte <= 0x9f) {
193
+ at++;
194
+ if (byte === 0x9b) {
195
+ // CSI。引数のあと 0x40 以上の終端バイトが来るまで読み飛ばす
196
+ while (at < data.length && data[at] < 0x40)
197
+ at++;
198
+ at++;
199
+ continue;
200
+ }
201
+ if (byte === 0x95) {
202
+ // MACRO。0x4F で終わる
203
+ while (at < data.length && data[at] !== 0x4f)
204
+ at++;
205
+ at++;
206
+ continue;
207
+ }
208
+ if (byte === SSZ || byte === MSZ)
209
+ half = true;
210
+ else if (byte === NSZ)
211
+ half = false;
212
+ else if (byte === SZX)
213
+ half = data[at] === SZX_TINY;
214
+ let params = C1_PARAMS.get(byte) ?? 0;
215
+ // COL と CDC は「色を直に指定する」形のときだけ引数が1つ増える
216
+ if ((byte === 0x90 || byte === 0x92) && data[at] === 0x20)
217
+ params = 2;
218
+ at += params;
219
+ continue;
220
+ }
221
+ // --- 図形文字 ---------------------------------------------------
222
+ const area = single !== null ? single : byte >= 0xa1 ? gr : gl;
223
+ single = null;
224
+ const set = g[area];
225
+ const first = byte & 0x7f;
226
+ if (set.bytes === 2) {
227
+ const second = (data[at + 1] ?? 0) & 0x7f;
228
+ at += 2;
229
+ if (second < 0x21)
230
+ continue;
231
+ out +=
232
+ set.kind === "blank"
233
+ ? ""
234
+ : twoByte((first << 8) | second, set.kind === "plane2");
235
+ continue;
236
+ }
237
+ at += 1;
238
+ out += oneByte(first, set.kind, half);
239
+ }
240
+ return out;
241
+ }
242
+ function oneByte(code, kind, half) {
243
+ switch (kind) {
244
+ case "alnum":
245
+ // 英数集合は ASCII と同じ並び。標準の大きさなら全角 (U+FF01〜) にずらす
246
+ return String.fromCharCode(half ? code : code + 0xfee0);
247
+ case "hiragana":
248
+ return code >= 0x74 && code <= 0x76 ? "" : (HIRA[code - 0x21] ?? "");
249
+ case "katakana":
250
+ return KATA[code - 0x21] ?? "";
251
+ case "ank": {
252
+ // JIS X 0201 の右半分 (半角カナ)。0x60 から先は空き
253
+ const char = ANK[code - 0x21];
254
+ return char === undefined || char === "�" ? "" : char;
255
+ }
256
+ default:
257
+ // モザイクと DRCS (`blank`)。画像なので何も出さない (字数だけ数える)
258
+ return "";
259
+ }
260
+ }
261
+ /** 呼び出し (ESC のあと)。LS2/LS3 と、GR 側の LS1R/LS2R/LS3R → [GL, GR] */
262
+ const LOCKING = new Map([
263
+ [0x6e, [2, null]],
264
+ [0x6f, [3, null]],
265
+ [0x7e, [null, 1]],
266
+ [0x7d, [null, 2]],
267
+ [0x7c, [null, 3]],
268
+ ]);
269
+ /**
270
+ * ESC のあとを読む。**指示 (どの表を G0〜G3 に載せるか) と
271
+ * 呼び出し (どの G を GL/GR に出すか) の2種類がある。**
272
+ *
273
+ * @returns 次に読むべき位置
274
+ */
275
+ function afterEscape(data, at, designate, invoke) {
276
+ const byte = data[at];
277
+ if (byte === undefined)
278
+ return at + 1;
279
+ const shift = LOCKING.get(byte);
280
+ if (shift !== undefined) {
281
+ invoke(shift[0], shift[1]);
282
+ return at + 1;
283
+ }
284
+ // 2バイト集合の指示。ESC 0x24 F は G0 への指示の略記
285
+ if (byte === 0x24) {
286
+ const next = data[at + 1];
287
+ if (next === undefined)
288
+ return at + 2;
289
+ if (next >= 0x28 && next <= 0x2b) {
290
+ // ESC 0x24 0x2x 0x20 F は2バイトDRCS。読めないので空へ倒す
291
+ if (data[at + 2] === 0x20) {
292
+ designate(next - 0x28, { bytes: 2, kind: "blank" });
293
+ return at + 4;
294
+ }
295
+ designate(next - 0x28, CHARSETS.get(data[at + 2]));
296
+ return at + 3;
297
+ }
298
+ designate(0, CHARSETS.get(next));
299
+ return at + 2;
300
+ }
301
+ // 1バイト集合の指示
302
+ if (byte >= 0x28 && byte <= 0x2b) {
303
+ const target = byte - 0x28;
304
+ if (data[at + 1] === 0x20) {
305
+ // 1バイトDRCS
306
+ designate(target, { bytes: 1, kind: "blank" });
307
+ return at + 3;
308
+ }
309
+ designate(target, CHARSETS.get(data[at + 1]));
310
+ return at + 2;
311
+ }
312
+ // 知らない指示。1バイトだけ飛ばして読み進める (止めるより取り返しがつく)
313
+ return at + 1;
314
+ }
@@ -0,0 +1,50 @@
1
+ /**
2
+ * 字幕の文字の表。**denpa が手で持つ** (字幕をデコードするのは [b24caption.ts](b24caption.ts)、番組表の外字は
3
+ * [aribtext-gaiji.ts](aribtext-gaiji.ts) がここの追加記号を引いて作る)。
4
+ *
5
+ * 元は libaribcaption v1.1.2 の表 (b24_conv_tables.hpp / b24_gaiji_table.hpp / b24_colors.cpp /
6
+ * b24_drcs_conv.cpp) に denpa の外字の直しを当てたもの。ここが元で、上流は追わない。
7
+ *
8
+ * libaribcaption: Copyright (C) 2021 magicxqq <xqq@xqq.im> (MIT。docs/licenses.md)
9
+ *
10
+ * **表の名前と `export const` の形は変えない。** danything/denpa-font の道具がこのファイルを
11
+ * 名前で読んでフォントに入れる字を決める (`ADDITIONAL_ROWS` も。`aribtext-gaiji.ts`・`fold.ts` も同じ)。
12
+ *
13
+ * - 漢字は EUC-JP で読んだものと違うところだけ持つ (`KANJI_DIFF`。番組表は EUC-JP のまま読む —
14
+ * 1区33点の 〜 / ~ などは字幕と番組表で違えてある。aribtext.ts の説明)
15
+ * - U+FFFD は規格で空いているところ
16
+ *
17
+ * ## 外字 (DRCS) の置き換えを足す
18
+ *
19
+ * 放送は字幕の外字を小さな画像で送ってくる。画像の MD5 (`b24caption.ts` が中身の画素から取る) が
20
+ * `DRCS_REPLACE` にあれば、その字に置き換えて描く (無ければ画像のまま)。足すときは:
21
+ *
22
+ * 1. 字幕の JSON (`/api/recordings/<id>/captions.json` の `drcs`) の `md5` を読み取る。`data` の画像は送るために
23
+ * なめらかにしたもの (drcs-smooth.ts) なので、`data` から MD5 を取っても表と合わない
24
+ * 2. `[MD5, 字のコードポイント]` を足し、行末に「何の字か・どこで見たか (局・日付)」を書く
25
+ * 3. フォントにその字があること (無い字に置き換えると豆腐になる。画像のままのほうがよい)
26
+ */
27
+ /** ひらがな集合 (0x21〜0x7E)。0x74〜0x76 は規格で空き (字幕は全角の空白で埋める) */
28
+ export declare const HIRAGANA = "\u3041\u3042\u3043\u3044\u3045\u3046\u3047\u3048\u3049\u304A\u304B\u304C\u304D\u304E\u304F\u3050\u3051\u3052\u3053\u3054\u3055\u3056\u3057\u3058\u3059\u305A\u305B\u305C\u305D\u305E\u305F\u3060\u3061\u3062\u3063\u3064\u3065\u3066\u3067\u3068\u3069\u306A\u306B\u306C\u306D\u306E\u306F\u3070\u3071\u3072\u3073\u3074\u3075\u3076\u3077\u3078\u3079\u307A\u307B\u307C\u307D\u307E\u307F\u3080\u3081\u3082\u3083\u3084\u3085\u3086\u3087\u3088\u3089\u308A\u308B\u308C\u308D\u308E\u308F\u3090\u3091\u3092\u3093\u3000\u3000\u3000\u309D\u309E\u30FC\u3002\u300C\u300D\u3001\u30FB";
29
+ /** カタカナ集合 (0x21〜0x7E) */
30
+ export declare const KATAKANA = "\u30A1\u30A2\u30A3\u30A4\u30A5\u30A6\u30A7\u30A8\u30A9\u30AA\u30AB\u30AC\u30AD\u30AE\u30AF\u30B0\u30B1\u30B2\u30B3\u30B4\u30B5\u30B6\u30B7\u30B8\u30B9\u30BA\u30BB\u30BC\u30BD\u30BE\u30BF\u30C0\u30C1\u30C2\u30C3\u30C4\u30C5\u30C6\u30C7\u30C8\u30C9\u30CA\u30CB\u30CC\u30CD\u30CE\u30CF\u30D0\u30D1\u30D2\u30D3\u30D4\u30D5\u30D6\u30D7\u30D8\u30D9\u30DA\u30DB\u30DC\u30DD\u30DE\u30DF\u30E0\u30E1\u30E2\u30E3\u30E4\u30E5\u30E6\u30E7\u30E8\u30E9\u30EA\u30EB\u30EC\u30ED\u30EE\u30EF\u30F0\u30F1\u30F2\u30F3\u30F4\u30F5\u30F6\u30FD\u30FE\u30FC\u3002\u300C\u300D\u3001\u30FB";
31
+ /** 中くらい (MSZ) のときに半角へ寄せる、かなの表の 0x79 以降 */
32
+ export declare const KANA_SYMBOLS_HALF = "\uFF70\uFF61\uFF62\uFF63\uFF64\uFF65";
33
+ /** JIS X 0201 カタカナ集合。字幕は全角で描く */
34
+ export declare const JISX0201 = "\u3002\u300C\u300D\u3001\u30FB\u30F2\u30A1\u30A3\u30A5\u30A7\u30A9\u30E3\u30E5\u30E7\u30C3\u30FC\u30A2\u30A4\u30A6\u30A8\u30AA\u30AB\u30AD\u30AF\u30B1\u30B3\u30B5\u30B7\u30B9\u30BB\u30BD\u30BF\u30C1\u30C4\u30C6\u30C8\u30CA\u30CB\u30CC\u30CD\u30CE\u30CF\u30D2\u30D5\u30D8\u30DB\u30DE\u30DF\u30E0\u30E1\u30E2\u30E4\u30E6\u30E8\u30E9\u30EA\u30EB\u30EC\u30ED\u30EF\u30F3\u309B\u309C\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD";
35
+ /** 同じものの半角 (中くらいのとき。番組表はいつもこちら) */
36
+ export declare const JISX0201_HALF = "\uFF61\uFF62\uFF63\uFF64\uFF65\uFF66\uFF67\uFF68\uFF69\uFF6A\uFF6B\uFF6C\uFF6D\uFF6E\uFF6F\uFF70\uFF71\uFF72\uFF73\uFF74\uFF75\uFF76\uFF77\uFF78\uFF79\uFF7A\uFF7B\uFF7C\uFF7D\uFF7E\uFF7F\uFF80\uFF81\uFF82\uFF83\uFF84\uFF85\uFF86\uFF87\uFF88\uFF89\uFF8A\uFF8B\uFF8C\uFF8D\uFF8E\uFF8F\uFF90\uFF91\uFF92\uFF93\uFF94\uFF95\uFF96\uFF97\uFF98\uFF99\uFF9A\uFF9B\uFF9C\uFF9D\uFF9E\uFF9F\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD";
37
+ /** 英数集合。字幕は全角で描く */
38
+ export declare const ALNUM_FULL = "\uFF01\uFF02\uFF03\uFF04\uFF05\uFF06\uFF07\uFF08\uFF09\uFF0A\uFF0B\uFF0C\uFF0D\uFF0E\uFF0F\uFF10\uFF11\uFF12\uFF13\uFF14\uFF15\uFF16\uFF17\uFF18\uFF19\uFF1A\uFF1B\uFF1C\uFF1D\uFF1E\uFF1F\uFF20\uFF21\uFF22\uFF23\uFF24\uFF25\uFF26\uFF27\uFF28\uFF29\uFF2A\uFF2B\uFF2C\uFF2D\uFF2E\uFF2F\uFF30\uFF31\uFF32\uFF33\uFF34\uFF35\uFF36\uFF37\uFF38\uFF39\uFF3A\uFF3B\uFFE5\uFF3D\uFF3E\uFF3F\uFF40\uFF41\uFF42\uFF43\uFF44\uFF45\uFF46\uFF47\uFF48\uFF49\uFF4A\uFF4B\uFF4C\uFF4D\uFF4E\uFF4F\uFF50\uFF51\uFF52\uFF53\uFF54\uFF55\uFF56\uFF57\uFF58\uFF59\uFF5A\uFF5B\uFF5C\uFF5D\uFFE3";
39
+ /** 同じものの半角 (中くらいのとき)。0x5C は ¥、0x7E は ‾ (番組表は ASCII のまま。バックスラッシュとチルダ) */
40
+ export declare const ALNUM_HALF = "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\u00A5]^_`abcdefghijklmnopqrstuvwxyz{|}\u203E";
41
+ /** 漢字の表の1・2区を、中くらいのときに半角へ寄せたもの */
42
+ export declare const KANJI_SYMBOLS_HALF = " \uFF64\uFF61,.\uFF65:;?!\uFF9E\uFF9F\u00B4`\u00A8^\u00AF_\u30FD\u30FE\u309D\u309E\u3003\u4EDD\u3005\u3006\u3007\uFF70\u2015\u2010/\\~\u2016|\u2026\u2025\u2018\u2019\u201C\u201D()\u3014\u3015[]{}\u3008\u3009\u300A\u300B\uFF62\uFF63\u300E\u300F\u3010\u3011+\u2212\u00B1\u00D7\u00F7=\u2260<>\u2266\u2267\u221E\u2234\u2642\u2640\u00B0\u2032\u2033\u2103\u00A5$\u00A2\u00A3%#&*@\u00A7\u2606\u2605\uFFEE\u25CF\u25CE\u25C7\u25C6\u25A1\uFFED\u25B3\u25B2\u25BD\u25BC\u203B\u3012\uFFEB\uFFE9\uFFEA\uFFEC\u3013'\"-~\u3033\u3034\u3035\u303B\u303C\u30FF\u309F\u2208\u220B\u2286\u2287\u2282\u2283\u222A\u2229\u2284\u2285\u228A\u228B\u2209\u2205\u2305\u2306\u2227\u2228\u00AC\u21D2\u21D4\u2200\u2203\u2295\u2296\u2297\u2225\u2226\u2985\u2986\u3018\u3019\u3016\u3017\u2220\u22A5\u2312\u2202\u2207\u2261\u2252\u226A\u226B\u221A\u223D\u221D\u2235\u222B\u222C\u2262\u2243\u2245\u2248\u2276\u2277\u2194\u212B\u2030\u266F\u266D\u266A\u2020\u2021\u00B6\u266E\u266B\u266C\u2669\u25EF";
43
+ /** 漢字の表 (1〜84区) のうち、EUC-JP で読んだものと違うところ。[区×94+点 (0 から), そこから続く字] の並び。85区から先は `ADDITIONAL` */
44
+ export declare const KANJI_DIFF: [number, string][];
45
+ /** 追加記号・追加漢字を1つの文字列にしたもの。(区 − 85) × 94 + (点 − 1) 番目のコードポイント */
46
+ export declare const ADDITIONAL: string;
47
+ /** 色の表 (CLUT)。8つの組 × 16色、RGBA の16進 */
48
+ export declare const CLUT: string[];
49
+ /** 外字 (DRCS) の画像の MD5 → 置き換える字。足し方は上の説明 */
50
+ export declare const DRCS_REPLACE: Map<string, number>;