import terminus-font-4.49.1

This commit is contained in:
Toomas Soome 2022-02-02 14:26:09 +02:00
parent cee3932f8c
commit c0f397da86
72 changed files with 48358 additions and 42872 deletions

View File

@ -1,3 +1,11 @@
Version 4.49.1:
* Fixed install-otb and uninstall-otb to use otbdir instead of x11dir.
Version 4.49:
* Added Open Type Bitmap support.
* Altered ascii grave in some sizes to be more useful as a back quote.
* Fixed 21B5, added 21B2 and 21B3.
Version 4.48:
* Added the basic 27 hebrew letters and sheqel, with uppercase height.

View File

@ -6,6 +6,8 @@ UCS2ANY = $(INT) $(BIN)/ucstoany.$(EXT)
BDF2PSF = $(INT) $(BIN)/bdftopsf.$(EXT)
UCS2X11 = $(INT) $(BIN)/ucstoany.$(EXT) -f
BDF2PCF = bdftopcf
#BDF2OTB = fontforge -lang=ff -c 'Open($$3); ScaleToEm(1024); Generate($$2)'
BDF2OTB = $(INT) $(BIN)/otb1cli.$(EXT)
REG_8859_1 = ISO8859 1
REG_8859_2 = ISO8859 2
@ -76,6 +78,8 @@ PCF_10646_1 = ter-x12n.pcf ter-x12b.pcf ter-x14n.pcf ter-x14b.pcf ter-x16n.pcf t
PCF_8BIT = $(PCF_8859_1) $(PCF_8859_2) $(PCF_8859_5) $(PCF_8859_7) $(PCF_8859_9) $(PCF_MS_1251) $(PCF_8859_13) $(PCF_8859_15) $(PCF_8859_16) $(PCF_IBM_437) $(PCF_KOI8_R) $(PCF_PT_154) $(PCF_KOI8_U)
PCF = $(PCF_10646_1)
OTB = ter-u12n.otb ter-u12b.otb ter-u14n.otb ter-u14b.otb ter-u16n.otb ter-u16b.otb ter-u18n.otb ter-u18b.otb ter-u20n.otb ter-u20b.otb ter-u22n.otb ter-u22b.otb ter-u24n.otb ter-u24b.otb ter-u28n.otb ter-u28b.otb ter-u32n.otb ter-u32b.otb
# Default
all: $(PSF) $(PCF)
@ -84,6 +88,7 @@ DESTDIR =
prefix = /usr/local
psfdir = $(prefix)/share/consolefonts
x11dir = $(prefix)/share/fonts/terminus
otbdir = $(prefix)/share/fonts/terminus
install: $(PSF) $(PCF)
mkdir -p $(DESTDIR)$(psfdir)
@ -288,9 +293,23 @@ install-pcf-8bit: $(PCF_8BIT)
uninstall-pcf-8bit:
for i in $(PCF_8BIT) ; do rm -f $(DESTDIR)$(x11dir)/$$i.gz ; done
# Open Type Bitmap
$(OTB): ter-u%.otb : ter-u%.bdf
$(BDF2OTB) -o $@ $<
otb: $(OTB)
install-otb: $(OTB)
mkdir -p $(DESTDIR)$(otbdir)
cp -f $(OTB) $(DESTDIR)$(otbdir)
uninstall-otb:
for i in $(OTB) ; do rm -f $(DESTDIR)$(otbdir)/$$i ; done
# Cleanup
clean:
rm -f $(PSF) $(PSF_VGAW) $(PCF) $(PCF_8BIT) $(FNT)
rm -f $(PSF) $(PSF_VGAW) $(PCF) $(PCF_8BIT) $(OTB)
.PHONY: all install uninstall fontdir psf install-psf uninstall-psf psf-vgaw install-psf-vgaw uninstall-psf-vgaw install-psf-ref uninstall-psf-ref pcf install-pcf uninstall-pcf pcf-8bit install-pcf-8bit uninstall-pcf-8bit clean
.PHONY: all install uninstall fontdir psf install-psf uninstall-psf psf-vgaw install-psf-vgaw uninstall-psf-vgaw install-psf-ref uninstall-psf-ref pcf install-pcf uninstall-pcf pcf-8bit install-pcf-8bit uninstall-pcf-8bit otb install-otb uninstall-otb clean

View File

@ -1,4 +1,4 @@
Copyright (c) 2019 Dimitar Toshkov Zhekov,
Copyright (C) 2020 Dimitar Toshkov Zhekov,
with Reserved Font Name "Terminus Font".
This Font Software is licensed under the SIL Open Font License, Version 1.1.

89
README
View File

@ -19,28 +19,33 @@ Contents:
3.1. Installation.
3.2. Notes.
4. Microsoft Windows.
4.1. Installation package.
4.2. Font file only.
4.3. Notes.
4. Open Type Bitmap.
4.1. Installation.
4.2. Notes.
5. Frequently Asked Questions.
5. Microsoft Windows.
5.1. Installation package.
5.2. Font file only.
5.3. Notes.
6. Legal information.
6.1. Licenses.
6.2. Copyright.
6. Frequently Asked Questions.
7. Legal information.
7.1. Licenses.
7.2. Copyright.
--
1. About.
This archive contains source code for generating and installing Terminus
Font for Linux console, X11 Window System and Microsoft Windows.
Font for Linux console, X11 Window System, Microsoft Windows and Open Type
Bitmap capable systems.
- version 4.48
- version 4.49.1
- sizes 6x12, 8x14, 8x16, 10x18, 10x20, 11x22, 12x24, 14x28, 16x32
- weights normal, bold, CRT VGA bold
- characters 1354
- characters 1356
- format Bitmap Distribution Format (BDF) version 2.1
The character set covers about 120 language sets and supports ISO8859-1/2/5/
@ -52,9 +57,10 @@ pseudographic characters.
1.1. Build requirements.
- GNU make
- Python 3.5.0+ (or node.js 6.9.0+ as an alternative)
- Python 3.5.0+ (or node.js 6.9.0+ as alternative)
- for X11 only: bdftopcf
- for the Windows installer only: GCC for Win32/i686, NSIS and patch.
- for Windows only: GCC for Win32/i686
- for the Windows installer only: NSIS and patch(1).
1.2. Quick installation.
@ -118,7 +124,7 @@ If your Python 3 executable is named python instead if python3:
$ ./configure INT=python
To use node.js instead of python (slower):
To use node.js instead of python:
$ ./configure INT=node EXT=js
@ -258,14 +264,47 @@ can be used as Windows-1252 and Windows-1254 respectively.
--
4. Microsoft Windows.
4. Open Type Bitmap.
- weights normal, bold
- code pages ISO10646-1 (unicode)
- format Linux/UNIX bitmap-only TrueType
4.1. Installation.
$ ./configure [--prefix=PREFIX | --otbdir=DIRECTORY]
$ make otb
# make install-otb
The files are installed in DIRECTORY.
The default DIRECTORY is PREFIX/share/fonts/terminus.
4.2. Notes
An OTB file is generated for each BDF file, instead of combining sizes by
weight, for the following reasons:
- KDE compatibility. With combined files, only the first size is available.
- Correct global font metrics. For example, the base line and character
width for 8x14 and 8x16 (relative to height) may never be identical.
otb1cli is NOT a full-featured BDF to sfnt convertor. It expands the bitmaps
first, uses the expanded widths, does not support overlapping characters,
and targets Linux/UNIX only.
--
5. Microsoft Windows.
- weights normal, bold
- code pages Windows-1252, 1250, 1253, 1254, 1251 and 1257
- format Font File Format version 2.0, compiled into FON
4.1. Installation package.
5.1. Installation package.
Make sure that no variant patches are applied to the font (p.1.4).
@ -276,7 +315,7 @@ Be patient, the process may take several minutes.
After that, open terminus.nsi and compile it.
4.2. Font file only.
5.2. Font file only.
> copy *.bdf win32
> cd win32
@ -285,14 +324,14 @@ After that, open terminus.nsi and compile it.
You can install terminus.fon via the regular means.
4.3. Notes.
5.3. Notes.
The Windows code pages contain a total of 384 characters. All other
characters (math, pseudographics etc.) are not currently available.
--
5. Frequently Asked Questions.
6. Frequently Asked Questions.
Q. Italic version?
@ -325,15 +364,15 @@ xlsfonts(1), fonts-conf(5) etc.
Q. My terminal emulator does not display cyrillic/pseudographics/...
A. If you have the 8-bit X11 code pages installed, and your emulator uses
"XLFD" font names, make sure hat name ends with "-10616-1" instead of
"-*-*".
"XLFD" font names, make sure that the font name ends with "-10616-1" instead
of "-*-*".
--
6. Legal information.
7. Legal information.
6.1. Licenses.
7.1. Licenses.
Terminus Font is licensed under the SIL Open Font License, Version 1.1.
The license is included as OFL.TXT, and is also available with a FAQ at:
@ -347,9 +386,9 @@ the GNU General Public License version 2.0 or (at your choice) any later
version.
6.2. Copyright.
7.2. Copyright.
Terminus Font 4.48, Copyright (C) 2019 Dimitar Toshkov Zhekov.
Terminus Font 4.49.1, Copyright (C) 2020 Dimitar Toshkov Zhekov.
Report bugs to <dimitar.zhekov@gmail.com>
Thanks to Anton Zinoviev, Tim Allen, Kir Koliushkin, Antonios Galanopoulos

View File

@ -19,28 +19,33 @@
3.1. Инсталация.
3.2. Забележки.
4. Open Type Bitmap.
4.1. Инсталация.
4.2. Забележки.
5. Microsoft Windows.
4.1. Инсталационен пакет.
4.2. Само файл с шрифта.
4.3. Забележки.
5.1. Инсталационен пакет.
5.2. Само файл с шрифта.
5.3. Забележки.
5. Често задавани въпроси.
6. Често задавани въпроси.
6. Правна информация.
6.1. Лицензи.
6.2. Авторство.
7. Правна информация.
7.1. Лицензи.
7.2. Авторство.
--
1. Обща информация.
Този архив съдържа изходен код за генериране и инсталиране на шрифта
Терминус за Линукс конзола, X11 Window System и Microsoft Windows.
Терминус за Линукс конзола, X11 Window System, Microsoft Windows и системи
поддържащи Open Type Bitmap.
- версия 4.48
- версия 4.49.1
- размери 6x12, 8x14, 8x16, 10x18, 10x20, 11x22, 12x24, 14x28, 16x32
- тежести нормален, удебелен, CRT VGA-удебелен
- символи 1354
- символи 1356
- формат Bitmap Distribution Format (BDF) версия 2.1
Набора символи покрива около 120 езикови набора и поддържа ISO8859-1/2/5/7/
@ -54,7 +59,8 @@ VGA, vt100
- GNU make
- Python 3.5.0+ (или node.js 6.9.0+ като алтернатива)
- само за X11: bdftopcf
- само за Windows инсталатора: GCC за Win32/i686, NSIS и patch.
- само за Windows: GCC за Win32/i686
- само за Windows инсталатора: NSIS и patch(1).
1.2. Бърза инсталация.
@ -66,7 +72,7 @@ $ make -j8
# make install fontdir
компилират и инсталират шрифтовете за Линукс конзола и X11 Window System.
Подразбиращия се префикс е /usr/local.
Подразбиращият се префикс е /usr/local.
1.3. Легенда.
@ -118,7 +124,7 @@ $ patch -p1 -i alt/<
$ ./configure INT=python
За да използвате node.js вместо python (по-бавно е):
За използване на node.js вместо python:
$ ./configure INT=node EXT=js
@ -258,14 +264,47 @@ ISO8859-1
--
4. Microsoft Windows.
4. Open Type Bitmap.
- тежести нормален, удебелен
- кодировки ISO10646-1 (уникод)
- формат растерен TrueType за Linux/UNIX
4.1. Инсталация.
$ ./configure [--prefix=ПРЕФИКС | --otbdir=ДИРЕКТОРИЯ]
$ make otb
# make install-otb
Файловете се инсталират в ДИРЕКТОРИЯ.
Подразбиращата се ДИРЕКТОРИЯ е ПРЕФИКС/share/fonts/terminus.
4.2. Забележки.
За всеки BDF файл се генерира отделен OTB файл, вместо да се комбинират
по тежест, по следните причини:
- Съвместимост с КДЕ. При комбинирани файлове е достъпен само първия размер.
- Коректни глобални размери. Например базовата линия и ширината на символите
(измервани по височината) не могат да бъдат еднакви за 8x14 и 8x16.
otb1cli НЕ Е пълноценен конвертор от BDF към TTF. Символите предварително
се растеризират, използват се растеризизираните ширини, не се поддържат
застъпващи се символи, и резултата е предназначен само за Linux/UNIX.
--
5. Microsoft Windows.
- тежести нормален, удебелен
- кодировки Windows-1252, 1250, 1253, 1254, 1251 and 1257
- формат Font File Format версия 2.0, компилиран във FON
4.1. Инстанационен пакет.
5.1. Инстанационен пакет.
Уверете се, че към шрифта не са прилагани корекции за варианти (т.1.4).
@ -276,7 +315,7 @@ ISO8859-1
След това отворете terminus.nsi и го компилирайте.
4.2. Само файл с шрифта.
5.2. Само файл с шрифта.
> copy *.bdf win32
> cd win32
@ -285,14 +324,14 @@ ISO8859-1
Можете са инсталирате terminus.fon по стандартните начини.
4.3. Забележки.
5.3. Забележки.
Кодовите страници за Windows съдържат общо 384 символа. Всички останали
символи (математика, превдографика и т.н.) засега не са достъпни.
--
5. Често задавани въпроси.
6. Често задавани въпроси.
В. Наклонена версия?
@ -325,15 +364,15 @@ xlsfonts(1), fonts-conf(5)
В. Моя терминален емулатор не извежда кирилица/псевдографика/...
О. Ако имате инсталирани 8-битовите кодови страници за X11, и емулатора
използва "XLFD" имена на шрифтовете, проверете дали името на завършва на
"-10616-1" вместо "-*-*".
използва "XLFD" имена на шрифтовете, уверете се че името на шрифта завършва
на "-10616-1" вместо "-*-*".
--
6. Правна информация.
7. Правна информация.
6.1. Лицензи.
7.1. Лицензи.
Terminus Font е лицензизан под SIL Open Font License, версия 1.1.
Лицензът е включен като OFL.TXT, и е достъпен заедно с FAQ на адрес:
@ -347,9 +386,9 @@ http://scripts.sil.org/OFL
усмотрение) която и да е по-късна версия.
6.2. Авторство.
7.2. Авторство.
Terminus Font 4.48, Copyright (C) 2019 Димитър Тошков Жеков.
Terminus Font 4.49.1, Copyright (C) 2020 Димитър Тошков Жеков.
Адрес за кореспонденция <dimitar.zhekov@gmail.com>
Благодаря на Антон Зиновиев, Тим Алън, Кир Колышкин, Антониос Галанопулос и

View File

@ -1,5 +1,5 @@
--- ./ter-u12b.bdf.orig 2019-07-28 21:07:36.104588100 +0300
+++ ./ter-u12b.bdf 2019-07-28 21:07:39.052993300 +0300
--- ./ter-u12b.bdf.orig 2020-12-28 20:34:18.635118400 +0200
+++ ./ter-u12b.bdf 2020-12-28 20:34:19.825120000 +0200
@@ -1292,2 +1291,0 @@
-70
-08
@ -112,8 +112,8 @@
+48
+58
+28
--- ./ter-u12n.bdf.orig 2019-07-28 21:07:35.995388000 +0300
+++ ./ter-u12n.bdf 2019-07-28 21:07:38.959393200 +0300
--- ./ter-u12n.bdf.orig 2020-12-28 20:34:18.605118300 +0200
+++ ./ter-u12n.bdf 2020-12-28 20:34:19.785120000 +0200
@@ -1292,2 +1291,0 @@
-70
-08
@ -226,8 +226,8 @@
+48
+58
+28
--- ./ter-u14b.bdf.orig 2019-07-28 21:07:36.322988500 +0300
+++ ./ter-u14b.bdf 2019-07-28 21:07:39.255793700 +0300
--- ./ter-u14b.bdf.orig 2020-12-28 20:34:18.655118400 +0200
+++ ./ter-u14b.bdf 2020-12-28 20:34:19.845120100 +0200
@@ -1425,2 +1424,0 @@
-7C
-06
@ -344,8 +344,8 @@
+6C
+6C
+34
--- ./ter-u14n.bdf.orig 2019-07-28 21:07:36.213788300 +0300
+++ ./ter-u14n.bdf 2019-07-28 21:07:39.162193500 +0300
--- ./ter-u14n.bdf.orig 2020-12-28 20:34:18.645118400 +0200
+++ ./ter-u14n.bdf 2020-12-28 20:34:19.845120100 +0200
@@ -1425,2 +1424,0 @@
-3C
-02
@ -462,8 +462,8 @@
+24
+2C
+14
--- ./ter-u14v.bdf.orig 2019-07-28 21:07:36.416588700 +0300
+++ ./ter-u14v.bdf 2019-07-28 21:07:39.364993900 +0300
--- ./ter-u14v.bdf.orig 2020-12-28 20:34:18.675118400 +0200
+++ ./ter-u14v.bdf 2020-12-28 20:34:19.875120100 +0200
@@ -1425,2 +1424,0 @@
-7C
-06
@ -580,8 +580,8 @@
+6C
+6C
+34
--- ./ter-u16b.bdf.orig 2019-07-28 21:07:36.634989100 +0300
+++ ./ter-u16b.bdf 2019-07-28 21:07:39.567794200 +0300
--- ./ter-u16b.bdf.orig 2020-12-28 20:34:18.685118400 +0200
+++ ./ter-u16b.bdf 2020-12-28 20:34:19.915120200 +0200
@@ -1557,2 +1556,0 @@
-7C
-06
@ -698,8 +698,8 @@
+6C
+6C
+34
--- ./ter-u16n.bdf.orig 2019-07-28 21:07:36.541388900 +0300
+++ ./ter-u16n.bdf 2019-07-28 21:07:39.458594000 +0300
--- ./ter-u16n.bdf.orig 2020-12-28 20:34:18.685118400 +0200
+++ ./ter-u16n.bdf 2020-12-28 20:34:19.885120100 +0200
@@ -1557,2 +1556,0 @@
-3C
-02
@ -816,8 +816,8 @@
+24
+2C
+14
--- ./ter-u16v.bdf.orig 2019-07-28 21:07:36.759789300 +0300
+++ ./ter-u16v.bdf 2019-07-28 21:07:39.661394400 +0300
--- ./ter-u16v.bdf.orig 2020-12-28 20:34:18.695118400 +0200
+++ ./ter-u16v.bdf 2020-12-28 20:34:19.915120200 +0200
@@ -1557,2 +1556,0 @@
-7C
-06
@ -934,8 +934,8 @@
+6C
+6C
+34
--- ./ter-u18b.bdf.orig 2019-07-28 21:07:36.993789700 +0300
+++ ./ter-u18b.bdf 2019-07-28 21:07:39.895394800 +0300
--- ./ter-u18b.bdf.orig 2020-12-28 20:34:18.725118500 +0200
+++ ./ter-u18b.bdf 2020-12-28 20:34:19.945120200 +0200
@@ -1690,3 +1689,0 @@
-3F00
-0180
@ -1079,8 +1079,8 @@
+6600
+6E00
+3600
--- ./ter-u18n.bdf.orig 2019-07-28 21:07:36.884589500 +0300
+++ ./ter-u18n.bdf 2019-07-28 21:07:39.786194600 +0300
--- ./ter-u18n.bdf.orig 2020-12-28 20:34:18.725118500 +0200
+++ ./ter-u18n.bdf 2020-12-28 20:34:19.945120200 +0200
@@ -1690,3 +1689,0 @@
-3E00
-0100
@ -1219,8 +1219,8 @@
+2200
+2600
+1A00
--- ./ter-u20b.bdf.orig 2019-07-28 21:07:37.290190200 +0300
+++ ./ter-u20b.bdf 2019-07-28 21:07:40.129395200 +0300
--- ./ter-u20b.bdf.orig 2020-12-28 20:34:18.735118500 +0200
+++ ./ter-u20b.bdf 2020-12-28 20:34:19.985120200 +0200
@@ -1823,3 +1822,0 @@
-3F00
-0180
@ -1364,8 +1364,8 @@
+6600
+6E00
+3600
--- ./ter-u20n.bdf.orig 2019-07-28 21:07:37.102989900 +0300
+++ ./ter-u20n.bdf 2019-07-28 21:07:40.020195000 +0300
--- ./ter-u20n.bdf.orig 2020-12-28 20:34:18.725118500 +0200
+++ ./ter-u20n.bdf 2020-12-28 20:34:19.985120200 +0200
@@ -1823,3 +1822,0 @@
-3E00
-0100
@ -1504,8 +1504,8 @@
+2200
+2600
+1A00
--- ./ter-u22b.bdf.orig 2019-07-28 21:07:37.524190600 +0300
+++ ./ter-u22b.bdf 2019-07-28 21:07:40.378995700 +0300
--- ./ter-u22b.bdf.orig 2020-12-28 20:34:18.775118600 +0200
+++ ./ter-u22b.bdf 2020-12-28 20:34:20.015120300 +0200
@@ -1955,5 +1955,2 @@
-3F00
-0180
@ -1711,8 +1711,8 @@
+3180
+3380
+1D80
--- ./ter-u22n.bdf.orig 2019-07-28 21:07:37.414990400 +0300
+++ ./ter-u22n.bdf 2019-07-28 21:07:40.254195400 +0300
--- ./ter-u22n.bdf.orig 2020-12-28 20:34:18.775118600 +0200
+++ ./ter-u22n.bdf 2020-12-28 20:34:19.985120200 +0200
@@ -1955,5 +1955,2 @@
-3E00
-0100
@ -1918,8 +1918,8 @@
+2100
+2300
+1D00
--- ./ter-u24b.bdf.orig 2019-07-28 21:07:37.773791100 +0300
+++ ./ter-u24b.bdf 2019-07-28 21:07:40.628596100 +0300
--- ./ter-u24b.bdf.orig 2020-12-28 20:34:18.795118600 +0200
+++ ./ter-u24b.bdf 2020-12-28 20:34:20.075120400 +0200
@@ -2088,4 +2087,0 @@
-3F80
-00C0
@ -2123,8 +2123,8 @@
+3180
+3380
+1D80
--- ./ter-u24n.bdf.orig 2019-07-28 21:07:37.648990900 +0300
+++ ./ter-u24n.bdf 2019-07-28 21:07:40.503795900 +0300
--- ./ter-u24n.bdf.orig 2020-12-28 20:34:18.795118600 +0200
+++ ./ter-u24n.bdf 2020-12-28 20:34:20.075120400 +0200
@@ -2088,4 +2087,0 @@
-3F00
-0080
@ -2328,8 +2328,8 @@
+1080
+1180
+0E80
--- ./ter-u28b.bdf.orig 2019-07-28 21:07:38.038991500 +0300
+++ ./ter-u28b.bdf 2019-07-28 21:07:40.893796600 +0300
--- ./ter-u28b.bdf.orig 2020-12-28 20:34:18.845118700 +0200
+++ ./ter-u28b.bdf 2020-12-28 20:34:20.105120400 +0200
@@ -2353,4 +2352,0 @@
-1FC0
-1FE0
@ -2552,8 +2552,8 @@
@@ -27322 +27322 @@
-0FE0
+0F60
--- ./ter-u28n.bdf.orig 2019-07-28 21:07:37.914191300 +0300
+++ ./ter-u28n.bdf 2019-07-28 21:07:40.768996300 +0300
--- ./ter-u28n.bdf.orig 2020-12-28 20:34:18.835118600 +0200
+++ ./ter-u28n.bdf 2020-12-28 20:34:20.105120400 +0200
@@ -2353,4 +2352,0 @@
-1FC0
-0060
@ -2750,8 +2750,8 @@
+1860
+18E0
+0F60
--- ./ter-u32b.bdf.orig 2019-07-28 21:07:38.335392100 +0300
+++ ./ter-u32b.bdf 2019-07-28 21:07:41.190197100 +0300
--- ./ter-u32b.bdf.orig 2020-12-28 20:34:18.865118700 +0200
+++ ./ter-u32b.bdf 2020-12-28 20:34:20.175120500 +0200
@@ -2620,5 +2619,0 @@
-3FF0
-3FF8
@ -3025,8 +3025,8 @@
+1C78
@@ -30443,0 +30443 @@
+07B8
--- ./ter-u32n.bdf.orig 2019-07-28 21:07:38.194991800 +0300
+++ ./ter-u32n.bdf 2019-07-28 21:07:41.034196800 +0300
--- ./ter-u32n.bdf.orig 2020-12-28 20:34:18.865118700 +0200
+++ ./ter-u32n.bdf 2020-12-28 20:34:20.155120500 +0200
@@ -2620,5 +2619,0 @@
-1FF0
-1FF8

81452
alt/br1.diff

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
--- ./ter-u12b.bdf.orig 2019-07-28 21:07:36.104588100 +0300
+++ ./ter-u12b.bdf 2019-07-28 21:07:45.090203900 +0300
--- ./ter-u12b.bdf.orig 2020-12-28 20:34:18.635118400 +0200
+++ ./ter-u12b.bdf 2020-12-28 20:34:21.775122800 +0200
@@ -10030,3 +10030,2 @@
-E0
-90
@ -25,8 +25,8 @@
+FC
+84
+00
--- ./ter-u12n.bdf.orig 2019-07-28 21:07:35.995388000 +0300
+++ ./ter-u12n.bdf 2019-07-28 21:07:45.012203800 +0300
--- ./ter-u12n.bdf.orig 2020-12-28 20:34:18.605118300 +0200
+++ ./ter-u12n.bdf 2020-12-28 20:34:21.775122800 +0200
@@ -10030,3 +10030,2 @@
-E0
-90
@ -52,8 +52,8 @@
+FC
+84
+00
--- ./ter-u14b.bdf.orig 2019-07-28 21:07:36.322988500 +0300
+++ ./ter-u14b.bdf 2019-07-28 21:07:45.293004300 +0300
--- ./ter-u14b.bdf.orig 2020-12-28 20:34:18.655118400 +0200
+++ ./ter-u14b.bdf 2020-12-28 20:34:21.815122800 +0200
@@ -11082,4 +11082,3 @@
-78
-CC
@ -83,8 +83,8 @@
+FF
+C3
+00
--- ./ter-u14n.bdf.orig 2019-07-28 21:07:36.213788300 +0300
+++ ./ter-u14n.bdf 2019-07-28 21:07:45.199404100 +0300
--- ./ter-u14n.bdf.orig 2020-12-28 20:34:18.645118400 +0200
+++ ./ter-u14n.bdf 2020-12-28 20:34:21.785122800 +0200
@@ -11082,4 +11082,3 @@
-38
-44
@ -113,8 +113,8 @@
+FE
+82
+00
--- ./ter-u14v.bdf.orig 2019-07-28 21:07:36.416588700 +0300
+++ ./ter-u14v.bdf 2019-07-28 21:07:45.386604400 +0300
--- ./ter-u14v.bdf.orig 2020-12-28 20:34:18.675118400 +0200
+++ ./ter-u14v.bdf 2020-12-28 20:34:21.815122800 +0200
@@ -11082,4 +11082,3 @@
-78
-CC
@ -144,8 +144,8 @@
+FF
+C3
+00
--- ./ter-u16b.bdf.orig 2019-07-28 21:07:36.634989100 +0300
+++ ./ter-u16b.bdf 2019-07-28 21:07:45.605004800 +0300
--- ./ter-u16b.bdf.orig 2020-12-28 20:34:18.685118400 +0200
+++ ./ter-u16b.bdf 2020-12-28 20:34:21.825122800 +0200
@@ -12134,4 +12134,3 @@
-78
-CC
@ -177,8 +177,8 @@
+C3
+00
+00
--- ./ter-u16n.bdf.orig 2019-07-28 21:07:36.541388900 +0300
+++ ./ter-u16n.bdf 2019-07-28 21:07:45.495804600 +0300
--- ./ter-u16n.bdf.orig 2020-12-28 20:34:18.685118400 +0200
+++ ./ter-u16n.bdf 2020-12-28 20:34:21.825122800 +0200
@@ -12134,4 +12134,3 @@
-38
-44
@ -209,8 +209,8 @@
+82
+00
+00
--- ./ter-u16v.bdf.orig 2019-07-28 21:07:36.759789300 +0300
+++ ./ter-u16v.bdf 2019-07-28 21:07:45.698605000 +0300
--- ./ter-u16v.bdf.orig 2020-12-28 20:34:18.695118400 +0200
+++ ./ter-u16v.bdf 2020-12-28 20:34:21.855122900 +0200
@@ -12134,4 +12134,3 @@
-78
-CC
@ -242,8 +242,8 @@
+C3
+00
+00
--- ./ter-u18b.bdf.orig 2019-07-28 21:07:36.993789700 +0300
+++ ./ter-u18b.bdf 2019-07-28 21:07:45.948205400 +0300
--- ./ter-u18b.bdf.orig 2020-12-28 20:34:18.725118500 +0200
+++ ./ter-u18b.bdf 2020-12-28 20:34:21.865122900 +0200
@@ -13187,5 +13187,3 @@
-3E00
-6300
@ -281,8 +281,8 @@
+C180
+C180
+0000
--- ./ter-u18n.bdf.orig 2019-07-28 21:07:36.884589500 +0300
+++ ./ter-u18n.bdf 2019-07-28 21:07:45.823405200 +0300
--- ./ter-u18n.bdf.orig 2020-12-28 20:34:18.725118500 +0200
+++ ./ter-u18n.bdf 2020-12-28 20:34:21.865122900 +0200
@@ -13187,5 +13187,3 @@
-3C00
-4200
@ -320,8 +320,8 @@
+4080
+4080
+0000
--- ./ter-u20b.bdf.orig 2019-07-28 21:07:37.290190200 +0300
+++ ./ter-u20b.bdf 2019-07-28 21:07:46.166605800 +0300
--- ./ter-u20b.bdf.orig 2020-12-28 20:34:18.735118500 +0200
+++ ./ter-u20b.bdf 2020-12-28 20:34:21.905122900 +0200
@@ -14239,5 +14239,4 @@
-3E00
-6300
@ -359,8 +359,8 @@
+C180
+C180
+0000
--- ./ter-u20n.bdf.orig 2019-07-28 21:07:37.102989900 +0300
+++ ./ter-u20n.bdf 2019-07-28 21:07:46.057405600 +0300
--- ./ter-u20n.bdf.orig 2020-12-28 20:34:18.725118500 +0200
+++ ./ter-u20n.bdf 2020-12-28 20:34:21.865122900 +0200
@@ -14239,5 +14239,4 @@
-3C00
-4200
@ -398,8 +398,8 @@
+4080
+4080
+0000
--- ./ter-u22b.bdf.orig 2019-07-28 21:07:37.524190600 +0300
+++ ./ter-u22b.bdf 2019-07-28 21:07:46.400606200 +0300
--- ./ter-u22b.bdf.orig 2020-12-28 20:34:18.775118600 +0200
+++ ./ter-u22b.bdf 2020-12-28 20:34:21.905122900 +0200
@@ -15291,8 +15291,5 @@
-3E00
-6300
@ -452,8 +452,8 @@
+C0C0
+0000
+0000
--- ./ter-u22n.bdf.orig 2019-07-28 21:07:37.414990400 +0300
+++ ./ter-u22n.bdf 2019-07-28 21:07:46.291406000 +0300
--- ./ter-u22n.bdf.orig 2020-12-28 20:34:18.775118600 +0200
+++ ./ter-u22n.bdf 2020-12-28 20:34:21.915123000 +0200
@@ -15291,8 +15291,6 @@
-3C00
-4200
@ -504,8 +504,8 @@
+4040
+0000
+0000
--- ./ter-u24b.bdf.orig 2019-07-28 21:07:37.773791100 +0300
+++ ./ter-u24b.bdf 2019-07-28 21:07:46.634606600 +0300
--- ./ter-u24b.bdf.orig 2020-12-28 20:34:18.795118600 +0200
+++ ./ter-u24b.bdf 2020-12-28 20:34:21.955123000 +0200
@@ -16344,2 +16344,5 @@
-3F00
-6180
@ -552,8 +552,8 @@
-3F80
+0000
+0000
--- ./ter-u24n.bdf.orig 2019-07-28 21:07:37.648990900 +0300
+++ ./ter-u24n.bdf 2019-07-28 21:07:46.525406400 +0300
--- ./ter-u24n.bdf.orig 2020-12-28 20:34:18.795118600 +0200
+++ ./ter-u24n.bdf 2020-12-28 20:34:21.915123000 +0200
@@ -16344,2 +16344,5 @@
-3E00
-4100
@ -600,8 +600,8 @@
-3F00
+0000
+0000
--- ./ter-u28b.bdf.orig 2019-07-28 21:07:38.038991500 +0300
+++ ./ter-u28b.bdf 2019-07-28 21:07:46.915407100 +0300
--- ./ter-u28b.bdf.orig 2020-12-28 20:34:18.845118700 +0200
+++ ./ter-u28b.bdf 2020-12-28 20:34:21.975123000 +0200
@@ -18448 +18448,5 @@
-3F00
+0000
@ -664,8 +664,8 @@
+6018
+0000
+0000
--- ./ter-u28n.bdf.orig 2019-07-28 21:07:37.914191300 +0300
+++ ./ter-u28n.bdf 2019-07-28 21:07:46.775006900 +0300
--- ./ter-u28n.bdf.orig 2020-12-28 20:34:18.835118600 +0200
+++ ./ter-u28n.bdf 2020-12-28 20:34:21.965123000 +0200
@@ -18448,4 +18448,6 @@
-3F00
-6180
@ -725,8 +725,8 @@
+6018
+0000
+0000
--- ./ter-u32b.bdf.orig 2019-07-28 21:07:38.335392100 +0300
+++ ./ter-u32b.bdf 2019-07-28 21:07:47.289807800 +0300
--- ./ter-u32b.bdf.orig 2020-12-28 20:34:18.865118700 +0200
+++ ./ter-u32b.bdf 2020-12-28 20:34:22.025123100 +0200
@@ -20554,8 +20554,6 @@
-3FC0
-7FE0
@ -792,8 +792,8 @@
+700E
+700E
+0000
--- ./ter-u32n.bdf.orig 2019-07-28 21:07:38.194991800 +0300
+++ ./ter-u32n.bdf 2019-07-28 21:07:47.149407500 +0300
--- ./ter-u32n.bdf.orig 2020-12-28 20:34:18.865118700 +0200
+++ ./ter-u32n.bdf 2020-12-28 20:34:21.985123000 +0200
@@ -20554,8 +20554,6 @@
-1FC0
-3FE0

View File

@ -1,5 +1,5 @@
--- ./ter-u12b.bdf.orig 2019-07-28 21:07:36.104588100 +0300
+++ ./ter-u12b.bdf 2019-07-28 21:07:48.054209100 +0300
--- ./ter-u12b.bdf.orig 2020-12-28 20:34:18.635118400 +0200
+++ ./ter-u12b.bdf 2020-12-28 20:34:22.635124000 +0200
@@ -10051,4 +10051,3 @@
-F8
-80
@ -33,8 +33,8 @@
+70
@@ -11006,0 +11006 @@
+70
--- ./ter-u12n.bdf.orig 2019-07-28 21:07:35.995388000 +0300
+++ ./ter-u12n.bdf 2019-07-28 21:07:47.976209000 +0300
--- ./ter-u12n.bdf.orig 2020-12-28 20:34:18.605118300 +0200
+++ ./ter-u12n.bdf 2020-12-28 20:34:22.625123900 +0200
@@ -10051,4 +10051,3 @@
-F8
-80
@ -68,8 +68,8 @@
+70
@@ -11006,0 +11006 @@
+70
--- ./ter-u14b.bdf.orig 2019-07-28 21:07:36.322988500 +0300
+++ ./ter-u14b.bdf 2019-07-28 21:07:48.257009500 +0300
--- ./ter-u14b.bdf.orig 2020-12-28 20:34:18.655118400 +0200
+++ ./ter-u14b.bdf 2020-12-28 20:34:22.675124000 +0200
@@ -11106,5 +11106,4 @@
-FE
-C0
@ -107,8 +107,8 @@
+7C
@@ -12162,0 +12162 @@
+7C
--- ./ter-u14n.bdf.orig 2019-07-28 21:07:36.213788300 +0300
+++ ./ter-u14n.bdf 2019-07-28 21:07:48.163409300 +0300
--- ./ter-u14n.bdf.orig 2020-12-28 20:34:18.645118400 +0200
+++ ./ter-u14n.bdf 2020-12-28 20:34:22.655124000 +0200
@@ -11106,5 +11106,4 @@
-7E
-40
@ -146,8 +146,8 @@
+3C
@@ -12162,0 +12162 @@
+3C
--- ./ter-u14v.bdf.orig 2019-07-28 21:07:36.416588700 +0300
+++ ./ter-u14v.bdf 2019-07-28 21:07:48.366209700 +0300
--- ./ter-u14v.bdf.orig 2020-12-28 20:34:18.675118400 +0200
+++ ./ter-u14v.bdf 2020-12-28 20:34:22.665124000 +0200
@@ -11106,5 +11106,4 @@
-FE
-C0
@ -185,8 +185,8 @@
+7C
@@ -12162,0 +12162 @@
+7C
--- ./ter-u16b.bdf.orig 2019-07-28 21:07:36.634989100 +0300
+++ ./ter-u16b.bdf 2019-07-28 21:07:48.553410000 +0300
--- ./ter-u16b.bdf.orig 2020-12-28 20:34:18.685118400 +0200
+++ ./ter-u16b.bdf 2020-12-28 20:34:22.695124000 +0200
@@ -12160,5 +12160,4 @@
-FE
-C0
@ -224,8 +224,8 @@
+7C
@@ -13316,0 +13316 @@
+7C
--- ./ter-u16n.bdf.orig 2019-07-28 21:07:36.541388900 +0300
+++ ./ter-u16n.bdf 2019-07-28 21:07:48.459809800 +0300
--- ./ter-u16n.bdf.orig 2020-12-28 20:34:18.685118400 +0200
+++ ./ter-u16n.bdf 2020-12-28 20:34:22.685124000 +0200
@@ -12160,5 +12160,4 @@
-7E
-40
@ -263,8 +263,8 @@
+3C
@@ -13316,0 +13316 @@
+3C
--- ./ter-u16v.bdf.orig 2019-07-28 21:07:36.759789300 +0300
+++ ./ter-u16v.bdf 2019-07-28 21:07:48.662610200 +0300
--- ./ter-u16v.bdf.orig 2020-12-28 20:34:18.695118400 +0200
+++ ./ter-u16v.bdf 2020-12-28 20:34:22.715124100 +0200
@@ -12160,5 +12160,4 @@
-FE
-C0
@ -302,8 +302,8 @@
+7C
@@ -13316,0 +13316 @@
+7C
--- ./ter-u18b.bdf.orig 2019-07-28 21:07:36.993789700 +0300
+++ ./ter-u18b.bdf 2019-07-28 21:07:48.881010600 +0300
--- ./ter-u18b.bdf.orig 2020-12-28 20:34:18.725118500 +0200
+++ ./ter-u18b.bdf 2020-12-28 20:34:22.725124100 +0200
@@ -13215,6 +13215,5 @@
-7F80
-6000
@ -347,8 +347,8 @@
+3F00
@@ -14473,0 +14473 @@
+3F00
--- ./ter-u18n.bdf.orig 2019-07-28 21:07:36.884589500 +0300
+++ ./ter-u18n.bdf 2019-07-28 21:07:48.771810400 +0300
--- ./ter-u18n.bdf.orig 2020-12-28 20:34:18.725118500 +0200
+++ ./ter-u18n.bdf 2020-12-28 20:34:22.715124100 +0200
@@ -13215,6 +13215,5 @@
-7F00
-4000
@ -392,8 +392,8 @@
+3E00
@@ -14473,0 +14473 @@
+3E00
--- ./ter-u20b.bdf.orig 2019-07-28 21:07:37.290190200 +0300
+++ ./ter-u20b.bdf 2019-07-28 21:07:49.115011000 +0300
--- ./ter-u20b.bdf.orig 2020-12-28 20:34:18.735118500 +0200
+++ ./ter-u20b.bdf 2020-12-28 20:34:22.775124200 +0200
@@ -14270,6 +14270,5 @@
-7F80
-6000
@ -437,8 +437,8 @@
+3F00
@@ -15628,0 +15628 @@
+3F00
--- ./ter-u20n.bdf.orig 2019-07-28 21:07:37.102989900 +0300
+++ ./ter-u20n.bdf 2019-07-28 21:07:48.990210800 +0300
--- ./ter-u20n.bdf.orig 2020-12-28 20:34:18.725118500 +0200
+++ ./ter-u20n.bdf 2020-12-28 20:34:22.735124100 +0200
@@ -14270,6 +14270,5 @@
-7F00
-4000
@ -482,8 +482,8 @@
+3E00
@@ -15628,0 +15628 @@
+3E00
--- ./ter-u22b.bdf.orig 2019-07-28 21:07:37.524190600 +0300
+++ ./ter-u22b.bdf 2019-07-28 21:07:49.349011400 +0300
--- ./ter-u22b.bdf.orig 2020-12-28 20:34:18.775118600 +0200
+++ ./ter-u22b.bdf 2020-12-28 20:34:22.775124200 +0200
@@ -15324,6 +15324,5 @@
-7FC0
-6000
@ -527,8 +527,8 @@
+3F80
@@ -16783,0 +16783 @@
+3F80
--- ./ter-u22n.bdf.orig 2019-07-28 21:07:37.414990400 +0300
+++ ./ter-u22n.bdf 2019-07-28 21:07:49.224211200 +0300
--- ./ter-u22n.bdf.orig 2020-12-28 20:34:18.775118600 +0200
+++ ./ter-u22n.bdf 2020-12-28 20:34:22.775124200 +0200
@@ -15324,6 +15324,5 @@
-7F80
-4000
@ -572,8 +572,8 @@
+3F00
@@ -16783,0 +16783 @@
+3F00
--- ./ter-u24b.bdf.orig 2019-07-28 21:07:37.773791100 +0300
+++ ./ter-u24b.bdf 2019-07-28 21:07:49.583011800 +0300
--- ./ter-u24b.bdf.orig 2020-12-28 20:34:18.795118600 +0200
+++ ./ter-u24b.bdf 2020-12-28 20:34:22.825124200 +0200
@@ -16379,7 +16379,6 @@
-7FE0
-6000
@ -623,8 +623,8 @@
+3FC0
@@ -17939,0 +17939 @@
+3FC0
--- ./ter-u24n.bdf.orig 2019-07-28 21:07:37.648990900 +0300
+++ ./ter-u24n.bdf 2019-07-28 21:07:49.458211600 +0300
--- ./ter-u24n.bdf.orig 2020-12-28 20:34:18.795118600 +0200
+++ ./ter-u24n.bdf 2020-12-28 20:34:22.775124200 +0200
@@ -16379,7 +16379,6 @@
-7FC0
-4000
@ -674,8 +674,8 @@
+3F80
@@ -17939,0 +17939 @@
+3F80
--- ./ter-u28b.bdf.orig 2019-07-28 21:07:38.038991500 +0300
+++ ./ter-u28b.bdf 2019-07-28 21:07:49.863812300 +0300
--- ./ter-u28b.bdf.orig 2020-12-28 20:34:18.845118700 +0200
+++ ./ter-u28b.bdf 2020-12-28 20:34:22.845124300 +0200
@@ -18488,11 +18488,8 @@
-7FF0
-7FF0
@ -751,8 +751,8 @@
+7000
+3FE0
+1FE0
--- ./ter-u28n.bdf.orig 2019-07-28 21:07:37.914191300 +0300
+++ ./ter-u28n.bdf 2019-07-28 21:07:49.723412100 +0300
--- ./ter-u28n.bdf.orig 2020-12-28 20:34:18.835118600 +0200
+++ ./ter-u28n.bdf 2020-12-28 20:34:22.835124200 +0200
@@ -18488,10 +18488,8 @@
-7FF0
-6000
@ -820,8 +820,8 @@
@@ -20250,0 +20249,2 @@
+3000
+1FE0
--- ./ter-u32b.bdf.orig 2019-07-28 21:07:38.335392100 +0300
+++ ./ter-u32b.bdf 2019-07-28 21:07:50.160212800 +0300
--- ./ter-u32b.bdf.orig 2020-12-28 20:34:18.865118700 +0200
+++ ./ter-u32b.bdf 2020-12-28 20:34:22.905124300 +0200
@@ -20599,12 +20599,9 @@
-7FFC
-7FFC
@ -905,8 +905,8 @@
+7800
+3FF8
+1FF8
--- ./ter-u32n.bdf.orig 2019-07-28 21:07:38.194991800 +0300
+++ ./ter-u32n.bdf 2019-07-28 21:07:50.004212600 +0300
--- ./ter-u32n.bdf.orig 2020-12-28 20:34:18.865118700 +0200
+++ ./ter-u32n.bdf 2020-12-28 20:34:22.855124300 +0200
@@ -20599,12 +20599,9 @@
-3FFC
-3FFC

View File

@ -1,5 +1,5 @@
--- ./ter-u12b.bdf.orig 2019-07-28 21:07:36.104588100 +0300
+++ ./ter-u12b.bdf 2019-07-28 21:07:50.940214200 +0300
--- ./ter-u12b.bdf.orig 2020-12-28 20:34:18.635118400 +0200
+++ ./ter-u12b.bdf 2020-12-28 20:34:23.545125200 +0200
@@ -189 +189 @@
-20
+40
@ -11,8 +11,8 @@
+20
+20
+10
--- ./ter-u12n.bdf.orig 2019-07-28 21:07:35.995388000 +0300
+++ ./ter-u12n.bdf 2019-07-28 21:07:50.846614000 +0300
--- ./ter-u12n.bdf.orig 2020-12-28 20:34:18.605118300 +0200
+++ ./ter-u12n.bdf 2020-12-28 20:34:23.535125200 +0200
@@ -189 +189 @@
-20
+40
@ -24,8 +24,8 @@
+20
+20
+10
--- ./ter-u14b.bdf.orig 2019-07-28 21:07:36.322988500 +0300
+++ ./ter-u14b.bdf 2019-07-28 21:07:51.158614600 +0300
--- ./ter-u14b.bdf.orig 2020-12-28 20:34:18.655118400 +0200
+++ ./ter-u14b.bdf 2020-12-28 20:34:23.575125300 +0200
@@ -205 +205 @@
-18
+30
@ -35,8 +35,8 @@
@@ -1401,2 +1402,0 @@
-00
-00
--- ./ter-u14n.bdf.orig 2019-07-28 21:07:36.213788300 +0300
+++ ./ter-u14n.bdf 2019-07-28 21:07:51.049414400 +0300
--- ./ter-u14n.bdf.orig 2020-12-28 20:34:18.645118400 +0200
+++ ./ter-u14n.bdf 2020-12-28 20:34:23.555125200 +0200
@@ -203,2 +203,2 @@
-10
-10
@ -48,8 +48,8 @@
@@ -1401,2 +1402,0 @@
-00
-00
--- ./ter-u14v.bdf.orig 2019-07-28 21:07:36.416588700 +0300
+++ ./ter-u14v.bdf 2019-07-28 21:07:51.252214800 +0300
--- ./ter-u14v.bdf.orig 2020-12-28 20:34:18.675118400 +0200
+++ ./ter-u14v.bdf 2020-12-28 20:34:23.575125300 +0200
@@ -205 +205 @@
-18
+30
@ -59,8 +59,8 @@
@@ -1401,2 +1402,0 @@
-00
-00
--- ./ter-u16b.bdf.orig 2019-07-28 21:07:36.634989100 +0300
+++ ./ter-u16b.bdf 2019-07-28 21:07:51.470615100 +0300
--- ./ter-u16b.bdf.orig 2020-12-28 20:34:18.685118400 +0200
+++ ./ter-u16b.bdf 2020-12-28 20:34:23.595125300 +0200
@@ -221 +221 @@
-18
+30
@ -70,8 +70,8 @@
@@ -1531,2 +1532,0 @@
-00
-00
--- ./ter-u16n.bdf.orig 2019-07-28 21:07:36.541388900 +0300
+++ ./ter-u16n.bdf 2019-07-28 21:07:51.361414900 +0300
--- ./ter-u16n.bdf.orig 2020-12-28 20:34:18.685118400 +0200
+++ ./ter-u16n.bdf 2020-12-28 20:34:23.585125300 +0200
@@ -219,2 +219,2 @@
-10
-10
@ -83,8 +83,8 @@
@@ -1531,2 +1532,0 @@
-00
-00
--- ./ter-u16v.bdf.orig 2019-07-28 21:07:36.759789300 +0300
+++ ./ter-u16v.bdf 2019-07-28 21:07:51.564215300 +0300
--- ./ter-u16v.bdf.orig 2020-12-28 20:34:18.695118400 +0200
+++ ./ter-u16v.bdf 2020-12-28 20:34:23.615125300 +0200
@@ -221 +221 @@
-18
+30
@ -94,60 +94,60 @@
@@ -1531,2 +1532,0 @@
-00
-00
--- ./ter-u18b.bdf.orig 2019-07-28 21:07:36.993789700 +0300
+++ ./ter-u18b.bdf 2019-07-28 21:07:51.813815700 +0300
--- ./ter-u18b.bdf.orig 2020-12-28 20:34:18.725118500 +0200
+++ ./ter-u18b.bdf 2020-12-28 20:34:23.635125400 +0200
@@ -238 +238 @@
-0C00
+1800
@@ -1658,0 +1659,3 @@
@@ -1659 +1659,3 @@
-3000
+0000
+1800
+1800
@@ -1661,3 +1663,0 @@
@@ -1662,2 +1663,0 @@
-0000
-0000
-0000
--- ./ter-u18n.bdf.orig 2019-07-28 21:07:36.884589500 +0300
+++ ./ter-u18n.bdf 2019-07-28 21:07:51.704615500 +0300
--- ./ter-u18n.bdf.orig 2020-12-28 20:34:18.725118500 +0200
+++ ./ter-u18n.bdf 2020-12-28 20:34:23.625125300 +0200
@@ -238 +238 @@
-0800
+1000
@@ -1658,0 +1659,3 @@
@@ -1659 +1659,3 @@
-2000
+0000
+1000
+1000
@@ -1661,3 +1663,0 @@
@@ -1662,2 +1663,0 @@
-0000
-0000
-0000
--- ./ter-u20b.bdf.orig 2019-07-28 21:07:37.290190200 +0300
+++ ./ter-u20b.bdf 2019-07-28 21:07:52.079016200 +0300
--- ./ter-u20b.bdf.orig 2020-12-28 20:34:18.735118500 +0200
+++ ./ter-u20b.bdf 2020-12-28 20:34:23.665125400 +0200
@@ -254 +254 @@
-0C00
+1800
@@ -1788,0 +1789,3 @@
@@ -1789 +1789,3 @@
-3000
+0000
+1800
+1800
@@ -1791,3 +1793,0 @@
@@ -1792,2 +1793,0 @@
-0000
-0000
-0000
--- ./ter-u20n.bdf.orig 2019-07-28 21:07:37.102989900 +0300
+++ ./ter-u20n.bdf 2019-07-28 21:07:51.923015900 +0300
--- ./ter-u20n.bdf.orig 2020-12-28 20:34:18.725118500 +0200
+++ ./ter-u20n.bdf 2020-12-28 20:34:23.635125400 +0200
@@ -254 +254 @@
-0800
+1000
@@ -1788,0 +1789,3 @@
@@ -1789 +1789,3 @@
-2000
+0000
+1000
+1000
@@ -1791,3 +1793,0 @@
@@ -1792,2 +1793,0 @@
-0000
-0000
-0000
--- ./ter-u22b.bdf.orig 2019-07-28 21:07:37.524190600 +0300
+++ ./ter-u22b.bdf 2019-07-28 21:07:52.313016600 +0300
--- ./ter-u22b.bdf.orig 2020-12-28 20:34:18.775118600 +0200
+++ ./ter-u22b.bdf 2020-12-28 20:34:23.675125400 +0200
@@ -267,4 +267,4 @@
-0C00
-0C00
@ -167,8 +167,8 @@
-0000
-0000
-0000
--- ./ter-u22n.bdf.orig 2019-07-28 21:07:37.414990400 +0300
+++ ./ter-u22n.bdf 2019-07-28 21:07:52.203816400 +0300
--- ./ter-u22n.bdf.orig 2020-12-28 20:34:18.775118600 +0200
+++ ./ter-u22n.bdf 2020-12-28 20:34:23.675125400 +0200
@@ -271 +271 @@
-0400
+0800
@ -184,12 +184,12 @@
+0400
+0400
+0200
--- ./ter-u24b.bdf.orig 2019-07-28 21:07:37.773791100 +0300
+++ ./ter-u24b.bdf 2019-07-28 21:07:52.562617100 +0300
--- ./ter-u24b.bdf.orig 2020-12-28 20:34:18.795118600 +0200
+++ ./ter-u24b.bdf 2020-12-28 20:34:23.715125500 +0200
@@ -288 +288 @@
-0600
+0C00
@@ -2049,5 +2048,0 @@
@@ -2050,5 +2049,0 @@
-1800
-0C00
-0600
@ -201,12 +201,12 @@
+0600
+0600
+0300
--- ./ter-u24n.bdf.orig 2019-07-28 21:07:37.648990900 +0300
+++ ./ter-u24n.bdf 2019-07-28 21:07:52.437816800 +0300
--- ./ter-u24n.bdf.orig 2020-12-28 20:34:18.795118600 +0200
+++ ./ter-u24n.bdf 2020-12-28 20:34:23.685125400 +0200
@@ -288 +288 @@
-0400
+0800
@@ -2049,5 +2048,0 @@
@@ -2050,5 +2049,0 @@
-1000
-0800
-0400
@ -218,20 +218,20 @@
+0400
+0400
+0200
--- ./ter-u28b.bdf.orig 2019-07-28 21:07:38.038991500 +0300
+++ ./ter-u28b.bdf 2019-07-28 21:07:52.827817500 +0300
--- ./ter-u28b.bdf.orig 2020-12-28 20:34:18.845118700 +0200
+++ ./ter-u28b.bdf 2020-12-28 20:34:23.735125500 +0200
@@ -320,2 +320,2 @@
-0300
-0300
+0600
+0600
@@ -2309,6 +2308,0 @@
-3800
-1C00
-0E00
-0700
-0000
-0000
-0000
@@ -2316,0 +2311,6 @@
+0600
+0600
@ -239,20 +239,20 @@
+0600
+0300
+0300
--- ./ter-u28n.bdf.orig 2019-07-28 21:07:37.914191300 +0300
+++ ./ter-u28n.bdf 2019-07-28 21:07:52.687417300 +0300
--- ./ter-u28n.bdf.orig 2020-12-28 20:34:18.835118600 +0200
+++ ./ter-u28n.bdf 2020-12-28 20:34:23.735125500 +0200
@@ -320,2 +320,2 @@
-0300
-0300
+0600
+0600
@@ -2309,6 +2308,0 @@
-1800
-0C00
-0600
-0300
-0000
-0000
-0000
@@ -2316,0 +2311,6 @@
+0600
+0600
@ -260,14 +260,14 @@
+0600
+0300
+0300
--- ./ter-u32b.bdf.orig 2019-07-28 21:07:38.335392100 +0300
+++ ./ter-u32b.bdf 2019-07-28 21:07:53.124218000 +0300
--- ./ter-u32b.bdf.orig 2020-12-28 20:34:18.865118700 +0200
+++ ./ter-u32b.bdf 2020-12-28 20:34:23.775125600 +0200
@@ -354,2 +354,2 @@
-0380
-0380
+0700
+0700
@@ -2570,6 +2569,0 @@
@@ -2571,6 +2570,0 @@
-1C00
-0E00
-0700
@ -281,14 +281,14 @@
+0380
+01C0
+01C0
--- ./ter-u32n.bdf.orig 2019-07-28 21:07:38.194991800 +0300
+++ ./ter-u32n.bdf 2019-07-28 21:07:52.968217800 +0300
--- ./ter-u32n.bdf.orig 2020-12-28 20:34:18.865118700 +0200
+++ ./ter-u32n.bdf 2020-12-28 20:34:23.765125500 +0200
@@ -354,2 +354,2 @@
-0180
-0180
+0300
+0300
@@ -2570,6 +2569,0 @@
@@ -2571,6 +2570,0 @@
-0E00
-0700
-0380

View File

@ -1,5 +1,5 @@
--- ./ter-u12b.bdf.orig 2019-07-28 21:08:05.760240200 +0300
+++ ./ter-u12b.bdf 2019-07-28 21:08:09.036246000 +0300
--- ./ter-u12b.bdf.orig 2020-12-28 20:34:27.995131500 +0200
+++ ./ter-u12b.bdf 2020-12-28 20:34:29.445133500 +0200
@@ -10030,3 +10030,2 @@
-E0
-90
@ -25,8 +25,8 @@
+FC
+84
+00
--- ./ter-u12n.bdf.orig 2019-07-28 21:08:05.666640100 +0300
+++ ./ter-u12n.bdf 2019-07-28 21:08:08.942645800 +0300
--- ./ter-u12n.bdf.orig 2020-12-28 20:34:27.975131400 +0200
+++ ./ter-u12n.bdf 2020-12-28 20:34:29.425133500 +0200
@@ -10030,3 +10030,2 @@
-E0
-90
@ -52,8 +52,8 @@
+FC
+84
+00
--- ./ter-u14b.bdf.orig 2019-07-28 21:08:05.963040600 +0300
+++ ./ter-u14b.bdf 2019-07-28 21:08:09.239046300 +0300
--- ./ter-u14b.bdf.orig 2020-12-28 20:34:28.025131500 +0200
+++ ./ter-u14b.bdf 2020-12-28 20:34:29.465133500 +0200
@@ -11082,4 +11082,3 @@
-78
-CC
@ -83,8 +83,8 @@
+FF
+C3
+00
--- ./ter-u14n.bdf.orig 2019-07-28 21:08:05.853840400 +0300
+++ ./ter-u14n.bdf 2019-07-28 21:08:09.145446200 +0300
--- ./ter-u14n.bdf.orig 2020-12-28 20:34:27.995131500 +0200
+++ ./ter-u14n.bdf 2020-12-28 20:34:29.465133500 +0200
@@ -11082,4 +11082,3 @@
-38
-44
@ -113,8 +113,8 @@
+FE
+82
+00
--- ./ter-u14v.bdf.orig 2019-07-28 21:08:06.056640800 +0300
+++ ./ter-u14v.bdf 2019-07-28 21:08:09.332646500 +0300
--- ./ter-u14v.bdf.orig 2020-12-28 20:34:28.025131500 +0200
+++ ./ter-u14v.bdf 2020-12-28 20:34:29.475133500 +0200
@@ -11082,4 +11082,3 @@
-78
-CC
@ -144,8 +144,8 @@
+FF
+C3
+00
--- ./ter-u16b.bdf.orig 2019-07-28 21:08:06.259441100 +0300
+++ ./ter-u16b.bdf 2019-07-28 21:08:09.535446900 +0300
--- ./ter-u16b.bdf.orig 2020-12-28 20:34:28.035131500 +0200
+++ ./ter-u16b.bdf 2020-12-28 20:34:29.515133600 +0200
@@ -12134,4 +12134,3 @@
-78
-CC
@ -177,8 +177,8 @@
+C3
+00
+00
--- ./ter-u16n.bdf.orig 2019-07-28 21:08:06.165840900 +0300
+++ ./ter-u16n.bdf 2019-07-28 21:08:09.426246700 +0300
--- ./ter-u16n.bdf.orig 2020-12-28 20:34:28.035131500 +0200
+++ ./ter-u16n.bdf 2020-12-28 20:34:29.485133500 +0200
@@ -12134,4 +12134,3 @@
-38
-44
@ -209,8 +209,8 @@
+82
+00
+00
--- ./ter-u16v.bdf.orig 2019-07-28 21:08:06.353041300 +0300
+++ ./ter-u16v.bdf 2019-07-28 21:08:09.629047000 +0300
--- ./ter-u16v.bdf.orig 2020-12-28 20:34:28.065131600 +0200
+++ ./ter-u16v.bdf 2020-12-28 20:34:29.515133600 +0200
@@ -12134,4 +12134,3 @@
-78
-CC
@ -242,8 +242,8 @@
+C3
+00
+00
--- ./ter-u18b.bdf.orig 2019-07-28 21:08:06.587041700 +0300
+++ ./ter-u18b.bdf 2019-07-28 21:08:09.863047400 +0300
--- ./ter-u18b.bdf.orig 2020-12-28 20:34:28.085131600 +0200
+++ ./ter-u18b.bdf 2020-12-28 20:34:29.535133600 +0200
@@ -13186,5 +13186,4 @@
-3E00
-6300
@ -281,8 +281,8 @@
+C180
+C180
+0000
--- ./ter-u18n.bdf.orig 2019-07-28 21:08:06.477841500 +0300
+++ ./ter-u18n.bdf 2019-07-28 21:08:09.738247200 +0300
--- ./ter-u18n.bdf.orig 2020-12-28 20:34:28.065131600 +0200
+++ ./ter-u18n.bdf 2020-12-28 20:34:29.515133600 +0200
@@ -13186,5 +13186,4 @@
-3C00
-4200
@ -320,8 +320,8 @@
+4080
+4080
+0000
--- ./ter-u20b.bdf.orig 2019-07-28 21:08:06.821042100 +0300
+++ ./ter-u20b.bdf 2019-07-28 21:08:10.081447800 +0300
--- ./ter-u20b.bdf.orig 2020-12-28 20:34:28.115131600 +0200
+++ ./ter-u20b.bdf 2020-12-28 20:34:29.575133700 +0200
@@ -14239,5 +14239,4 @@
-3E00
-6300
@ -359,8 +359,8 @@
+C180
+C180
+0000
--- ./ter-u20n.bdf.orig 2019-07-28 21:08:06.711841900 +0300
+++ ./ter-u20n.bdf 2019-07-28 21:08:09.972247600 +0300
--- ./ter-u20n.bdf.orig 2020-12-28 20:34:28.085131600 +0200
+++ ./ter-u20n.bdf 2020-12-28 20:34:29.565133700 +0200
@@ -14239,5 +14239,4 @@
-3C00
-4200
@ -398,8 +398,8 @@
+4080
+4080
+0000
--- ./ter-u22b.bdf.orig 2019-07-28 21:08:07.055042500 +0300
+++ ./ter-u22b.bdf 2019-07-28 21:08:10.331048300 +0300
--- ./ter-u22b.bdf.orig 2020-12-28 20:34:28.135131700 +0200
+++ ./ter-u22b.bdf 2020-12-28 20:34:29.605133700 +0200
@@ -15291,8 +15291,5 @@
-3E00
-6300
@ -452,8 +452,8 @@
+C0C0
+0000
+0000
--- ./ter-u22n.bdf.orig 2019-07-28 21:08:06.930242300 +0300
+++ ./ter-u22n.bdf 2019-07-28 21:08:10.206248000 +0300
--- ./ter-u22n.bdf.orig 2020-12-28 20:34:28.115131600 +0200
+++ ./ter-u22n.bdf 2020-12-28 20:34:29.575133700 +0200
@@ -15291,8 +15291,6 @@
-3C00
-4200
@ -504,8 +504,8 @@
+4040
+0000
+0000
--- ./ter-u24b.bdf.orig 2019-07-28 21:08:07.289042900 +0300
+++ ./ter-u24b.bdf 2019-07-28 21:08:10.565048700 +0300
--- ./ter-u24b.bdf.orig 2020-12-28 20:34:28.165131700 +0200
+++ ./ter-u24b.bdf 2020-12-28 20:34:29.615133700 +0200
@@ -16344,2 +16344,5 @@
-3F00
-6180
@ -552,8 +552,8 @@
-3F80
+0000
+0000
--- ./ter-u24n.bdf.orig 2019-07-28 21:08:07.164242700 +0300
+++ ./ter-u24n.bdf 2019-07-28 21:08:10.440248500 +0300
--- ./ter-u24n.bdf.orig 2020-12-28 20:34:28.135131700 +0200
+++ ./ter-u24n.bdf 2020-12-28 20:34:29.625133700 +0200
@@ -16344,2 +16344,5 @@
-3E00
-4100
@ -600,8 +600,8 @@
-3F00
+0000
+0000
--- ./ter-u28b.bdf.orig 2019-07-28 21:08:07.616643500 +0300
+++ ./ter-u28b.bdf 2019-07-28 21:08:10.845849200 +0300
--- ./ter-u28b.bdf.orig 2020-12-28 20:34:28.185131700 +0200
+++ ./ter-u28b.bdf 2020-12-28 20:34:29.665133800 +0200
@@ -18448 +18448,5 @@
-3F00
+0000
@ -664,8 +664,8 @@
+6018
+0000
+0000
--- ./ter-u28n.bdf.orig 2019-07-28 21:08:07.413843100 +0300
+++ ./ter-u28n.bdf 2019-07-28 21:08:10.705448900 +0300
--- ./ter-u28n.bdf.orig 2020-12-28 20:34:28.175131700 +0200
+++ ./ter-u28n.bdf 2020-12-28 20:34:29.635133800 +0200
@@ -18448,4 +18448,6 @@
-3F00
-6180
@ -725,8 +725,8 @@
+6018
+0000
+0000
--- ./ter-u32b.bdf.orig 2019-07-28 21:08:07.913044000 +0300
+++ ./ter-u32b.bdf 2019-07-28 21:08:11.142249700 +0300
--- ./ter-u32b.bdf.orig 2020-12-28 20:34:28.225131800 +0200
+++ ./ter-u32b.bdf 2020-12-28 20:34:29.675133800 +0200
@@ -20554,8 +20554,6 @@
-3FC0
-7FE0
@ -792,8 +792,8 @@
+700E
+700E
+0000
--- ./ter-u32n.bdf.orig 2019-07-28 21:08:07.757043700 +0300
+++ ./ter-u32n.bdf 2019-07-28 21:08:10.986249400 +0300
--- ./ter-u32n.bdf.orig 2020-12-28 20:34:28.205131800 +0200
+++ ./ter-u32n.bdf 2020-12-28 20:34:29.675133800 +0200
@@ -20554,8 +20554,6 @@
-1FC0
-3FE0

View File

@ -1,5 +1,5 @@
--- ./ter-u12b.bdf.orig 2019-07-28 21:08:05.760240200 +0300
+++ ./ter-u12b.bdf 2019-07-28 21:08:11.937851100 +0300
--- ./ter-u12b.bdf.orig 2020-12-28 20:34:27.995131500 +0200
+++ ./ter-u12b.bdf 2020-12-28 20:34:30.355134800 +0200
@@ -10182,2 +10182,2 @@
-00
-00
@ -27,8 +27,8 @@
+C0
+40
+48
--- ./ter-u12n.bdf.orig 2019-07-28 21:08:05.666640100 +0300
+++ ./ter-u12n.bdf 2019-07-28 21:08:11.844250900 +0300
--- ./ter-u12n.bdf.orig 2020-12-28 20:34:27.975131400 +0200
+++ ./ter-u12n.bdf 2020-12-28 20:34:30.315134700 +0200
@@ -10182,2 +10182,2 @@
-00
-00
@ -56,8 +56,8 @@
+C0
+40
+48
--- ./ter-u14b.bdf.orig 2019-07-28 21:08:05.963040600 +0300
+++ ./ter-u14b.bdf 2019-07-28 21:08:12.140651400 +0300
--- ./ter-u14b.bdf.orig 2020-12-28 20:34:28.025131500 +0200
+++ ./ter-u14b.bdf 2020-12-28 20:34:30.365134800 +0200
@@ -11250,3 +11250,3 @@
-00
-00
@ -95,8 +95,8 @@
+60
+60
+63
--- ./ter-u14n.bdf.orig 2019-07-28 21:08:05.853840400 +0300
+++ ./ter-u14n.bdf 2019-07-28 21:08:12.031451200 +0300
--- ./ter-u14n.bdf.orig 2020-12-28 20:34:27.995131500 +0200
+++ ./ter-u14n.bdf 2020-12-28 20:34:30.365134800 +0200
@@ -11250,3 +11250,3 @@
-00
-00
@ -134,8 +134,8 @@
+40
+40
+42
--- ./ter-u14v.bdf.orig 2019-07-28 21:08:06.056640800 +0300
+++ ./ter-u14v.bdf 2019-07-28 21:08:12.234251600 +0300
--- ./ter-u14v.bdf.orig 2020-12-28 20:34:28.025131500 +0200
+++ ./ter-u14v.bdf 2020-12-28 20:34:30.385134800 +0200
@@ -11250,3 +11250,3 @@
-00
-00
@ -173,8 +173,8 @@
+60
+60
+63
--- ./ter-u16b.bdf.orig 2019-07-28 21:08:06.259441100 +0300
+++ ./ter-u16b.bdf 2019-07-28 21:08:12.452652000 +0300
--- ./ter-u16b.bdf.orig 2020-12-28 20:34:28.035131500 +0200
+++ ./ter-u16b.bdf 2020-12-28 20:34:30.405134800 +0200
@@ -12318,3 +12318,3 @@
-00
-00
@ -212,8 +212,8 @@
+60
+60
+63
--- ./ter-u16n.bdf.orig 2019-07-28 21:08:06.165840900 +0300
+++ ./ter-u16n.bdf 2019-07-28 21:08:12.343451800 +0300
--- ./ter-u16n.bdf.orig 2020-12-28 20:34:28.035131500 +0200
+++ ./ter-u16n.bdf 2020-12-28 20:34:30.395134800 +0200
@@ -12318,3 +12318,3 @@
-00
-00
@ -251,8 +251,8 @@
+40
+40
+42
--- ./ter-u16v.bdf.orig 2019-07-28 21:08:06.353041300 +0300
+++ ./ter-u16v.bdf 2019-07-28 21:08:12.655452300 +0300
--- ./ter-u16v.bdf.orig 2020-12-28 20:34:28.065131600 +0200
+++ ./ter-u16v.bdf 2020-12-28 20:34:30.405134800 +0200
@@ -12318,3 +12318,3 @@
-00
-00
@ -290,8 +290,8 @@
+60
+60
+63
--- ./ter-u18b.bdf.orig 2019-07-28 21:08:06.587041700 +0300
+++ ./ter-u18b.bdf 2019-07-28 21:08:12.889452800 +0300
--- ./ter-u18b.bdf.orig 2020-12-28 20:34:28.085131600 +0200
+++ ./ter-u18b.bdf 2020-12-28 20:34:30.445134900 +0200
@@ -13386,4 +13386,4 @@
-0000
-0000
@ -333,8 +333,8 @@
+6000
+6000
+6180
--- ./ter-u18n.bdf.orig 2019-07-28 21:08:06.477841500 +0300
+++ ./ter-u18n.bdf 2019-07-28 21:08:12.764652500 +0300
--- ./ter-u18n.bdf.orig 2020-12-28 20:34:28.065131600 +0200
+++ ./ter-u18n.bdf 2020-12-28 20:34:30.445134900 +0200
@@ -13386,4 +13386,4 @@
-0000
-0000
@ -376,8 +376,8 @@
+4000
+4000
+4100
--- ./ter-u20b.bdf.orig 2019-07-28 21:08:06.821042100 +0300
+++ ./ter-u20b.bdf 2019-07-28 21:08:13.107853100 +0300
--- ./ter-u20b.bdf.orig 2020-12-28 20:34:28.115131600 +0200
+++ ./ter-u20b.bdf 2020-12-28 20:34:30.455134900 +0200
@@ -14455,4 +14455,4 @@
-0000
-0000
@ -425,8 +425,8 @@
+6000
+6000
+6180
--- ./ter-u20n.bdf.orig 2019-07-28 21:08:06.711841900 +0300
+++ ./ter-u20n.bdf 2019-07-28 21:08:12.998652900 +0300
--- ./ter-u20n.bdf.orig 2020-12-28 20:34:28.085131600 +0200
+++ ./ter-u20n.bdf 2020-12-28 20:34:30.445134900 +0200
@@ -14455,4 +14455,4 @@
-0000
-0000
@ -474,8 +474,8 @@
+4000
+4000
+4100
--- ./ter-u22b.bdf.orig 2019-07-28 21:08:07.055042500 +0300
+++ ./ter-u22b.bdf 2019-07-28 21:08:13.341853500 +0300
--- ./ter-u22b.bdf.orig 2020-12-28 20:34:28.135131700 +0200
+++ ./ter-u22b.bdf 2020-12-28 20:34:30.505135000 +0200
@@ -15523,4 +15523,4 @@
-0000
-0000
@ -525,8 +525,8 @@
+3000
+30C0
+3180
--- ./ter-u22n.bdf.orig 2019-07-28 21:08:06.930242300 +0300
+++ ./ter-u22n.bdf 2019-07-28 21:08:13.232653400 +0300
--- ./ter-u22n.bdf.orig 2020-12-28 20:34:28.115131600 +0200
+++ ./ter-u22n.bdf 2020-12-28 20:34:30.485134900 +0200
@@ -15523,4 +15523,4 @@
-0000
-0000
@ -574,8 +574,8 @@
+2000
+2000
+2080
--- ./ter-u24b.bdf.orig 2019-07-28 21:08:07.289042900 +0300
+++ ./ter-u24b.bdf 2019-07-28 21:08:13.607054000 +0300
--- ./ter-u24b.bdf.orig 2020-12-28 20:34:28.165131700 +0200
+++ ./ter-u24b.bdf 2020-12-28 20:34:30.515135000 +0200
@@ -16592,4 +16592,4 @@
-0000
-0000
@ -625,8 +625,8 @@
+3000
+3060
+30C0
--- ./ter-u24n.bdf.orig 2019-07-28 21:08:07.164242700 +0300
+++ ./ter-u24n.bdf 2019-07-28 21:08:13.482253800 +0300
--- ./ter-u24n.bdf.orig 2020-12-28 20:34:28.135131700 +0200
+++ ./ter-u24n.bdf 2020-12-28 20:34:30.505135000 +0200
@@ -16592,4 +16592,4 @@
-0000
-0000
@ -674,8 +674,8 @@
+2000
+2000
+2040
--- ./ter-u28b.bdf.orig 2019-07-28 21:08:07.616643500 +0300
+++ ./ter-u28b.bdf 2019-07-28 21:08:13.950254600 +0300
--- ./ter-u28b.bdf.orig 2020-12-28 20:34:28.185131700 +0200
+++ ./ter-u28b.bdf 2020-12-28 20:34:30.555135000 +0200
@@ -18728,5 +18728,5 @@
-0000
-0000
@ -735,8 +735,8 @@
+3000
+3070
+30E0
--- ./ter-u28n.bdf.orig 2019-07-28 21:08:07.413843100 +0300
+++ ./ter-u28n.bdf 2019-07-28 21:08:13.809854400 +0300
--- ./ter-u28n.bdf.orig 2020-12-28 20:34:28.175131700 +0200
+++ ./ter-u28n.bdf 2020-12-28 20:34:30.535135000 +0200
@@ -18728,5 +18728,5 @@
-0000
-0000
@ -796,8 +796,8 @@
+3000
+3030
+3060
--- ./ter-u32b.bdf.orig 2019-07-28 21:08:07.913044000 +0300
+++ ./ter-u32b.bdf 2019-07-28 21:08:14.262255200 +0300
--- ./ter-u32b.bdf.orig 2020-12-28 20:34:28.225131800 +0200
+++ ./ter-u32b.bdf 2020-12-28 20:34:30.585135100 +0200
@@ -20866,6 +20866,6 @@
-0000
-0000
@ -867,8 +867,8 @@
+3800
+381C
+3838
--- ./ter-u32n.bdf.orig 2019-07-28 21:08:07.757043700 +0300
+++ ./ter-u32n.bdf 2019-07-28 21:08:14.090654900 +0300
--- ./ter-u32n.bdf.orig 2020-12-28 20:34:28.205131800 +0200
+++ ./ter-u32n.bdf 2020-12-28 20:34:30.585135100 +0200
@@ -20866,6 +20866,6 @@
-0000
-0000
@ -938,8 +938,8 @@
+1800
+181C
+1838
--- ./dup/xos4-2.dup.orig 2019-03-13 11:25:47.071547400 +0200
+++ ./dup/xos4-2.dup 2019-07-28 21:08:05.463839700 +0300
--- ./dup/xos4-2.dup.orig 2019-03-13 21:55:47.071547500 +0200
+++ ./dup/xos4-2.dup 2020-12-28 20:34:27.655131000 +0200
@@ -107 +107 @@
-0138 043A
+006B 043A

View File

@ -1,5 +1,5 @@
--- ./ter-u18b.bdf.orig 2019-07-28 21:07:36.993789700 +0300
+++ ./ter-u18b.bdf 2019-07-28 21:08:06.587041700 +0300
--- ./ter-u18b.bdf.orig 2020-12-28 20:34:18.725118500 +0200
+++ ./ter-u18b.bdf 2020-12-28 20:34:28.085131600 +0200
@@ -36 +35,0 @@
-0000
@@ -40,0 +40 @@
@ -1295,101 +1295,107 @@
@@ -20361 +20361 @@
-0000
+0180
@@ -20486 +20485,0 @@
@@ -20386 +20386 @@
-0000
@@ -20498,0 +20498 @@
+C000
@@ -20413 +20413 @@
-0000
+0180
@@ -20536 +20535,0 @@
-0000
@@ -20548,0 +20548 @@
+3600
@@ -20536 +20536 @@
@@ -20586 +20586 @@
-0000
+3600
@@ -20586 +20585,0 @@
@@ -20636 +20635,0 @@
-0000
@@ -20593,0 +20593 @@
@@ -20643,0 +20643 @@
+3600
@@ -20611 +20610,0 @@
@@ -20661 +20660,0 @@
-0000
@@ -20620,0 +20620 @@
@@ -20670,0 +20670 @@
+1E00
@@ -20636,2 +20635,0 @@
@@ -20686,2 +20685,0 @@
-0000
-0000
@@ -20642,0 +20641 @@
@@ -20692,0 +20691 @@
+0180
@@ -20647,0 +20647 @@
@@ -20697,0 +20697 @@
+0180
@@ -20659,4 +20659,2 @@
@@ -20709,4 +20709,2 @@
-0000
-0000
-0000
-0300
+0180
+0180
@@ -20663,0 +20662,2 @@
@@ -20713,0 +20712,2 @@
+0380
+0780
@@ -20665 +20664,0 @@
@@ -20715 +20714,0 @@
-0580
@@ -20672,0 +20672 @@
@@ -20722,0 +20722 @@
+6180
@@ -20674,2 +20674,2 @@
@@ -20724,2 +20724,2 @@
-6000
-0000
+C000
+C000
@@ -20711 +20710,0 @@
@@ -20761 +20760,0 @@
-0000
@@ -20716,0 +20716 @@
@@ -20766,0 +20766 @@
+1E00
@@ -20736 +20735,0 @@
@@ -20786 +20785,0 @@
-0000
@@ -20745,0 +20745 @@
@@ -20795,0 +20795 @@
+1E00
@@ -20761,2 +20760,0 @@
@@ -20811,2 +20810,0 @@
-0000
-0000
@@ -20767,0 +20766 @@
@@ -20817,0 +20816 @@
+6000
@@ -20770,0 +20770 @@
@@ -20820,0 +20820 @@
+6000
@@ -20784,4 +20784,2 @@
@@ -20834,4 +20834,2 @@
-0000
-0000
-0000
-0180
+00C0
+00C0
@@ -20789 +20787 @@
@@ -20839 +20837 @@
-1B00
+1980
@@ -20790,0 +20789 @@
@@ -20840,0 +20839 @@
+6300
@@ -20795,0 +20795,2 @@
@@ -20845,0 +20845,2 @@
+7800
+3800
@@ -20797 +20797,0 @@
@@ -20847 +20847,0 @@
-1800
@@ -20799,2 +20799,2 @@
@@ -20849,2 +20849,2 @@
-3000
-0000
+6000
+6000
@@ -20836,2 +20835,0 @@
@@ -20886,2 +20885,0 @@
-0000
-0000
@@ -20842,0 +20841 @@
@@ -20892,0 +20891 @@
+0180
@@ -20845,0 +20845 @@
@@ -20895,0 +20895 @@
+0180
@@ -20859,3 +20858,0 @@
@@ -20909,3 +20908,0 @@
-0000
-0000
-0000
@@ -20863,2 +20860,2 @@
@@ -20913,2 +20910,2 @@
-7C00
-3600
+6000
+3E00
@@ -20867,9 +20864,12 @@
@@ -20917,9 +20914,12 @@
-1980
-7F80
-0D80
@ -1411,125 +1417,125 @@
+3F80
+00C0
+00C0
@@ -21059 +21058,0 @@
@@ -21109 +21108,0 @@
-0000
@@ -21066,0 +21066 @@
@@ -21116,0 +21116 @@
+0300
@@ -21136 +21136 @@
@@ -21186 +21186 @@
-0000
+3600
@@ -21214 +21213,0 @@
@@ -21264 +21263,0 @@
-0000
@@ -21223,0 +21223 @@
@@ -21273,0 +21273 @@
+6180
@@ -21239 +21239 @@
@@ -21289 +21289 @@
-0000
+6180
@@ -21336 +21335,0 @@
@@ -21386 +21385,0 @@
-0000
@@ -21341,0 +21341 @@
@@ -21391,0 +21391 @@
+6000
@@ -21361 +21360,0 @@
@@ -21411 +21410,0 @@
-0000
@@ -21366,0 +21366 @@
@@ -21416,0 +21416 @@
+0180
@@ -21487 +21486,0 @@
@@ -21537 +21536,0 @@
-0000
@@ -21501,0 +21501 @@
@@ -21551,0 +21551 @@
+0000
@@ -21512 +21511,0 @@
@@ -21562 +21561,0 @@
-0000
@@ -21526,0 +21526 @@
@@ -21576,0 +21576 @@
+0000
@@ -21539 +21539 @@
@@ -21589 +21589 @@
-0000
+0C00
@@ -21561 +21560,0 @@
@@ -21611 +21610,0 @@
-0000
@@ -21573,0 +21573 @@
@@ -21623,0 +21623 @@
+6180
@@ -21586 +21586 @@
@@ -21636 +21636 @@
-0000
+6180
@@ -21661 +21660,0 @@
@@ -21711 +21710,0 @@
-0000
@@ -21673,0 +21673 @@
@@ -21723,0 +21723 @@
+1800
@@ -21686 +21685,0 @@
@@ -21736 +21735,0 @@
-0000
@@ -21698,0 +21698 @@
@@ -21748,0 +21748 @@
+0600
@@ -21711 +21711 @@
@@ -21761 +21761 @@
-0000
+1800
@@ -21736 +21736 @@
@@ -21786 +21786 @@
-0000
+0600
@@ -21811 +21810,0 @@
@@ -21861 +21860,0 @@
-0000
@@ -21826,0 +21826 @@
@@ -21876,0 +21876 @@
+0C00
@@ -22485 +22485 @@
-0000
+CC00
@@ -22499 +22499 @@
-0000
+0600
@@ -22510 +22510 @@
-0000
+C000
@@ -22519,0 +22520 @@
+1800
@@ -22526 +22526,0 @@
-0000
@@ -22535 +22535 @@
-0000
+CC00
@@ -22543 +22542,0 @@
@@ -22549 +22549 @@
-0000
@@ -22549,0 +22549 @@
+0600
@@ -22560 +22559,0 @@
@@ -22560 +22560 @@
-0000
@@ -22562,0 +22562 @@
+C000
@@ -22569,0 +22570 @@
+1800
@@ -22576 +22576,0 @@
-0000
@@ -22585 +22584,0 @@
-0000
@@ -22589,0 +22589 @@
+C000
@@ -22596,0 +22597 @@
+1E00
@@ -22601 +22601,0 @@
-0000
@@ -22610 +22610 @@
@@ -22585 +22585 @@
-0000
+CC00
@@ -22622,0 +22623 @@
@@ -22593 +22592,0 @@
-0000
@@ -22599,0 +22599 @@
+0600
@@ -22610 +22609,0 @@
-0000
@@ -22612,0 +22612 @@
+C000
@@ -22619,0 +22620 @@
+1800
@@ -22626 +22626,0 @@
-0000
@@ -26436 +26436 @@
@@ -22635 +22634,0 @@
-0000
@@ -22639,0 +22639 @@
+C000
@@ -22646,0 +22647 @@
+1E00
@@ -22651 +22651,0 @@
-0000
@@ -22660 +22660 @@
-0000
+CC00
@@ -22672,0 +22673 @@
+1800
@@ -22676 +22676,0 @@
-0000
@@ -26486 +26486 @@
-0000
+7F80
@@ -26761 +26760,0 @@
@@ -26811 +26810,0 @@
-0000
@@ -26772,0 +26772 @@
@@ -26822,0 +26822 @@
+8040
@@ -26786 +26785,0 @@
-0000
@@ -26797,0 +26797 @@
+FFC0
@@ -26836 +26835,0 @@
-0000
@@ -26842,0 +26842 @@
+6180
@@ -26861 +26860,0 @@
@@ -26847,0 +26847 @@
+FFC0
@@ -26886 +26885,0 @@
-0000
@@ -26866,8 +26865,9 @@
@@ -26892,0 +26892 @@
+6180
@@ -26911 +26910,0 @@
-0000
@@ -26916,8 +26915,9 @@
-3E00
-6300
-6300
@ -1547,35 +1553,35 @@
+C300
+C300
+7E00
@@ -26886 +26885,0 @@
@@ -26936 +26935,0 @@
-0000
@@ -26894,0 +26894 @@
@@ -26944,0 +26944 @@
+FFC0
@@ -26911 +26910,0 @@
@@ -26961 +26960,0 @@
-0000
@@ -26920,0 +26920 @@
@@ -26970,0 +26970 @@
+FFC0
@@ -26986 +26985,0 @@
@@ -27036 +27035,0 @@
-0000
@@ -26996,0 +26996 @@
@@ -27046,0 +27046 @@
+3000
@@ -27011 +27010,0 @@
@@ -27061 +27060,0 @@
-0000
@@ -27020,0 +27020 @@
@@ -27070,0 +27070 @@
+6180
@@ -33685 +33685 @@
@@ -33735 +33735 @@
-0000
+C000
@@ -33693,0 +33694 @@
@@ -33743,0 +33744 @@
+1980
@@ -33701 +33701,0 @@
@@ -33751 +33751,0 @@
-0000
@@ -33861 +33860,0 @@
@@ -33911 +33910,0 @@
-0000
@@ -33862,0 +33862 @@
@@ -33912,0 +33912 @@
+6180
--- ./ter-u18n.bdf.orig 2019-07-28 21:07:36.884589500 +0300
+++ ./ter-u18n.bdf 2019-07-28 21:08:06.477841500 +0300
--- ./ter-u18n.bdf.orig 2020-12-28 20:34:18.725118500 +0200
+++ ./ter-u18n.bdf 2020-12-28 20:34:28.065131600 +0200
@@ -36,2 +36 @@
-0000
-7700
@ -2270,10 +2276,10 @@
+4900
@@ -10711 +10710,0 @@
-0000
@@ -10717 +10716 @@
-0800
@@ -10716,0 +10716 @@
+1400
@@ -10719,0 +10719 @@
@@ -10718 +10718 @@
-0800
+1400
@@ -10736 +10736 @@
-0000
@ -2453,11 +2459,11 @@
+4900
@@ -12861 +12860,0 @@
-0000
@@ -12866,0 +12866 @@
+1400
@@ -12868 +12868 @@
@@ -12867 +12866 @@
-0800
+1400
@@ -12869,0 +12869 @@
+1400
@@ -12886 +12886 @@
-0000
+4100
@ -2598,10 +2604,10 @@
+0800
@@ -15086 +15085,0 @@
-0000
@@ -15092 +15091 @@
-0800
@@ -15091,0 +15091 @@
+1400
@@ -15094,0 +15094 @@
@@ -15093 +15093 @@
-0800
+1400
@@ -15136 +15135,0 @@
-0000
@ -2849,10 +2855,10 @@
+4400
@@ -19786 +19785,0 @@
-0000
@@ -19789,0 +19789 @@
+4500
@@ -19795 +19795 @@
@@ -19790 +19789 @@
-5500
+4500
@@ -19797,0 +19797 @@
+5100
@@ -19836 +19835,0 @@
-0000
@ -2914,98 +2920,101 @@
@@ -20361 +20361 @@
-0000
+0080
@@ -20486 +20485,0 @@
@@ -20386 +20386 @@
-0000
@@ -20498,0 +20498 @@
+8000
@@ -20536 +20535,0 @@
-0000
@@ -20548,0 +20548 @@
+1400
@@ -20536 +20536 @@
@@ -20586 +20586 @@
-0000
+1400
@@ -20586 +20585,0 @@
@@ -20636 +20635,0 @@
-0000
@@ -20594,0 +20594 @@
@@ -20644,0 +20644 @@
+1400
@@ -20611 +20610,0 @@
@@ -20661 +20660,0 @@
-0000
@@ -20623,0 +20623 @@
@@ -20673,0 +20673 @@
+0800
@@ -20636,2 +20635,0 @@
@@ -20686,2 +20685,0 @@
-0000
-0000
@@ -20642,0 +20641 @@
@@ -20692,0 +20691 @@
+0100
@@ -20647,0 +20647 @@
@@ -20697,0 +20697 @@
+0100
@@ -20659,4 +20659,2 @@
@@ -20709,4 +20709,2 @@
-0000
-0000
-0000
-0200
+0100
+0100
@@ -20663,0 +20662 @@
@@ -20713,0 +20712 @@
+0300
@@ -20672,0 +20672 @@
@@ -20722,0 +20722 @@
+4100
@@ -20674,2 +20674,2 @@
@@ -20724,2 +20724,2 @@
-4000
-0000
+8000
+8000
@@ -20711 +20710,0 @@
@@ -20761 +20760,0 @@
-0000
@@ -20722,0 +20722 @@
@@ -20772,0 +20772 @@
+4100
@@ -20736 +20735,0 @@
@@ -20786 +20785,0 @@
-0000
@@ -20739,0 +20739 @@
@@ -20789,0 +20789 @@
+4100
@@ -20761,2 +20760,0 @@
@@ -20811,2 +20810,0 @@
-0000
-0000
@@ -20767,0 +20766 @@
@@ -20817,0 +20816 @@
+4000
@@ -20770,0 +20770 @@
@@ -20820,0 +20820 @@
+4000
@@ -20784,4 +20784,2 @@
@@ -20834,4 +20834,2 @@
-0000
-0000
-0000
-0100
+0080
+0080
@@ -20789 +20787 @@
@@ -20839 +20837 @@
-1200
+1100
@@ -20790,0 +20789 @@
@@ -20840,0 +20839 @@
+4200
@@ -20795,0 +20795,2 @@
@@ -20845,0 +20845,2 @@
+5000
+3000
@@ -20797 +20797,0 @@
@@ -20847 +20847,0 @@
-1000
@@ -20799,2 +20799,2 @@
@@ -20849,2 +20849,2 @@
-2000
-0000
+4000
+4000
@@ -20836,2 +20835,0 @@
@@ -20886,2 +20885,0 @@
-0000
-0000
@@ -20842,0 +20841 @@
@@ -20892,0 +20891 @@
+0100
@@ -20845,0 +20845 @@
@@ -20895,0 +20895 @@
+0100
@@ -20859,3 +20858,0 @@
@@ -20909,3 +20908,0 @@
-0000
-0000
-0000
@@ -20863,2 +20860,2 @@
@@ -20913,2 +20910,2 @@
-7800
-2400
+4000
+3C00
@@ -20867,9 +20864,12 @@
@@ -20917,9 +20914,12 @@
-1100
-7F00
-0900
@ -3027,123 +3036,123 @@
+3D00
+0080
+0080
@@ -21059 +21058,0 @@
@@ -21109 +21108,0 @@
-0000
@@ -21066,0 +21066 @@
@@ -21116,0 +21116 @@
+0200
@@ -21136 +21136 @@
@@ -21186 +21186 @@
-0000
+1400
@@ -21214 +21213,0 @@
@@ -21264 +21263,0 @@
-0000
@@ -21223,0 +21223 @@
@@ -21273,0 +21273 @@
+4100
@@ -21239 +21239 @@
@@ -21289 +21289 @@
-0000
+4100
@@ -21336 +21335,0 @@
@@ -21386 +21385,0 @@
-0000
@@ -21341,0 +21341 @@
@@ -21391,0 +21391 @@
+4000
@@ -21361 +21360,0 @@
@@ -21411 +21410,0 @@
-0000
@@ -21366,0 +21366 @@
@@ -21416,0 +21416 @@
+0100
@@ -21487 +21486,0 @@
@@ -21537 +21536,0 @@
-0000
@@ -21501,0 +21501 @@
@@ -21551,0 +21551 @@
+0000
@@ -21512 +21511,0 @@
@@ -21562 +21561,0 @@
-0000
@@ -21526,0 +21526 @@
@@ -21576,0 +21576 @@
+0000
@@ -21539 +21539 @@
@@ -21589 +21589 @@
-0000
+0800
@@ -21561 +21560,0 @@
@@ -21611 +21610,0 @@
-0000
@@ -21573,0 +21573 @@
@@ -21623,0 +21623 @@
+4100
@@ -21586 +21586 @@
@@ -21636 +21636 @@
-0000
+4100
@@ -21661 +21660,0 @@
@@ -21711 +21710,0 @@
-0000
@@ -21673,0 +21673 @@
@@ -21723,0 +21723 @@
+1000
@@ -21686 +21685,0 @@
@@ -21736 +21735,0 @@
-0000
@@ -21698,0 +21698 @@
@@ -21748,0 +21748 @@
+0400
@@ -21711 +21711 @@
@@ -21761 +21761 @@
-0000
+1000
@@ -21736 +21736 @@
@@ -21786 +21786 @@
-0000
+0400
@@ -21811 +21810,0 @@
@@ -21861 +21860,0 @@
-0000
@@ -21826,0 +21826 @@
@@ -21876,0 +21876 @@
+0800
@@ -22485 +22485 @@
-0000
+4400
@@ -22499 +22499 @@
-0000
+0200
@@ -22510 +22510 @@
-0000
+4000
@@ -22519,0 +22520 @@
+0800
@@ -22526 +22526,0 @@
-0000
@@ -22535 +22535 @@
-0000
+4400
@@ -22543 +22542,0 @@
@@ -22549 +22549 @@
-0000
@@ -22549,0 +22549 @@
+0200
@@ -22560 +22559,0 @@
@@ -22560 +22560 @@
-0000
@@ -22562,0 +22562 @@
+4000
@@ -22569,0 +22570 @@
+0800
@@ -22576 +22576,0 @@
-0000
@@ -22585 +22584,0 @@
-0000
@@ -22589,0 +22589 @@
+4000
@@ -22596,0 +22597 @@
+0A00
@@ -22601 +22601,0 @@
-0000
@@ -22610 +22610 @@
@@ -22585 +22585 @@
-0000
+4400
@@ -22622,0 +22623 @@
@@ -22593 +22592,0 @@
-0000
@@ -22599,0 +22599 @@
+0200
@@ -22610 +22609,0 @@
-0000
@@ -22612,0 +22612 @@
+4000
@@ -22619,0 +22620 @@
+0800
@@ -22626 +22626,0 @@
-0000
@@ -26436 +26436 @@
@@ -22635 +22634,0 @@
-0000
@@ -22639,0 +22639 @@
+4000
@@ -22646,0 +22647 @@
+0A00
@@ -22651 +22651,0 @@
-0000
@@ -22660 +22660 @@
-0000
+4400
@@ -22672,0 +22673 @@
+0800
@@ -22676 +22676,0 @@
-0000
@@ -26486 +26486 @@
-0000
+7F00
@@ -26761 +26760,0 @@
@@ -26811 +26810,0 @@
-0000
@@ -26772,0 +26772 @@
@@ -26822,0 +26822 @@
+8080
@@ -26786 +26785,0 @@
-0000
@@ -26797,0 +26797 @@
+FF80
@@ -26836 +26835,0 @@
-0000
@@ -26842,0 +26842 @@
@@ -26847,0 +26847 @@
+FF80
@@ -26886 +26885,0 @@
-0000
@@ -26892,0 +26892 @@
+4100
@@ -26861,13 +26861,13 @@
@@ -26911,13 +26911,13 @@
-0000
-0F00
-0300
@ -3170,30 +3179,30 @@
+8200
+8200
+7C00
@@ -26886 +26885,0 @@
@@ -26936 +26935,0 @@
-0000
@@ -26894,0 +26894 @@
@@ -26944,0 +26944 @@
+FF80
@@ -26911 +26910,0 @@
@@ -26961 +26960,0 @@
-0000
@@ -26922,0 +26922 @@
@@ -26972,0 +26972 @@
+0800
@@ -26986 +26985,0 @@
@@ -27036 +27035,0 @@
-0000
@@ -26997,0 +26997 @@
@@ -27047,0 +27047 @@
+1000
@@ -27011 +27010,0 @@
@@ -27061 +27060,0 @@
-0000
@@ -27021,0 +27021 @@
@@ -27071,0 +27071 @@
+4100
@@ -33685 +33685 @@
@@ -33735 +33735 @@
-0000
+4000
@@ -33693,0 +33694 @@
@@ -33743,0 +33744 @@
+0880
@@ -33701 +33701,0 @@
@@ -33751 +33751,0 @@
-0000
@@ -33861 +33860,0 @@
@@ -33911 +33910,0 @@
-0000
@@ -33862,0 +33862 @@
@@ -33912,0 +33912 @@
+4100

View File

@ -1,5 +1,5 @@
--- ./ter-u12b.bdf.orig 2019-07-28 21:07:36.104588100 +0300
+++ ./ter-u12b.bdf 2019-07-28 21:07:53.888619400 +0300
--- ./ter-u12b.bdf.orig 2020-12-28 20:34:18.635118400 +0200
+++ ./ter-u12b.bdf 2020-12-28 20:34:24.405126400 +0200
@@ -10147,0 +10148,3 @@
+98
+A8
@ -40,8 +40,8 @@
-88
-88
-78
--- ./ter-u12n.bdf.orig 2019-07-28 21:07:35.995388000 +0300
+++ ./ter-u12n.bdf 2019-07-28 21:07:53.795019200 +0300
--- ./ter-u12n.bdf.orig 2020-12-28 20:34:18.605118300 +0200
+++ ./ter-u12n.bdf 2020-12-28 20:34:24.385126400 +0200
@@ -10147,0 +10148,3 @@
+98
+A8
@ -82,8 +82,8 @@
-88
-88
-78
--- ./ter-u14b.bdf.orig 2019-07-28 21:07:36.322988500 +0300
+++ ./ter-u14b.bdf 2019-07-28 21:07:54.091419700 +0300
--- ./ter-u14b.bdf.orig 2020-12-28 20:34:18.655118400 +0200
+++ ./ter-u14b.bdf 2020-12-28 20:34:24.425126500 +0200
@@ -11212,0 +11213,4 @@
+CE
+DE
@ -134,8 +134,8 @@
-C6
-C6
-7E
--- ./ter-u14n.bdf.orig 2019-07-28 21:07:36.213788300 +0300
+++ ./ter-u14n.bdf 2019-07-28 21:07:53.997819600 +0300
--- ./ter-u14n.bdf.orig 2020-12-28 20:34:18.645118400 +0200
+++ ./ter-u14n.bdf 2020-12-28 20:34:24.425126500 +0200
@@ -11212,0 +11213,4 @@
+46
+4A
@ -186,8 +186,8 @@
-42
-42
-3E
--- ./ter-u14v.bdf.orig 2019-07-28 21:07:36.416588700 +0300
+++ ./ter-u14v.bdf 2019-07-28 21:07:54.185019900 +0300
--- ./ter-u14v.bdf.orig 2020-12-28 20:34:18.675118400 +0200
+++ ./ter-u14v.bdf 2020-12-28 20:34:24.445126500 +0200
@@ -11212,0 +11213,4 @@
+CE
+DE
@ -238,8 +238,8 @@
-C6
-C6
-7E
--- ./ter-u16b.bdf.orig 2019-07-28 21:07:36.634989100 +0300
+++ ./ter-u16b.bdf 2019-07-28 21:07:54.387820300 +0300
--- ./ter-u16b.bdf.orig 2020-12-28 20:34:18.685118400 +0200
+++ ./ter-u16b.bdf 2020-12-28 20:34:24.455126500 +0200
@@ -12276,0 +12277,4 @@
+CE
+DE
@ -290,8 +290,8 @@
-C6
-C6
-7E
--- ./ter-u16n.bdf.orig 2019-07-28 21:07:36.541388900 +0300
+++ ./ter-u16n.bdf 2019-07-28 21:07:54.294220100 +0300
--- ./ter-u16n.bdf.orig 2020-12-28 20:34:18.685118400 +0200
+++ ./ter-u16n.bdf 2020-12-28 20:34:24.455126500 +0200
@@ -12276,0 +12277,4 @@
+46
+4A
@ -342,8 +342,8 @@
-42
-42
-3E
--- ./ter-u16v.bdf.orig 2019-07-28 21:07:36.759789300 +0300
+++ ./ter-u16v.bdf 2019-07-28 21:07:54.497020400 +0300
--- ./ter-u16v.bdf.orig 2020-12-28 20:34:18.695118400 +0200
+++ ./ter-u16v.bdf 2020-12-28 20:34:24.465126500 +0200
@@ -12276,0 +12277,4 @@
+CE
+DE
@ -394,8 +394,8 @@
-C6
-C6
-7E
--- ./ter-u18b.bdf.orig 2019-07-28 21:07:36.993789700 +0300
+++ ./ter-u18b.bdf 2019-07-28 21:07:54.715420800 +0300
--- ./ter-u18b.bdf.orig 2020-12-28 20:34:18.725118500 +0200
+++ ./ter-u18b.bdf 2020-12-28 20:34:24.495126600 +0200
@@ -13341,0 +13342,5 @@
+6380
+6780
@ -456,8 +456,8 @@
-6180
-6180
-3F80
--- ./ter-u18n.bdf.orig 2019-07-28 21:07:36.884589500 +0300
+++ ./ter-u18n.bdf 2019-07-28 21:07:54.606220600 +0300
--- ./ter-u18n.bdf.orig 2020-12-28 20:34:18.725118500 +0200
+++ ./ter-u18n.bdf 2020-12-28 20:34:24.495126600 +0200
@@ -13341,0 +13342,5 @@
+4300
+4500
@ -518,8 +518,8 @@
-4100
-4100
-3F00
--- ./ter-u20b.bdf.orig 2019-07-28 21:07:37.290190200 +0300
+++ ./ter-u20b.bdf 2019-07-28 21:07:54.949421200 +0300
--- ./ter-u20b.bdf.orig 2020-12-28 20:34:18.735118500 +0200
+++ ./ter-u20b.bdf 2020-12-28 20:34:24.515126600 +0200
@@ -14406,0 +14407,5 @@
+6380
+6780
@ -580,8 +580,8 @@
-6180
-6180
-3F80
--- ./ter-u20n.bdf.orig 2019-07-28 21:07:37.102989900 +0300
+++ ./ter-u20n.bdf 2019-07-28 21:07:54.840221100 +0300
--- ./ter-u20n.bdf.orig 2020-12-28 20:34:18.725118500 +0200
+++ ./ter-u20n.bdf 2020-12-28 20:34:24.505126600 +0200
@@ -14406,0 +14407,5 @@
+4300
+4500
@ -642,8 +642,8 @@
-4100
-4100
-3F00
--- ./ter-u22b.bdf.orig 2019-07-28 21:07:37.524190600 +0300
+++ ./ter-u22b.bdf 2019-07-28 21:07:55.183421700 +0300
--- ./ter-u22b.bdf.orig 2020-12-28 20:34:18.775118600 +0200
+++ ./ter-u22b.bdf 2020-12-28 20:34:24.555126600 +0200
@@ -15470,0 +15471,6 @@
+61C0
+63C0
@ -714,8 +714,8 @@
-60C0
-30C0
-1FC0
--- ./ter-u22n.bdf.orig 2019-07-28 21:07:37.414990400 +0300
+++ ./ter-u22n.bdf 2019-07-28 21:07:55.058621400 +0300
--- ./ter-u22n.bdf.orig 2020-12-28 20:34:18.775118600 +0200
+++ ./ter-u22n.bdf 2020-12-28 20:34:24.545126600 +0200
@@ -15470,0 +15471,6 @@
+4180
+4280
@ -786,8 +786,8 @@
-4080
-2080
-1F80
--- ./ter-u24b.bdf.orig 2019-07-28 21:07:37.773791100 +0300
+++ ./ter-u24b.bdf 2019-07-28 21:07:55.417422100 +0300
--- ./ter-u24b.bdf.orig 2020-12-28 20:34:18.795118600 +0200
+++ ./ter-u24b.bdf 2020-12-28 20:34:24.555126600 +0200
@@ -16535,0 +16536,7 @@
+60E0
+61E0
@ -868,8 +868,8 @@
-6060
-3060
-1FE0
--- ./ter-u24n.bdf.orig 2019-07-28 21:07:37.648990900 +0300
+++ ./ter-u24n.bdf 2019-07-28 21:07:55.292621800 +0300
--- ./ter-u24n.bdf.orig 2020-12-28 20:34:18.795118600 +0200
+++ ./ter-u24n.bdf 2020-12-28 20:34:24.555126600 +0200
@@ -16535,0 +16536,7 @@
+40C0
+4140
@ -950,8 +950,8 @@
-4040
-2040
-1FC0
--- ./ter-u28b.bdf.orig 2019-07-28 21:07:38.038991500 +0300
+++ ./ter-u28b.bdf 2019-07-28 21:07:55.682622500 +0300
--- ./ter-u28b.bdf.orig 2020-12-28 20:34:18.845118700 +0200
+++ ./ter-u28b.bdf 2020-12-28 20:34:24.615126700 +0200
@@ -18664,0 +18665,9 @@
+6070
+60F0
@ -1052,8 +1052,8 @@
-7030
-3FF0
-1FF0
--- ./ter-u28n.bdf.orig 2019-07-28 21:07:37.914191300 +0300
+++ ./ter-u28n.bdf 2019-07-28 21:07:55.542222300 +0300
--- ./ter-u28n.bdf.orig 2020-12-28 20:34:18.835118600 +0200
+++ ./ter-u28n.bdf 2020-12-28 20:34:24.605126700 +0200
@@ -18665,0 +18666,8 @@
+6070
+60F0
@ -1144,8 +1144,8 @@
-6030
-3030
-1FF0
--- ./ter-u32b.bdf.orig 2019-07-28 21:07:38.335392100 +0300
+++ ./ter-u32b.bdf 2019-07-28 21:07:55.963423000 +0300
--- ./ter-u32b.bdf.orig 2020-12-28 20:34:18.865118700 +0200
+++ ./ter-u32b.bdf 2020-12-28 20:34:24.625126700 +0200
@@ -20796,0 +20797,9 @@
+703C
+707C
@ -1246,8 +1246,8 @@
-781C
-3FFC
-1FFC
--- ./ter-u32n.bdf.orig 2019-07-28 21:07:38.194991800 +0300
+++ ./ter-u32n.bdf 2019-07-28 21:07:55.823022800 +0300
--- ./ter-u32n.bdf.orig 2020-12-28 20:34:18.865118700 +0200
+++ ./ter-u32n.bdf 2020-12-28 20:34:24.625126700 +0200
@@ -20795,0 +20796,10 @@
+301C
+303C

View File

@ -1,5 +1,5 @@
--- ./ter-u12b.bdf.orig 2019-07-28 21:07:36.104588100 +0300
+++ ./ter-u12b.bdf 2019-07-28 21:08:02.765035000 +0300
--- ./ter-u12b.bdf.orig 2020-12-28 20:34:18.635118400 +0200
+++ ./ter-u12b.bdf 2020-12-28 20:34:27.095130200 +0200
@@ -10182,2 +10182,2 @@
-00
-00
@ -27,8 +27,8 @@
+C0
+40
+48
--- ./ter-u12n.bdf.orig 2019-07-28 21:07:35.995388000 +0300
+++ ./ter-u12n.bdf 2019-07-28 21:08:02.671434800 +0300
--- ./ter-u12n.bdf.orig 2020-12-28 20:34:18.605118300 +0200
+++ ./ter-u12n.bdf 2020-12-28 20:34:27.065130200 +0200
@@ -10182,2 +10182,2 @@
-00
-00
@ -56,8 +56,8 @@
+C0
+40
+48
--- ./ter-u14b.bdf.orig 2019-07-28 21:07:36.322988500 +0300
+++ ./ter-u14b.bdf 2019-07-28 21:08:02.967835300 +0300
--- ./ter-u14b.bdf.orig 2020-12-28 20:34:18.655118400 +0200
+++ ./ter-u14b.bdf 2020-12-28 20:34:27.105130200 +0200
@@ -11250,3 +11250,3 @@
-00
-00
@ -95,8 +95,8 @@
+60
+60
+63
--- ./ter-u14n.bdf.orig 2019-07-28 21:07:36.213788300 +0300
+++ ./ter-u14n.bdf 2019-07-28 21:08:02.858635100 +0300
--- ./ter-u14n.bdf.orig 2020-12-28 20:34:18.645118400 +0200
+++ ./ter-u14n.bdf 2020-12-28 20:34:27.095130200 +0200
@@ -11250,3 +11250,3 @@
-00
-00
@ -134,8 +134,8 @@
+40
+40
+42
--- ./ter-u14v.bdf.orig 2019-07-28 21:07:36.416588700 +0300
+++ ./ter-u14v.bdf 2019-07-28 21:08:03.061435500 +0300
--- ./ter-u14v.bdf.orig 2020-12-28 20:34:18.675118400 +0200
+++ ./ter-u14v.bdf 2020-12-28 20:34:27.125130200 +0200
@@ -11250,3 +11250,3 @@
-00
-00
@ -173,8 +173,8 @@
+60
+60
+63
--- ./ter-u16b.bdf.orig 2019-07-28 21:07:36.634989100 +0300
+++ ./ter-u16b.bdf 2019-07-28 21:08:03.279835900 +0300
--- ./ter-u16b.bdf.orig 2020-12-28 20:34:18.685118400 +0200
+++ ./ter-u16b.bdf 2020-12-28 20:34:27.135130300 +0200
@@ -12318,3 +12318,3 @@
-00
-00
@ -212,8 +212,8 @@
+60
+60
+63
--- ./ter-u16n.bdf.orig 2019-07-28 21:07:36.541388900 +0300
+++ ./ter-u16n.bdf 2019-07-28 21:08:03.170635700 +0300
--- ./ter-u16n.bdf.orig 2020-12-28 20:34:18.685118400 +0200
+++ ./ter-u16n.bdf 2020-12-28 20:34:27.135130300 +0200
@@ -12318,3 +12318,3 @@
-00
-00
@ -251,8 +251,8 @@
+40
+40
+42
--- ./ter-u16v.bdf.orig 2019-07-28 21:07:36.759789300 +0300
+++ ./ter-u16v.bdf 2019-07-28 21:08:03.373436000 +0300
--- ./ter-u16v.bdf.orig 2020-12-28 20:34:18.695118400 +0200
+++ ./ter-u16v.bdf 2020-12-28 20:34:27.135130300 +0200
@@ -12318,3 +12318,3 @@
-00
-00
@ -290,8 +290,8 @@
+60
+60
+63
--- ./ter-u18b.bdf.orig 2019-07-28 21:07:36.993789700 +0300
+++ ./ter-u18b.bdf 2019-07-28 21:08:03.591836400 +0300
--- ./ter-u18b.bdf.orig 2020-12-28 20:34:18.725118500 +0200
+++ ./ter-u18b.bdf 2020-12-28 20:34:27.185130300 +0200
@@ -13387,3 +13387,3 @@
-0000
-0000
@ -329,8 +329,8 @@
+E000
+6000
+6180
--- ./ter-u18n.bdf.orig 2019-07-28 21:07:36.884589500 +0300
+++ ./ter-u18n.bdf 2019-07-28 21:08:03.482636200 +0300
--- ./ter-u18n.bdf.orig 2020-12-28 20:34:18.725118500 +0200
+++ ./ter-u18n.bdf 2020-12-28 20:34:27.175130300 +0200
@@ -13387,3 +13387,3 @@
-0000
-0000
@ -368,8 +368,8 @@
+4000
+4000
+4100
--- ./ter-u20b.bdf.orig 2019-07-28 21:07:37.290190200 +0300
+++ ./ter-u20b.bdf 2019-07-28 21:08:03.810236800 +0300
--- ./ter-u20b.bdf.orig 2020-12-28 20:34:18.735118500 +0200
+++ ./ter-u20b.bdf 2020-12-28 20:34:27.195130300 +0200
@@ -14455,4 +14455,4 @@
-0000
-0000
@ -417,8 +417,8 @@
+6000
+6000
+6180
--- ./ter-u20n.bdf.orig 2019-07-28 21:07:37.102989900 +0300
+++ ./ter-u20n.bdf 2019-07-28 21:08:03.701036600 +0300
--- ./ter-u20n.bdf.orig 2020-12-28 20:34:18.725118500 +0200
+++ ./ter-u20n.bdf 2020-12-28 20:34:27.185130300 +0200
@@ -14455,4 +14455,4 @@
-0000
-0000
@ -466,8 +466,8 @@
+4000
+4000
+4100
--- ./ter-u22b.bdf.orig 2019-07-28 21:07:37.524190600 +0300
+++ ./ter-u22b.bdf 2019-07-28 21:08:04.059837200 +0300
--- ./ter-u22b.bdf.orig 2020-12-28 20:34:18.775118600 +0200
+++ ./ter-u22b.bdf 2020-12-28 20:34:27.235130400 +0200
@@ -15523,4 +15523,4 @@
-0000
-0000
@ -517,8 +517,8 @@
+3000
+30C0
+3180
--- ./ter-u22n.bdf.orig 2019-07-28 21:07:37.414990400 +0300
+++ ./ter-u22n.bdf 2019-07-28 21:08:03.935037000 +0300
--- ./ter-u22n.bdf.orig 2020-12-28 20:34:18.775118600 +0200
+++ ./ter-u22n.bdf 2020-12-28 20:34:27.225130400 +0200
@@ -15523,4 +15523,4 @@
-0000
-0000
@ -566,8 +566,8 @@
+2000
+2000
+2080
--- ./ter-u24b.bdf.orig 2019-07-28 21:07:37.773791100 +0300
+++ ./ter-u24b.bdf 2019-07-28 21:08:04.293837700 +0300
--- ./ter-u24b.bdf.orig 2020-12-28 20:34:18.795118600 +0200
+++ ./ter-u24b.bdf 2020-12-28 20:34:27.245130400 +0200
@@ -16592,4 +16592,4 @@
-0000
-0000
@ -617,8 +617,8 @@
+3000
+3060
+30C0
--- ./ter-u24n.bdf.orig 2019-07-28 21:07:37.648990900 +0300
+++ ./ter-u24n.bdf 2019-07-28 21:08:04.169037400 +0300
--- ./ter-u24n.bdf.orig 2020-12-28 20:34:18.795118600 +0200
+++ ./ter-u24n.bdf 2020-12-28 20:34:27.245130400 +0200
@@ -16592,4 +16592,4 @@
-0000
-0000
@ -666,8 +666,8 @@
+2000
+2000
+2040
--- ./ter-u28b.bdf.orig 2019-07-28 21:07:38.038991500 +0300
+++ ./ter-u28b.bdf 2019-07-28 21:08:04.559038100 +0300
--- ./ter-u28b.bdf.orig 2020-12-28 20:34:18.845118700 +0200
+++ ./ter-u28b.bdf 2020-12-28 20:34:27.295130500 +0200
@@ -18728,5 +18728,5 @@
-0000
-0000
@ -727,8 +727,8 @@
+3000
+3070
+30E0
--- ./ter-u28n.bdf.orig 2019-07-28 21:07:37.914191300 +0300
+++ ./ter-u28n.bdf 2019-07-28 21:08:04.418637900 +0300
--- ./ter-u28n.bdf.orig 2020-12-28 20:34:18.835118600 +0200
+++ ./ter-u28n.bdf 2020-12-28 20:34:27.285130500 +0200
@@ -18728,5 +18728,5 @@
-0000
-0000
@ -788,8 +788,8 @@
+3000
+3030
+3060
--- ./ter-u32b.bdf.orig 2019-07-28 21:07:38.335392100 +0300
+++ ./ter-u32b.bdf 2019-07-28 21:08:04.855438600 +0300
--- ./ter-u32b.bdf.orig 2020-12-28 20:34:18.865118700 +0200
+++ ./ter-u32b.bdf 2020-12-28 20:34:27.305130500 +0200
@@ -20866,6 +20866,6 @@
-0000
-0000
@ -859,8 +859,8 @@
+3800
+381C
+3838
--- ./ter-u32n.bdf.orig 2019-07-28 21:07:38.194991800 +0300
+++ ./ter-u32n.bdf 2019-07-28 21:08:04.699438400 +0300
--- ./ter-u32n.bdf.orig 2020-12-28 20:34:18.865118700 +0200
+++ ./ter-u32n.bdf 2020-12-28 20:34:27.305130500 +0200
@@ -20866,6 +20866,6 @@
-0000
-0000
@ -930,8 +930,8 @@
+1800
+181C
+1838
--- ./dup/xos4-2.dup.orig 2019-03-13 11:25:47.071547400 +0200
+++ ./dup/xos4-2.dup 2019-07-28 21:08:05.463839700 +0300
--- ./dup/xos4-2.dup.orig 2019-03-13 21:55:47.071547500 +0200
+++ ./dup/xos4-2.dup 2020-12-28 20:34:27.655131000 +0200
@@ -107 +107 @@
-0138 043A
+006B 043A

View File

@ -1,5 +1,5 @@
--- ./ter-u12b.bdf.orig 2019-07-28 21:07:36.104588100 +0300
+++ ./ter-u12b.bdf 2019-07-28 21:07:56.790224500 +0300
--- ./ter-u12b.bdf.orig 2020-12-28 20:34:18.635118400 +0200
+++ ./ter-u12b.bdf 2020-12-28 20:34:25.265127600 +0200
@@ -1506 +1506 @@
-70
+18
@ -35,8 +35,8 @@
@@ -14977 +14977 @@
-70
+18
--- ./ter-u12n.bdf.orig 2019-07-28 21:07:35.995388000 +0300
+++ ./ter-u12n.bdf 2019-07-28 21:07:56.681024300 +0300
--- ./ter-u12n.bdf.orig 2020-12-28 20:34:18.605118300 +0200
+++ ./ter-u12n.bdf 2020-12-28 20:34:25.255127600 +0200
@@ -1506 +1506 @@
-70
+18
@ -72,8 +72,8 @@
@@ -14977 +14977 @@
-70
+18
--- ./ter-u14b.bdf.orig 2019-07-28 21:07:36.322988500 +0300
+++ ./ter-u14b.bdf 2019-07-28 21:07:56.977424800 +0300
--- ./ter-u14b.bdf.orig 2020-12-28 20:34:18.655118400 +0200
+++ ./ter-u14b.bdf 2020-12-28 20:34:25.305127700 +0200
@@ -1653,10 +1653,10 @@
-38
-18
@ -263,8 +263,8 @@
+30
+30
+1C
--- ./ter-u14n.bdf.orig 2019-07-28 21:07:36.213788300 +0300
+++ ./ter-u14n.bdf 2019-07-28 21:07:56.883824600 +0300
--- ./ter-u14n.bdf.orig 2020-12-28 20:34:18.645118400 +0200
+++ ./ter-u14n.bdf 2020-12-28 20:34:25.305127700 +0200
@@ -1662 +1662 @@
-38
+0C
@ -300,8 +300,8 @@
@@ -16551 +16551 @@
-38
+0C
--- ./ter-u14v.bdf.orig 2019-07-28 21:07:36.416588700 +0300
+++ ./ter-u14v.bdf 2019-07-28 21:07:57.071025000 +0300
--- ./ter-u14v.bdf.orig 2020-12-28 20:34:18.675118400 +0200
+++ ./ter-u14v.bdf 2020-12-28 20:34:25.315127700 +0200
@@ -1653,10 +1653,10 @@
-38
-18
@ -491,8 +491,8 @@
+30
+30
+1C
--- ./ter-u16b.bdf.orig 2019-07-28 21:07:36.634989100 +0300
+++ ./ter-u16b.bdf 2019-07-28 21:07:57.320625400 +0300
--- ./ter-u16b.bdf.orig 2020-12-28 20:34:18.685118400 +0200
+++ ./ter-u16b.bdf 2020-12-28 20:34:25.345127800 +0200
@@ -1807,10 +1807,10 @@
-38
-18
@ -679,8 +679,8 @@
+30
+30
+1C
--- ./ter-u16n.bdf.orig 2019-07-28 21:07:36.541388900 +0300
+++ ./ter-u16n.bdf 2019-07-28 21:07:57.180225200 +0300
--- ./ter-u16n.bdf.orig 2020-12-28 20:34:18.685118400 +0200
+++ ./ter-u16n.bdf 2020-12-28 20:34:25.315127700 +0200
@@ -1816 +1816 @@
-38
+0C
@ -719,8 +719,8 @@
@@ -18124 +18124 @@
-38
+0C
--- ./ter-u16v.bdf.orig 2019-07-28 21:07:36.759789300 +0300
+++ ./ter-u16v.bdf 2019-07-28 21:07:57.414225600 +0300
--- ./ter-u16v.bdf.orig 2020-12-28 20:34:18.695118400 +0200
+++ ./ter-u16v.bdf 2020-12-28 20:34:25.355127800 +0200
@@ -1807,10 +1807,10 @@
-38
-18
@ -907,8 +907,8 @@
+30
+30
+1C
--- ./ter-u18b.bdf.orig 2019-07-28 21:07:36.993789700 +0300
+++ ./ter-u18b.bdf 2019-07-28 21:07:57.648226000 +0300
--- ./ter-u18b.bdf.orig 2020-12-28 20:34:18.725118500 +0200
+++ ./ter-u18b.bdf 2020-12-28 20:34:25.365127800 +0200
@@ -1973 +1973 @@
-1E00
+0700
@ -947,8 +947,8 @@
@@ -19699 +19699 @@
-1E00
+0700
--- ./ter-u18n.bdf.orig 2019-07-28 21:07:36.884589500 +0300
+++ ./ter-u18n.bdf 2019-07-28 21:07:57.539025800 +0300
--- ./ter-u18n.bdf.orig 2020-12-28 20:34:18.725118500 +0200
+++ ./ter-u18n.bdf 2020-12-28 20:34:25.365127800 +0200
@@ -1973 +1973 @@
-1C00
+0600
@ -987,8 +987,8 @@
@@ -19699 +19699 @@
-1C00
+0600
--- ./ter-u20b.bdf.orig 2019-07-28 21:07:37.290190200 +0300
+++ ./ter-u20b.bdf 2019-07-28 21:07:57.882226400 +0300
--- ./ter-u20b.bdf.orig 2020-12-28 20:34:18.735118500 +0200
+++ ./ter-u20b.bdf 2020-12-28 20:34:25.395127800 +0200
@@ -2128 +2128 @@
-1E00
+0700
@ -1027,8 +1027,8 @@
@@ -21272 +21272 @@
-1E00
+0700
--- ./ter-u20n.bdf.orig 2019-07-28 21:07:37.102989900 +0300
+++ ./ter-u20n.bdf 2019-07-28 21:07:57.773026200 +0300
--- ./ter-u20n.bdf.orig 2020-12-28 20:34:18.725118500 +0200
+++ ./ter-u20n.bdf 2020-12-28 20:34:25.395127800 +0200
@@ -2128 +2128 @@
-1C00
+0600
@ -1067,8 +1067,8 @@
@@ -21272 +21272 @@
-1C00
+0600
--- ./ter-u22b.bdf.orig 2019-07-28 21:07:37.524190600 +0300
+++ ./ter-u22b.bdf 2019-07-28 21:07:58.116226800 +0300
--- ./ter-u22b.bdf.orig 2020-12-28 20:34:18.775118600 +0200
+++ ./ter-u22b.bdf 2020-12-28 20:34:25.415127900 +0200
@@ -2270,14 +2270,14 @@
-1E00
-0600
@ -1295,8 +1295,8 @@
@@ -22846 +22846 @@
-1E00
+0700
--- ./ter-u22n.bdf.orig 2019-07-28 21:07:37.414990400 +0300
+++ ./ter-u22n.bdf 2019-07-28 21:07:57.991426600 +0300
--- ./ter-u22n.bdf.orig 2020-12-28 20:34:18.775118600 +0200
+++ ./ter-u22n.bdf 2020-12-28 20:34:25.415127900 +0200
@@ -2270,14 +2270,14 @@
-1C00
-0400
@ -1571,8 +1571,8 @@
+0800
+0800
+0600
--- ./ter-u24b.bdf.orig 2019-07-28 21:07:37.773791100 +0300
+++ ./ter-u24b.bdf 2019-07-28 21:07:58.350227200 +0300
--- ./ter-u24b.bdf.orig 2020-12-28 20:34:18.795118600 +0200
+++ ./ter-u24b.bdf 2020-12-28 20:34:25.455127900 +0200
@@ -2439 +2439 @@
-1F80
+03C0
@ -1616,8 +1616,8 @@
@@ -24420 +24420 @@
-0F00
+0380
--- ./ter-u24n.bdf.orig 2019-07-28 21:07:37.648990900 +0300
+++ ./ter-u24n.bdf 2019-07-28 21:07:58.225427000 +0300
--- ./ter-u24n.bdf.orig 2020-12-28 20:34:18.795118600 +0200
+++ ./ter-u24n.bdf 2020-12-28 20:34:25.455127900 +0200
@@ -2439 +2439 @@
-1F00
+0380
@ -1661,8 +1661,8 @@
@@ -24420 +24420 @@
-0E00
+0300
--- ./ter-u28b.bdf.orig 2019-07-28 21:07:38.038991500 +0300
+++ ./ter-u28b.bdf 2019-07-28 21:07:58.631027700 +0300
--- ./ter-u28b.bdf.orig 2020-12-28 20:34:18.845118700 +0200
+++ ./ter-u28b.bdf 2020-12-28 20:34:25.475127900 +0200
@@ -2733,18 +2733,18 @@
-0F00
-0F00
@ -1989,8 +1989,8 @@
-0780
+03C0
+01C0
--- ./ter-u28n.bdf.orig 2019-07-28 21:07:37.914191300 +0300
+++ ./ter-u28n.bdf 2019-07-28 21:07:58.490627500 +0300
--- ./ter-u28n.bdf.orig 2020-12-28 20:34:18.835118600 +0200
+++ ./ter-u28n.bdf 2020-12-28 20:34:25.475127900 +0200
@@ -2733,18 +2733,18 @@
-0F00
-0300
@ -2315,8 +2315,8 @@
@@ -27567 +27567 @@
-0780
+01C0
--- ./ter-u32b.bdf.orig 2019-07-28 21:07:38.335392100 +0300
+++ ./ter-u32b.bdf 2019-07-28 21:07:58.927428200 +0300
--- ./ter-u32b.bdf.orig 2020-12-28 20:34:18.865118700 +0200
+++ ./ter-u32b.bdf 2020-12-28 20:34:25.515128000 +0200
@@ -3043,20 +3043,20 @@
-0F80
-0F80
@ -2648,8 +2648,8 @@
-0FE0
+03F0
+01F0
--- ./ter-u32n.bdf.orig 2019-07-28 21:07:38.194991800 +0300
+++ ./ter-u32n.bdf 2019-07-28 21:07:58.771428000 +0300
--- ./ter-u32n.bdf.orig 2020-12-28 20:34:18.865118700 +0200
+++ ./ter-u32n.bdf 2020-12-28 20:34:25.515128000 +0200
@@ -3043,20 +3043,20 @@
-0780
-0780

View File

@ -1,5 +1,5 @@
--- ./ter-u12b.bdf.orig 2019-07-28 21:07:36.104588100 +0300
+++ ./ter-u12b.bdf 2019-07-28 21:07:59.769829700 +0300
--- ./ter-u12b.bdf.orig 2020-12-28 20:34:18.635118400 +0200
+++ ./ter-u12b.bdf 2020-12-28 20:34:26.185128900 +0200
@@ -1840,3 +1839,0 @@
-48
-A8
@ -8,8 +8,8 @@
+48
+A8
+90
--- ./ter-u12n.bdf.orig 2019-07-28 21:07:35.995388000 +0300
+++ ./ter-u12n.bdf 2019-07-28 21:07:59.676229500 +0300
--- ./ter-u12n.bdf.orig 2020-12-28 20:34:18.605118300 +0200
+++ ./ter-u12n.bdf 2020-12-28 20:34:26.185128900 +0200
@@ -1840,3 +1839,0 @@
-48
-A8
@ -18,8 +18,8 @@
+48
+A8
+90
--- ./ter-u14b.bdf.orig 2019-07-28 21:07:36.322988500 +0300
+++ ./ter-u14b.bdf 2019-07-28 21:07:59.972630100 +0300
--- ./ter-u14b.bdf.orig 2020-12-28 20:34:18.655118400 +0200
+++ ./ter-u14b.bdf 2020-12-28 20:34:26.225129000 +0200
@@ -2030,3 +2029,0 @@
-73
-DB
@ -28,8 +28,8 @@
+73
+DB
+CE
--- ./ter-u14n.bdf.orig 2019-07-28 21:07:36.213788300 +0300
+++ ./ter-u14n.bdf 2019-07-28 21:07:59.879029900 +0300
--- ./ter-u14n.bdf.orig 2020-12-28 20:34:18.645118400 +0200
+++ ./ter-u14n.bdf 2020-12-28 20:34:26.205129000 +0200
@@ -2030,3 +2029,0 @@
-62
-92
@ -38,8 +38,8 @@
+62
+92
+8C
--- ./ter-u14v.bdf.orig 2019-07-28 21:07:36.416588700 +0300
+++ ./ter-u14v.bdf 2019-07-28 21:08:00.081830300 +0300
--- ./ter-u14v.bdf.orig 2020-12-28 20:34:18.675118400 +0200
+++ ./ter-u14v.bdf 2020-12-28 20:34:26.225129000 +0200
@@ -2030,3 +2029,0 @@
-73
-DB
@ -48,8 +48,8 @@
+73
+DB
+CE
--- ./ter-u16b.bdf.orig 2019-07-28 21:07:36.634989100 +0300
+++ ./ter-u16b.bdf 2019-07-28 21:08:00.284630600 +0300
--- ./ter-u16b.bdf.orig 2020-12-28 20:34:18.685118400 +0200
+++ ./ter-u16b.bdf 2020-12-28 20:34:26.235129000 +0200
@@ -2220,3 +2219,0 @@
-73
-DB
@ -58,8 +58,8 @@
+73
+DB
+CE
--- ./ter-u16n.bdf.orig 2019-07-28 21:07:36.541388900 +0300
+++ ./ter-u16n.bdf 2019-07-28 21:08:00.191030500 +0300
--- ./ter-u16n.bdf.orig 2020-12-28 20:34:18.685118400 +0200
+++ ./ter-u16n.bdf 2020-12-28 20:34:26.245129000 +0200
@@ -2220,3 +2219,0 @@
-62
-92
@ -68,8 +68,8 @@
+62
+92
+8C
--- ./ter-u16v.bdf.orig 2019-07-28 21:07:36.759789300 +0300
+++ ./ter-u16v.bdf 2019-07-28 21:08:00.378230800 +0300
--- ./ter-u16v.bdf.orig 2020-12-28 20:34:18.695118400 +0200
+++ ./ter-u16v.bdf 2020-12-28 20:34:26.265129000 +0200
@@ -2220,3 +2219,0 @@
-73
-DB
@ -78,8 +78,8 @@
+73
+DB
+CE
--- ./ter-u18b.bdf.orig 2019-07-28 21:07:36.993789700 +0300
+++ ./ter-u18b.bdf 2019-07-28 21:08:00.596631200 +0300
--- ./ter-u18b.bdf.orig 2020-12-28 20:34:18.725118500 +0200
+++ ./ter-u18b.bdf 2020-12-28 20:34:26.275129100 +0200
@@ -2410,4 +2409,0 @@
-3980
-6D80
@ -90,8 +90,8 @@
+6D80
+6D80
+6700
--- ./ter-u18n.bdf.orig 2019-07-28 21:07:36.884589500 +0300
+++ ./ter-u18n.bdf 2019-07-28 21:08:00.487431000 +0300
--- ./ter-u18n.bdf.orig 2020-12-28 20:34:18.725118500 +0200
+++ ./ter-u18n.bdf 2020-12-28 20:34:26.275129100 +0200
@@ -2410,4 +2409,0 @@
-3100
-4900
@ -102,8 +102,8 @@
+4900
+4900
+4600
--- ./ter-u20b.bdf.orig 2019-07-28 21:07:37.290190200 +0300
+++ ./ter-u20b.bdf 2019-07-28 21:08:00.830631600 +0300
--- ./ter-u20b.bdf.orig 2020-12-28 20:34:18.735118500 +0200
+++ ./ter-u20b.bdf 2020-12-28 20:34:26.305129100 +0200
@@ -2600,4 +2599,0 @@
-3980
-6D80
@ -114,8 +114,8 @@
+6D80
+6D80
+6700
--- ./ter-u20n.bdf.orig 2019-07-28 21:07:37.102989900 +0300
+++ ./ter-u20n.bdf 2019-07-28 21:08:00.721431400 +0300
--- ./ter-u20n.bdf.orig 2020-12-28 20:34:18.725118500 +0200
+++ ./ter-u20n.bdf 2020-12-28 20:34:26.295129100 +0200
@@ -2600,4 +2599,0 @@
-3100
-4900
@ -126,8 +126,8 @@
+4900
+4900
+4600
--- ./ter-u22b.bdf.orig 2019-07-28 21:07:37.524190600 +0300
+++ ./ter-u22b.bdf 2019-07-28 21:08:01.064632000 +0300
--- ./ter-u22b.bdf.orig 2020-12-28 20:34:18.775118600 +0200
+++ ./ter-u22b.bdf 2020-12-28 20:34:26.325129100 +0200
@@ -2790,4 +2789,0 @@
-38C0
-6CC0
@ -138,8 +138,8 @@
+6CC0
+66C0
+6380
--- ./ter-u22n.bdf.orig 2019-07-28 21:07:37.414990400 +0300
+++ ./ter-u22n.bdf 2019-07-28 21:08:00.955431800 +0300
--- ./ter-u22n.bdf.orig 2020-12-28 20:34:18.775118600 +0200
+++ ./ter-u22n.bdf 2020-12-28 20:34:26.325129100 +0200
@@ -2790,4 +2789,0 @@
-3080
-4880
@ -150,8 +150,8 @@
+4880
+4480
+4300
--- ./ter-u24b.bdf.orig 2019-07-28 21:07:37.773791100 +0300
+++ ./ter-u24b.bdf 2019-07-28 21:08:01.329832500 +0300
--- ./ter-u24b.bdf.orig 2020-12-28 20:34:18.795118600 +0200
+++ ./ter-u24b.bdf 2020-12-28 20:34:26.355129200 +0200
@@ -2981,4 +2980,0 @@
-3C60
-6660
@ -162,8 +162,8 @@
+6660
+6660
+63C0
--- ./ter-u24n.bdf.orig 2019-07-28 21:07:37.648990900 +0300
+++ ./ter-u24n.bdf 2019-07-28 21:08:01.189432200 +0300
--- ./ter-u24n.bdf.orig 2020-12-28 20:34:18.795118600 +0200
+++ ./ter-u24n.bdf 2020-12-28 20:34:26.365129200 +0200
@@ -2981,4 +2980,0 @@
-3840
-4440
@ -174,8 +174,8 @@
+4440
+4440
+4380
--- ./ter-u28b.bdf.orig 2019-07-28 21:07:38.038991500 +0300
+++ ./ter-u28b.bdf 2019-07-28 21:08:01.595032900 +0300
--- ./ter-u28b.bdf.orig 2020-12-28 20:34:18.845118700 +0200
+++ ./ter-u28b.bdf 2020-12-28 20:34:26.385129200 +0200
@@ -3361,5 +3360,0 @@
-3C30
-7E30
@ -188,8 +188,8 @@
+6730
+63F0
+61E0
--- ./ter-u28n.bdf.orig 2019-07-28 21:07:37.914191300 +0300
+++ ./ter-u28n.bdf 2019-07-28 21:08:01.470232700 +0300
--- ./ter-u28n.bdf.orig 2020-12-28 20:34:18.835118600 +0200
+++ ./ter-u28n.bdf 2020-12-28 20:34:26.385129200 +0200
@@ -3361,5 +3360,0 @@
-3C30
-6630
@ -202,8 +202,8 @@
+6330
+6330
+61E0
--- ./ter-u32b.bdf.orig 2019-07-28 21:07:38.335392100 +0300
+++ ./ter-u32b.bdf 2019-07-28 21:08:01.891433400 +0300
--- ./ter-u32b.bdf.orig 2020-12-28 20:34:18.865118700 +0200
+++ ./ter-u32b.bdf 2020-12-28 20:34:26.435129300 +0200
@@ -3743,6 +3742,0 @@
-1E1C
-3F1C
@ -218,8 +218,8 @@
+73DC
+71F8
+70F0
--- ./ter-u32n.bdf.orig 2019-07-28 21:07:38.194991800 +0300
+++ ./ter-u32n.bdf 2019-07-28 21:08:01.735433200 +0300
--- ./ter-u32n.bdf.orig 2020-12-28 20:34:18.865118700 +0200
+++ ./ter-u32n.bdf 2020-12-28 20:34:26.425129300 +0200
@@ -3743,6 +3742,0 @@
-0E0C
-1F0C

View File

@ -1,135 +1,135 @@
module.exports = {
"env": {
"es6": true,
"node": true,
"browser": false
'env': {
'es6': true,
'node': true,
'browser': false
},
"extends": "eslint:recommended",
"parserOptions": {
"sourceType": "module"
'extends': 'eslint:recommended',
'parserOptions': {
'sourceType': 'module'
},
"rules": {
"indent": [
"error",
"tab"
'rules': {
'indent': [
'error',
'tab'
],
"linebreak-style": [
"error",
"unix"
'linebreak-style': [
'error',
'unix'
],
"quotes": [
"warn",
"single"
'quotes': [
'warn',
'single'
],
"semi": [
"error",
"always"
'semi': [
'error',
'always'
],
"curly": [
"error",
"all"
'curly': [
'error',
'all'
],
"brace-style": [
"error",
"1tbs"
'brace-style': [
'error',
'1tbs'
],
"no-empty" : "warn",
"no-unused-vars" : "warn",
"no-console": "warn",
"consistent-return": "error",
"class-methods-use-this": "warn",
"eqeqeq": [
"error",
"always", {
"null": "ignore"
'no-empty' : 'warn',
'no-unused-vars' : 'warn',
'no-console': 'warn',
'consistent-return': 'error',
'class-methods-use-this': 'warn',
'eqeqeq': [
'error',
'always', {
'null': 'ignore'
}
],
"no-alert": "warn",
"no-caller": "error",
"no-eval": "error",
"no-extend-native": "warn",
"no-implicit-coercion": "error",
"no-implied-eval": "error",
"no-invalid-this": "error",
"no-loop-func": "error",
"no-new-func": "warn",
"no-new-wrappers": "error",
"no-proto": "error",
"no-return-assign": "warn",
"no-return-await": "warn",
"no-script-url": "error",
"no-self-compare": "error",
"no-sequences": "error",
"no-throw-literal": "error",
"no-unmodified-loop-condition": "warn",
"no-unused-expressions": "warn",
"no-useless-return": "warn",
"no-warning-comments": "warn",
"prefer-promise-reject-errors": "warn",
"no-label-var": "error",
"no-shadow": [
"warn", {
"builtinGlobals": true,
"hoist": "all"
'no-alert': 'warn',
'no-caller': 'error',
'no-eval': 'error',
'no-extend-native': 'warn',
'no-implicit-coercion': 'error',
'no-implied-eval': 'error',
'no-invalid-this': 'error',
'no-loop-func': 'error',
'no-new-func': 'warn',
'no-new-wrappers': 'error',
'no-proto': 'error',
'no-return-assign': 'warn',
'no-return-await': 'warn',
'no-script-url': 'error',
'no-self-compare': 'error',
'no-sequences': 'error',
'no-throw-literal': 'error',
'no-unmodified-loop-condition': 'warn',
'no-unused-expressions': 'warn',
'no-useless-return': 'warn',
'no-warning-comments': 'warn',
'prefer-promise-reject-errors': 'warn',
'no-label-var': 'error',
'no-shadow': [
'warn', {
'builtinGlobals': true,
'hoist': 'all'
}
],
"no-shadow-restricted-names": "error",
"no-undefined": "error",
"no-use-before-define": "error",
"no-new-require": "error",
"no-path-concat": "error",
"camelcase": "error",
"comma-dangle": [
"error",
"never"
'no-shadow-restricted-names': 'error',
'no-undefined': 'error',
'no-use-before-define': 'error',
'no-new-require': 'error',
'no-path-concat': 'error',
'camelcase': 'error',
'comma-dangle': [
'error',
'never'
],
"eol-last": [
"error",
"always"
'eol-last': [
'error',
'always'
],
"func-call-spacing": "warn",
"lines-around-directive": [
"warn",
"always"
'func-call-spacing': 'warn',
'lines-around-directive': [
'warn',
'always'
],
"max-params": [
"warn", {
"max": 7
'max-params': [
'warn', {
'max': 7
}
],
"max-statements-per-line": [
"warn", {
"max": 1
'max-statements-per-line': [
'warn', {
'max': 1
}
],
"new-cap": [
"error"
'new-cap': [
'error'
],
"no-array-constructor": "warn",
"no-mixed-operators": [
"error", {
"groups": [
["&", "|", "^", "~", "<<", ">>", ">>>"],
["==", "!=", "===", "!==", ">", ">=", "<", "<="],
["&&", "||"],
["in", "instanceof"]
'no-array-constructor': 'warn',
'no-mixed-operators': [
'error', {
'groups': [
[ '&', '|', '^', '~', '<<', '>>', '>>>' ],
[ '==', '!=', '===', '!==', '>', '>=', '<', '<=' ],
[ '&&', '||' ],
[ 'in', 'instanceof' ]
],
"allowSamePrecedence": false
'allowSamePrecedence': false
}
],
"no-trailing-spaces": "warn",
"no-unneeded-ternary": "warn",
"no-whitespace-before-property": "error",
"operator-linebreak": "warn",
"semi-spacing": "warn",
"no-confusing-arrow": [
"error", {
"allowParens": true
'no-trailing-spaces': 'warn',
'no-unneeded-ternary': 'warn',
'no-whitespace-before-property': 'error',
'operator-linebreak': 'warn',
'semi-spacing': 'warn',
'no-confusing-arrow': [
'error', {
'allowParens': true
}
],
"no-duplicate-imports": "warn",
"prefer-rest-params": "warn",
"prefer-spread": "warn",
"no-unsafe-negation": "warn"
'no-duplicate-imports': 'warn',
'prefer-rest-params': 'warn',
'prefer-spread': 'warn',
'no-unsafe-negation': 'warn'
}
};

View File

@ -1,25 +1,28 @@
//
// Copyright (c) 2018 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
/*
Copyright (C) 2017-2020 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at your option)
any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
'use strict';
const fnutil = require('./fnutil.js');
const WIDTH_MAX = 127;
const HEIGHT_MAX = 255;
const SWIDTH_MAX = 32000;
// -- Width --
const DPARSE_LIMIT = 512;
const SPARSE_LIMIT = 32000;
class Width {
constructor(x, y) {
@ -27,23 +30,27 @@ class Width {
this.y = y;
}
static _parse(name, value, limitX, limitY) {
static parse(name, value, limit) {
const words = fnutil.splitWords(name, value, 2);
return new Width(fnutil.parseDec(name + ' X', words[0], -limitX, limitX),
fnutil.parseDec(name + ' Y', words[1], -limitY, limitY));
return new Width(fnutil.parseDec(name + '.x', words[0], -limit, limit),
fnutil.parseDec(name + '.y', words[1], -limit, limit));
}
static parseS(value) {
return Width._parse('SWIDTH', value, SWIDTH_MAX, SWIDTH_MAX);
static parseS(name, value) {
return Width.parse(name, value, SPARSE_LIMIT);
}
static parseD(value) {
return Width._parse('DWIDTH', value, WIDTH_MAX, HEIGHT_MAX);
static parseD(name, value) {
return Width.parse(name, value, DPARSE_LIMIT);
}
toString() {
return `${this.x} ${this.y}`;
}
}
// -- BBX --
class BBX {
constructor(width, height, xoff, yoff) {
this.width = width;
@ -55,10 +62,10 @@ class BBX {
static parse(name, value) {
const words = fnutil.splitWords(name, value, 4);
return new BBX(fnutil.parseDec('width', words[0], 1, WIDTH_MAX),
fnutil.parseDec('height', words[1], 1, HEIGHT_MAX),
fnutil.parseDec('bbxoff', words[2], -WIDTH_MAX, WIDTH_MAX),
fnutil.parseDec('bbyoff', words[3], -WIDTH_MAX, WIDTH_MAX));
return new BBX(fnutil.parseDec(name + '.width', words[0], 1, DPARSE_LIMIT),
fnutil.parseDec(name + '.height', words[1], 1, DPARSE_LIMIT),
fnutil.parseDec(name + '.xoff', words[2], -DPARSE_LIMIT, DPARSE_LIMIT),
fnutil.parseDec(name + '.yoff', words[3], -DPARSE_LIMIT, DPARSE_LIMIT));
}
rowSize() {
@ -70,93 +77,45 @@ class BBX {
}
}
// -- Props --
function skipComments(line) {
return line.startsWith('COMMENT') ? null : line;
}
class Props {
constructor() {
this.names = [];
this.values = [];
}
add(name, value) {
this.names.push(name);
this.values.push(value);
}
clone() {
let props = new Props();
props.names = this.names.slice();
props.values = this.values.slice();
return props;
}
class Props extends Map {
forEach(callback) {
for (let index = 0; index < this.names.length; index++) {
callback(this.names[index], this.values[index]);
}
super.forEach((value, name) => callback(name, value));
}
get(name) {
return this.values[this.names.indexOf(name)];
read(input, name, callback) {
return this.parse(input.readLines(skipComments), name, callback);
}
parse(line, name, callback) {
if (line === null || !line.startsWith(name)) {
if (line == null || !line.startsWith(name)) {
throw new Error(name + ' expected');
}
let value = line.substring(name.length).trimLeft();
const value = line.substring(name.length).trimLeft();
this.add(name, value);
this.set(name, value);
return callback == null ? value : callback(name, value);
}
push(line) {
this.add('', line);
}
set(name, value) {
let index = this.names.indexOf(name);
if (index !== -1) {
this.values[index] = value;
} else {
this.add(name, value);
}
super.set(name, value.toString());
}
}
// -- Base --
class Base {
constructor() {
this.props = new Props();
this.bbx = null;
this.finis = [];
}
readFinish(input, endText) {
if (this.readNext(input, this.finis) !== endText) {
throw new Error(endText + ' expected');
}
this.finis.push(endText);
}
readNext(input, comout = this.props) {
return input.readLines(line => {
if (line.startsWith('COMMENT')) {
comout.push(line);
return null;
}
return line;
});
}
readProp(input, name, callback) {
return this.props.parse(this.readNext(input), name, callback);
}
}
// -- Char --
class Char extends Base {
constructor() {
super();
@ -166,25 +125,25 @@ class Char extends Base {
this.data = null;
}
static bitmap(data, rowSize) {
const bitmap = data.toString('hex').toUpperCase();
const regex = new RegExp(`.{${rowSize << 1}}`, 'g');
bitmap() {
const bitmap = this.data.toString('hex').toUpperCase();
const regex = new RegExp(`.{${this.bbx.rowSize() << 1}}`, 'g');
return bitmap.replace(regex, '$&\n');
}
_read(input) {
// HEADER
this.readProp(input, 'STARTCHAR');
this.code = this.readProp(input, 'ENCODING', fnutil.parseDec);
this.swidth = this.readProp(input, 'SWIDTH', (name, value) => Width.parseS(value));
this.dwidth = this.readProp(input, 'DWIDTH', (name, value) => Width.parseD(value));
this.bbx = this.readProp(input, 'BBX', BBX.parse);
this.props.read(input, 'STARTCHAR');
this.code = this.props.read(input, 'ENCODING', fnutil.parseDec);
this.swidth = this.props.read(input, 'SWIDTH', Width.parseS);
this.dwidth = this.props.read(input, 'DWIDTH', Width.parseD);
this.bbx = this.props.read(input, 'BBX', BBX.parse);
let line = this.readNext(input);
let line = input.readLines(skipComments);
if (line !== null && line.startsWith('ATTRIBUTES')) {
if (line != null && line.startsWith('ATTRIBUTES')) {
this.props.parse(line, 'ATTRIBUTES');
line = this.readNext(input);
line = input.readLines(skipComments);
}
// BITMAP
@ -196,11 +155,14 @@ class Char extends Base {
let bitmap = '';
for (let y = 0; y < this.bbx.height; y++) {
line = this.readNext(input);
line = input.readLines(skipComments);
if (line === null) {
if (line == null) {
throw new Error('bitmap data expected');
}
if (line.match(/^[\dA-Fa-f]+$/) == null) {
throw new Error('invalid bitmap character(s)');
}
if (line.length === rowLen) {
bitmap += line;
} else {
@ -208,13 +170,11 @@ class Char extends Base {
}
}
// FINAL
this.readFinish(input, 'ENDCHAR');
if (bitmap.match(/^[\dA-Fa-f]+$/) != null) {
this.data = Buffer.from(bitmap, 'hex');
} else {
throw new Error('invalid BITMAP data characters');
// FINAL
if (input.readLines(skipComments) !== 'ENDCHAR') {
throw new Error('ENDCHAR expected');
}
return this;
}
@ -229,11 +189,11 @@ class Char extends Base {
this.props.forEach((name, value) => {
header += (name + ' ' + value).trim() + '\n';
});
output.writeLine(header + Char.bitmap(this.data, this.bbx.rowSize()) + this.finis.join('\n'));
output.writeLine(header + this.bitmap() + 'ENDCHAR');
}
}
// -- Font --
const XLFD = {
FOUNDRY: 1,
FAMILY_NAME: 2,
@ -260,73 +220,70 @@ class Font extends Base {
this.defaultCode = -1;
}
getAscent() {
let ascent = this.props.get('FONT_ASCENT');
if (ascent != null) {
return fnutil.parseDec('FONT_ASCENT', ascent, -HEIGHT_MAX, HEIGHT_MAX);
}
return this.bbx.height + this.bbx.yoff;
get bold() {
return this.xlfd[XLFD.WEIGHT_NAME].toLowerCase().includes('bold');
}
getBold() {
return Number(this.xlfd[XLFD.WEIGHT_NAME].toLowerCase().includes('bold'));
get italic() {
return ['I', 'O'].indexOf(this.xlfd[XLFD.SLANT]) !== -1;
}
getItalic() {
return Number(this.xlfd[XLFD.SLANT].match(/^[IO]/) != null);
get proportional() {
return this.xlfd[XLFD.SPACING] === 'P';
}
_read(input) {
// HEADER
let line = input.readLines(Font.skipEmpty);
let line = input.readLine();
if (this.props.parse(line, 'STARTFONT') !== '2.1') {
throw new Error('STARTFONT 2.1 expected');
}
this.xlfd = this.readProp(input, 'FONT', (name, value) => value.split('-', 16));
this.xlfd = this.props.read(input, 'FONT', (name, value) => value.split('-', 16));
if (this.xlfd.length !== 15 || this.xlfd[0] !== '') {
throw new Error('non-XLFD font names are not supported');
}
this.readProp(input, 'SIZE');
this.bbx = this.readProp(input, 'FONTBOUNDINGBOX', BBX.parse);
line = this.readNext(input);
this.props.read(input, 'SIZE');
this.bbx = this.props.read(input, 'FONTBOUNDINGBOX', BBX.parse);
line = input.readLines(skipComments);
if (line !== null && line.startsWith('STARTPROPERTIES')) {
if (line != null && line.startsWith('STARTPROPERTIES')) {
const numProps = this.props.parse(line, 'STARTPROPERTIES', fnutil.parseDec);
for (let i = 0; i < numProps; i++) {
line = this.readNext(input);
line = input.readLines(skipComments);
if (line === null) {
if (line == null) {
throw new Error('property expected');
}
let match = line.match(/^(\w+)\s+([-\d"].*)$/);
const match = line.match(/^(\w+)\s+([-\d"].*)$/);
if (match == null) {
throw new Error('invalid property format');
}
let name = match[1];
let value = match[2];
const name = match[1];
const value = match[2];
if (this.props.get(name) != null) {
throw new Error('duplicate property');
}
if (name === 'DEFAULT_CHAR') {
this.defaultCode = fnutil.parseDec(name, value);
}
this.props.add(name, value);
this.props.set(name, value);
}
if (this.readProp(input, 'ENDPROPERTIES') !== '') {
if (this.props.read(input, 'ENDPROPERTIES') !== '') {
throw new Error('ENDPROPERTIES expected');
}
line = this.readNext(input);
line = input.readLines(skipComments);
}
// GLYPHS
const numChars = this.props.parse(line, 'CHARS', (name, value) => fnutil.parseDec(name, value, 1, CHARS_MAX));
const numChars = fnutil.parseDec('CHARS', this.props.parse(line, 'CHARS'), 1, CHARS_MAX);
for (let i = 0; i < numChars; i++) {
this.chars.push(Char.read(input));
@ -337,36 +294,35 @@ class Font extends Base {
}
// FINAL
this.readFinish(input, 'ENDFONT');
if (input.readLines(Font.skipEmpty) != null) {
if (input.readLines(skipComments) !== 'ENDFONT') {
throw new Error('ENDFONT expected');
}
if (input.readLine() != null) {
throw new Error('garbage after ENDFONT');
}
return this;
}
static read(input) {
return (new Font())._read(input);
}
static skipEmpty(line) {
return line.length > 0 ? line : null;
return (new Font())._read(input, false);
}
write(output) {
this.props.forEach((name, value) => output.writeProp(name, value));
this.chars.forEach(char => char.write(output));
output.writeLine(this.finis.join('\n'));
output.writeLine('ENDFONT');
}
}
// -- Export --
module.exports = Object.freeze({
WIDTH_MAX,
HEIGHT_MAX,
SWIDTH_MAX,
DPARSE_LIMIT,
SPARSE_LIMIT,
Width,
BBX,
skipComments,
Props,
Base,
Char,
XLFD,
CHARS_MAX,

View File

@ -1,27 +1,31 @@
#
# Copyright (c) 2018 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
# Copyright (C) 2017-2020 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of
# the License, or (at your option) any later version.
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
import re
import codecs
from collections import OrderedDict
from enum import IntEnum, unique
import fnutil
WIDTH_MAX = 127
HEIGHT_MAX = 255
SWIDTH_MAX = 32000
# -- Width --
DPARSE_LIMIT = 512
SPARSE_LIMIT = 32000
class Width:
def __init__(self, x, y):
@ -30,25 +34,27 @@ def __init__(self, x, y):
@staticmethod
def _parse(name, value, limit_x, limit_y):
def parse(name, value, limit):
words = fnutil.split_words(name, value, 2)
return Width(fnutil.parse_dec('width x', words[0], -limit_x, limit_x),
fnutil.parse_dec('width y', words[1], -limit_y, limit_y))
return Width(fnutil.parse_dec(name + '.x', words[0], -limit, limit),
fnutil.parse_dec(name + '.y', words[1], -limit, limit))
@staticmethod
def parse_s(value):
return Width._parse('SWIDTH', value, SWIDTH_MAX, SWIDTH_MAX)
def parse_s(name, value):
return Width.parse(name, value, SPARSE_LIMIT)
@staticmethod
def parse_d(value):
return Width._parse('DWIDTH', value, WIDTH_MAX, HEIGHT_MAX)
def parse_d(name, value):
return Width.parse(name, value, DPARSE_LIMIT)
OFFSET_MIN = -128
OFFSET_MAX = 127
def __str__(self):
return '%d %d' % (self.x, self.y)
# -- BXX --
class BBX:
def __init__(self, width, height, xoff, yoff):
self.width = width
@ -60,10 +66,10 @@ def __init__(self, width, height, xoff, yoff):
@staticmethod
def parse(name, value):
words = fnutil.split_words(name, value, 4)
return BBX(fnutil.parse_dec('width', words[0], 1, WIDTH_MAX),
fnutil.parse_dec('height', words[1], 1, HEIGHT_MAX),
fnutil.parse_dec('bbxoff', words[2], -WIDTH_MAX, WIDTH_MAX),
fnutil.parse_dec('bbyoff', words[3], -WIDTH_MAX, WIDTH_MAX))
return BBX(fnutil.parse_dec('width', words[0], 1, DPARSE_LIMIT),
fnutil.parse_dec('height', words[1], 1, DPARSE_LIMIT),
fnutil.parse_dec('bbxoff', words[2], -DPARSE_LIMIT, DPARSE_LIMIT),
fnutil.parse_dec('bbyoff', words[3], -DPARSE_LIMIT, DPARSE_LIMIT))
def row_size(self):
@ -74,48 +80,18 @@ def __str__(self):
return '%d %d %d %d' % (self.width, self.height, self.xoff, self.yoff)
class Props:
def __init__(self):
self.names = []
self.values = []
def add(self, name, value):
self.names.append(name)
self.values.append(value)
def clone(self):
props = Props()
props.names = self.names[:]
props.values = self.values[:]
return props
def get(self, name):
try:
return self.values[self.names.index(name)]
except ValueError:
return None
class Iter:
def __init__(self, props):
self.index = 0
self.props = props
def __next__(self):
if self.index == len(self.props.names):
raise StopIteration
result = (self.props.names[self.index], self.props.values[self.index])
self.index += 1
return result
# -- Props --
def skip_comments(line):
return None if line[:7] == b'COMMENT' else line
class Props(OrderedDict):
def __iter__(self):
return Props.Iter(self)
return self.items().__iter__()
def read(self, input, name, callback=None):
return self.parse(input.read_lines(skip_comments), name, callback)
def parse(self, line, name, callback=None):
@ -123,36 +99,23 @@ def parse(self, line, name, callback=None):
raise Exception(name + ' expected')
value = line[len(name):].lstrip()
self.add(name, value)
self[name] = value
return value if callback is None else callback(name, value)
def set(self, name, value):
try:
self.values[self.names.index(name)] = value
except ValueError:
self.add(name, value)
self[name] = value if isinstance(value, (bytes, bytearray)) else bytes(str(value), 'ascii')
# -- Base --
class Base:
def __init__(self):
self.props = Props()
self.bbx = None
self.finis = []
def keep_comments(self, line):
if not line.startswith(b'COMMENT'):
return line
self.props.add('', line)
return None
def keep_finishes(self, line):
self.finis.append(line)
return None if line.startswith(b'COMMENT') else line
# -- Char
HEX_BYTES = (48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70)
class Char(Base):
def __init__(self):
@ -163,55 +126,51 @@ def __init__(self):
self.data = None
@staticmethod
def bitmap(data, row_size):
def bitmap(self):
bitmap = ''
row_size = self.bbx.row_size()
for index in range(0, len(data), row_size):
bitmap += data[index : index + row_size].hex() + '\n'
for index in range(0, len(self.data), row_size):
bitmap += self.data[index : index + row_size].hex() + '\n'
return bytes(bitmap, 'ascii').upper()
def _read(self, input):
# HEADER
read_next = lambda: input.read_lines(lambda line: self.keep_comments(line))
read_prop = lambda name, callback=None: self.props.parse(read_next(), name, callback)
read_prop('STARTCHAR')
self.code = read_prop('ENCODING', fnutil.parse_dec)
self.swidth = read_prop('SWIDTH', lambda _, value: Width.parse_s(value))
self.dwidth = read_prop('DWIDTH', lambda _, value: Width.parse_d(value))
self.bbx = read_prop('BBX', BBX.parse)
line = read_next()
self.props.read(input, 'STARTCHAR')
self.code = self.props.read(input, 'ENCODING', fnutil.parse_dec)
self.swidth = self.props.read(input, 'SWIDTH', Width.parse_s)
self.dwidth = self.props.read(input, 'DWIDTH', Width.parse_d)
self.bbx = self.props.read(input, 'BBX', BBX.parse)
line = input.read_lines(skip_comments)
if line and line.startswith(b'ATTRIBUTES'):
self.props.parse(line, 'ATTRIBUTES')
line = read_next()
line = input.read_lines(skip_comments)
# BITMAP
if self.props.parse(line, 'BITMAP') != b'':
if self.props.parse(line, 'BITMAP'):
raise Exception('BITMAP expected')
row_len = self.bbx.row_size() * 2
bitmap = b''
self.data = bytearray()
for _ in range(0, self.bbx.height):
line = read_next()
line = input.read_lines(skip_comments)
if not line:
raise Exception('bitmap data expected')
if len(line) == row_len:
bitmap += line
self.data += codecs.decode(line, 'hex')
else:
raise Exception('invalid bitmap length')
# FINAL
if input.read_lines(lambda line: self.keep_finishes(line)) != b'ENDCHAR':
if input.read_lines(skip_comments) != b'ENDCHAR':
raise Exception('ENDCHAR expected')
self.data = codecs.decode(bitmap, 'hex') # no spaces allowed
return self
@ -224,9 +183,10 @@ def write(self, output):
for [name, value] in self.props:
output.write_prop(name, value)
output.write_line(Char.bitmap(self.data, self.bbx.row_size()) + b'\n'.join(self.finis))
output.write_line(self.bitmap() + b'ENDCHAR')
# -- Font --
@unique
class XLFD(IntEnum):
FOUNDRY = 1
@ -254,48 +214,44 @@ def __init__(self):
self.default_code = -1
def get_ascent(self):
ascent = self.props.get('FONT_ASCENT')
if ascent is not None:
return fnutil.parse_dec('FONT_ASCENT', ascent, -HEIGHT_MAX, HEIGHT_MAX)
return self.bbx.height + self.bbx.yoff
@property
def bold(self):
return b'bold' in self.xlfd[XLFD.WEIGHT_NAME].lower()
def get_bold(self):
return int(b'bold' in self.xlfd[XLFD.WEIGHT_NAME].lower())
@property
def italic(self):
return self.xlfd[XLFD.SLANT] in [b'I', b'O']
def get_italic(self):
return int(re.search(b'^[IO]', self.xlfd[XLFD.SLANT]) is not None)
@property
def proportional(self):
return self.xlfd[XLFD.SPACING] == b'P'
def _read(self, input):
# HEADER
read_next = lambda: input.read_lines(lambda line: self.keep_comments(line))
read_prop = lambda name, callback=None: self.props.parse(read_next(), name, callback)
line = input.read_lines(Font.skip_empty)
line = input.read_line()
if self.props.parse(line, 'STARTFONT') != b'2.1':
raise Exception('STARTFONT 2.1 expected')
self.xlfd = read_prop('FONT', lambda name, value: value.split(b'-', 15))
self.xlfd = self.props.read(input, 'FONT', lambda name, value: value.split(b'-', 15))
if len(self.xlfd) != 15 or self.xlfd[0] != b'':
raise Exception('non-XLFD font names are not supported')
read_prop('SIZE')
self.bbx = read_prop('FONTBOUNDINGBOX', BBX.parse)
line = read_next()
self.props.read(input, 'SIZE')
self.bbx = self.props.read(input, 'FONTBOUNDINGBOX', BBX.parse)
line = input.read_lines(skip_comments)
if line and line.startswith(b'STARTPROPERTIES'):
num_props = self.props.parse(line, 'STARTPROPERTIES', fnutil.parse_dec)
for _ in range(0, num_props):
line = read_next()
line = input.read_lines(skip_comments)
if not line:
if line is None:
raise Exception('property expected')
match = re.fullmatch(br'(\w+)\s+([-\d"].*)', line)
@ -306,18 +262,21 @@ def _read(self, input):
name = str(match.group(1), 'ascii')
value = match.group(2)
if self.props.get(name) is not None:
raise Exception('duplicate property')
if name == 'DEFAULT_CHAR':
self.default_code = fnutil.parse_dec(name, value)
self.props.add(name, value)
self.props[name] = value
if read_prop('ENDPROPERTIES') != b'':
if self.props.read(input, 'ENDPROPERTIES') != b'':
raise Exception('ENDPROPERTIES expected')
line = read_next()
line = input.read_lines(skip_comments)
# GLYPHS
num_chars = self.props.parse(line, 'CHARS', lambda name, value: fnutil.parse_dec(name, value, 1, CHARS_MAX))
num_chars = fnutil.parse_dec('CHARS', self.props.parse(line, 'CHARS'), 1, CHARS_MAX)
for _ in range(0, num_chars):
self.chars.append(Char.read(input))
@ -326,10 +285,10 @@ def _read(self, input):
raise Exception('invalid DEFAULT_CHAR')
# FINAL
if input.read_lines(lambda line: self.keep_finishes(line)) != b'ENDFONT':
if input.read_lines(skip_comments) != b'ENDFONT':
raise Exception('ENDFONT expected')
if input.read_lines(Font.skip_empty):
if input.read_line() is not None:
raise Exception('garbage after ENDFONT')
return self
@ -340,11 +299,6 @@ def read(input):
return Font()._read(input) # pylint: disable=protected-access
@staticmethod
def skip_empty(line):
return line if line else None
def write(self, output):
for [name, value] in self.props:
output.write_prop(name, value)
@ -352,4 +306,4 @@ def write(self, output):
for char in self.chars:
char.write(output)
output.write_line(b'\n'.join(self.finis))
output.write_line(b'ENDFONT')

455
bin/bdfcheck.js Normal file
View File

@ -0,0 +1,455 @@
/*
Copyright (C) 2017-2020 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at your option)
any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
'use strict';
const fnutil = require('./fnutil.js');
const fncli = require('./fncli.js');
const fnio = require('./fnio.js');
const bdf = require('./bdf.js');
// -- Params --
class Params extends fncli.Params {
constructor() {
super();
this.asciiChars = true;
this.bbxExceeds = true;
this.duplCodes = -1;
this.extraBits = true;
this.attributes = true;
this.duplNames = -1;
this.duplProps = true;
this.commonSlant = true;
this.commonWeight = true;
this.xlfdFontNm = true;
this.yWidthZero = true;
}
}
// -- Options --
const HELP = ('' +
'usage: bdfcheck [options] [INPUT...]\n' +
'Check BDF font(s) for various problems\n' +
'\n' +
' -A disable non-ascii characters check\n' +
' -B disable BBX exceeding FONTBOUNDINGBOX checks\n' +
' -c/-C enable/disable duplicate character codes check\n' +
' (default = enabled for registry ISO10646)\n' +
' -E disable extra bits check\n' +
' -I disable ATTRIBUTES check\n' +
' -n/-N enable duplicate character names check\n' +
' (default = enabled for registry ISO10646)\n' +
' -P disable duplicate properties check\n' +
' -S disable common slant check\n' +
' -W disable common weight check\n' +
' -X disable XLFD font name check\n' +
' -Y disable zero WIDTH Y check\n' +
' --help display this help and exit\n' +
' --version display the program version and license, and exit\n' +
' --excstk display the exception stack on error\n' +
'\n' +
'File directives: COMMENT bdfcheck --enable|disable-<check-name>\n' +
' (also available as long command line options)\n' +
'\n' +
'Check names: ascii-chars, bbx-exceeds, duplicate-codes, extra-bits,\n' +
' attributes, duplicate-names, duplicate-properties, common-slant,\n' +
' common-weight, xlfd-font, ywidth-zero\n' +
'\n' +
'The input BDF(s) must be v2.1 with unicode encoding.\n');
const VERSION = 'bdfcheck 1.61, Copyright (C) 2017-2020 Dimitar Toshkov Zhekov\n\n' + fnutil.GPL2PLUS_LICENSE;
class Options extends fncli.Options {
constructor() {
super([], HELP, VERSION);
}
parse(name, directive, params) {
const value = name.startsWith('--enable') || name[1].match('[a-z]');
switch (name) {
case '-A':
case '--enable-ascii-chars':
case '--disable-ascii-chars':
params.asciiChars = value;
break;
case '-B':
case '--enable-bbx-exceeds':
case '--disable-bbx-exceeds':
params.bbxExceeds = value;
break;
case '-c':
case '-C':
case '--enable-duplicate-codes':
case '--disable-duplicate-codes':
params.duplCodes = value;
break;
case '-E':
case '--enable-extra-bits':
case '--disable-extra-bits':
params.extraBits = value;
break;
case '-I':
case '--enable-attributes':
case '--disable-attributes':
params.attributes = value;
break;
case '-n':
case '-N':
case '--enable-duplicate-names':
case '--disable-duplicate-names':
params.duplNames = value;
break;
case '-P':
case '--enable-duplicate-properties':
case '--disable-duplicate-properties':
params.duplProps = value;
break;
case '-S':
case '--enable-common-slant':
case '--disable-common-slant':
params.commonSlant = value;
break;
case '-W':
case '--enable-common-weight':
case '--disable-common-weight':
params.commonWeight = value;
break;
case '-X':
case '--enable-xlfd-font':
case '--disable-xlfd-font':
params.xlfdFontNm = value;
break;
case '-Y':
case '--enable-ywidth-zero':
case '--disable-ywidth-zero':
params.yWidthZero = value;
break;
default:
return directive !== true && this.fallback(name, params);
}
return directive !== true || name.startsWith('--');
}
}
// -- DupMap --
class DupMap extends Map {
constructor(prefix, descript, severity) {
super();
this.prefix = prefix;
this.descript = descript;
this.severity = severity;
}
check() {
this.forEach((lines, value) => {
if (lines.length > 1) {
let text = `duplicate ${this.descript} ${value} at lines`;
for (let index = 0; index < lines.length; index++) {
text += (index === 0 ? ' ' : index === lines.length - 1 ? ' and ' : ', ');
text += lines[index];
}
fnutil.message(this.prefix, this.severity, text);
}
});
}
push(value, lineNo) {
let lines = this.get(value);
if (lines != null) {
lines.push(lineNo);
} else {
this.set(value, [lineNo]);
}
}
}
// -- InputFileStream --
const MODE = Object.freeze({
META: 0,
PROPS: 1,
BITMAP: 2
});
class InputFileStream extends fnio.InputFileStream {
constructor(fileName, parsed) {
super(fileName);
this.parsed = parsed;
this.mode = MODE.META;
this.proplocs = new DupMap(this.location(), 'property');
this.namelocs = new DupMap(this.location(), 'character name', 'warning');
this.codelocs = new DupMap(this.location(), 'encoding', 'warning');
this.HANDLERS = [
[ 'STARTCHAR', value => this.appendName(value) ],
[ 'ENCODING', value => this.appendCode(value) ],
[ 'SWIDTH', value => this.checkWidth('SWIDTH', value, bdf.Width.parseS) ],
[ 'DWIDTH', value => this.checkWidth('DWIDTH', value, bdf.Width.parseD) ],
[ 'BBX', value => this.setLastBox(value) ],
[ 'BITMAP', () => this.setMode(MODE.BITMAP) ],
[ 'SIZE', InputFileStream.checkSize ],
[ 'ATTRIBUTES', value => this.checkAttr(value) ],
[ 'STARTPROPERTIES', () => this.setMode(MODE.PROPS) ],
[ 'FONTBOUNDINGBOX', value => this.setFontBox(value) ]
];
this.xlfdName = false;
this.lastBox = null;
this.fontBox = null;
this.options = new Options();
}
append(option, valocs, value) {
if (option) {
valocs.push(value, this.lineNo);
}
}
appendCode(value) {
fnutil.parseDec('encoding', value);
this.append(this.parsed.duplCodes, this.codelocs, value);
}
appendName(value) {
this.append(this.parsed.duplNames, this.namelocs, `"${value}"`);
}
checkWidth(name, value, parse) {
if (this.parsed.yWidthZero && parse(name, value).y !== 0) {
fnutil.warning(this.location(), `non-zero ${name} Y`);
}
}
setFontBox(value) {
this.fontBox = bdf.BBX.parse('FONTBOUNDINGBOX', value);
}
setLastBox(value) {
const bbx = bdf.BBX.parse('BBX', value);
if (this.parsed.bbxExceeds) {
let exceeds = [];
if (bbx.xoff < this.fontBox.xoff) {
exceeds.push('xoff < FONTBOUNDINGBOX xoff');
}
if (bbx.yoff < this.fontBox.yoff) {
exceeds.push('yoff < FONTBOUNDINGBOX yoff');
}
if (bbx.width > this.fontBox.width) {
exceeds.push('width > FONTBOUNDINGBOX width');
}
if (bbx.height > this.fontBox.height) {
exceeds.push('height > FONTBOUNDINGBOX height');
}
exceeds.forEach(exceed => {
fnutil.message(this.location(), '', exceed);
});
}
this.lastBox = bbx;
}
setMode(newMode) {
this.mode = newMode;
}
static checkSize(value) {
const words = fnutil.splitWords('SIZE', value, 3);
fnutil.parseDec('point size', words[0], 1, null);
fnutil.parseDec('x resolution', words[1], 1, null);
fnutil.parseDec('y resolution', words[2], 1, null);
}
checkAttr(value) {
if (!value.match(/^[\dA-Fa-f]{4}$/)) {
throw new Error('ATTRIBUTES must be 4 hex-encoded characters');
}
if (this.parsed.attributes) {
fnutil.warning(this.location(), 'ATTRIBUTES may cause problems with freetype');
}
}
checkFont(value) {
const xlfd = value.substring(4).trimLeft().split('-', 16);
if (xlfd.length === 15 && xlfd[0] === '') {
let unicode = (xlfd[bdf.XLFD.CHARSET_REGISTRY].toUpperCase() === 'ISO10646');
if (this.parsed.duplCodes === -1) {
this.parsed.duplCodes = unicode;
}
if (this.parsed.duplNames === -1) {
this.parsed.duplNames = unicode;
}
if (this.parsed.commonWeight) {
let weight = xlfd[bdf.XLFD.WEIGHT_NAME];
let compare = weight.toLowerCase();
let consider = compare.includes('bold') ? 'Bold' : 'Normal';
if (compare === 'medium' || compare === 'regular') {
compare = 'normal';
}
if (compare !== consider.toLowerCase()) {
fnutil.warning(this.location(), `weight "${weight}" may be considered ${consider}`);
}
}
if (this.parsed.commonSlant) {
let slant = xlfd[bdf.XLFD.SLANT];
let consider = slant.match(/^[IO]/) ? 'Italic' : 'Regular';
if (slant.match(/^[IOR]$/) == null) {
fnutil.warning(this.location(), `slant "${slant}" may be considered ${consider}`);
}
}
} else {
if (this.parsed.xlfdFontNm) {
fnutil.warning(this.location(), 'non-XLFD font name');
}
value = 'FONT --------------';
}
return value;
}
checkProp(line) {
const match = line.match(/^(\w+)\s+([-\d"].*)$/);
if (match == null) {
throw new Error('invalid property format');
}
const name = match[1];
const value = match[2];
if (value.startsWith('"')) {
if (value.length < 2 || !value.endsWith('"')) {
throw new Error('no closing double quote');
}
if (value.substring(1, value.length - 1).match(/[^"]"[^"]/)) {
throw new Error('unescaped double quote');
}
} else {
fnutil.parseDec('value', value, null, null);
}
this.append(this.parsed.duplProps, this.proplocs, name);
return `P${this.lineNo} 1`;
}
checkBitmap(line) {
if (line.length !== this.lastBox.rowSize() * 2) {
throw new Error('invalid bitmap length');
} else if (line.match(/^[\dA-Fa-f]+$/) == null) {
throw new Error('invalid bitmap data');
} else if (this.parsed.extraBits) {
const data = Buffer.from(line, 'hex');
const checkX = (this.lastBox.width - 1) | 7;
const lastByte = data[data.length - 1];
let bitNo = 7 - (this.lastBox.Width & 7);
for (let x = this.lastBox.Width; x <= checkX; x++) {
if (lastByte & (1 << bitNo)) {
fnutil.warning(this.location(), `extra bit(s) starting with x=${x}`);
break;
}
bitNo--;
}
}
}
checkLine(line) {
if (line.match(/[^\t\f\v\u0020-\u00ff]/)) {
throw new Error('control character(s)');
}
if (this.parsed.asciiChars && line.match(/[\u007f-\u00ff]/)) {
fnutil.warning(this.location(), 'non-ascii character(s)');
}
switch (this.mode) {
case MODE.META:
if (!this.xlfdName && line.startsWith('FONT')) {
line = this.checkFont(line);
this.xlfdName = true;
} else {
this.HANDLERS.findIndex(function(handler) {
if (line.startsWith(handler[0])) {
handler[1](line.substring(handler[0].length).trimLeft());
return true;
}
return false;
});
}
break;
case MODE.PROPS:
if (line.startsWith('ENDPROPERTIES')) {
this.mode = MODE.META;
} else {
line = this.checkProp(line);
}
break;
default: // MODE.BITMAP
if (line.startsWith('ENDCHAR')) {
this.mode = MODE.META;
} else {
this.checkBitmap(line);
}
}
return line;
}
readCheck(line, callback) {
const match = line.match(/^COMMENT\s*bdfcheck\s+(-.*)$/);
if (match && !this.options.parse(match[1], true, this.parsed)) {
throw new Error('invalid bdfcheck directive');
}
line = callback(line);
return line != null ? this.checkLine(line) : null;
}
readLines(callback) {
return super.readLines(line => this.readCheck(line, callback));
}
}
// -- Main --
function mainProgram(nonopt, parsed) {
(nonopt.length >= 1 ? nonopt : [null]).forEach(input => {
let ifs = new InputFileStream(input, parsed);
try {
bdf.Font.read(ifs);
ifs.close();
} catch (e) {
e.message = ifs.location() + e.message;
throw e;
}
ifs.proplocs.check();
ifs.namelocs.check();
ifs.codelocs.check();
});
}
if (require.main === module) {
fncli.start('bdfcheck.js', new Options(), new Params(), mainProgram);
}

380
bin/bdfcheck.py Normal file
View File

@ -0,0 +1,380 @@
#
# Copyright (C) 2017-2020 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
import re
import codecs
from collections import OrderedDict
from enum import IntEnum, unique
import fnutil
import fncli
import fnio
import bdf
# -- Params --
class Params(fncli.Params): # pylint: disable=too-many-instance-attributes
def __init__(self):
fncli.Params.__init__(self)
self.ascii_chars = True
self.bbx_exceeds = True
self.dupl_codes = -1
self.extra_bits = True
self.attributes = True
self.dupl_names = -1
self.dupl_props = True
self.common_slant = True
self.common_weight = True
self.xlfd_fontnm = True
self.ywidth_zero = True
# -- Options --
HELP = ('' +
'usage: bdfcheck [options] [INPUT...]\n' +
'Check BDF font(s) for various problems\n' +
'\n' +
' -A disable non-ascii characters check\n' +
' -B disable BBX exceeding FONTBOUNDINGBOX checks\n' +
' -c/-C enable/disable duplicate character codes check\n' +
' (default = enabled for registry ISO10646)\n' +
' -E disable extra bits check\n' +
' -I disable ATTRIBUTES check\n' +
' -n/-N enable duplicate character names check\n' +
' (default = enabled for registry ISO10646)\n' +
' -P disable duplicate properties check\n' +
' -S disable common slant check\n' +
' -W disable common weight check\n' +
' -X disable XLFD font name check\n' +
' -Y disable zero WIDTH Y check\n' +
' --help display this help and exit\n' +
' --version display the program version and license, and exit\n' +
' --excstk display the exception stack on error\n' +
'\n' +
'File directives: COMMENT bdfcheck --enable|disable-<check-name>\n' +
' (also available as long command line options)\n' +
'\n' +
'Check names: ascii-chars, bbx-exceeds, duplicate-codes, extra-bits,\n' +
' attributes, duplicate-names, duplicate-properties, common-slant,\n' +
' common-weight, xlfd-font, ywidth-zero\n' +
'\n' +
'The input BDF(s) must be v2.1 with unicode encoding.\n')
VERSION = 'bdfcheck 1.62, Copyright (C) 2017-2020 Dimitar Toshkov Zhekov\n\n' + fnutil.GPL2PLUS_LICENSE
class Options(fncli.Options):
def __init__(self):
fncli.Options.__init__(self, [], HELP, VERSION)
def parse(self, name, directive, params):
value = name.startswith('--enable') or name[1].islower()
if name in ['-A', '--enable-ascii-chars', '--disable-ascii-chars']:
params.ascii_chars = value
elif name in ['-B', '--enable-bbx-exceeds', '--disable-bbx-exceeds']:
params.bbx_exceeds = value
elif name in ['-c', '-C', '--enable-duplicate-codes', '--disable-duplicate-codes']:
params.dupl_codes = value
elif name in ['-E', '--enable-extra-bits', '--disable-extra-bits']:
params.extra_bits = value
elif name in ['-I', '--enable-attributes', '--disable-attributes']:
params.attributes = value
elif name in ['-n', '-N', '--enable-duplicate-names', '--disable-duplicate-names']:
params.dupl_names = value
elif name in ['-P', '--enable-duplicate-properties', '--disable-duplicate-properties']:
params.dupl_props = value
elif name in ['-S', '--enable-common-slant', '--disable-common-slant']:
params.common_slant = value
elif name in ['-W', '--enable-common-weight', '--disable-common-weight']:
params.common_weight = value
elif name in ['-X', '--enable-xlfd-font', '--disable-xlfd-font']:
params.xlfd_fontnm = value
elif name in ['-Y', '--enable-ywidth-zero', '--disable-ywidth-zero']:
params.ywidth_zero = value
else:
return directive is not True and self.fallback(name, params)
return directive is not True or name.startswith('--')
# -- DupMap --
class DupMap(OrderedDict):
def __init__(self, prefix, severity, descript, quote):
OrderedDict.__init__(self)
self.prefix = prefix
self.descript = descript
self.severity = severity
self.quote = quote
def check(self):
for value, lines in self.items():
if len(lines) > 1:
text = 'duplicate %s %s at lines' % (self.descript, str(value))
for index, line in enumerate(lines):
text += ' ' if index == 0 else ' and ' if index == len(lines) - 1 else ', '
text += str(line)
fnutil.message(self.prefix, self.severity, text)
def push(self, value, line_no):
try:
self[value].append(line_no)
except KeyError:
self[value] = [line_no]
# -- InputFileStream --
@unique
class MODE(IntEnum):
META = 0
PROPS = 1
BITMAP = 2
class InputFileStream(fnio.InputFileStream):
def __init__(self, file_name, parsed):
fnio.InputFileStream.__init__(self, file_name)
self.parsed = parsed
self.mode = MODE.META
self.proplocs = DupMap(self.location(), 'error', 'property', '')
self.namelocs = DupMap(self.location(), 'warning', 'character name', '"')
self.codelocs = DupMap(self.location(), 'warning', 'encoding', '')
self.handlers = [
(b'STARTCHAR', lambda value: self.append_name(value)),
(b'ENCODING', lambda value: self.append_code(value)),
(b'SWIDTH', lambda value: self.check_width('SWIDTH', value, bdf.Width.parse_s)),
(b'DWIDTH', lambda value: self.check_width('DWIDTH', value, bdf.Width.parse_d)),
(b'BBX', lambda value: self.set_last_box(value)),
(b'BITMAP', lambda _: self.set_mode(MODE.BITMAP)),
(b'SIZE', InputFileStream.check_size),
(b'ATTRIBUTES', lambda value: self.check_attr(value)),
(b'STARTPROPERTIES', lambda _: self.set_mode(MODE.PROPS)),
(b'FONTBOUNDINGBOX', lambda value: self.set_font_box(value)),
]
self.xlfd_name = False
self.last_box = None
self.font_box = None
self.options = Options()
def append(self, option, valocs, value):
if option:
valocs.push(str(value, 'ascii'), self.line_no)
def append_code(self, value):
fnutil.parse_dec('encoding', value)
self.append(self.parsed.dupl_codes, self.codelocs, value)
def append_name(self, value):
self.append(self.parsed.dupl_names, self.namelocs, b'"%s"' % value)
def check_width(self, name, value, parse):
if self.parsed.ywidth_zero and parse(name, value).y != 0:
fnutil.warning(self.location(), 'non-zero %s Y' % name)
def set_font_box(self, value):
self.font_box = bdf.BBX.parse('FONTBOUNDINGBOX', value)
def set_last_box(self, value):
bbx = bdf.BBX.parse('BBX', value)
if self.parsed.bbx_exceeds:
exceeds = []
if bbx.xoff < self.font_box.xoff:
exceeds.append('xoff < FONTBOUNDINGBOX xoff')
if bbx.yoff < self.font_box.yoff:
exceeds.append('yoff < FONTBOUNDINGBOX yoff')
if bbx.width > self.font_box.width:
exceeds.append('width > FONTBOUNDINGBOX width')
if bbx.height > self.font_box.height:
exceeds.append('height > FONTBOUNDINGBOX height')
for exceed in exceeds:
fnutil.message(self.location(), '', exceed)
self.last_box = bbx
def set_mode(self, new_mode):
self.mode = new_mode
def check(self):
self.process(bdf.Font.read)
self.proplocs.check()
self.namelocs.check()
self.codelocs.check()
@staticmethod
def check_size(value):
words = fnutil.split_words('SIZE', value, 3)
fnutil.parse_dec('point size', words[0], 1, None)
fnutil.parse_dec('x resolution', words[1], 1, None)
fnutil.parse_dec('y resolution', words[2], 1, None)
def check_attr(self, value):
if not re.fullmatch(br'[\dA-Fa-f]{4}', value):
raise Exception('ATTRIBUTES must be 4 hex-encoded characters')
if self.parsed.attributes:
fnutil.warning(self.location(), 'ATTRIBUTES may cause problems with freetype')
def check_font(self, value):
xlfd = value[4:].lstrip().split(b'-', 15)
if len(xlfd) == 15 and xlfd[0] == b'':
unicode = (xlfd[bdf.XLFD.CHARSET_REGISTRY].upper() == b'ISO10646')
if self.parsed.dupl_codes == -1:
self.parsed.dupl_codes = unicode
if self.parsed.dupl_names == -1:
self.parsed.dupl_names = unicode
if self.parsed.common_weight:
weight = str(xlfd[bdf.XLFD.WEIGHT_NAME], 'ascii')
compare = weight.lower()
consider = 'Bold' if 'bold' in compare else 'Normal'
if compare in ['medium', 'regular']:
compare = 'normal'
if compare != consider.lower():
fnutil.warning(self.location(), 'weight "%s" may be considered %s' % (weight, consider))
if self.parsed.common_slant:
slant = str(xlfd[bdf.XLFD.SLANT], 'ascii')
consider = 'Italic' if re.search('^[IO]', slant) else 'Regular'
if not re.fullmatch('[IOR]', slant):
fnutil.warning(self.location(), 'slant "%s" may be considered %s' % (slant, consider))
else:
if self.parsed.xlfd_fontnm:
fnutil.warning(self.location(), 'non-XLFD font name')
value = b'FONT --------------'
return value
def check_prop(self, line):
match = re.fullmatch(br'(\w+)\s+([-\d"].*)', line)
if not match:
raise Exception('invalid property format')
name = match.group(1)
value = match.group(2)
if value.startswith(b'"'):
if len(value) < 2 or not value.endswith(b'"'):
raise Exception('no closing double quote')
if re.search(b'[^"]"[^"]', value[1 : len(value) - 1]):
raise Exception('unescaped double quote')
else:
fnutil.parse_dec('value', value, None, None)
self.append(self.parsed.dupl_props, self.proplocs, name)
return b'P%d 1' % self.line_no
def check_bitmap(self, line):
if len(line) != self.last_box.row_size() * 2:
raise Exception('invalid bitmap length')
data = codecs.decode(line, 'hex')
if self.parsed.extra_bits:
check_x = (self.last_box.width - 1) | 7
last_byte = data[len(data) - 1]
bit_no = 7 - (self.last_box.width & 7)
for x in range(self.last_box.width, check_x + 1):
if last_byte & (1 << bit_no):
fnutil.warning(self.location(), 'extra bit(s) starting with x=%d' % x)
break
bit_no -= 1
def check_line(self, line):
if re.search(b'[^\t\f\v\x20-\xff]', line):
raise Exception('control character(s)')
if self.parsed.ascii_chars and re.search(b'[\x7f-\xff]', line):
fnutil.warning(self.location(), 'non-ascii character(s)')
if self.mode == MODE.META:
if not self.xlfd_name and line.startswith(b'FONT'):
line = self.check_font(line)
self.xlfd_name = True
else:
for handler in self.handlers:
if line.startswith(handler[0]):
handler[1](line[len(handler[0]):].lstrip())
break
elif self.mode == MODE.PROPS:
if line.startswith(b'ENDPROPERTIES'):
self.mode = MODE.META
else:
line = self.check_prop(line)
else: # MODE.BITMAP
if line.startswith(b'ENDCHAR'):
self.mode = MODE.META
else:
self.check_bitmap(line)
return line
def read_check(self, line, callback):
match = re.search(br'^COMMENT\s*bdfcheck\s+(-.*)$', line)
if match and not self.options.parse(str(match[1], 'ascii'), True, self.parsed):
raise Exception('invalid bdfcheck directive')
line = callback(line)
return self.check_line(line) if line is not None else None
def read_lines(self, callback):
return fnio.InputFileStream.read_lines(self, lambda line: self.read_check(line, callback))
# -- Main --
def main_program(nonopt, parsed):
for input_name in nonopt or [None]:
InputFileStream(input_name, parsed).check()
if __name__ == '__main__':
fncli.start('bdfcheck.py', Options(), Params(), main_program)

287
bin/bdfexp.js Normal file
View File

@ -0,0 +1,287 @@
/*
Copyright (C) 2017-2020 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at your option)
any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
'use strict';
const fnutil = require('./fnutil.js');
const fncli = require('./fncli.js');
const fnio = require('./fnio.js');
const bdf = require('./bdf.js');
// -- Font --
class Font extends bdf.Font {
constructor() {
super();
this.minWidth = 0; // used in proportional()
this.avgWidth = 0;
}
_expand(char) {
if (char.dwidth.x >= 0) {
if (char.bbx.xoff >= 0) {
var width = Math.max(char.bbx.xoff + char.bbx.width, char.dwidth.x);
var dstXOff = char.bbx.xoff;
var expXOff = 0;
} else {
width = Math.max(char.bbx.width, char.dwidth.x - char.bbx.xoff);
dstXOff = 0;
expXOff = char.bbx.xoff;
}
} else {
const revXOff = char.bbx.xoff + char.bbx.width;
if (revXOff <= 0) {
width = -Math.min(char.dwidth.x, char.bbx.xoff);
dstXOff = width + char.bbx.xoff;
expXOff = -width;
} else {
width = Math.max(char.bbx.width, revXOff - char.dwidth.x);
dstXOff = width - char.bbx.width;
expXOff = revXOff - width;
}
}
const height = this.bbx.height;
if (width === char.bbx.width && height === char.bbx.height) {
return;
}
const srcRowSize = char.bbx.rowSize();
const dstRowSize = (width + 7) >> 3;
const dstYMax = this.pxAscender - char.bbx.yoff;
const dstYMin = dstYMax - char.bbx.height;
const copyRow = (dstXOff & 7) === 0;
const dstData = Buffer.alloc(dstRowSize * height);
for (let dstY = dstYMin; dstY < dstYMax; dstY++) {
let srcByteNo = (dstY - dstYMin) * srcRowSize;
let dstByteNo = dstY * dstRowSize + (dstXOff >> 3);
if (copyRow) {
char.data.copy(dstData, dstByteNo, srcByteNo, srcByteNo + srcRowSize);
} else {
let srcBitNo = 7;
let dstBitNo = 7 - (dstXOff & 7);
for (let x = 0; x < char.bbx.width; x++) {
if (char.data[srcByteNo] & (1 << srcBitNo)) {
dstData[dstByteNo] |= (1 << dstBitNo);
}
if (--srcBitNo < 0) {
srcBitNo = 7;
srcByteNo++;
}
if (--dstBitNo < 0) {
dstBitNo = 7;
dstByteNo++;
}
}
}
}
char.bbx = new bdf.BBX(width, height, expXOff, this.bbx.yoff);
char.props.set('BBX', char.bbx);
char.data = dstData;
}
expand() {
// PREXPAND / VERTICAL
const ascent = this.props.get('FONT_ASCENT');
const descent = this.props.get('FONT_DESCENT');
let pxAscent = (ascent == null ? 0 : fnutil.parseDec('FONT_ASCENT', ascent, 0, bdf.DPARSE_LIMIT));
let pxDescent = (descent == null ? 0 : fnutil.parseDec('FONT_DESCENT', descent, 0, bdf.DPARSE_LIMIT));
this.chars.forEach(char => {
pxAscent = Math.max(pxAscent, char.bbx.height + char.bbx.yoff);
pxDescent = Math.max(pxDescent, -char.bbx.yoff);
});
this.bbx.height = pxAscent + pxDescent;
this.bbx.yoff = -pxDescent;
// EXPAND / HORIZONTAL
let totalWidth = 0;
this.minWidth = this.chars[0].bbx.width;
this.chars.forEach(char => {
this._expand(char);
this.minWidth = Math.min(this.minWidth, char.bbx.width);
this.bbx.width = Math.max(this.bbx.width, char.bbx.width);
this.bbx.xoff = Math.min(this.bbx.xoff, char.bbx.xoff);
totalWidth += char.bbx.width;
});
this.avgWidth = fnutil.round(totalWidth / this.chars.length);
this.props.set('FONTBOUNDINGBOX', this.bbx);
}
expandX() {
this.chars.forEach(char => {
if (char.dwidth.x !== char.bbx.width) { // preserve SWIDTH if possible
char.swidth.x = fnutil.round(char.bbx.width * 1000 / this.bbx.height);
char.props.set('SWIDTH', char.swidth);
char.dwidth.x = char.bbx.width;
char.props.set('DWIDTH', char.dwidth);
}
char.bbx.xoff = 0;
char.props.set('BBX', char.bbx);
});
this.bbx.xoff = 0;
this.props.set('FONTBOUNDINGBOX', this.bbx);
}
expandY() {
const props = new Map([
[ 'FONT_ASCENT', this.pxAscender ],
[ 'FONT_DESCENT', -this.pxDescender ],
[ 'PIXEL_SIZE', this.bbx.height ]
]);
props.forEach((value, name) => {
if (this.props.get(name) != null) {
this.props.set(name, value);
}
});
this.xlfd[bdf.XLFD.PIXEL_SIZE] = this.bbx.height.toString();
this.props.set('FONT', this.xlfd.join('-'));
}
get proportional() {
return this.bbx.width > this.minWidth || super.proportional;
}
get pxAscender() {
return this.bbx.height + this.bbx.yoff;
}
get pxDescender() {
return this.bbx.yoff;
}
_read(input) {
super._read(input);
this.expand();
return this;
}
static read(input) {
return (new Font())._read(input);
}
_updateProp(name, value) {
if (this.props.get(name) != null) {
this.props.set(name, value);
}
}
}
// -- Export --
module.exports = Object.freeze({
Font
});
// -- Params --
class Params extends fncli.Params {
constructor() {
super();
this.expandX = false;
this.expandY = false;
this.output = null;
}
}
// -- Options --
const HELP = ('' +
'usage: bdfexp [-X] [-Y] [-o OUTPUT] [INPUT]\n' +
'Expand BDF font bitmaps\n' +
'\n' +
' -X zero xoffs, set character S/DWIDTH.X from the output\n' +
' BBX.width if needed\n' +
' -Y enlarge FONT_ASCENT, FONT_DESCENT and PIXEL_SIZE to\n' +
' cover the font bounding box, if needed\n' +
' -o OUTPUT output file (default = stdout)\n' +
' --help display this help and exit\n' +
' --version display the program version and license, and exit\n' +
' --excstk display the exception stack on error\n' +
'\n' +
'The input must be a BDF 2.1 font with unicode encoding.\n');
const VERSION = 'bdfexp 1.60, Copyright (C) 2017-2020 Dimitar Toshkov Zhekov\n\n' + fnutil.GPL2PLUS_LICENSE;
class Options extends fncli.Options {
constructor() {
super(['-o'], HELP, VERSION);
}
parse(name, value, params) {
switch (name) {
case '-X':
params.expandX = true;
break;
case '-Y':
params.expandY = true;
break;
case '-o':
params.output = value;
break;
default:
this.fallback(name, params);
}
}
}
// -- Main --
function mainProgram(nonopt, parsed) {
if (nonopt.length > 1) {
throw new Error('invalid number of arguments, try --help');
}
// READ INPUT
let ifs = new fnio.InputFileStream(nonopt[0]);
try {
var font = Font.read(ifs);
ifs.close();
} catch (e) {
e.message = ifs.location() + e.message;
throw e;
}
// EXTRA ACTIONS
if (parsed.expandX) {
font.expandX();
}
if (parsed.expandY) {
font.expandY();
}
// WRITE OUTPUT
let ofs = new fnio.OutputFileStream(parsed.output);
try {
font.write(ofs);
ofs.close();
} catch (e) {
e.message = ofs.location() + e.message() + ofs.destroy();
throw e;
}
}
if (require.main === module) {
fncli.start('bdfexp.js', new Options(), new Params(), mainProgram);
}

245
bin/bdfexp.py Normal file
View File

@ -0,0 +1,245 @@
#
# Copyright (C) 2017-2020 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
from collections import OrderedDict
import fnutil
import fncli
import fnio
import bdf
# -- Font --
class Font(bdf.Font):
def __init__(self):
bdf.Font.__init__(self)
self.min_width = 0 # used in proportional()
self.avg_width = 0
def _expand(self, char):
if char.dwidth.x >= 0:
if char.bbx.xoff >= 0:
width = max(char.bbx.xoff + char.bbx.width, char.dwidth.x)
dst_xoff = char.bbx.xoff
exp_xoff = 0
else:
width = max(char.bbx.width, char.dwidth.x - char.bbx.xoff)
dst_xoff = 0
exp_xoff = char.bbx.xoff
else:
rev_xoff = char.bbx.xoff + char.bbx.width
if rev_xoff <= 0:
width = -min(char.dwidth.x, char.bbx.xoff)
dst_xoff = width + char.bbx.xoff
exp_xoff = -width
else:
width = max(char.bbx.width, rev_xoff - char.dwidth.x)
dst_xoff = width - char.bbx.width
exp_xoff = rev_xoff - width
height = self.bbx.height
if width == char.bbx.width and height == char.bbx.height:
return
src_row_size = char.bbx.row_size()
dst_row_size = (width + 7) >> 3
dst_ymax = self.px_ascender - char.bbx.yoff
dst_ymin = dst_ymax - char.bbx.height
copy_row = (dst_xoff & 7) == 0
dst_data = bytearray(dst_row_size * height)
for dst_y in range(dst_ymin, dst_ymax):
src_byte_no = (dst_y - dst_ymin) * src_row_size
dst_byte_no = dst_y * dst_row_size + (dst_xoff >> 3)
if copy_row:
dst_data[dst_byte_no : dst_byte_no + src_row_size] = \
char.data[src_byte_no : src_byte_no + src_row_size]
else:
src_bit_no = 7
dst_bit_no = 7 - (dst_xoff & 7)
for _ in range(0, char.bbx.width):
if char.data[src_byte_no] & (1 << src_bit_no):
dst_data[dst_byte_no] |= (1 << dst_bit_no)
if src_bit_no > 0:
src_bit_no -= 1
else:
src_bit_no = 7
src_byte_no += 1
if dst_bit_no > 0:
dst_bit_no -= 1
else:
dst_bit_no = 7
dst_byte_no += 1
char.bbx = bdf.BBX(width, height, exp_xoff, self.bbx.yoff)
char.props.set('BBX', char.bbx)
char.data = dst_data
def expand(self):
# PREXPAND / VERTICAL
ascent = self.props.get('FONT_ASCENT')
descent = self.props.get('FONT_DESCENT')
px_ascent = 0 if ascent is None else fnutil.parse_dec('FONT_ASCENT', ascent, 0, bdf.DPARSE_LIMIT)
px_descent = 0 if descent is None else fnutil.parse_dec('FONT_DESCENT', descent, 0, bdf.DPARSE_LIMIT)
for char in self.chars:
px_ascent = max(px_ascent, char.bbx.height + char.bbx.yoff)
px_descent = max(px_descent, -char.bbx.yoff)
self.bbx.height = px_ascent + px_descent
self.bbx.yoff = -px_descent
# EXPAND / HORIZONTAL
total_width = 0
self.min_width = self.chars[0].bbx.width
for char in self.chars:
self._expand(char)
self.min_width = min(self.min_width, char.bbx.width)
self.bbx.width = max(self.bbx.width, char.bbx.width)
self.bbx.xoff = min(self.bbx.xoff, char.bbx.xoff)
total_width += char.bbx.width
self.avg_width = round(total_width / len(self.chars))
self.props.set('FONTBOUNDINGBOX', self.bbx)
def expand_x(self):
for char in self.chars:
if char.dwidth.x != char.bbx.width:
char.swidth.x = round(char.bbx.width * 1000 / self.bbx.height)
char.props.set('SWIDTH', char.swidth)
char.dwidth.x = char.bbx.width
char.props.set('DWIDTH', char.dwidth)
char.bbx.xoff = 0
char.props.set('BBX', char.bbx)
self.bbx.xoff = 0
self.props.set('FONTBOUNDINGBOX', self.bbx)
def expand_y(self):
props = OrderedDict((
('FONT_ASCENT', self.px_ascender),
('FONT_DESCENT', -self.px_descender),
('PIXEL_SIZE', self.bbx.height)
))
for [name, value] in props.items():
if self.props.get(name) is not None:
self.props.set(name, value)
self.xlfd[bdf.XLFD.PIXEL_SIZE] = bytes(str(self.bbx.height), 'ascii')
self.props.set('FONT', b'-'.join(self.xlfd))
@property
def proportional(self):
return self.bbx.width > self.min_width or bdf.Font.proportional.fget(self) # pylint: disable=no-member
@property
def px_ascender(self):
return self.bbx.height + self.bbx.yoff
@property
def px_descender(self):
return self.bbx.yoff
def _read(self, input):
bdf.Font._read(self, input)
self.expand()
return self
@staticmethod
def read(input):
return Font()._read(input) # pylint: disable=protected-access
# -- Params --
class Params(fncli.Params):
def __init__(self):
fncli.Params.__init__(self)
self.expand_x = False
self.expand_y = False
self.output_name = None
# -- Options --
HELP = ('' +
'usage: bdfexp [-X] [-Y] [-o OUTPUT] [INPUT]\n' +
'Expand BDF font bitmaps\n' +
'\n' +
' -X zero xoffs, set character S/DWIDTH.X from the output\n' +
' BBX.width if needed\n' +
' -Y enlarge FONT_ASCENT, FONT_DESCENT and PIXEL_SIZE to\n' +
' cover the font bounding box, if needed\n' +
' -o OUTPUT output file (default = stdout)\n' +
' --help display this help and exit\n' +
' --version display the program version and license, and exit\n' +
' --excstk display the exception stack on error\n' +
'\n' +
'The input must be a BDF 2.1 font with unicode encoding.\n')
VERSION = 'bdfexp 1.62, Copyright (C) 2017-2020 Dimitar Toshkov Zhekov\n\n' + fnutil.GPL2PLUS_LICENSE
class Options(fncli.Options):
def __init__(self):
fncli.Options.__init__(self, ['-o'], HELP, VERSION)
def parse(self, name, value, params):
if name == '-X':
params.expand_x = True
elif name == '-Y':
params.expand_y = True
elif name == '-o':
params.output_name = value
else:
self.fallback(name, params)
# -- Main --
def main_program(nonopt, parsed):
if len(nonopt) > 1:
raise Exception('invalid number of arguments, try --help')
# READ INPUT
font = fnio.read_file(nonopt[0] if nonopt else None, Font.read)
# EXTRA ACTIONS
if parsed.expand_x:
font.expand_x()
if parsed.expand_y:
font.expand_y()
# WRITE OUTPUT
fnio.write_file(parsed.output_name, lambda ofs: font.write(ofs))
if __name__ == '__main__':
fncli.start('bdfexp.py', Options(), Params(), main_program)

View File

@ -1,28 +1,30 @@
//
// Copyright (c) 2019 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
/*
Copyright (C) 2017-2020 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at your option)
any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
'use strict';
const tty = require('tty');
const fnutil = require('./fnutil.js');
const fncli = require('./fncli.js');
const fnio = require('./fnio.js');
const bdf = require('./bdf.js');
const bmpf = require('./bmpf.js');
const bdfexp = require('./bdfexp.js');
// -- Params --
class Params extends fncli.Params {
constructor() {
super();
@ -33,7 +35,7 @@ class Params extends fncli.Params {
}
}
// -- Options --
const HELP = ('' +
'usage: bdftofnt [-c CHARSET] [-m MINCHAR] [-f FAMILY] [-o OUTPUT] [INPUT]\n' +
'Convert a BDF font to Windows FNT\n' +
@ -41,14 +43,14 @@ const HELP = ('' +
' -c CHARSET fnt character set (default = 0, see wingdi.h ..._CHARSET)\n' +
' -m MINCHAR fnt minimum character code (8-bit CP decimal, not unicode)\n' +
' -f FAMILY fnt family: DontCare, Roman, Swiss, Modern or Decorative\n' +
' -o OUTPUT output file (default = stdout, must not be a terminal)\n' +
' -o OUTPUT output file (default = stdout, may not be a terminal)\n' +
' --help display this help and exit\n' +
' --version display the program version and license, and exit\n' +
' --excstk display the exception stack on error\n' +
'\n' +
'The input must be a BDF 2.1 font encoded in the unicode range.\n');
'The input must be a BDF 2.1 font with unicode encoding.\n');
const VERSION = 'bdftofnt 1.55, Copyright (C) 2019 Dimitar Toshkov Zhekov\n\n' + fnutil.GPL2PLUS_LICENSE;
const VERSION = 'bdftofnt 1.60, Copyright (C) 2017-2020 Dimitar Toshkov Zhekov\n\n' + fnutil.GPL2PLUS_LICENSE;
const FNT_FAMILIES = [ 'DontCare', 'Roman', 'Swiss', 'Modern', 'Decorative' ];
@ -60,16 +62,16 @@ class Options extends fncli.Options {
parse(name, value, params) {
switch (name) {
case '-c':
params.charSet = fnutil.parseDec('charset', value, 0, 255);
params.charSet = fnutil.parseDec('CHARSET', value, 0, 255);
break;
case '-m':
params.minChar = fnutil.parseDec('minchar', value, 0, 255);
params.minChar = fnutil.parseDec('MINCHAR', value, 0, 255);
break;
case '-f':
params.fntFamily = FNT_FAMILIES.indexOf(value);
if (params.fntFamily === -1) {
throw new Error('invalid fnt family');
throw new Error('invalid FAMILY');
}
break;
case '-o':
@ -81,10 +83,11 @@ class Options extends fncli.Options {
}
}
// -- Main --
const FNT_HEADER_SIZE = 118;
const FNT_CHARSETS = [238, 204, 0, 161, 162, 177, 178, 186, 163];
function mainProgram(nonopt, parsed) {
const WIN_FONTHEADERSIZE = 118;
if (nonopt.length > 1) {
throw new Error('invalid number of arguments, try --help');
}
@ -93,10 +96,10 @@ function mainProgram(nonopt, parsed) {
let minChar = parsed.minChar;
// READ INPUT
let ifs = new fnio.InputStream(nonopt[0]);
let ifs = new fnio.InputFileStream(nonopt[0]);
try {
var font = bmpf.Font.read(ifs);
var font = bdfexp.Font.read(ifs);
ifs.close();
} catch (e) {
e.message = ifs.location() + e.message;
@ -108,8 +111,6 @@ function mainProgram(nonopt, parsed) {
const encoding = font.xlfd[bdf.XLFD.CHARSET_ENCODING];
if (encoding.toLowerCase().match(/^(cp)?125[0-8]$/)) {
const FNT_CHARSETS = [238, 204, 0, 161, 162, 177, 178, 186, 163];
charSet = FNT_CHARSETS[parseInt(encoding.substring(encoding.length - 1), 10)];
} else {
charSet = 255;
@ -137,16 +138,16 @@ function mainProgram(nonopt, parsed) {
}
// HEADER
var vtell = WIN_FONTHEADERSIZE + (numChars + 1) * 4;
var vtell = FNT_HEADER_SIZE + (numChars + 1) * 4;
var bitsOffset = vtell;
var ctable = [];
var widthBytes = 0;
// CTABLE/GLYPHS
font.chars.forEach(char => {
const rowSize = char.rowSize();
const rowSize = char.bbx.rowSize();
ctable.push(char.width);
ctable.push(char.bbx.width);
ctable.push(vtell);
vtell += rowSize * font.bbx.height;
widthBytes += rowSize;
@ -173,16 +174,11 @@ function mainProgram(nonopt, parsed) {
}
// WRITE
let ofs = new fnio.OutputStream(parsed.output);
if (tty.isatty(ofs.fd)) {
throw new Error('binary output may not be send to a terminal, use -o or redirect/pipe it');
}
let ofs = new fnio.OutputFileStream(parsed.output, null);
try {
// HEADER
const family = font.xlfd[bdf.XLFD.FAMILY_NAME];
const proportional = font.getProportional();
let copyright = font.props.get('COPYRIGHT');
copyright = (copyright != null) ? fnutil.unquote(copyright).substring(0, 60) : '';
@ -193,17 +189,17 @@ function mainProgram(nonopt, parsed) {
ofs.write16(fnutil.round(font.bbx.height * 72 / 96));
ofs.write16(96); // vertical resolution
ofs.write16(96); // horizontal resolution
ofs.write16(font.getAscent()); // base line
ofs.write16(font.pxAscender); // base line
ofs.write16(0); // internal leading
ofs.write16(0); // external leading
ofs.write8(font.getItalic());
ofs.write8(Number(font.italic));
ofs.write8(0); // underline
ofs.write8(0); // strikeout
ofs.write16(400 + 300 * font.getBold());
ofs.write16(font.bold ? 700 : 400);
ofs.write8(charSet);
ofs.write16(proportional ? 0 : font.avgWidth);
ofs.write16(font.proportional ? 0 : font.bbx.width);
ofs.write16(font.bbx.height);
ofs.write8((parsed.fntFamily << 4) + proportional);
ofs.write8((parsed.fntFamily << 4) + Number(font.proportional));
ofs.write16(font.avgWidth);
ofs.write16(font.bbx.width);
ofs.write8(minChar);
@ -215,11 +211,9 @@ function mainProgram(nonopt, parsed) {
if (font.defaultCode !== -1) {
defaultIndex = font.chars.findIndex(char => char.code === font.defaultCode);
}
if (minChar <= 0x20 && maxChar >= 0x20) {
breakIndex = 0x20 - minChar;
}
ofs.write8(defaultIndex);
ofs.write8(breakIndex);
ofs.write16(widthBytes);
@ -233,10 +227,10 @@ function mainProgram(nonopt, parsed) {
ctable.forEach(value => ofs.write16(value));
// GLYPHS
let data = Buffer.alloc(font.bbx.height * font.bbx.rowSize());
const data = Buffer.alloc(font.bbx.height * font.bbx.rowSize());
font.chars.forEach(char => {
const rowSize = char.rowSize();
const rowSize = char.bbx.rowSize();
let counter = 0;
// MS coordinates
for (let n = 0; n < rowSize; n++) {
@ -257,7 +251,6 @@ function mainProgram(nonopt, parsed) {
}
}
if (require.main === module) {
fncli.start('bdftofnt.js', new Options(), new Params(), mainProgram);
}

View File

@ -1,15 +1,19 @@
#
# Copyright (c) 2019 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
# Copyright (C) 2017-2020 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of
# the License, or (at your option) any later version.
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
import re
@ -18,18 +22,19 @@
import fncli
import fnio
import bdf
import bmpf
import bdfexp
# -- Params --
class Params(fncli.Params):
def __init__(self):
fncli.Params.__init__(self)
self.char_set = -1
self.min_char = -1
self.fnt_family = 0
self.output = None
self.output_name = None
# -- Options --
HELP = ('' +
'usage: bdftofnt [-c CHARSET] [-m MINCHAR] [-f FAMILY] [-o OUTPUT] [INPUT]\n' +
'Convert a BDF font to Windows FNT\n' +
@ -37,14 +42,14 @@ def __init__(self):
' -c CHARSET fnt character set (default = 0, see wingdi.h ..._CHARSET)\n' +
' -m MINCHAR fnt minimum character code (8-bit CP decimal, not unicode)\n' +
' -f FAMILY fnt family: DontCare, Roman, Swiss, Modern or Decorative\n' +
' -o OUTPUT output file (default = stdout, must not be a terminal)\n' +
' -o OUTPUT output file (default = stdout, may not be a terminal)\n' +
' --help display this help and exit\n' +
' --version display the program version and license, and exit\n' +
' --excstk display the exception stack on error\n' +
'\n' +
'The input must be a BDF font encoded in the unicode range.\n')
'The input must be a BDF 2.1 font with unicode encoding.\n')
VERSION = 'bdftofnt 1.55, Copyright (C) 2019 Dimitar Toshkov Zhekov\n\n' + fnutil.GPL2PLUS_LICENSE
VERSION = 'bdftofnt 1.62, Copyright (C) 2017-2020 Dimitar Toshkov Zhekov\n\n' + fnutil.GPL2PLUS_LICENSE
FNT_FAMILIES = ['DontCare', 'Roman', 'Swiss', 'Modern', 'Decorative']
@ -55,21 +60,22 @@ def __init__(self):
def parse(self, name, value, params):
if name == '-c':
params.char_set = fnutil.parse_dec('charset', value, 0, 255)
params.char_set = fnutil.parse_dec('CHARSET', value, 0, 255)
elif name == '-m':
params.min_char = fnutil.parse_dec('minchar', value, 0, 255)
params.min_char = fnutil.parse_dec('MINCHAR', value, 0, 255)
elif name == '-f':
if value in FNT_FAMILIES:
params.fnt_family = FNT_FAMILIES.index(value)
else:
raise Exception('invalid fnt family')
raise Exception('invalid FAMILY')
elif name == '-o':
params.output = value
params.output_name = value
else:
self.fallback(name, params)
WIN_FONTHEADERSIZE = 118
# -- Main --
FNT_HEADER_SIZE = 118
FNT_CHARSETS = [238, 204, 0, 161, 162, 177, 178, 186, 163]
def main_program(nonopt, parsed):
@ -80,13 +86,8 @@ def main_program(nonopt, parsed):
min_char = parsed.min_char
# READ INPUT
ifs = fnio.InputStream(nonopt[0] if nonopt else None)
try:
font = bmpf.Font.read(ifs)
ifs.close()
except Exception as ex:
raise Exception(ifs.location() + str(ex))
ifs = fnio.InputFileStream(nonopt[0] if nonopt else None)
font = ifs.process(bdfexp.Font.read)
# COMPUTE
if char_set == -1:
@ -115,15 +116,15 @@ def main_program(nonopt, parsed):
raise Exception('the maximum character code is too big, (re)specify -m')
# HEADER
vtell = WIN_FONTHEADERSIZE + (num_chars + 1) * 4
vtell = FNT_HEADER_SIZE + (num_chars + 1) * 4
bits_offset = vtell
ctable = []
width_bytes = 0
# CTABLE/GLYPHS
for char in font.chars:
row_size = char.row_size()
ctable.append(char.width)
row_size = char.bbx.row_size()
ctable.append(char.bbx.width)
ctable.append(vtell)
vtell += row_size * font.bbx.height
width_bytes += row_size
@ -142,43 +143,38 @@ def main_program(nonopt, parsed):
raise Exception('the total character width is too big')
except Exception as ex:
raise Exception(ifs.location() + str(ex))
ex.message = ifs.location() + getattr(ex, 'message', str(ex))
raise
# WRITE
ofs = fnio.OutputStream(parsed.output)
if ofs.file.isatty():
raise Exception('binary output may not be send to a terminal, use -o or redirect/pipe it')
try:
def write_fnt(output):
# HEADER
family = font.xlfd[bdf.XLFD.FAMILY_NAME]
copyright = font.props.get('COPYRIGHT')
copyright = fnutil.unquote(copyright)[:60] if copyright is not None else b''
proportional = font.get_proportional()
ofs.write16(0x0200) # font version
ofs.write32(vtell + len(family) + 1) # total size
ofs.write_zstr(copyright, 60 - len(copyright))
ofs.write16(0) # gdi, device type
ofs.write16(round(font.bbx.height * 72 / 96))
ofs.write16(96) # vertical resolution
ofs.write16(96) # horizontal resolution
ofs.write16(font.get_ascent()) # base line
ofs.write16(0) # internal leading
ofs.write16(0) # external leading
ofs.write8(font.get_italic())
ofs.write8(0) # underline
ofs.write8(0) # strikeout
ofs.write16(400 + 300 * font.get_bold())
ofs.write8(char_set)
ofs.write16(0 if proportional else font.bbx.width)
ofs.write16(font.bbx.height)
ofs.write8((parsed.fnt_family << 4) + proportional)
ofs.write16(font.avg_width)
ofs.write16(font.bbx.width)
ofs.write8(min_char)
ofs.write8(max_char)
output.write16(0x0200) # font version
output.write32(vtell + len(family) + 1) # total size
output.write_zstr(copyright, 60 - len(copyright))
output.write16(0) # gdi, device type
output.write16(round(font.bbx.height * 72 / 96))
output.write16(96) # vertical resolution
output.write16(96) # horizontal resolution
output.write16(font.px_ascender) # base line
output.write16(0) # internal leading
output.write16(0) # external leading
output.write8(int(font.italic))
output.write8(0) # underline
output.write8(0) # strikeout
output.write16(700 if font.bold else 400)
output.write8(char_set)
output.write16(0 if font.proportional else font.bbx.width)
output.write16(font.bbx.height)
output.write8((parsed.fnt_family << 4) + int(font.proportional))
output.write16(font.avg_width)
output.write16(font.bbx.width)
output.write8(min_char)
output.write8(max_char)
default_index = max_char - min_char
break_index = 0
@ -189,39 +185,37 @@ def main_program(nonopt, parsed):
if min_char <= 0x20 <= max_char:
break_index = 0x20 - min_char
ofs.write8(default_index)
ofs.write8(break_index)
ofs.write16(width_bytes)
ofs.write32(0) # device name
ofs.write32(vtell)
ofs.write32(0) # gdi bits pointer
ofs.write32(bits_offset)
ofs.write8(0) # reserved
output.write8(default_index)
output.write8(break_index)
output.write16(width_bytes)
output.write32(0) # device name
output.write32(vtell)
output.write32(0) # gdi bits pointer
output.write32(bits_offset)
output.write8(0) # reserved
# CTABLE
for value in ctable:
ofs.write16(value)
output.write16(value)
# GLYPHS
data = bytearray(font.bbx.height * font.bbx.row_size())
for char in font.chars:
row_size = char.row_size()
row_size = char.bbx.row_size()
counter = 0
# MS coordinates
for n in range(0, row_size):
for y in range(0, font.bbx.height):
data[counter] = char.data[row_size * y + n]
counter += 1
ofs.write(data[:counter])
ofs.write(bytes(sentinel * font.bbx.height))
output.write(data[:counter])
output.write(bytes(sentinel * font.bbx.height))
# FAMILY
ofs.write_zstr(family, 1)
ofs.close()
output.write_zstr(family, 1)
except Exception as ex:
raise Exception(ofs.location() + str(ex) + ofs.destroy())
fnio.write_file(parsed.output_name, write_fnt, encoding=None)
if __name__ == '__main__':

View File

@ -1,27 +1,29 @@
//
// Copyright (c) 2019 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
/*
Copyright (C) 2017-2019 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at your option)
any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
'use strict';
const tty = require('tty');
const fnutil = require('./fnutil.js');
const fncli = require('./fncli.js');
const fnio = require('./fnio.js');
const bmpf = require('./bmpf.js');
const bdfexp = require('./bdfexp.js');
// -- Params --
class Params extends fncli.Params {
constructor() {
super();
@ -31,7 +33,7 @@ class Params extends fncli.Params {
}
}
// -- Options --
const HELP = ('' +
'usage: bdftopsf [-1|-2|-r] [-g|-G] [-o OUTPUT] [INPUT.bdf] [TABLE...]\n' +
'Convert a BDF font to PC Screen Font or raw font\n' +
@ -42,7 +44,7 @@ const HELP = ('' +
' 192...223 (default for VGA text mode compliant PSF fonts\n' +
' with 224 to 512 characters starting with unicode 00A3)\n' +
' -G do not exchange characters 0...31 and 192...223\n' +
' -o OUTPUT output file (default = stdout, must not be a terminal)\n' +
' -o OUTPUT output file (default = stdout, may not be a terminal)\n' +
' --help display this help and exit\n' +
' --version display the program version and license, and exit\n' +
' --excstk display the exception stack on error\n' +
@ -54,7 +56,7 @@ const HELP = ('' +
'are stored sequentially in the PSF unicode table for their character.\n' +
'<ss> is always specified as FFFE, although it is stored as FE in PSF2.\n');
const VERSION = 'bdftopsf 1.50, Copyright (C) 2019 Dimitar Toshkov Zhekov\n\n' + fnutil.GPL2PLUS_VERSION;
const VERSION = 'bdftopsf 1.58, Copyright (C) 2017-2019 Dimitar Toshkov Zhekov\n\n' + fnutil.GPL2PLUS_VERSION;
class Options extends fncli.Options {
constructor() {
@ -87,7 +89,7 @@ class Options extends fncli.Options {
}
}
// -- Main --
function mainProgram(nonopt, parsed) {
const bdfile = nonopt.length > 0 && nonopt[0].toLowerCase().endsWith('.bdf');
let version = parsed.version;
@ -95,16 +97,16 @@ function mainProgram(nonopt, parsed) {
let ver1Unicodes = true;
// READ INPUT
let ifs = new fnio.InputStream(bdfile ? nonopt[0] : null);
let ifs = new fnio.InputFileStream(bdfile ? nonopt[0] : null);
try {
var font = bmpf.Font.read(ifs);
var font = bdfexp.Font.read(ifs);
ifs.close();
font.chars.forEach(char => {
const prefix = `char ${char.code}: `;
if (char.width !== font.bbx.width) {
if (char.bbx.width !== font.bbx.width) {
throw new Error(prefix + 'output width not equal to maximum output width');
}
if (char.code === 65534) {
@ -165,7 +167,7 @@ function mainProgram(nonopt, parsed) {
}
if (font.chars.findIndex(char => char.code === uni) !== -1) {
if (uni >= 0x10000) {
if (uni > fnutil.UNICODE_BMP_MAX) {
ver1Unicodes = false;
}
if (table == null) {
@ -178,7 +180,7 @@ function mainProgram(nonopt, parsed) {
if (dup === 0xFFFF) {
throw new Error('FFFF is not a character');
}
if (dup >= 0x10000) {
if (dup > fnutil.UNICODE_BMP_MAX) {
ver1Unicodes = false;
}
if (table.indexOf(dup) === -1 || table.indexOf(0xFFFE) !== -1) {
@ -186,13 +188,13 @@ function mainProgram(nonopt, parsed) {
}
});
if (version === 1 && !ver1Unicodes) {
throw new Error('-1 requires unicodes <= FFFF');
throw new Error('-1 requires unicodes <= ' + fnutil.UNICODE_BMP_MAX.toString(16));
}
}
}
nonopt.slice(Number(bdfile)).forEach(name => {
ifs = new fnio.InputStream(name);
ifs = new fnio.InputFileStream(name);
try {
ifs.readLines(loadExtra);
@ -219,11 +221,7 @@ function mainProgram(nonopt, parsed) {
}
// WRITE
let ofs = new fnio.OutputStream(parsed.output);
if (tty.isatty(ofs.fd)) {
throw new Error('binary output may not be send to a terminal, use -o or redirect/pipe it');
}
let ofs = new fnio.OutputFileStream(parsed.output, null);
try {
// HEADER
@ -290,7 +288,6 @@ function mainProgram(nonopt, parsed) {
}
}
if (require.main === module) {
fncli.start('bdftopsf.js', new Options(), new Params(), mainProgram);
}

View File

@ -1,33 +1,36 @@
#
# Copyright (c) 2019 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
# Copyright (C) 2017-2020 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of
# the License, or (at your option) any later version.
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
import re
import fnutil
import fncli
import fnio
import bmpf
import bdfexp
# -- Params --
class Params(fncli.Params):
def __init__(self):
fncli.Params.__init__(self)
self.version = -1
self.exchange = -1
self.output = None
self.output_name = None
# -- Options --
HELP = ('' +
'usage: bdftopsf [-1|-2|-r] [-g|-G] [-o OUTPUT] [INPUT.bdf] [TABLE...]\n' +
'Convert a BDF font to PC Screen Font or raw font\n' +
@ -38,7 +41,7 @@ def __init__(self):
' 192...223 (default for VGA text mode compliant PSF fonts\n' +
' with 224 to 512 characters starting with unicode 00A3)\n' +
' -G do not exchange characters 0...31 and 192...223\n' +
' -o OUTPUT output file (default = stdout, must not be a terminal)\n' +
' -o OUTPUT output file (default = stdout, may not be a terminal)\n' +
' --help display this help and exit\n' +
' --version display the program version and license, and exit\n' +
' --excstk display the exception stack on error\n' +
@ -50,7 +53,7 @@ def __init__(self):
'are stored sequentially in the PSF unicode table for their character.\n' +
'<ss> is always specified as FFFE, although it is stored as FE in PSF2.\n')
VERSION = 'bdftopsf 1.50, Copyright (C) 2019 Dimitar Toshkov Zhekov\n\n' + fnutil.GPL2PLUS_LICENSE
VERSION = 'bdftopsf 1.62, Copyright (C) 2017-2020 Dimitar Toshkov Zhekov\n\n' + fnutil.GPL2PLUS_LICENSE
class Options(fncli.Options):
def __init__(self):
@ -67,11 +70,12 @@ def parse(self, name, value, params):
elif name == '-G':
params.exchange = False
elif name == '-o':
params.output = value
params.output_name = value
else:
self.fallback(name, params)
# -- Main --
def main_program(nonopt, parsed):
version = parsed.version
exchange = parsed.exchange
@ -79,16 +83,14 @@ def main_program(nonopt, parsed):
ver1_unicodes = True
# READ INPUT
ifs = fnio.InputStream(nonopt[0] if bdfile else None)
ifs = fnio.InputFileStream(nonopt[0] if bdfile else None)
font = ifs.process(bdfexp.Font.read)
try:
font = bmpf.Font.read(ifs)
ifs.close()
for char in font.chars:
prefix = 'char %d: ' % char.code
if char.width != font.bbx.width:
if char.bbx.width != font.bbx.width:
raise Exception(prefix + 'output width not equal to maximum output width')
if char.code == 65534:
@ -121,15 +123,15 @@ def main_program(nonopt, parsed):
raise Exception('-g/--vga requires an 8x8, 8x14 or 8x16 font')
except Exception as ex:
raise Exception(ifs.location() + str(ex))
ex.message = ifs.location() + getattr(ex, 'message', str(ex))
raise
# READ TABLES
tables = dict()
def load_extra(line):
nonlocal ver1_unicodes
words = re.split(br'\s+', line)
words = line.split()
if len(words) < 2:
raise Exception('invalid format')
@ -140,7 +142,7 @@ def load_extra(line):
raise Exception('FFFE is not a character')
if next((char for char in font.chars if char.code == uni), None):
if uni >= 0x10000:
if uni > fnutil.UNICODE_BMP_MAX:
ver1_unicodes = False
if uni not in tables:
@ -154,23 +156,17 @@ def load_extra(line):
if dup == 0xFFFF:
raise Exception('FFFF is not a character')
if dup >= 0x10000:
if dup > fnutil.UNICODE_BMP_MAX:
ver1_unicodes = False
if not dup in table or 0xFFFE in table:
tables[uni].append(dup)
if version == 1 and not ver1_unicodes:
raise Exception('-1 requires unicodes <= FFFF')
raise Exception('-1 requires unicodes <= %X' % fnutil.UNICODE_BMP_MAX)
for name in nonopt[int(bdfile):]:
ifs = fnio.InputStream(name)
try:
ifs.read_lines(load_extra)
ifs.close()
except Exception as ex:
raise Exception(ifs.location() + str(ex))
for table_name in nonopt[int(bdfile):]:
fnio.read_file(table_name, lambda ifs: ifs.read_lines(load_extra))
# VERSION
if version == -1:
@ -184,54 +180,49 @@ def load_extra(line):
font.chars = font.chars[192:224] + font.chars[32:192] + font.chars[0:32] + font.chars[224:]
# WRITE
ofs = fnio.OutputStream(parsed.output)
if ofs.file.isatty():
raise Exception('binary output may not be send to a terminal, use -o or redirect/pipe it')
try:
def write_psf(output):
# HEADER
if version == 1:
ofs.write8(0x36)
ofs.write8(0x04)
ofs.write8((len(font.chars) >> 8) + 1)
ofs.write8(font.bbx.height)
output.write8(0x36)
output.write8(0x04)
output.write8((len(font.chars) >> 8) + 1)
output.write8(font.bbx.height)
elif version == 2:
ofs.write32(0x864AB572)
ofs.write32(0x00000000)
ofs.write32(0x00000020)
ofs.write32(0x00000001)
ofs.write32(len(font.chars))
ofs.write32(len(font.chars[0].data))
ofs.write32(font.bbx.height)
ofs.write32(font.bbx.width)
output.write32(0x864AB572)
output.write32(0x00000000)
output.write32(0x00000020)
output.write32(0x00000001)
output.write32(len(font.chars))
output.write32(len(font.chars[0].data))
output.write32(font.bbx.height)
output.write32(font.bbx.width)
# GLYPHS
for char in font.chars:
ofs.write(char.data)
output.write(char.data)
# UNICODES
if version > 0:
def write_unicode(code):
if version == 1:
ofs.write16(code)
output.write16(code)
elif code <= 0x7F:
ofs.write8(code)
output.write8(code)
elif code in [0xFFFE, 0xFFFF]:
ofs.write8(code & 0xFF)
output.write8(code & 0xFF)
else:
if code <= 0x7FF:
ofs.write8(0xC0 + (code >> 6))
output.write8(0xC0 + (code >> 6))
else:
if code <= 0xFFFF:
ofs.write8(0xE0 + (code >> 12))
output.write8(0xE0 + (code >> 12))
else:
ofs.write8(0xF0 + (code >> 18))
ofs.write8(0x80 + ((code >> 12) & 0x3F))
output.write8(0xF0 + (code >> 18))
output.write8(0x80 + ((code >> 12) & 0x3F))
ofs.write8(0x80 + ((code >> 6) & 0x3F))
output.write8(0x80 + ((code >> 6) & 0x3F))
ofs.write8(0x80 + (code & 0x3F))
output.write8(0x80 + (code & 0x3F))
for char in font.chars:
if char.code != 0xFFFF:
@ -243,11 +234,7 @@ def write_unicode(code):
write_unicode(0xFFFF)
# FINISH
ofs.close()
except Exception as ex:
raise Exception(ofs.location() + str(ex) + ofs.destroy())
fnio.write_file(parsed.output_name, write_psf, encoding=None)
if __name__ == '__main__':

View File

@ -1,159 +0,0 @@
//
// Copyright (c) 2018 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
'use strict';
const fnutil = require('./fnutil.js');
const bdf = require('./bdf.js');
class Char {
constructor(code, name, width, data) {
this.code = code;
this.name = name;
this.width = width;
this.data = data;
}
static from(char, fbbox) {
const deltaYOff = char.bbx.yoff - fbbox.yoff; // ~DSB
let width;
let dstXOff;
if (char.dwidth.x >= 0) {
if (char.bbx.xoff >= 0) {
width = Math.max(char.bbx.width + char.bbx.xoff, char.dwidth.x);
dstXOff = char.bbx.xoff;
} else {
width = Math.max(char.bbx.width, char.dwidth.x - char.bbx.xoff);
dstXOff = 0;
}
} else {
dstXOff = Math.max(char.bbx.xoff - char.dwidth.x, 0);
width = char.bbx.width + dstXOff;
}
if (width > bdf.WIDTH_MAX) {
throw new Error(`char ${char.code}: output width > ${bdf.WIDTH_MAX}`);
}
if (char.bbx.yoff < fbbox.yoff) {
throw new Error(`char ${char.code}: BBX yoff < FONTBOUNDINGBOX yoff`);
}
const height = fbbox.height;
const srcRowSize = char.bbx.rowSize();
const dstRowSize = (width + 7) >> 3;
const dstYMax = height - deltaYOff;
const dstYMin = dstYMax - char.bbx.height;
const compatRow = dstXOff === 0 && width >= char.bbx.width;
let data;
if (compatRow && srcRowSize === dstRowSize && dstYMin === 0 && dstYMax === height) {
data = char.data;
} else if (dstYMin < 0) {
throw new Error(`char ${char.code}: start row ${dstYMin}`);
} else {
data = Buffer.alloc(dstRowSize * height);
for (let dstY = dstYMin; dstY < dstYMax; dstY++) {
let srcByteNo = (dstY - dstYMin) * srcRowSize;
let dstByteNo = dstY * dstRowSize + (dstXOff >> 3);
if (compatRow) {
char.data.copy(data, dstByteNo, srcByteNo, srcByteNo + srcRowSize);
} else {
let srcBitNo = 7;
let dstBitNo = 7 - (dstXOff & 7);
for (let x = 0; x < char.bbx.width; x++) {
if (char.data[srcByteNo] & (1 << srcBitNo)) {
data[dstByteNo] |= (1 << dstBitNo);
}
if (--srcBitNo < 0) {
srcBitNo = 7;
srcByteNo++;
}
if (--dstBitNo < 0) {
dstBitNo = 7;
dstByteNo++;
}
}
}
}
}
return new Char(char.code, char.props.get('STARTCHAR'), width, data);
}
packedSize() {
return (this.width * (this.data.length / this.rowSize()) + 7) >> 3;
}
rowSize() {
return (this.width + 7) >> 3;
}
write(output, height, yoffset) {
let header = `STARTCHAR ${this.name}\nENCODING ${this.code}\n`;
const swidth = fnutil.round(this.width * 1000 / height);
header += `SWIDTH ${swidth} 0\nDWIDTH ${this.width} 0\nBBX ${this.width} ${height} 0 ${yoffset}\n`;
output.writeLine(header + 'BITMAP\n' + bdf.Char.bitmap(this.data, this.rowSize()) + 'ENDCHAR');
}
}
class Font extends bdf.Font {
constructor() {
super();
this.minWidth = bdf.WIDTH_MAX;
this.avgWidth = 0;
}
_read(input) {
let totalWidth = 0;
super._read(input);
this.chars = this.chars.map(char => Char.from(char, this.bbx));
this.bbx.xoff = 0;
this.chars.forEach(char => {
this.minWidth = Math.min(this.minWidth, char.width);
this.bbx.width = Math.max(this.bbx.width, char.width);
totalWidth += char.width;
});
this.avgWidth = fnutil.round(totalWidth / this.chars.length);
this.props.set('FONTBOUNDINGBOX', this.bbx.toString());
return this;
}
static read(input) {
return (new Font())._read(input);
}
getProportional() {
return Number(this.bbx.width > this.minWidth);
}
write(output) {
this.props.forEach((name, value) => output.writeProp(name, value));
this.chars.forEach(char => char.write(output, this.bbx.height, this.bbx.yoff));
output.writeLine('ENDFONT');
}
}
module.exports = Object.freeze({
Char,
Font
});

View File

@ -1,147 +0,0 @@
#
# Copyright (c) 2018 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of
# the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
import bdf
class Char:
def __init__(self, code, name, width, data):
self.code = code
self.name = name
self.width = width
self.data = data
@staticmethod
def from_bdf(char, fbbox):
delta_yoff = char.bbx.yoff - fbbox.yoff # ~DSB
if delta_yoff < 0:
raise Exception('char %d: BBX yoff < FONTBOUNDINGBOX yoff' % char.code)
if char.dwidth.x >= 0:
if char.bbx.xoff >= 0:
width = max(char.bbx.width + char.bbx.xoff, char.dwidth.x)
dst_xoff = char.bbx.xoff
else:
width = max(char.bbx.width, char.dwidth.x - char.bbx.xoff)
dst_xoff = 0
else:
dst_xoff = max(char.bbx.xoff - char.dwidth.x, 0)
width = char.bbx.width + dst_xoff
if width > bdf.WIDTH_MAX:
raise Exception('char %d: output width > %d' % (char.code, bdf.WIDTH_MAX))
height = fbbox.height
src_row_size = char.bbx.row_size()
dst_row_size = (width + 7) >> 3
dst_ymax = height - delta_yoff
dst_ymin = dst_ymax - char.bbx.height
compat_row = dst_xoff == 0 and width >= char.bbx.width
if compat_row and src_row_size == dst_row_size and dst_ymin == 0 and dst_ymax == height:
data = char.data
elif dst_ymin < 0:
raise Exception('char %d: start row %d' % (char.code, dst_ymin))
elif compat_row:
src_byte_no = 0
data = bytearray(dst_ymin * dst_row_size)
line_fill = bytes(dst_row_size - src_row_size)
for dst_y in range(dst_ymin, dst_ymax):
data += char.data[src_byte_no : src_byte_no + src_row_size] + line_fill
src_byte_no += src_row_size
data += bytes(delta_yoff * dst_row_size)
else:
data = bytearray(dst_row_size * height)
for dst_y in range(dst_ymin, dst_ymax):
src_byte_no = (dst_y - dst_ymin) * src_row_size
dst_byte_no = dst_y * dst_row_size + (dst_xoff >> 3)
src_bit_no = 7
dst_bit_no = 7 - (dst_xoff & 7)
for _ in range(0, char.bbx.width):
if char.data[src_byte_no] & (1 << src_bit_no):
data[dst_byte_no] |= (1 << dst_bit_no)
if src_bit_no > 0:
src_bit_no -= 1
else:
src_bit_no = 7
src_byte_no += 1
if dst_bit_no > 0:
dst_bit_no -= 1
else:
dst_bit_no = 7
dst_byte_no += 1
return Char(char.code, char.props.get('STARTCHAR'), width, data)
def row_size(self):
return (self.width + 7) >> 3
def write(self, output, max_width, yoffset):
output.write_line(b'STARTCHAR %s\nENCODING %d' % (self.name, self.code))
output.write_line(b'SWIDTH %d 0\nDWIDTH %d 0' % (round(self.width * 1000 / max_width), self.width))
output.write_line(b'BBX %d %d 0 %d' % (self.width, len(self.data) / self.row_size(), yoffset))
output.write_line(b'BITMAP\n' + bdf.Char.bitmap(self.data, self.row_size()) + b'ENDCHAR')
class Font(bdf.Font):
def __init__(self):
bdf.Font.__init__(self)
self.min_width = bdf.WIDTH_MAX
self.avg_width = 0
def _read(self, input):
bdf.Font._read(self, input)
self.chars = [Char.from_bdf(char, self.bbx) for char in self.chars]
self.bbx.xoff = 0
total_width = 0
for char in self.chars:
self.min_width = min(self.min_width, char.width)
self.bbx.width = max(self.bbx.width, char.width)
total_width += char.width
self.avg_width = round(total_width / len(self.chars))
self.props.set('FONTBOUNDINGBOX', bytes(str(self.bbx), 'ascii'))
return self
@staticmethod
def read(input):
return Font()._read(input) # pylint: disable=protected-access
def get_proportional(self):
return int(self.bbx.width > self.min_width)
def write(self, output):
for [name, value] in self.props:
output.write_prop(name, value)
for char in self.chars:
char.write(output, self.bbx.width, self.bbx.yoff)
output.write_line(b'ENDFONT')

View File

@ -1,27 +1,31 @@
//
// Copyright (c) 2019 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
/*
Copyright (C) 2018-2020 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at your option)
any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
'use strict';
// -- Params --
class Params {
constructor() {
this.excstk = false;
}
}
// -- Options --
class Options {
constructor(needArgs, helpText, versionText) {
needArgs.forEach(name => {
@ -64,7 +68,6 @@ class Options {
}
}
Options.Reader = class {
constructor(options, args, skip) {
this.options = options;
@ -111,7 +114,7 @@ Options.Reader = class {
value = null;
}
if (value === null && Number(this.options.needsArg(name)) > 0) {
if (value == null && Number(this.options.needsArg(name)) > 0) {
if (++optind === this.args.length) {
throw new Error(`option "${name}" requires an argument`);
}
@ -128,9 +131,9 @@ Options.Reader = class {
Object.defineProperty(Options, 'Reader', { 'enumerable': false });
Object.defineProperty(Options.Reader, 'name', { value: 'Reader' });
// -- Main --
function start(programName, options, params, mainProgram) { // eslint-disable-line consistent-return
let parsed = (params != null) ? params : new Params();
const parsed = (params != null) ? params : new Params();
try {
const version = process.version.match(/^v?(\d+)\.(\d+)/);
@ -157,15 +160,19 @@ function start(programName, options, params, mainProgram) { // eslint-disable-l
}
} catch (e) {
if (parsed.excstk) {
if (e.stack != null) {
process.stderr.write(e.stack + '\n');
} else {
throw e;
}
} else {
process.stderr.write(`${process.argv.length >= 2 ? process.argv[1] : programName}: ${e.message}\n`);
process.exit(1);
}
process.exit(1);
}
}
// -- Exports --
module.exports = Object.freeze({
Params,
Options,

View File

@ -1,27 +1,32 @@
#
# Copyright (c) 2019 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
# Copyright (C) 2018-2020 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of
# the License, or (at your option) any later version.
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
import sys
import os
import re
# -- Params --
class Params:
def __init__(self):
self.excstk = False
# -- Options --
class Options:
def __init__(self, need_args, help_text, version_text):
for name in need_args:
@ -126,10 +131,12 @@ def __next__(self):
return (name, value)
# -- Main --
def start(program_name, options, params, main_program):
parsed = Params() if params is None else params
try:
if sys.hexversion < 0x3050000:
raise Exception('python 3.5.0 or later required')
@ -148,7 +155,8 @@ def start(program_name, options, params, main_program):
except Exception as ex:
if parsed.excstk:
raise
raise # loses the message information, but preserves the start() caller stack info
sys.stderr.write('%s: %s\n' % (sys.argv[0] if sys.argv[0] else program_name, str(ex)))
message = getattr(ex, 'message', str(ex))
sys.stderr.write('%s: %s\n' % (sys.argv[0] if sys.argv[0] else program_name, message))
sys.exit(1)

View File

@ -1,43 +1,31 @@
//
// Copyright (c) 2018 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
/*
Copyright (C) 2017-2020 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at your option)
any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
'use strict';
const tty = require('tty');
const fs = require('fs');
const BINARY_ENCODING = 'latin1';
(function() {
let orig = Buffer.alloc(256);
for (let i = 0; i < 256; i++) {
orig[i] = i;
}
const test = Buffer.from(orig.toString(BINARY_ENCODING), BINARY_ENCODING);
if (orig.compare(test) !== 0) {
throw new Error(`the ${BINARY_ENCODING} encoding is not 8-bit clean`);
}
})();
// -- InputFileStream --
const BLOCK_SIZE = 4096;
class InputStream {
constructor(fileName, encoding = BINARY_ENCODING) {
class InputFileStream {
constructor(fileName, encoding = 'binary') {
if (fileName != null) {
this.fd = fs.openSync(fileName, 'r');
this.stName = fileName;
@ -46,8 +34,7 @@ class InputStream {
this.stName = '<stdin>';
}
this.encoding = encoding;
this.lineNo = 0;
this.eof = false;
this.unseek();
this.lines = [];
this.index = 0;
this.buffer = Buffer.alloc(BLOCK_SIZE);
@ -55,11 +42,14 @@ class InputStream {
}
close() {
this.lineNo = 0;
this.eof = false;
this.unseek();
fs.closeSync(this.fd);
}
fstat() {
return (this.fd === process.stdin.fd || tty.isatty(this.fd)) ? null : fs.fstatSync(this.fd);
}
location() {
let location = ' ';
@ -81,8 +71,7 @@ class InputStream {
return 0;
}
if (e.code !== 'EAGAIN') {
this.lineNo = 0;
this.eof = false;
this.unseek();
throw e;
}
}
@ -125,11 +114,16 @@ class InputStream {
return line;
}
unseek() {
this.lineNo = 0;
this.eof = false;
}
}
class OutputStream {
constructor(fileName) {
// -- OutputFileStream --
class OutputFileStream {
constructor(fileName, encoding = 'binary') {
if (fileName != null) {
this.fd = fs.openSync(fileName, 'w');
this.stName = fileName;
@ -137,6 +131,10 @@ class OutputStream {
this.fd = process.stdout.fd;
this.stName = '<stdout>';
}
if (encoding == null && tty.isatty(this.fd)) {
throw new Error(this.location() + 'binary output may not be send to a terminal');
}
this.encoding = (encoding == null ? 'binary' : encoding);
this.fbbuf = Buffer.alloc(4);
this.closeAttempt = false;
}
@ -191,23 +189,22 @@ class OutputStream {
fs.writeSync(this.fd, this.fbbuf, 0, 4);
}
writeLine(bstr) {
fs.writeSync(this.fd, bstr + '\n', null, BINARY_ENCODING);
writeLine(text) {
fs.writeSync(this.fd, text + '\n', null, this.encoding);
}
writeProp(name, value) {
this.writeLine((name + ' ' + value).trim());
this.writeLine((name + ' ' + value).trimRight());
}
writeZStr(bstr, numZeros) {
fs.writeSync(this.fd, bstr, null, BINARY_ENCODING);
fs.writeSync(this.fd, bstr, null, 'binary');
this.write(Buffer.alloc(numZeros));
}
}
// -- Export --
module.exports = Object.freeze({
BINARY_ENCODING,
InputStream,
OutputStream
InputFileStream,
OutputFileStream
});

View File

@ -1,15 +1,19 @@
#
# Copyright (c) 2018 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
# Copyright (C) 2017-2020 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of
# the License, or (at your option) any later version.
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
import codecs
@ -17,42 +21,46 @@
import sys
import os
BINARY_ENCODING = '_fnio_binary'
class InputStream:
def __init__(self, file_name, encoding=BINARY_ENCODING):
# -- InputFileStream --
class InputFileStream:
def __init__(self, file_name, encoding='binary'):
if file_name is not None:
if encoding == BINARY_ENCODING:
self.file = open(file_name, 'rb')
else:
self.file = open(file_name, 'r', encoding=encoding)
self.file = open(file_name, 'r') if encoding is None else open(file_name, 'rb')
self.st_name = file_name
else:
if encoding == BINARY_ENCODING:
self.file = sys.stdin.buffer
elif encoding is None:
self.file = sys.stdin
else:
self.file = codecs.getreader(encoding)(sys.stdin.buffer)
self.file = sys.stdin if encoding is None else sys.stdin.buffer
self.st_name = '<stdin>'
if encoding not in [None, 'binary']:
self.file = codecs.getreader(encoding)(self.file)
self.line_no = 0
self.eof = False
def close(self):
self.line_no = 0
self.eof = False
self.unseek()
self.file.close()
def fstat(self):
return None if (self.file == sys.stdin.buffer or self.file.isatty()) else os.fstat(self.file.fileno())
def location(self):
return '%s:%s' % (self.st_name, 'EOF: ' if self.eof else '%d: ' % self.line_no if self.line_no > 0 else ' ')
def process(self, callback):
try:
result = callback(self)
self.close()
return result
except Exception as ex:
ex.message = self.location() + getattr(ex, 'message', str(ex))
raise
def read_line(self):
return self.read_lines(lambda line: line)
@ -66,16 +74,21 @@ def read_lines(self, callback):
if line is not None:
return line
except OSError:
self.line_no = 0
self.eof = False
self.unseek()
raise
self.eof = True
return None
class OutputStream:
def __init__(self, file_name):
def unseek(self):
self.line_no = 0
self.eof = False
# -- OutputFileStream --
class OutputFileStream:
def __init__(self, file_name, encoding='binary'):
if file_name is not None:
self.file = open(file_name, 'wb')
self.st_name = file_name
@ -83,59 +96,81 @@ def __init__(self, file_name):
self.file = sys.stdout.buffer
self.st_name = '<stdout>'
if encoding is None and self.file.isatty():
raise Exception(self.location() + 'binary output may not be send to a terminal')
self.encoding = (None if encoding == 'binary' else encoding)
self.close_attempt = False
def abort(self):
errors = ''
if self.file != sys.stdout.buffer:
if not self.close_attempt:
try:
self.close()
except Exception as ex:
errors += '\n%sclose: %s' % (self.location(), str(ex))
try:
os.remove(self.st_name)
except Exception as ex:
errors += '\n%sunlink: %s' % (self.location(), str(ex))
return errors
def close(self):
self.close_attempt = True
self.file.close()
def destroy(self):
errors = ''
if self.file != sys.stdout.buffer:
if not self.close_attempt:
try:
self.file.close()
except Exception as ex:
errors += '\n%s: close: %s' % (self.st_name, str(ex))
try:
os.remove(self.st_name)
except Exception as ex:
errors += '\n%s: unlink: %s' % (self.st_name, str(ex))
return errors
def location(self):
return self.st_name + ': '
def write(self, buffer):
self.file.write(buffer)
def process(self, callback):
try:
callback(self)
self.close()
except Exception as ex:
ex.message = self.location() + getattr(ex, 'message', str(ex)) + self.abort()
raise
def write(self, data):
self.file.write(data)
def write8(self, value):
self.file.write(struct.pack('B', value))
self.write(struct.pack('B', value))
def write16(self, value):
self.file.write(struct.pack('<H', value))
self.write(struct.pack('<H', value))
def write32(self, value):
self.file.write(struct.pack('<L', value))
self.write(struct.pack('<L', value))
def write_line(self, bstr):
self.file.write(bstr + b'\n')
def write_line(self, text):
self.write((text if self.encoding is None else bytes(text, self.encoding)) + b'\n')
def write_prop(self, name, value):
self.write_line((bytes(name, 'ascii') + b' ' + value).strip())
self.write_line((bytes(name, 'ascii') + b' ' + value).rstrip())
def write_zstr(self, bstr, num_zeros):
self.file.write(bstr + bytes(num_zeros))
self.write(bstr + bytes(num_zeros))
# -- read/write file --
def read_file(file_name, callback, encoding='binary'):
return InputFileStream(file_name, encoding).process(callback)
def write_file(file_name, callback, encoding='binary'):
return OutputFileStream(file_name, encoding).process(callback)

View File

@ -1,21 +1,26 @@
//
// Copyright (c) 2018 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
/*
Copyright (C) 2017-2019 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at your option)
any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
'use strict';
// -- Various --
const UNICODE_MAX = 1114111; // 0x10FFFF
const UNICODE_BMP_MAX = 65535; // 0xFFFF
function parseDec(name, s, minValue = 0, maxValue = UNICODE_MAX) {
if (s.match(/^\s*-?\d+\s*$/) == null) {
@ -56,9 +61,9 @@ function unihex(code) {
}
function round(value) {
let result = Math.round(value);
const esround = Math.round(value);
return result - Number(result % 2 !== 0 && result - value === 0.5);
return esround - Number(esround % 2 !== 0 && esround - value === 0.5);
}
function quote(s) {
@ -75,13 +80,12 @@ function unquote(s, name) {
return s;
}
function warning(prefix, message) {
if (prefix.endsWith(':')) {
prefix += ' ';
} else if (prefix.length > 0 && !prefix.endsWith(': ')) {
prefix += ': ';
}
process.stderr.write(`${prefix}warning: ${message}\n`);
function message(prefix, severity, text) {
process.stderr.write(`${prefix}${severity ? severity + ': ' : ''}${text}\n`);
}
function warning(prefix, text) {
message(prefix, 'warning', text);
}
function splitWords(name, value, count) {
@ -95,25 +99,31 @@ function splitWords(name, value, count) {
}
const GPL2PLUS_LICENSE = ('' +
'This program is free software; you can redistribute it and/or\n' +
'modify it under the terms of the GNU General Public License as\n' +
'published by the Free Software Foundation; either version 2 of\n' +
'the License, or (at your option) any later version.\n' +
'This program is free software; you can redistribute it and/or modify it\n' +
'under the terms of the GNU General Public License as published by the Free\n' +
'Software Foundation; either version 2 of the License, or (at your option)\n' +
'any later version.\n' +
'\n' +
'This program is distributed in the hope that it will be useful,\n' +
'but WITHOUT ANY WARRANTY; without even the implied warranty of\n' +
'MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n' +
'GNU General Public License for more details.\n');
'This program is distributed in the hope that it will be useful, but\n' +
'WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\n' +
'or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License\n' +
'for more details.\n' +
'\n' +
'You should have received a copy of the GNU General Public License along\n' +
'with this program; if not, write to the Free Software Foundation, Inc.,\n' +
'51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n');
// -- Exports --
module.exports = Object.freeze({
UNICODE_MAX,
UNICODE_BMP_MAX,
parseDec,
parseHex,
unihex,
round,
quote,
unquote,
message,
warning,
splitWords,
GPL2PLUS_LICENSE

View File

@ -1,23 +1,26 @@
#
# Copyright (c) 2018 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
# Copyright (C) 2017-2020 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of
# the License, or (at your option) any later version.
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
import sys
import re
# -- Various --
UNICODE_MAX = 1114111 # 0x10FFFF
UNICODE_BMP_MAX = 65535 # 0xFFFF
def parse_dec(name, s, min_value=0, max_value=UNICODE_MAX):
try:
@ -62,17 +65,16 @@ def unquote(bstr, name=None):
return bstr
def warning(prefix, message):
if prefix.endswith(':'):
prefix += ' '
elif prefix and not prefix.endswith(': '):
prefix += ': '
sys.stderr.write('%swarning: %s\n' % (prefix, message))
def message(prefix, severity, text):
sys.stderr.write('%s%s%s\n' % (prefix, severity + ': ' if severity else '', text))
def split_words(name, bstr, count):
words = re.split(br'\s+', bstr, count)
def warning(prefix, text):
message(prefix, 'warning', text)
def split_words(name, value, count):
words = value.split(None, count)
if len(words) != count:
raise Exception('%s must contain %d values' % (name, count))
@ -81,12 +83,16 @@ def split_words(name, bstr, count):
GPL2PLUS_LICENSE = ('' +
'This program is free software; you can redistribute it and/or\n' +
'modify it under the terms of the GNU General Public License as\n' +
'published by the Free Software Foundation; either version 2 of\n' +
'the License, or (at your option) any later version.\n' +
'This program is free software; you can redistribute it and/or modify it\n' +
'under the terms of the GNU General Public License as published by the Free\n' +
'Software Foundation; either version 2 of the License, or (at your option)\n' +
'any later version.\n' +
'\n' +
'This program is distributed in the hope that it will be useful,\n' +
'but WITHOUT ANY WARRANTY; without even the implied warranty of\n' +
'MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n' +
'GNU General Public License for more details.\n')
'This program is distributed in the hope that it will be useful, but\n' +
'WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\n' +
'or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License\n' +
'for more details.\n' +
'\n' +
'You should have received a copy of the GNU General Public License along\n' +
'with this program; if not, write to the Free Software Foundation, Inc.,\n' +
'51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n')

129
bin/otb1cli.js Normal file
View File

@ -0,0 +1,129 @@
/*
Copyright (C) 2018-2020 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at your option)
any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
'use strict';
const fnutil = require('./fnutil.js');
const fncli = require('./fncli.js');
const fnio = require('./fnio.js');
const otb1exp = require('./otb1exp.js');
// -- Params --
class Params extends otb1exp.Params {
constructor() {
super();
this.output = null;
this.encoding = 'utf-8';
this.realTime = true;
}
}
// -- Options --
const HELP = ('' +
'usage: otb1cli [options] [INPUT]\n' +
'Convert a BDF font to OTB\n' +
'\n' +
' -o OUTPUT output file (default = stdout, may not be a terminal)\n' +
' -d DIR-HINT set font direction hint (default = 0)\n' +
' -e EM-SIZE set em size (default = 1024)\n' +
' -g LINE-GAP set line gap (default = 0)\n' +
' -l LOW-PPEM set lowest recorded PPEM (default = font height)\n' +
' -E ENCODING BDF string properties encoding (default = utf-8)\n' +
' -W WLANG-ID set Windows name-s language ID (default = 0x0409)\n' +
' -T use the current date and time for created/modified\n' +
' (default = get them from INPUT if not stdin/terminal)\n' +
' -X set xMaxExtent = 0 (default = max character width)\n' +
' -L write a single loca entry (default = CHARS entries)\n' +
' -P write PostScript glyph names (default = no names)\n' +
'\n' +
'Notes:\n' +
' The input must be a BDF 2.1 font with unicode encoding.\n' +
' All bitmaps are expanded first. Bitmap widths are used.\n' +
' Overlapping characters are not supported.\n');
const VERSION = 'otb1cli 0.22, Copyright (C) 2018-2020 Dimitar Toshkov Zhekov\n\n' + fnutil.GPL2PLUS_LICENSE;
class Options extends otb1exp.Options {
constructor() {
super(['-o', '-E'], HELP, VERSION);
}
parse(name, value, params) {
switch (name) {
case '-o':
params.output = value;
break;
case '-E':
params.encoding = value;
break;
case '-T':
params.realTime = false;
break;
default:
super.parse(name, value, params);
}
}
}
// -- Main --
function mainProgram(nonopt, parsed) {
if (nonopt.length > 1) {
throw new Error('invalid number of arguments, try --help');
}
// READ INPUT
let ifs = new fnio.InputFileStream(nonopt[0], parsed.encoding);
try {
if (parsed.realTime) {
try {
const stat = ifs.fstat();
if (stat != null) {
parsed.created = stat.birthtime;
parsed.modified = stat.mtime;
}
} catch (e) {
fnutil.warning(ifs.location(), e.message);
}
}
var font = otb1exp.Font.read(ifs, parsed);
ifs.close();
} catch (e) {
e.message = ifs.location() + e.message;
throw e;
}
// WRITE OUTPUT
let ofs = new fnio.OutputFileStream(parsed.output, null);
try {
const table = new otb1exp.SFNT(font);
ofs.write(table.data.slice(0, table.size));
ofs.close();
} catch (e) {
e.message = ofs.location() + e.message + ofs.destroy();
throw e;
}
}
if (require.main === module) {
fncli.start('otb1cli.js', new Options(), new Params(), mainProgram);
}

99
bin/otb1cli.py Normal file
View File

@ -0,0 +1,99 @@
#
# Copyright (C) 2018-2020 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
from datetime import datetime, timezone
import fnutil
import fncli
import fnio
import otb1exp
# -- Params --
class Params(otb1exp.Params):
def __init__(self):
otb1exp.Params.__init__(self)
self.output_name = None
self.real_time = True
# -- Options --
HELP = ('' +
'usage: otb1cli [options] [INPUT]\n' +
'Convert a BDF font to OTB\n' +
'\n' +
' -o OUTPUT output file (default = stdout, may not be a terminal)\n' +
' -d DIR-HINT set font direction hint (default = 0)\n' +
' -e EM-SIZE set em size (default = 1024)\n' +
' -g LINE-GAP set line gap (default = 0)\n' +
' -l LOW-PPEM set lowest recorded PPEM (default = font height)\n' +
' -E ENCODING BDF string properties encoding (default = utf-8)\n' +
' -W WLANG-ID set Windows name-s language ID (default = 0x0409)\n' +
' -T use the current date and time for created/modified\n' +
' (default = get them from INPUT if not stdin/terminal)\n' +
' -X set xMaxExtent = 0 (default = max character width)\n' +
' -L write a single loca entry (default = CHARS entries)\n' +
' -P write PostScript glyph names (default = no names)\n' +
'\n' +
'Notes:\n' +
' The input must be a BDF 2.1 font with unicode encoding.\n' +
' All bitmaps are expanded first. Bitmap widths are used.\n' +
' Overlapping characters are not supported.\n')
VERSION = 'otb1cli 0.24, Copyright (C) 2018-2020 Dimitar Toshkov Zhekov\n\n' + fnutil.GPL2PLUS_LICENSE
class Options(otb1exp.Options):
def __init__(self):
otb1exp.Options.__init__(self, ['-o'], HELP, VERSION)
def parse(self, name, value, params):
if name == '-o':
params.output_name = value
elif name == '-T':
params.real_time = False
else:
otb1exp.Options.parse(self, name, value, params)
# -- Main --
def main_program(nonopt, parsed):
if len(nonopt) > 1:
raise Exception('invalid number of arguments, try --help')
# READ INPUT
def read_otb(ifs):
if parsed.real_time:
try:
stat = ifs.fstat()
if stat:
parsed.created = datetime.fromtimestamp(stat.st_ctime, timezone.utc)
parsed.modified = datetime.fromtimestamp(stat.st_mtime, timezone.utc)
except Exception as ex:
fnutil.warning(ifs.location(), str(ex))
return otb1exp.Font.read(ifs, parsed)
font = fnio.read_file(nonopt[0] if nonopt else None, read_otb)
# WRITE OUTPUT
sfnt = otb1exp.SFNT(font)
fnio.write_file(parsed.output_name, lambda ofs: ofs.write(sfnt.data), encoding=None)
if __name__ == '__main__':
fncli.start('otb1cli.py', Options(), Params(), main_program)

895
bin/otb1exp.js Normal file
View File

@ -0,0 +1,895 @@
/*
Copyright (C) 2017-2020 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at your option)
any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
'use strict';
const fnutil = require('./fnutil.js');
const fncli = require('./fncli.js');
const bdf = require('./bdf.js');
const bdfexp = require('./bdfexp.js');
const otb1get = require('./otb1get.js');
// -- Table --
const TS_EMPTY = 0;
const TS_SMALL = 64;
const TS_LARGE = 1024;
class Table {
constructor(size, name) {
this.data = Buffer.alloc(size);
this.size = 0;
this.tableName = name;
}
checkSize(size) {
if (size !== this.size) {
throw new Error(`internal error: ${this.tableName} size = ${this.size} instead of ${size}`);
}
}
checksum() {
let cksum = 0;
for (let offset = 0; offset < this.size; offset += 4) {
cksum += this.data.readUInt32BE(offset);
}
return cksum >>> 0;
}
ensure(count) {
if (this.size + count > this.data.length) {
let newSize = this.data.length << 1;
while (this.size + count > newSize) {
newSize <<= 1;
}
const newData = Buffer.alloc(newSize);
this.data.copy(newData, 0, 0, this.size);
this.data = newData;
}
}
get padding() {
return ((this.size + 1) & 3) ^ 1;
}
rewriteUInt32(value, offset) {
this.data.writeUInt32BE(value, offset);
}
write(buffer) {
this.ensure(buffer.length);
buffer.copy(this.data, this.size);
this.size += buffer.length;
}
writeRC(size, writer, name) {
this.ensure(size);
try {
writer(this.size);
} catch (e) {
e.message = e.message.replace('"value"', `"${this.tableName}.${name}"`);
throw e;
}
this.size += size;
}
writeInt8(value, name) {
this.writeRC(1, (offset) => this.data.writeInt8(value, offset), name);
}
writeInt16(value, name) {
this.writeRC(2, (offset) => this.data.writeInt16BE(value, offset), name);
}
writeInt32(value, name) {
this.writeRC(4, (offset) => this.data.writeInt32BE(value, offset), name);
}
writeInt64(value, name) {
this.writeRC(8, (offset) => this.data.writeInt64BE(value, offset), name);
}
writeUInt8(value, name) {
this.writeRC(1, (offset) => this.data.writeUInt8(value, offset), name);
}
writeUInt16(value, name) {
this.writeRC(2, (offset) => this.data.writeUInt16BE(value, offset), name);
}
writeUInt32(value, name) {
this.writeRC(4, (offset) => this.data.writeUInt32BE(value, offset), name);
}
writeUInt48(value, name) {
this.writeUInt16(name, 0);
this.writeRC(6, (offset) => this.data.writeUIntBE(value, offset, 6), name);
}
writeFixed(value, name) {
this.writeRC(4, (offset) => this.data.writeInt32BE(fnutil.round(value * 65536), offset), name);
}
writeTable(table) {
this.write(table.data.slice(0, table.size));
}
}
// -- Params --
const EM_SIZE_MIN = 64;
const EM_SIZE_MAX = 16384;
const EM_SIZE_DEFAULT = 1024;
class Params extends fncli.Params {
constructor() {
super();
this.created = new Date();
this.modified = this.created;
this.dirHint = 0;
this.emSize = EM_SIZE_DEFAULT;
this.lineGap = 0;
this.lowPPem = 0;
this.wLangId = 0x0409;
this.xMaxExtent = true;
this.singleLoca = false;
this.postNames = false;
}
}
// -- Options --
class Options extends fncli.Options {
constructor(needArgs, helpText, versionText) {
super(needArgs.concat(['-d', '-e', '-g', '-l', '-W']), helpText, versionText);
}
parse(name, value, params) {
switch (name) {
case '-d':
params.dirHint = fnutil.parseDec('DIR-HINT', value, -2, 2);
break;
case '-e':
params.emSize = fnutil.parseDec('EM-SIZE', value, EM_SIZE_MIN, EM_SIZE_MAX);
break;
case '-g':
params.lineGap = fnutil.parseDec('LINE-GAP', value, 0, EM_SIZE_MAX << 1);
break;
case '-l':
params.lowPPem = fnutil.parseDec('LOW-PPEM', value, 1, bdf.DPARSE_LIMIT);
break;
case '-W':
params.wLangId = fnutil.parseHex('WLANG-ID', value, 0, 0x7FFF);
break;
case '-X':
params.xMaxExtent = false;
break;
case '-L':
params.singleLoca = true;
break;
case '-P':
params.postNames = true;
break;
default:
this.fallback(name, params);
}
}
}
// -- Font --
class Font extends bdfexp.Font {
constructor(params) {
super();
this.params = params;
this.emAscender = 0;
this.emDescender = 0;
this.emMaxWidth = 0;
this.macStyle = 0;
this.lineSize = 0;
}
get bmpOnly() {
return this.maxCode <= fnutil.UNICODE_BMP_MAX;
}
get created() {
return Font.sfntime(this.params.created);
}
emScale(value, divisor) {
return fnutil.round(value * this.params.emSize / (divisor || this.bbx.height));
}
get italicAngle() {
const value = this.props.get('ITALIC_ANGLE'); // must be integer
return value != null ? fnutil.parseDec('ITALIC_ANGLE', value, -45, 45) : this.italic ? -11.5 : 0;
}
get maxCode() {
return this.chars.slice(-1)[0].code;
}
get minCode() {
return this.chars[0].code;
}
get modified() {
return Font.sfntime(this.params.modified);
}
prepare() {
this.chars.sort((c1, c2) => c1.code - c2.code);
this.chars = this.chars.filter((c, index, array) => index === 0 || c.code !== array[index - 1].code);
this.props.set('CHARS', this.chars.length);
this.emAscender = this.emScale(this.pxAscender);
this.emDescender = this.emAscender - this.params.emSize;
this.emMaxWidth = this.emScaleWidth(this);
this.macStyle = Number(this.bold) + (Number(this.italic) << 1);
this.lineSize = this.emScale(fnutil.round(this.bbx.height / 17) || 1);
}
_read(input) {
super._read(input);
this.prepare();
return this;
}
static read(input, params) {
return (new Font(params))._read(input);
}
emScaleWidth(base) {
return this.emScale(base.bbx.width);
}
static sfntime(stamp) {
return Math.floor((stamp - Date.UTC(1904, 0, 1)) / 1000);
}
get underlinePosition() {
return fnutil.round((this.emDescender + this.lineSize) / 2);
}
get xMaxExtent() {
return this.params.xMaxExtent ? this.emMaxWidth : 0;
}
}
// -- BDAT --
const BDAT_HEADER_SIZE = 4;
const BDAT_METRIC_SIZE = 5;
class BDAT extends Table {
constructor(font) {
super(TS_LARGE, 'EBDT');
// header
this.writeFixed(2, 'version');
// format 1 data
font.chars.forEach(char => {
this.writeUInt8(font.bbx.height, 'height');
this.writeUInt8(char.bbx.width, 'width');
this.writeInt8(0, 'bearingX');
this.writeInt8(font.pxAscender, 'bearingY');
this.writeUInt8(char.bbx.width, 'advance');
this.write(char.data); // imageData
});
}
static getCharSize(char) {
return BDAT_METRIC_SIZE + char.data.length;
}
}
// -- BLOC --
const BLOC_TABLE_SIZE_OFFSET = 12;
const BLOC_PREFIX_SIZE = 0x38; // header 0x08 + 1 bitmapSizeTable * 0x30
const BLOC_INDEX_ARRAY_SIZE = 8; // 1 index record * 0x08
class BLOC extends Table {
constructor(font) {
super(TS_SMALL, 'EBLC');
// header
this.writeFixed(2, 'version');
this.writeUInt32(1, 'numSizes');
// bitmapSizeTable
this.writeUInt32(BLOC_PREFIX_SIZE, 'indexSubTableArrayOffset');
this.writeUInt32(0, 'indexTableSize'); // adjusted later
this.writeUInt32(1, 'numberOfIndexSubTables');
this.writeUInt32(0, 'colorRef');
// hori
this.writeInt8(font.pxAscender, 'hori ascender');
this.writeInt8(font.pxDescender, 'hori descender');
this.writeUInt8(font.bbx.width, 'hori widthMax');
this.writeInt8(1, 'hori caretSlopeNumerator');
this.writeInt8(0, 'hori caretSlopeDenominator');
this.writeInt8(0, 'hori caretOffset');
this.writeInt8(0, 'hori minOriginSB');
this.writeInt8(0, 'hori minAdvanceSB');
this.writeInt8(font.pxAscender, 'hori maxBeforeBL');
this.writeInt8(font.pxDescender, 'hori minAfterBL');
this.writeInt16(0, 'hori padd');
// vert
this.writeInt8(0, 'vert ascender');
this.writeInt8(0, 'vert descender');
this.writeUInt8(0, 'vert widthMax');
this.writeInt8(0, 'vert caretSlopeNumerator');
this.writeInt8(0, 'vert caretSlopeDenominator');
this.writeInt8(0, 'vert caretOffset');
this.writeInt8(0, 'vert minOriginSB');
this.writeInt8(0, 'vert minAdvanceSB');
this.writeInt8(0, 'vert maxBeforeBL');
this.writeInt8(0, 'vert minAfterBL');
this.writeInt16(0, 'vert padd');
// (bitmapSizeTable)
this.writeUInt16(0, 'startGlyphIndex');
this.writeUInt16(font.chars.length - 1, 'endGlyphIndex');
this.writeUInt8(font.bbx.height, 'ppemX');
this.writeUInt8(font.bbx.height, 'ppemY');
this.writeUInt8(1, 'bitDepth');
this.writeUInt8(1, 'flags'); // small metrics are horizontal
// indexSubTableArray
this.writeUInt16(0, 'firstGlyphIndex');
this.writeUInt16(font.chars.length - 1, 'lastGlyphIndex');
this.writeUInt32(BLOC_INDEX_ARRAY_SIZE, 'additionalOffsetToIndexSubtable');
// indexSubtableHeader
this.writeUInt16(font.proportional ? 1 : 2, 'indexFormat');
this.writeUInt16(1, 'imageFormat'); // BDAT -> small metrics, byte-aligned
this.writeUInt32(BDAT_HEADER_SIZE, 'imageDataOffset');
// indexSubtable data
if (font.proportional) {
let offset = 0;
font.chars.forEach(char => {
this.writeUInt32(offset, 'offsetArray[]');
offset += BDAT.getCharSize(char);
});
this.writeUInt32(offset, 'offsetArray[]');
} else {
this.writeUInt32(BDAT.getCharSize(font.chars[0]), 'imageSize');
this.writeUInt8(font.bbx.height, 'height');
this.writeUInt8(font.bbx.width, 'width');
this.writeInt8(0, 'horiBearingX');
this.writeInt8(font.pxAscender, 'horiBearingY');
this.writeUInt8(font.bbx.width, 'horiAdvance');
this.writeInt8(-(font.bbx.width >> 1), 'vertBearingX');
this.writeInt8(0, 'vertBearingY');
this.writeUInt8(font.bbx.height, 'vertAdvance');
}
// adjust
this.rewriteUInt32(this.size - BLOC_PREFIX_SIZE, BLOC_TABLE_SIZE_OFFSET);
}
}
// -- OS/2 --
const OS_2_TABLE_SIZE = 96;
class OS_2 extends Table {
constructor(font) {
super(TS_SMALL, 'OS/2');
// Version 4
const xAvgCharWidth = font.emScale(font.avgWidth); // otb1get.xAvgCharWidth(font);
const ulCharRanges = otb1get.ulCharRanges(font);
const ulCodePages = font.bmpOnly ? otb1get.ulCodePages(font) : [0, 0];
// mostly from FontForge
const scriptXSize = font.emScale(30, 100);
const scriptYSize = font.emScale(40, 100);
const subscriptYOff = scriptYSize >> 1;
const xfactor = Math.tan(font.italicAngle * Math.PI / 180);
const subscriptXOff = 0; // stub, no overlapping characters yet
const superscriptYOff = font.emAscender - scriptYSize;
const superscriptXOff = -fnutil.round(xfactor * superscriptYOff);
// write
this.writeUInt16(4, 'version');
this.writeInt16(xAvgCharWidth, 'xAvgCharWidth');
this.writeUInt16(font.bold ? 700 : 400, 'usWeightClass');
this.writeUInt16(5, 'usWidthClass'); // medium
this.writeInt16(0, 'fsType');
this.writeInt16(scriptXSize, 'ySubscriptXSize');
this.writeInt16(scriptYSize, 'ySubscriptYSize');
this.writeInt16(subscriptXOff, 'ySubscriptXOffset');
this.writeInt16(subscriptYOff, 'ySubscriptYOffset');
this.writeInt16(scriptXSize, 'ySuperscriptXSize');
this.writeInt16(scriptYSize, 'ySuperscriptYSize');
this.writeInt16(superscriptXOff, 'ySuperscriptXOffset');
this.writeInt16(superscriptYOff, 'ySuperscriptYOffset');
this.writeInt16(font.lineSize, 'yStrikeoutSize');
this.writeInt16(font.emScale(25, 100), 'yStrikeoutPosition');
this.writeInt16(0, 'sFamilyClass'); // no classification
this.writeUInt8(2, 'bFamilyType'); // text and display
this.writeUInt8(0, 'bSerifStyle'); // any
this.writeUInt8(font.bold ? 8 : 6, 'bWeight');
this.writeUInt8(font.proportional ? 3 : 9, 'bProportion');
this.writeUInt8(0, 'bContrast');
this.writeUInt8(0, 'bStrokeVariation');
this.writeUInt8(0, 'bArmStyle');
this.writeUInt8(0, 'bLetterform');
this.writeUInt8(0, 'bMidline');
this.writeUInt8(0, 'bXHeight');
this.writeUInt32(ulCharRanges[0], 'ulCharRange1');
this.writeUInt32(ulCharRanges[1], 'ulCharRange2');
this.writeUInt32(ulCharRanges[2], 'ulCharRange3');
this.writeUInt32(ulCharRanges[3], 'ulCharRange4');
this.writeUInt32(0x586F7334, 'achVendID'); // 'Xos4'
this.writeUInt16(OS_2.fsSelection(font), 'fsSelection');
this.writeUInt16(Math.min(font.minCode, fnutil.UNICODE_BMP_MAX), 'firstChar');
this.writeUInt16(Math.min(font.maxCode, fnutil.UNICODE_BMP_MAX), 'lastChar');
this.writeInt16(font.emAscender, 'sTypoAscender');
this.writeInt16(font.emDescender, 'sTypoDescender');
this.writeInt16(font.params.lineGap, 'sTypoLineGap');
this.writeUInt16(font.emAscender, 'usWinAscent');
this.writeUInt16(-font.emDescender, 'usWinDescent');
this.writeUInt32(ulCodePages[0], 'ulCodePageRange1');
this.writeUInt32(ulCodePages[1], 'ulCodePageRange2');
this.writeInt16(font.emScale(font.pxAscender * 0.6), 'sxHeight'); // stub
this.writeInt16(font.emScale(font.pxAscender * 0.8), 'sCapHeight'); // stub
this.writeUInt16(OS_2.defaultChar(font), 'usDefaultChar');
this.writeUInt16(OS_2.breakChar(font), 'usBreakChar');
this.writeUInt16(1, 'usMaxContext');
// check
this.checkSize(OS_2_TABLE_SIZE);
}
static breakChar(font) {
return font.chars.findIndex(char => char.code === 0x20) !== -1 ? 0x20 : font.minCode;
}
static defaultChar(font) {
if (font.defaultCode !== -1 && font.defaultCode <= fnutil.UNICODE_BMP_MAX) {
return font.defaultCode;
}
return font.minCode && font.maxCode;
}
static fsSelection(font) {
const fsSelection = Number(font.bold) * 5 + Number(font.italic);
return fsSelection || (font.xlfd[bdf.XLFD.SLANT] === 'R' ? 0x40 : 0);
}
}
// -- cmap --
const CMAP_4_PREFIX_SIZE = 12;
const CMAP_4_FORMAT_SIZE = 16;
const CMAP_4_SEGMENT_SIZE = 8;
const CMAP_12_PREFIX_SIZE = 20;
const CMAP_12_FORMAT_SIZE = 16;
const CMAP_12_GROUP_SIZE = 12;
class CMapRange {
constructor(glyphIndex = 0, startCode = 0, finalCode = -2) {
this.glyphIndex = glyphIndex;
this.startCode = startCode;
this.finalCode = finalCode;
}
get idDelta() {
return (this.glyphIndex - this.startCode) & 0xFFFF;
}
}
class CMAP extends Table {
constructor(font) {
super(TS_LARGE, 'cmap');
// make ranges
let ranges = [];
let range = new CMapRange();
for (let index = 0; index < font.chars.length; index++) {
let code = font.chars[index].code;
if (code === range.finalCode + 1) {
range.finalCode++;
} else {
range = new CMapRange(index, code, code);
ranges.push(range);
}
}
// write
if (font.bmpOnly) {
if (font.maxCode < 0xFFFF) {
ranges.push(new CMapRange(0, 0xFFFF, 0xFFFF));
}
this.writeFormat4(ranges);
} else {
this.writeFormat12(ranges);
}
}
writeFormat4(ranges) {
// index
this.writeUInt16(0, 'version');
this.writeUInt16(1, 'numberSubtables');
// encoding subtables index
this.writeUInt16(3, 'platformID'); // Microsoft
this.writeUInt16(1, 'platformSpecificID'); // Unicode BMP (UCS-2)
this.writeUInt32(CMAP_4_PREFIX_SIZE, 'offset'); // for Unicode BMP (UCS-2)
// cmap format 4
const segCount = ranges.length;
const subtableSize = CMAP_4_FORMAT_SIZE + segCount * CMAP_4_SEGMENT_SIZE;
const searchRange = 2 << Math.floor(Math.log2(segCount));
this.writeUInt16(4, 'format');
this.writeUInt16(subtableSize, 'length');
this.writeUInt16(0, 'language'); // none/independent
this.writeUInt16(segCount * 2, 'segCountX2');
this.writeUInt16(searchRange, 'searchRange');
this.writeUInt16(Math.log2(searchRange / 2), 'entrySelector');
this.writeUInt16((segCount * 2) - searchRange, 'rangeShift');
ranges.forEach(range => {
this.writeUInt16(range.finalCode, 'endCode');
});
this.writeUInt16(0, 'reservedPad');
ranges.forEach(range => {
this.writeUInt16(range.startCode, 'startCode');
});
ranges.forEach(range => {
this.writeUInt16(range.idDelta, 'idDelta');
});
ranges.forEach(() => this.writeUInt16(0), 'idRangeOffset');
// check
this.checkSize(CMAP_4_PREFIX_SIZE + subtableSize);
}
writeFormat12(ranges) {
// index
this.writeUInt16(0, 'version');
this.writeUInt16(2, 'numberSubtables');
// encoding subtables
this.writeUInt16(0, 'platformID'); // Unicode
this.writeUInt16(4, 'platformSpecificID'); // Unicode 2.0+ full range
this.writeUInt32(CMAP_12_PREFIX_SIZE, 'offset'); // for Unicode 2.0+ full range
this.writeUInt16(3, 'platformID'); // Microsoft
this.writeUInt16(10, 'platformSpecificID'); // Unicode UCS-4
this.writeUInt32(CMAP_12_PREFIX_SIZE, 'offset'); // for Unicode UCS-4
// cmap format 12
const subtableSize = CMAP_12_FORMAT_SIZE + ranges.length * CMAP_12_GROUP_SIZE;
this.writeFixed(12, 'format');
this.writeUInt32(subtableSize, 'length');
this.writeUInt32(0, 'language'); // none/independent
this.writeUInt32(ranges.length, 'nGroups');
this.ranges.forEach(range => {
this.writeUInt32(range.startCode, 'startCharCode');
this.writeUInt32(range.finalCode, 'endCharCode');
this.writeUInt32(range.glyphIndex, 'startGlyphID');
});
// check
this.checkSize(CMAP_12_PREFIX_SIZE + subtableSize);
}
}
// -- glyf --
class GLYF extends Table {
constructor() {
super(TS_EMPTY, 'glyf');
}
}
// -- head --
const HEAD_TABLE_SIZE = 54;
const HEAD_CHECKSUM_OFFSET = 8;
class HEAD extends Table {
constructor(font) {
super(TS_SMALL, 'head');
this.writeFixed(1, 'version');
this.writeFixed(1, 'fontRevision');
this.writeUInt32(0, 'checksumAdjustment'); // adjusted later
this.writeUInt32(0x5F0F3CF5, 'magicNumber');
this.writeUInt16(HEAD.flags(font), 'flags');
this.writeUInt16(font.params.emSize, 'unitsPerEm');
this.writeUInt48(font.created, 'created');
this.writeUInt48(font.modified, 'modified');
this.writeInt16(0, 'xMin');
this.writeInt16(font.emDescender, 'yMin');
this.writeInt16(font.emMaxWidth, 'xMax');
this.writeInt16(font.emAscender, 'yMax');
this.writeUInt16(font.macStyle, 'macStyle');
this.writeUInt16(font.params.lowPPem || font.bbx.height, 'lowestRecPPEM');
this.writeInt16(font.params.dirHint, 'fontDirectionHint');
this.writeInt16(0, 'indexToLocFormat'); // short
this.writeInt16(0, 'glyphDataFormat'); // current
// check
this.checkSize(HEAD_TABLE_SIZE);
}
static flags(font) {
return otb1get.containsRTL(font) ? 0x020B : 0x0B; // y0 base, x0 lsb, scale int
}
}
// -- hhea --
const HHEA_TABLE_SIZE = 36;
class HHEA extends Table {
constructor(font) {
super(TS_SMALL, 'hhea');
this.writeFixed(1, 'version');
this.writeInt16(font.emAscender, 'ascender');
this.writeInt16(font.emDescender, 'descender');
this.writeInt16(font.params.lineGap, 'lineGap');
this.writeUInt16(font.emMaxWidth, 'advanceWidthMax');
this.writeInt16(0, 'minLeftSideBearing');
this.writeInt16(0, 'minRightSideBearing');
this.writeInt16(font.xMaxExtent, 'xMaxExtent');
this.writeInt16(font.italic ? 100 : 1, 'caretSlopeRise');
this.writeInt16(font.italic ? 20 : 0, 'caretSlopeRun');
this.writeInt16(0, 'caretOffset');
this.writeInt16(0, 'reserved');
this.writeInt16(0, 'reserved');
this.writeInt16(0, 'reserved');
this.writeInt16(0, 'reserved');
this.writeInt16(0, 'metricDataFormat'); // current
this.writeUInt16(font.chars.length, 'numOfLongHorMetrics');
// check
this.checkSize(HHEA_TABLE_SIZE);
}
}
// -- hmtx --
class HMTX extends Table {
constructor(font) {
super(TS_LARGE, 'hmtx');
font.chars.forEach(char => {
this.writeUInt16(font.emScaleWidth(char), 'advanceWidth');
this.writeInt16(0, 'leftSideBearing');
});
}
}
// -- loca --
class LOCA extends Table {
constructor(font) {
super(TS_SMALL, 'loca');
if (!font.params.singleLoca) {
font.chars.forEach(() => this.writeUInt16(0, 'offset'));
}
this.writeUInt16(0, 'offset');
}
}
// -- maxp --
const MAXP_TABLE_SIZE = 32;
class MAXP extends Table {
constructor(font) {
super(TS_SMALL, 'maxp');
this.writeFixed(1, 'version');
this.writeUInt16(font.chars.length, 'numGlyphs');
this.writeUInt16(0, 'maxPoints');
this.writeUInt16(0, 'maxContours');
this.writeUInt16(0, 'maxComponentPoints');
this.writeUInt16(0, 'maxComponentContours');
this.writeUInt16(2, 'maxZones');
this.writeUInt16(0, 'maxTwilightPoints');
this.writeUInt16(1, 'maxStorage');
this.writeUInt16(1, 'maxFunctionDefs');
this.writeUInt16(0, 'maxInstructionDefs');
this.writeUInt16(64, 'maxStackElements');
this.writeUInt16(0, 'maxSizeOfInstructions');
this.writeUInt16(0, 'maxComponentElements');
this.writeUInt16(0, 'maxComponentDepth');
// check
this.checkSize(MAXP_TABLE_SIZE);
}
}
// -- name --
const NAME_ID = {
COPYRIGHT: 0,
FONT_FAMILY: 1,
FONT_SUBFAMILY: 2,
UNIQUE_SUBFAMILY: 3,
FULL_FONT_NAME: 4,
LICENSE: 14
};
const NAME_HEADER_SIZE = 6;
const NAME_RECORD_SIZE = 12;
class NAME extends Table {
constructor(font) {
super(TS_LARGE, 'name');
// compute names
let names = new Map();
const copyright = font.props.get('COPYRIGHT');
if (copyright != null) {
names.set(NAME_ID.COPYRIGHT, fnutil.unquote(copyright));
}
const family = font.xlfd[bdf.XLFD.FAMILY_NAME];
const style = ['Regular', 'Bold', 'Italic', 'Bold Italic'][font.macStyle];
names.set(NAME_ID.FONT_FAMILY, family);
names.set(NAME_ID.FONT_SUBFAMILY, style);
names.set(NAME_ID.UNIQUE_SUBFAMILY, `${family} ${style} bitmap height ${font.bbx.height}`);
names.set(NAME_ID.FULL_FONT_NAME, `${family} ${style}`);
let license = font.props.get('LICENSE');
const notice = font.props.get('NOTICE');
if (license == null && notice != null && notice.toLowerCase().includes('license')) {
license = notice;
}
if (license != null) {
names.set(NAME_ID.LICENSE, fnutil.unquote(license));
}
// header
const count = names.size * (1 + 1); // Unicode + Microsoft
const stringOffset = NAME_HEADER_SIZE + NAME_RECORD_SIZE * count;
this.writeUInt16(0, 'format');
this.writeUInt16(count, 'count');
this.writeUInt16(stringOffset, 'stringOffset');
// name records / create values
let values = new Table(TS_LARGE, 'name');
names.forEach((str, nameID) => {
const value = Buffer.from(str, 'utf16le').swap16();
const bmp = font.bmpOnly && value.length === str.length * 2;
// Unicode
this.writeUInt16(0, 'platformID'); // Unicode
this.writeUInt16(bmp ? 3 : 4, 'platformSpecificID');
this.writeUInt16(0, 'languageID');
this.writeUInt16(nameID, 'nameID');
this.writeUInt16(value.length, 'length'); // in bytes
this.writeUInt16(values.size, 'offset');
// Windows
this.writeUInt16(3, 'platformID'); // Microsoft
this.writeUInt16(bmp ? 1 : 10, 'platformSpecificID');
this.writeUInt16(font.params.wLangId, 'languageID');
this.writeUInt16(nameID, 'nameID');
this.writeUInt16(value.length, 'length'); // in bytes
this.writeUInt16(values.size, 'offset');
// value
values.write(value);
});
// write values
this.writeTable(values);
// check
this.checkSize(stringOffset + values.size);
}
}
// -- post --
const POST_TABLE_SIZE = 32;
class POST extends Table {
constructor(font) {
super(TS_SMALL, 'post');
this.writeFixed(font.params.postNames ? 2 : 3, 'format');
this.writeFixed(font.italicAngle, 'italicAngle');
this.writeInt16(font.underlinePosition, 'underlinePosition');
this.writeInt16(font.lineSize, 'underlineThickness');
this.writeUInt32(font.proportional ? 0 : 1, 'isFixedPitch');
this.writeUInt32(0, 'minMemType42');
this.writeUInt32(0, 'maxMemType42');
this.writeUInt32(0, 'minMemType1');
this.writeUInt32(0, 'maxMemType1');
// names
if (font.params.postNames) {
let postNames = otb1get.postMacNames();
const postMacCount = postNames.length;
this.writeUInt16(font.chars.length, 'numberOfGlyphs');
font.chars.forEach(char => {
const name = char.props.get('STARTCHAR');
const index = postNames.indexOf(name);
if (index !== -1) {
this.writeUInt16(index, 'glyphNameIndex');
} else {
this.writeUInt16(postNames.length, 'glyphNameIndex');
postNames.push(name);
}
});
postNames.slice(postMacCount).forEach(name => {
this.writeUInt8(name.length, 'glyphNameLength');
this.write(Buffer.from(name, 'binary'));
});
// check
} else {
this.checkSize(POST_TABLE_SIZE);
}
}
}
// -- SFNT --
const SFNT_HEADER_SIZE = 12;
const SFNT_RECORD_SIZE = 16;
const SFNT_SUBTABLES = [ BDAT, BLOC, OS_2, CMAP, GLYF, HEAD, HHEA, HMTX, LOCA, MAXP, NAME, POST ];
class SFNT extends Table {
constructor(font) {
super(TS_LARGE, 'SFNT');
// create tables
let tables = [];
SFNT_SUBTABLES.forEach(Ctor => {
tables.push(new Ctor(font));
});
// header
const numTables = tables.length;
const entrySelector = Math.floor(Math.log2(numTables));
const searchRange = 16 << entrySelector;
const contentOffset = SFNT_HEADER_SIZE + numTables * SFNT_RECORD_SIZE;
let offset = contentOffset;
let content = new Table(TS_LARGE, 'SFNT');
let headChecksumOffset = -1;
this.writeFixed(1, 'sfntVersion');
this.writeUInt16(numTables, 'numTables');
this.writeUInt16(searchRange, 'searchRange');
this.writeUInt16(entrySelector, 'entrySelector');
this.writeUInt16(numTables * 16 - searchRange, 'rangeShift');
// table records / create content
tables.forEach(table => {
this.write(Buffer.from(table.tableName, 'binary'));
this.writeUInt32(table.checksum(), 'checkSum');
this.writeUInt32(offset, 'offset');
this.writeUInt32(table.size, 'length');
// create content
if (table.tableName === 'head') {
headChecksumOffset = offset + HEAD_CHECKSUM_OFFSET;
}
const paddedSize = table.size + table.padding;
content.write(table.data.slice(0, paddedSize));
offset += paddedSize;
});
// write content
this.writeTable(content);
// check
this.checkSize(contentOffset + content.size);
// adjust
if (headChecksumOffset !== -1) {
this.rewriteUInt32((0xB1B0AFBA - this.checksum()) >>> 0, headChecksumOffset);
}
}
}
// -- Export --
module.exports = Object.freeze({
TS_EMPTY,
TS_SMALL,
TS_LARGE,
Table,
EM_SIZE_MIN,
EM_SIZE_MAX,
EM_SIZE_DEFAULT,
Params,
Options,
Font,
BDAT,
BLOC,
OS_2,
CMAP,
GLYF,
HEAD,
HHEA,
HMTX,
LOCA,
MAXP,
NAME,
POST,
SFNT
});

808
bin/otb1exp.py Normal file
View File

@ -0,0 +1,808 @@
#
# Copyright (C) 2017-2020 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
import struct
import codecs
import math
from datetime import datetime, timezone
from itertools import groupby
from enum import IntEnum, unique
from collections import OrderedDict
import fnutil
import fncli
import bdf
import bdfexp
import otb1get
# -- Table --
class Table:
def __init__(self, name):
self.data = bytearray(0)
self.table_name = name
def check_size(self, size):
if size != self.size:
raise Exception('internal error: %s size = %d instead of %d' % (self.table_name, self.size, size))
def checksum(self):
cksum = 0
data = self.data + self.padding
for offset in range(0, self.size, 4):
cksum += struct.unpack('>L', data[offset : offset + 4])[0]
return cksum & 0xFFFFFFFF
def pack(self, format, value, name):
try:
return struct.pack(format, value)
except struct.error as ex:
raise Exception('%s.%s: %s' % (self.table_name, name, str(ex)))
@property
def size(self):
return len(self.data)
@property
def padding(self):
return bytes(((self.size + 1) & 3) ^ 1)
def rewrite_uint32(self, value, offset):
self.data[offset : offset + 4] = struct.pack('>L', value)
def write(self, data):
self.data += data
def write_int8(self, value, name):
self.data += self.pack('b', value, name)
def write_uint8(self, value, name):
self.data += self.pack('B', value, name)
def write_int16(self, value, name):
self.data += self.pack('>h', value, name)
def write_uint16(self, value, name):
self.data += self.pack('>H', value, name)
def write_uint32(self, value, name):
self.data += self.pack('>L', value, name)
def write_uint64(self, value, name):
self.data += self.pack('>Q', value, name)
def write_fixed(self, value, name):
self.data += self.pack('>l', round(value * 65536), name)
def write_table(self, table):
self.data += table.data
# -- Params --
EM_SIZE_MIN = 64
EM_SIZE_MAX = 16384
EM_SIZE_DEFAULT = 1024
class Params(fncli.Params): # pylint: disable=too-many-instance-attributes
def __init__(self):
fncli.Params.__init__(self)
self.created = datetime.now(timezone.utc)
self.modified = self.created
self.dir_hint = 0
self.em_size = EM_SIZE_DEFAULT
self.line_gap = 0
self.low_ppem = 0
self.encoding = 'utf_8'
self.w_lang_id = 0x0409
self.x_max_extent = True
self.single_loca = False
self.post_names = False
# -- Options --
class Options(fncli.Options):
def __init__(self, need_args, help_text, version_text):
fncli.Options.__init__(self, need_args + ['-d', '-e', '-g', '-l', '-E', '-W'], help_text, version_text)
def parse(self, name, value, params):
if name == '-d':
params.dir_hint = fnutil.parse_dec('DIR-HINT', value, -2, 2)
elif name == '-e':
params.em_size = fnutil.parse_dec('EM-SIZE', value, EM_SIZE_MIN, EM_SIZE_MAX)
elif name == '-g':
params.line_gap = fnutil.parse_dec('LINE-GAP', value, 0, EM_SIZE_MAX << 1)
elif name == '-l':
params.low_ppem = fnutil.parse_dec('LOW-PPEM', value, 1, bdf.DPARSE_LIMIT)
elif name == '-E':
params.encoding = value
elif name == '-W':
params.w_lang_id = fnutil.parse_hex('WLANG-ID', value, 0, 0x7FFF)
elif name == '-X':
params.x_max_extent = False
elif name == '-L':
params.single_loca = True
elif name == '-P':
params.post_names = True
else:
self.fallback(name, params)
# -- Font --
class Font(bdfexp.Font):
def __init__(self, params):
bdfexp.Font.__init__(self)
self.params = params
self.em_ascender = 0
self.em_descender = 0
self.em_max_width = 0
self.mac_style = 0
self.line_size = 0
@property
def bmp_only(self):
return self.max_code <= fnutil.UNICODE_BMP_MAX
@property
def created(self):
return Font.sfntime(self.params.created)
def decode(self, data):
return codecs.decode(data, self.params.encoding)
def em_scale(self, value, divisor=0):
return round(value * self.params.em_size / (divisor or self.bbx.height))
def em_scale_width(self, base):
return self.em_scale(base.bbx.width)
@property
def italic_angle(self):
value = self.props.get('ITALIC_ANGLE') # must be integer
return fnutil.parse_dec('ITALIC_ANGLE', value, -45, 45) if value else -11.5 if self.italic else 0
@property
def max_code(self):
return self.chars[-1].code
@property
def min_code(self):
return self.chars[0].code
@property
def modified(self):
return Font.sfntime(self.params.modified)
def prepare(self):
self.chars.sort(key=lambda c: c.code)
self.chars = [next(elem[1]) for elem in groupby(self.chars, key=lambda c: c.code)]
self.props.set('CHARS', len(self.chars))
self.em_ascender = self.em_scale(self.px_ascender)
self.em_descender = self.em_ascender - self.params.em_size
self.em_max_width = self.em_scale_width(self)
self.mac_style = int(self.bold) + (int(self.italic) << 1)
self.line_size = self.em_scale(round(self.bbx.height / 17) or 1)
def _read(self, input):
bdfexp.Font._read(self, input)
self.prepare()
return self
@staticmethod
def read(input, params): # pylint: disable=arguments-differ
return Font(params)._read(input) # pylint: disable=protected-access
@staticmethod
def sfntime(stamp):
return math.floor((stamp - datetime(1904, 1, 1, tzinfo=timezone.utc)).total_seconds())
@property
def underline_position(self):
return round((self.em_descender + self.line_size) / 2)
@property
def x_max_extent(self):
return self.em_max_width if self.params.x_max_extent else 0
# -- BDAT --
BDAT_HEADER_SIZE = 4
BDAT_METRIC_SIZE = 5
class BDAT(Table):
def __init__(self, font):
Table.__init__(self, 'EBDT')
# header
self.write_fixed(2, 'version')
# format 1 data
for char in font.chars:
self.write_uint8(font.bbx.height, 'height')
self.write_uint8(char.bbx.width, 'width')
self.write_int8(0, 'bearingX')
self.write_int8(font.px_ascender, 'bearingY')
self.write_uint8(char.bbx.width, 'advance')
self.write(char.data) # imageData
@staticmethod
def get_char_size(char):
return BDAT_METRIC_SIZE + len(char.data)
# -- BLOC --
BLOC_TABLE_SIZE_OFFSET = 12
BLOC_PREFIX_SIZE = 0x38 # header 0x08 + 1 bitmapSizeTable * 0x30
BLOC_INDEX_ARRAY_SIZE = 8 # 1 index record * 0x08
class BLOC(Table):
def __init__(self, font):
Table.__init__(self, 'EBLC')
# header
self.write_fixed(2, 'version')
self.write_uint32(1, 'numSizes')
# bitmapSizeTable
self.write_uint32(BLOC_PREFIX_SIZE, 'indexSubTableArrayOffset')
self.write_uint32(0, 'indexTableSize') # adjusted later
self.write_uint32(1, 'numberOfIndexSubTables')
self.write_uint32(0, 'colorRef')
# hori
self.write_int8(font.px_ascender, 'hori ascender')
self.write_int8(font.px_descender, 'hori descender')
self.write_uint8(font.bbx.width, 'hori widthMax')
self.write_int8(1, 'hori caretSlopeNumerator')
self.write_int8(0, 'hori caretSlopeDenominator')
self.write_int8(0, 'hori caretOffset')
self.write_int8(0, 'hori minOriginSB')
self.write_int8(0, 'hori minAdvanceSB')
self.write_int8(font.px_ascender, 'hori maxBeforeBL')
self.write_int8(font.px_descender, 'hori minAfterBL')
self.write_int16(0, 'hori padd')
# vert
self.write_int8(0, 'vert ascender')
self.write_int8(0, 'vert descender')
self.write_uint8(0, 'vert widthMax')
self.write_int8(0, 'vert caretSlopeNumerator')
self.write_int8(0, 'vert caretSlopeDenominator')
self.write_int8(0, 'vert caretOffset')
self.write_int8(0, 'vert minOriginSB')
self.write_int8(0, 'vert minAdvanceSB')
self.write_int8(0, 'vert maxBeforeBL')
self.write_int8(0, 'vert minAfterBL')
self.write_int16(0, 'vert padd')
# (bitmapSizeTable)
self.write_uint16(0, 'startGlyphIndex')
self.write_uint16(len(font.chars) - 1, 'endGlyphIndex')
self.write_uint8(font.bbx.height, 'ppemX')
self.write_uint8(font.bbx.height, 'ppemY')
self.write_uint8(1, 'bitDepth')
self.write_uint8(1, 'flags') # small metrics are horizontal
# indexSubTableArray
self.write_uint16(0, 'firstGlyphIndex')
self.write_uint16(len(font.chars) - 1, 'lastGlyphIndex')
self.write_uint32(BLOC_INDEX_ARRAY_SIZE, 'additionalOffsetToIndexSubtable')
# indexSubtableHeader
self.write_uint16(1 if font.proportional else 2, 'indexFormat')
self.write_uint16(1, 'imageFormat') # BDAT -> small metrics, byte-aligned
self.write_uint32(BDAT_HEADER_SIZE, 'imageDataOffset')
# indexSubtable data
if font.proportional:
offset = 0
for char in font.chars:
self.write_uint32(offset, 'offsetArray[]')
offset += BDAT.get_char_size(char)
self.write_uint32(offset, 'offsetArray[]')
else:
self.write_uint32(BDAT.get_char_size(font.chars[0]), 'imageSize')
self.write_uint8(font.bbx.height, 'height')
self.write_uint8(font.bbx.width, 'width')
self.write_int8(0, 'horiBearingX')
self.write_int8(font.px_ascender, 'horiBearingY')
self.write_uint8(font.bbx.width, 'horiAdvance')
self.write_int8(-(font.bbx.width >> 1), 'vertBearingX')
self.write_int8(0, 'vertBearingY')
self.write_uint8(font.bbx.height, 'vertAdvance')
# adjust
self.rewrite_uint32(self.size - BLOC_PREFIX_SIZE, BLOC_TABLE_SIZE_OFFSET)
# -- OS/2 --
OS_2_TABLE_SIZE = 96
class OS_2(Table): # pylint: disable=invalid-name
def __init__(self, font):
Table.__init__(self, 'OS/2')
# Version 4
x_avg_char_width = font.em_scale(font.avg_width) # otb1get.x_avg_char_width(font)
ul_char_ranges = otb1get.ul_char_ranges(font)
ul_code_pages = otb1get.ul_code_pages(font) if font.bmp_only else [0, 0]
# mostly from FontForge
script_xsize = font.em_scale(30, 100)
script_ysize = font.em_scale(40, 100)
subscript_yoff = script_ysize >> 1
xfactor = math.tan(font.italic_angle * math.pi / 180)
subscript_xoff = 0 # stub, no overlapping characters yet
superscript_yoff = font.em_ascender - script_ysize
superscript_xoff = -round(xfactor * superscript_yoff)
# write
self.write_uint16(4, 'version')
self.write_int16(x_avg_char_width, 'xAvgCharWidth')
self.write_uint16(700 if font.bold else 400, 'usWeightClass')
self.write_uint16(5, 'usWidthClass') # medium
self.write_int16(0, 'fsType')
self.write_int16(script_xsize, 'ySubscriptXSize')
self.write_int16(script_ysize, 'ySubscriptYSize')
self.write_int16(subscript_xoff, 'ySubscriptXOffset')
self.write_int16(subscript_yoff, 'ySubscriptYOffset')
self.write_int16(script_xsize, 'ySuperscriptXSize')
self.write_int16(script_ysize, 'ySuperscriptYSize')
self.write_int16(superscript_xoff, 'ySuperscriptXOffset')
self.write_int16(superscript_yoff, 'ySuperscriptYOffset')
self.write_int16(font.line_size, 'yStrikeoutSize')
self.write_int16(font.em_scale(25, 100), 'yStrikeoutPosition')
self.write_int16(0, 'sFamilyClass') # no classification
self.write_uint8(2, 'bFamilyType') # text and display
self.write_uint8(0, 'bSerifStyle') # any
self.write_uint8(8 if font.bold else 6, 'bWeight')
self.write_uint8(3 if font.proportional else 9, 'bProportion')
self.write_uint8(0, 'bContrast')
self.write_uint8(0, 'bStrokeVariation')
self.write_uint8(0, 'bArmStyle')
self.write_uint8(0, 'bLetterform')
self.write_uint8(0, 'bMidline')
self.write_uint8(0, 'bXHeight')
self.write_uint32(ul_char_ranges[0], 'ulCharRange1')
self.write_uint32(ul_char_ranges[1], 'ulCharRange2')
self.write_uint32(ul_char_ranges[2], 'ulCharRange3')
self.write_uint32(ul_char_ranges[3], 'ulCharRange4')
self.write_uint32(0x586F7334, 'achVendID') # 'Xos4'
self.write_uint16(OS_2.fs_selection(font), 'fsSelection')
self.write_uint16(min(font.min_code, fnutil.UNICODE_BMP_MAX), 'firstChar')
self.write_uint16(min(font.max_code, fnutil.UNICODE_BMP_MAX), 'lastChar')
self.write_int16(font.em_ascender, 'sTypoAscender')
self.write_int16(font.em_descender, 'sTypoDescender')
self.write_int16(font.params.line_gap, 'sTypoLineGap')
self.write_uint16(font.em_ascender, 'usWinAscent')
self.write_uint16(-font.em_descender, 'usWinDescent')
self.write_uint32(ul_code_pages[0], 'ulCodePageRange1')
self.write_uint32(ul_code_pages[1], 'ulCodePageRange2')
self.write_int16(font.em_scale(font.px_ascender * 0.6), 'sxHeight') # stub
self.write_int16(font.em_scale(font.px_ascender * 0.8), 'sCapHeight') # stub
self.write_uint16(OS_2.default_char(font), 'usDefaultChar')
self.write_uint16(OS_2.break_char(font), 'usBreakChar')
self.write_uint16(1, 'usMaxContext')
# check
self.check_size(OS_2_TABLE_SIZE)
@staticmethod
def break_char(font):
return 0x20 if next((char for char in font.chars if char.code == 0x20), None) else font.min_code
@staticmethod
def default_char(font):
if font.default_code != -1 and font.default_code <= fnutil.UNICODE_BMP_MAX:
return font.default_code
return 0 if font.min_code == 0 else font.max_code
@staticmethod
def fs_selection(font):
fs_selection = int(font.bold) * 5 + int(font.italic)
return fs_selection if fs_selection != 0 else 0x40 if font.xlfd[bdf.XLFD.SLANT] == 'R' else 0
# -- cmap --
CMAP_4_PREFIX_SIZE = 12
CMAP_4_FORMAT_SIZE = 16
CMAP_4_SEGMENT_SIZE = 8
CMAP_12_PREFIX_SIZE = 20
CMAP_12_FORMAT_SIZE = 16
CMAP_12_GROUP_SIZE = 12
class CMapRange:
def __init__(self, glyph_index=0, start_code=0, final_code=-2):
self.glyph_index = glyph_index
self.start_code = start_code
self.final_code = final_code
@property
def id_delta(self):
return (self.glyph_index - self.start_code) & 0xFFFF
class CMAP(Table):
def __init__(self, font):
Table.__init__(self, 'cmap')
# make ranges
ranges = []
range = CMapRange()
index = -1
for char in font.chars:
index += 1
code = char.code
if code == range.final_code + 1:
range.final_code += 1
else:
range = CMapRange(index, code, code)
ranges.append(range)
# write
if font.bmp_only:
if font.max_code < 0xFFFF:
ranges.append(CMapRange(0, 0xFFFF, 0xFFFF))
self.write_format_4(ranges)
else:
self.write_format_12(ranges)
def write_format_4(self, ranges):
# index
self.write_uint16(0, 'version')
self.write_uint16(1, 'numberSubtables')
# encoding subtables index
self.write_uint16(3, 'platformID') # Microsoft
self.write_uint16(1, 'platformSpecificID') # Unicode BMP (UCS-2)
self.write_uint32(CMAP_4_PREFIX_SIZE, 'offset') # for Unicode BMP (UCS-2)
# cmap format 4
seg_count = len(ranges)
subtable_size = CMAP_4_FORMAT_SIZE + seg_count * CMAP_4_SEGMENT_SIZE
search_range = 2 << math.floor(math.log2(seg_count))
self.write_uint16(4, 'format')
self.write_uint16(subtable_size, 'length')
self.write_uint16(0, 'language') # none/independent
self.write_uint16(seg_count * 2, 'segCountX2')
self.write_uint16(search_range, 'searchRange')
self.write_uint16(int(math.log2(search_range / 2)), 'entrySelector')
self.write_uint16((seg_count * 2) - search_range, 'rangeShift')
for range in ranges:
self.write_uint16(range.final_code, 'endCode')
self.write_uint16(0, 'reservedPad')
for range in ranges:
self.write_uint16(range.start_code, 'startCode')
for range in ranges:
self.write_uint16(range.id_delta, 'idDelta')
for _ in ranges:
self.write_uint16(0, 'idRangeOffset')
# check
self.check_size(CMAP_4_PREFIX_SIZE + subtable_size)
def write_format_12(self, ranges):
# index
self.write_uint16(0, 'version')
self.write_uint16(2, 'numberSubtables')
# encoding subtables
self.write_uint16(0, 'platformID') # Unicode
self.write_uint16(4, 'platformSpecificID') # Unicode 2.0+ full range
self.write_uint32(CMAP_12_PREFIX_SIZE, 'offset') # for Unicode 2.0+ full range
self.write_uint16(3, 'platformID') # Microsoft
self.write_uint16(10, 'platformSpecificID') # Unicode UCS-4
self.write_uint32(CMAP_12_PREFIX_SIZE, 'offset') # for Unicode UCS-4
# cmap format 12
subtable_size = CMAP_12_FORMAT_SIZE + len(ranges) * CMAP_12_GROUP_SIZE
self.write_fixed(12, 'format')
self.write_uint32(subtable_size, 'length')
self.write_uint32(0, 'language') # none/independent
self.write_uint32(len(ranges), 'nGroups')
for range in ranges:
self.write_uint32(range.start_code, 'startCharCode')
self.write_uint32(range.final_code, 'endCharCode')
self.write_uint32(range.glyph_index, 'startGlyphID')
# check
self.check_size(CMAP_12_PREFIX_SIZE + subtable_size)
# -- glyf --
class GLYF(Table):
def __init__(self, _font):
Table.__init__(self, 'glyf')
# -- head --
HEAD_TABLE_SIZE = 54
HEAD_CHECKSUM_OFFSET = 8
class HEAD(Table):
def __init__(self, font):
Table.__init__(self, 'head')
self.write_fixed(1, 'version')
self.write_fixed(1, 'fontRevision')
self.write_uint32(0, 'checksumAdjustment') # adjusted later
self.write_uint32(0x5F0F3CF5, 'magicNumber')
self.write_uint16(HEAD.flags(font), 'flags')
self.write_uint16(font.params.em_size, 'unitsPerEm')
self.write_uint64(font.created, 'created')
self.write_uint64(font.modified, 'modified')
self.write_int16(0, 'xMin')
self.write_int16(font.em_descender, 'yMin')
self.write_int16(font.em_max_width, 'xMax')
self.write_int16(font.em_ascender, 'yMax')
self.write_uint16(font.mac_style, 'macStyle')
self.write_uint16(font.params.low_ppem or font.bbx.height, 'lowestRecPPEM')
self.write_int16(font.params.dir_hint, 'fontDirectionHint')
self.write_int16(0, 'indexToLocFormat') # short
self.write_int16(0, 'glyphDataFormat') # current
# check
self.check_size(HEAD_TABLE_SIZE)
@staticmethod
def flags(font):
return 0x20B if otb1get.contains_rtl(font) else 0x0B # y0 base, x0 lsb, scale int
# -- hhea --
HHEA_TABLE_SIZE = 36
class HHEA(Table):
def __init__(self, font):
Table.__init__(self, 'hhea')
self.write_fixed(1, 'version')
self.write_int16(font.em_ascender, 'ascender')
self.write_int16(font.em_descender, 'descender')
self.write_int16(font.params.line_gap, 'lineGap')
self.write_uint16(font.em_max_width, 'advanceWidthMax')
self.write_int16(0, 'minLeftSideBearing')
self.write_int16(0, 'minRightSideBearing')
self.write_int16(font.x_max_extent, 'xMaxExtent')
self.write_int16(100 if font.italic else 1, 'caretSlopeRise')
self.write_int16(20 if font.italic else 0, 'caretSlopeRun')
self.write_int16(0, 'caretOffset')
self.write_int16(0, 'reserved')
self.write_int16(0, 'reserved')
self.write_int16(0, 'reserved')
self.write_int16(0, 'reserved')
self.write_int16(0, 'metricDataFormat') # current
self.write_uint16(len(font.chars), 'numOfLongHorMetrics')
# check
self.check_size(HHEA_TABLE_SIZE)
# -- hmtx --
class HMTX(Table):
def __init__(self, font):
Table.__init__(self, 'hmtx')
for char in font.chars:
self.write_uint16(font.em_scale_width(char), 'advanceWidth')
self.write_int16(0, 'leftSideBearing')
# -- loca --
class LOCA(Table):
def __init__(self, font):
Table.__init__(self, 'loca')
if not font.params.single_loca:
for _ in font.chars:
self.write_uint16(0, 'offset')
self.write_uint16(0, 'offset')
# -- maxp --
MAXP_TABLE_SIZE = 32
class MAXP(Table):
def __init__(self, font):
Table.__init__(self, 'maxp')
self.write_fixed(1, 'version')
self.write_uint16(len(font.chars), 'numGlyphs')
self.write_uint16(0, 'maxPoints')
self.write_uint16(0, 'maxContours')
self.write_uint16(0, 'maxComponentPoints')
self.write_uint16(0, 'maxComponentContours')
self.write_uint16(2, 'maxZones')
self.write_uint16(0, 'maxTwilightPoints')
self.write_uint16(1, 'maxStorage')
self.write_uint16(1, 'maxFunctionDefs')
self.write_uint16(0, 'maxInstructionDefs')
self.write_uint16(64, 'maxStackElements')
self.write_uint16(0, 'maxSizeOfInstructions')
self.write_uint16(0, 'maxComponentElements')
self.write_uint16(0, 'maxComponentDepth')
# check
self.check_size(MAXP_TABLE_SIZE)
# -- name --
@unique # pylint: disable=invalid-name
class NAME_ID(IntEnum): # pylint: disable=invalid-name
COPYRIGHT = 0
FONT_FAMILY = 1
FONT_SUBFAMILY = 2
UNIQUE_SUBFAMILY = 3
FULL_FONT_NAME = 4
LICENSE = 14
NAME_HEADER_SIZE = 6
NAME_RECORD_SIZE = 12
class NAME(Table):
def __init__(self, font):
Table.__init__(self, 'name')
# compute names
names = OrderedDict()
copyright = font.props.get('COPYRIGHT')
if copyright is not None:
names[NAME_ID.COPYRIGHT] = fnutil.unquote(copyright)
family = font.xlfd[bdf.XLFD.FAMILY_NAME]
style = [b'Regular', b'Bold', b'Italic', b'Bold Italic'][font.mac_style]
names[NAME_ID.FONT_FAMILY] = family
names[NAME_ID.FONT_SUBFAMILY] = style
names[NAME_ID.UNIQUE_SUBFAMILY] = b'%s %s bitmap height %d' % (family, style, font.bbx.height)
names[NAME_ID.FULL_FONT_NAME] = b'%s %s' % (family, style)
license = font.props.get('LICENSE')
notice = font.props.get('NOTICE')
if license is None and notice is not None and b'license' in notice.lower():
license = notice
if license is not None:
names[NAME_ID.LICENSE] = fnutil.unquote(license)
# header
count = len(names) * (1 + 1) # Unicode + Microsoft
string_offset = NAME_HEADER_SIZE + NAME_RECORD_SIZE * count
self.write_uint16(0, 'format')
self.write_uint16(count, 'count')
self.write_uint16(string_offset, 'stringOffset')
# name records / create values
values = Table('name')
for [name_id, bstr] in names.items():
s = font.decode(bstr)
value = codecs.encode(s, 'utf_16_be')
bmp = font.bmp_only and len(value) == len(s) * 2
# Unicode
self.write_uint16(0, 'platformID') # Unicode
self.write_uint16(3 if bmp else 4, 'platformSpecificID')
self.write_uint16(0, 'languageID') # none
self.write_uint16(name_id, 'nameID')
self.write_uint16(len(value), 'length') # in bytes
self.write_uint16(values.size, 'offset')
# Microsoft
self.write_uint16(3, 'platformID') # Microsoft
self.write_uint16(1 if bmp else 10, 'platformSpecificID')
self.write_uint16(font.params.w_lang_id, 'languageID')
self.write_uint16(name_id, 'nameID')
self.write_uint16(len(value), 'length') # in bytes
self.write_uint16(values.size, 'offset')
# value
values.write(value)
# write values
self.write_table(values)
# check
self.check_size(string_offset + values.size)
# -- post --
POST_TABLE_SIZE = 32
class POST(Table):
def __init__(self, font):
Table.__init__(self, 'post')
self.write_fixed(2 if font.params.post_names else 3, 'format')
self.write_fixed(font.italic_angle, 'italicAngle')
self.write_int16(font.underline_position, 'underlinePosition')
self.write_int16(font.line_size, 'underlineThickness')
self.write_uint32(0 if font.proportional else 1, 'isFixedPitch')
self.write_uint32(0, 'minMemType42')
self.write_uint32(0, 'maxMemType42')
self.write_uint32(0, 'minMemType1')
self.write_uint32(0, 'maxMemType1')
# names
if font.params.post_names:
self.write_uint16(len(font.chars), 'numberOfGlyphs')
post_names = otb1get.post_mac_names()
post_mac_count = len(post_names)
for name in [char.props['STARTCHAR'] for char in font.chars]:
if name in post_names:
self.write_uint16(post_names.index(name), 'glyphNameIndex')
else:
self.write_uint16(len(post_names), 'glyphNameIndex')
post_names.append(name)
for name in post_names[post_mac_count:]:
self.write_uint8(len(name), 'glyphNameLength')
self.write(name)
# check
else:
self.check_size(POST_TABLE_SIZE)
# -- SFNT --
SFNT_HEADER_SIZE = 12
SFNT_RECORD_SIZE = 16
SFNT_SUBTABLES = (BDAT, BLOC, OS_2, CMAP, GLYF, HEAD, HHEA, HMTX, LOCA, MAXP, NAME, POST)
class SFNT(Table):
def __init__(self, font):
Table.__init__(self, 'SFNT')
# create tables
tables = []
for ctor in SFNT_SUBTABLES:
tables.append(ctor(font))
# header
num_tables = len(tables)
entry_selector = math.floor(math.log2(num_tables))
search_range = 16 << entry_selector
content_offset = SFNT_HEADER_SIZE + num_tables * SFNT_RECORD_SIZE
offset = content_offset
content = Table('SFNT')
head_checksum_offset = -1
self.write_fixed(1, 'sfntVersion')
self.write_uint16(num_tables, 'numTables')
self.write_uint16(search_range, 'searchRange')
self.write_uint16(entry_selector, 'entrySelector')
self.write_uint16(num_tables * 16 - search_range, 'rangeShift')
# table records / create content
for table in tables:
self.write(bytes(table.table_name, 'ascii'))
self.write_uint32(table.checksum(), 'checkSum')
self.write_uint32(offset, 'offset')
self.write_uint32(len(table.data), 'length')
# create content
if table.table_name == 'head':
head_checksum_offset = offset + HEAD_CHECKSUM_OFFSET
padded_data = table.data + table.padding
content.write(padded_data)
offset += len(padded_data)
# write content
self.write_table(content)
# check
self.check_size(content_offset + len(content.data))
# adjust
if head_checksum_offset != -1:
self.rewrite_uint32((0xB1B0AFBA - self.checksum()) & 0xFFFFFFFF, head_checksum_offset)

706
bin/otb1get.js Normal file
View File

@ -0,0 +1,706 @@
/*
Copyright (C) 2018-2020 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at your option)
any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
'use strict';
const fnutil = require('./fnutil.js');
// -- xAvgCharWidth --
const WEIGHT_FACTORS = [
[ 'a', 64 ],
[ 'b', 14 ],
[ 'c', 27 ],
[ 'd', 35 ],
[ 'e', 100 ],
[ 'f', 20 ],
[ 'g', 14 ],
[ 'h', 42 ],
[ 'i', 63 ],
[ 'j', 3 ],
[ 'k', 6 ],
[ 'l', 35 ],
[ 'm', 20 ],
[ 'n', 56 ],
[ 'o', 56 ],
[ 'p', 17 ],
[ 'q', 4 ],
[ 'r', 49 ],
[ 's', 56 ],
[ 't', 71 ],
[ 'u', 31 ],
[ 'v', 10 ],
[ 'w', 18 ],
[ 'x', 3 ],
[ 'y', 18 ],
[ 'z', 2 ],
[ ' ', 166 ]
];
function xAvgCharWidth(font) {
let xAvgTotalWidth = 0;
for (let factor of WEIGHT_FACTORS) {
const char = font.chars.find(_char => _char.code === factor[0].charCodeAt(0));
if (char == null) {
return 0;
}
xAvgTotalWidth += font.scaleWidth(char) * factor[1];
}
return fnutil.round(xAvgTotalWidth / 1000);
}
// -- ulCharRanges --
const CHAR_RANGES = [
[ 0, 0x0000, 0x007F ],
[ 1, 0x0080, 0x00FF ],
[ 2, 0x0100, 0x017F ],
[ 3, 0x0180, 0x024F ],
[ 4, 0x0250, 0x02AF ],
[ 4, 0x1D00, 0x1D7F ],
[ 4, 0x1D80, 0x1DBF ],
[ 5, 0x02B0, 0x02FF ],
[ 5, 0xA700, 0xA71F ],
[ 6, 0x0300, 0x036F ],
[ 6, 0x1DC0, 0x1DFF ],
[ 7, 0x0370, 0x03FF ],
[ 8, 0x2C80, 0x2CFF ],
[ 9, 0x0400, 0x04FF ],
[ 9, 0x0500, 0x052F ],
[ 9, 0x2DE0, 0x2DFF ],
[ 9, 0xA640, 0xA69F ],
[ 10, 0x0530, 0x058F ],
[ 11, 0x0590, 0x05FF ],
[ 12, 0xA500, 0xA63F ],
[ 13, 0x0600, 0x06FF ],
[ 13, 0x0750, 0x077F ],
[ 14, 0x07C0, 0x07FF ],
[ 15, 0x0900, 0x097F ],
[ 16, 0x0980, 0x09FF ],
[ 17, 0x0A00, 0x0A7F ],
[ 18, 0x0A80, 0x0AFF ],
[ 19, 0x0B00, 0x0B7F ],
[ 20, 0x0B80, 0x0BFF ],
[ 21, 0x0C00, 0x0C7F ],
[ 22, 0x0C80, 0x0CFF ],
[ 23, 0x0D00, 0x0D7F ],
[ 24, 0x0E00, 0x0E7F ],
[ 25, 0x0E80, 0x0EFF ],
[ 26, 0x10A0, 0x10FF ],
[ 26, 0x2D00, 0x2D2F ],
[ 27, 0x1B00, 0x1B7F ],
[ 28, 0x1100, 0x11FF ],
[ 29, 0x1E00, 0x1EFF ],
[ 29, 0x2C60, 0x2C7F ],
[ 29, 0xA720, 0xA7FF ],
[ 30, 0x1F00, 0x1FFF ],
[ 31, 0x2000, 0x206F ],
[ 31, 0x2E00, 0x2E7F ],
[ 32, 0x2070, 0x209F ],
[ 33, 0x20A0, 0x20CF ],
[ 34, 0x20D0, 0x20FF ],
[ 35, 0x2100, 0x214F ],
[ 36, 0x2150, 0x218F ],
[ 37, 0x2190, 0x21FF ],
[ 37, 0x27F0, 0x27FF ],
[ 37, 0x2900, 0x297F ],
[ 37, 0x2B00, 0x2BFF ],
[ 38, 0x2200, 0x22FF ],
[ 38, 0x2A00, 0x2AFF ],
[ 38, 0x27C0, 0x27EF ],
[ 38, 0x2980, 0x29FF ],
[ 39, 0x2300, 0x23FF ],
[ 40, 0x2400, 0x243F ],
[ 41, 0x2440, 0x245F ],
[ 42, 0x2460, 0x24FF ],
[ 43, 0x2500, 0x257F ],
[ 44, 0x2580, 0x259F ],
[ 45, 0x25A0, 0x25FF ],
[ 46, 0x2600, 0x26FF ],
[ 47, 0x2700, 0x27BF ],
[ 48, 0x3000, 0x303F ],
[ 49, 0x3040, 0x309F ],
[ 50, 0x30A0, 0x30FF ],
[ 50, 0x31F0, 0x31FF ],
[ 51, 0x3100, 0x312F ],
[ 51, 0x31A0, 0x31BF ],
[ 52, 0x3130, 0x318F ],
[ 53, 0xA840, 0xA87F ],
[ 54, 0x3200, 0x32FF ],
[ 55, 0x3300, 0x33FF ],
[ 56, 0xAC00, 0xD7AF ],
[ 57, 0xD800, 0xDFFF ],
[ 58, 0x10900, 0x1091F ],
[ 59, 0x4E00, 0x9FFF ],
[ 59, 0x2E80, 0x2EFF ],
[ 59, 0x2F00, 0x2FDF ],
[ 59, 0x2FF0, 0x2FFF ],
[ 59, 0x3400, 0x4DBF ],
[ 59, 0x20000, 0x2A6DF ],
[ 59, 0x3190, 0x319F ],
[ 60, 0xE000, 0xF8FF ],
[ 61, 0x31C0, 0x31EF ],
[ 61, 0xF900, 0xFAFF ],
[ 61, 0x2F800, 0x2FA1F ],
[ 62, 0xFB00, 0xFB4F ],
[ 63, 0xFB50, 0xFDFF ],
[ 64, 0xFE20, 0xFE2F ],
[ 65, 0xFE10, 0xFE1F ],
[ 65, 0xFE30, 0xFE4F ],
[ 66, 0xFE50, 0xFE6F ],
[ 67, 0xFE70, 0xFEFF ],
[ 68, 0xFF00, 0xFFEF ],
[ 69, 0xFFF0, 0xFFFF ],
[ 70, 0x0F00, 0x0FFF ],
[ 71, 0x0700, 0x074F ],
[ 72, 0x0780, 0x07BF ],
[ 73, 0x0D80, 0x0DFF ],
[ 74, 0x1000, 0x109F ],
[ 75, 0x1200, 0x137F ],
[ 75, 0x1380, 0x139F ],
[ 75, 0x2D80, 0x2DDF ],
[ 76, 0x13A0, 0x13FF ],
[ 77, 0x1400, 0x167F ],
[ 78, 0x1680, 0x169F ],
[ 79, 0x16A0, 0x16FF ],
[ 80, 0x1780, 0x17FF ],
[ 80, 0x19E0, 0x19FF ],
[ 81, 0x1800, 0x18AF ],
[ 82, 0x2800, 0x28FF ],
[ 83, 0xA000, 0xA48F ],
[ 83, 0xA490, 0xA4CF ],
[ 84, 0x1700, 0x171F ],
[ 84, 0x1720, 0x173F ],
[ 84, 0x1740, 0x175F ],
[ 84, 0x1760, 0x177F ],
[ 85, 0x10300, 0x1032F ],
[ 86, 0x10330, 0x1034F ],
[ 87, 0x10400, 0x1044F ],
[ 88, 0x1D000, 0x1D0FF ],
[ 88, 0x1D100, 0x1D1FF ],
[ 88, 0x1D200, 0x1D24F ],
[ 89, 0x1D400, 0x1D7FF ],
[ 90, 0xF0000, 0xFFFFD ],
[ 90, 0x100000, 0x10FFFD ],
[ 91, 0xFE00, 0xFE0F ],
[ 91, 0xE0100, 0xE01EF ],
[ 92, 0xE0000, 0xE007F ],
[ 93, 0x1900, 0x194F ],
[ 94, 0x1950, 0x197F ],
[ 95, 0x1980, 0x19DF ],
[ 96, 0x1A00, 0x1A1F ],
[ 97, 0x2C00, 0x2C5F ],
[ 98, 0x2D30, 0x2D7F ],
[ 99, 0x4DC0, 0x4DFF ],
[ 100, 0xA800, 0xA82F ],
[ 101, 0x10000, 0x1007F ],
[ 101, 0x10080, 0x100FF ],
[ 101, 0x10100, 0x1013F ],
[ 102, 0x10140, 0x1018F ],
[ 103, 0x10380, 0x1039F ],
[ 104, 0x103A0, 0x103DF ],
[ 105, 0x10450, 0x1047F ],
[ 106, 0x10480, 0x104AF ],
[ 107, 0x10800, 0x1083F ],
[ 108, 0x10A00, 0x10A5F ],
[ 109, 0x1D300, 0x1D35F ],
[ 110, 0x12000, 0x123FF ],
[ 110, 0x12400, 0x1247F ],
[ 111, 0x1D360, 0x1D37F ],
[ 112, 0x1B80, 0x1BBF ],
[ 113, 0x1C00, 0x1C4F ],
[ 114, 0x1C50, 0x1C7F ],
[ 115, 0xA880, 0xA8DF ],
[ 116, 0xA900, 0xA92F ],
[ 117, 0xA930, 0xA95F ],
[ 118, 0xAA00, 0xAA5F ],
[ 119, 0x10190, 0x101CF ],
[ 120, 0x101D0, 0x101FF ],
[ 121, 0x102A0, 0x102DF ],
[ 121, 0x10280, 0x1029F ],
[ 121, 0x10920, 0x1093F ],
[ 122, 0x1F030, 0x1F09F ],
[ 122, 0x1F000, 0x1F02F ]
];
function ulCharRanges(font) {
let charRanges = [0, 0, 0, 0];
font.chars.forEach(char => {
const unicode = char.code;
const range = CHAR_RANGES.find(_range => unicode >= _range[1] && unicode <= _range[2]);
if (range != null) {
charRanges[range[0] >> 5] |= 1 << (range[0] & 0x1F);
}
});
if (font.maxCode >= 0x10000) {
charRanges[57 >> 5] |= 1 << (57 & 0x1F);
}
return [ charRanges[0] >>> 0, charRanges[1] >>> 0, charRanges[2] >>> 0, charRanges[3] >>> 0 ];
}
// -- ulCodePages --
function ulCodePages(font) {
const spaceIndex = font.chars.findIndex(char => char.code === 0x20);
const ascii = Number(spaceIndex !== -1 && font.chars[spaceIndex + 0x5E].code === 0x7E);
const findf = (unicode) => Number(font.chars.findIndex(char => char.code === unicode) !== -1);
const graph = findf(0x2524);
const radic = findf(0x221A);
let codePages = [0, 0];
// conditions from FontForge
font.chars.forEach(char => {
switch (char.code) {
case 0x00DE:
codePages[0] |= (ascii) << 0; // 1252 Latin1
break;
case 0x255A:
codePages[1] |= (ascii) << 30; // 850 WE/Latin1
codePages[1] |= (ascii) << 31; // 437 US
break;
case 0x013D:
codePages[0] |= (ascii) << 1; // 1250 Latin 2: Eastern Europe
codePages[1] |= (ascii & graph) << 26; // 852 Latin 2
break;
case 0x0411:
codePages[0] |= 1 << 2; // 1251 Cyrillic
codePages[1] |= (findf(0x255C) & graph) << 17; // 866 MS-DOS Russian
codePages[1] |= (findf(0x0405) & graph) << 25; // 855 IBM Cyrillic
break;
case 0x0386:
codePages[0] |= 1 << 3; // 1253 Greek
codePages[1] |= (findf(0x00BD) & graph) << 16; // 869 IBM Greek
codePages[1] |= (graph & radic) << 28; // 737 Greek; former 437 G
break;
case 0x0130:
codePages[0] |= (ascii) << 4; // 1254 Turkish
codePages[1] |= (ascii & graph) << 24; // 857 IBM Turkish
break;
case 0x05D0:
codePages[0] |= 1 << 5; // 1255 Hebrew
codePages[1] |= (graph & radic) << 21; // 862 Hebrew
break;
case 0x0631:
codePages[0] |= 1 << 6; // 1256 Arabic
codePages[1] |= (radic) << 19; // 864 Arabic
codePages[1] |= (graph) << 29; // 708 Arabic; ASMO 708
break;
case 0x0157:
codePages[0] |= (ascii) << 7; // 1257 Windows Baltic
codePages[1] |= (ascii & graph) << 27; // 775 MS-DOS Baltic
break;
case 0x20AB:
codePages[0] |= 1 << 8; // 1258 Vietnamese
break;
case 0x0E45:
codePages[0] |= 1 << 16; // 874 Thai
break;
case 0x30A8:
codePages[0] |= 1 << 17; // 932 JIS/Japan
break;
case 0x3105:
codePages[0] |= 1 << 18; // 936 Chinese: Simplified chars
break;
case 0x3131:
codePages[0] |= 1 << 19; // 949 Korean Wansung
break;
case 0x592E:
codePages[0] |= 1 << 20; // 950 Chinese: Traditional chars
break;
case 0xACF4:
codePages[0] |= 1 << 21; // 1361 Korean Johab
break;
case 0x2030:
codePages[0] |= (findf(0x2211) & ascii) << 29; // Macintosh Character Set (Roman)
break;
case 0x2665:
codePages[0] |= (ascii) << 30; // OEM Character Set
break;
case 0x00C5:
codePages[1] |= (ascii & graph & radic) << 18; // 865 MS-DOS Nordic
break;
case 0x00E9:
codePages[1] |= (ascii & graph & radic) << 20; // 863 MS-DOS Canadian French
break;
case 0x00F5:
codePages[1] |= (ascii & graph & radic) << 23; // 860 MS-DOS Portuguese
break;
case 0x00FE:
codePages[1] |= (ascii & graph) << 22; // 861 MS-DOS Icelandic
break;
default :
if (char.code >= 0xF000 && char.code <= 0xF0FF) {
codePages[0] |= 1 << 31; // Symbol Character Set
}
break;
}
});
return [ codePages[0] >>> 0, codePages[1] >>> 0 ];
}
// -- containsRTL --
const RTL_RANGES = [
[ 0x05BE, 0x05BE ],
[ 0x05C0, 0x05C0 ],
[ 0x05C3, 0x05C3 ],
[ 0x05C6, 0x05C6 ],
[ 0x05D0, 0x05EA ],
[ 0x05EF, 0x05F4 ],
[ 0x0608, 0x0608 ],
[ 0x060B, 0x060B ],
[ 0x060D, 0x060D ],
[ 0x061B, 0x061C ],
[ 0x061E, 0x064A ],
[ 0x066D, 0x066F ],
[ 0x0671, 0x06D5 ],
[ 0x06E5, 0x06E6 ],
[ 0x06EE, 0x06EF ],
[ 0x06FA, 0x070D ],
[ 0x070F, 0x0710 ],
[ 0x0712, 0x072F ],
[ 0x074D, 0x07A5 ],
[ 0x07B1, 0x07B1 ],
[ 0x07C0, 0x07EA ],
[ 0x07F4, 0x07F5 ],
[ 0x07FA, 0x07FA ],
[ 0x07FE, 0x0815 ],
[ 0x081A, 0x081A ],
[ 0x0824, 0x0824 ],
[ 0x0828, 0x0828 ],
[ 0x0830, 0x083E ],
[ 0x0840, 0x0858 ],
[ 0x085E, 0x085E ],
[ 0x0860, 0x086A ],
[ 0x08A0, 0x08B4 ],
[ 0x08B6, 0x08BD ],
[ 0x200F, 0x200F ],
[ 0x202B, 0x202B ],
[ 0x202E, 0x202E ],
[ 0xFB1D, 0xFB1D ],
[ 0xFB1F, 0xFB28 ],
[ 0xFB2A, 0xFB36 ],
[ 0xFB38, 0xFB3C ],
[ 0xFB3E, 0xFB3E ],
[ 0xFB40, 0xFB41 ],
[ 0xFB43, 0xFB44 ],
[ 0xFB46, 0xFBC1 ],
[ 0xFBD3, 0xFD3D ],
[ 0xFD50, 0xFD8F ],
[ 0xFD92, 0xFDC7 ],
[ 0xFDF0, 0xFDFC ],
[ 0xFE70, 0xFE74 ],
[ 0xFE76, 0xFEFC ],
[ 0x10800, 0x10FFF ],
[ 0x1E800, 0x1EFFF ],
[ -1, 0 ]
];
function containsRTL(font) {
let index = 0;
for (let char of font.chars) {
while (char.code > RTL_RANGES[index][1]) {
if (RTL_RANGES[++index][0] === -1) {
break;
}
}
if (char.code >= RTL_RANGES[index][0]) {
return 0x200;
}
}
return 0x000;
}
// -- postMacIndex --
const POST_MAC_NAMES = [
'.notdef',
'.null',
'nonmarkingreturn',
'space',
'exclam',
'quotedbl',
'numbersign',
'dollar',
'percent',
'ampersand',
'quotesingle',
'parenleft',
'parenright',
'asterisk',
'plus',
'comma',
'hyphen',
'period',
'slash',
'zero',
'one',
'two',
'three',
'four',
'five',
'six',
'seven',
'eight',
'nine',
'colon',
'semicolon',
'less',
'equal',
'greater',
'question',
'at',
'A',
'B',
'C',
'D',
'E',
'F',
'G',
'H',
'I',
'J',
'K',
'L',
'M',
'N',
'O',
'P',
'Q',
'R',
'S',
'T',
'U',
'V',
'W',
'X',
'Y',
'Z',
'bracketleft',
'backslash',
'bracketright',
'asciicircum',
'underscore',
'grave',
'a',
'b',
'c',
'd',
'e',
'f',
'g',
'h',
'i',
'j',
'k',
'l',
'm',
'n',
'o',
'p',
'q',
'r',
's',
't',
'u',
'v',
'w',
'x',
'y',
'z',
'braceleft',
'bar',
'braceright',
'asciitilde',
'Adieresis',
'Aring',
'Ccedilla',
'Eacute',
'Ntilde',
'Odieresis',
'Udieresis',
'aacute',
'agrave',
'acircumflex',
'adieresis',
'atilde',
'aring',
'ccedilla',
'eacute',
'egrave',
'ecircumflex',
'edieresis',
'iacute',
'igrave',
'icircumflex',
'idieresis',
'ntilde',
'oacute',
'ograve',
'ocircumflex',
'odieresis',
'otilde',
'uacute',
'ugrave',
'ucircumflex',
'udieresis',
'dagger',
'degree',
'cent',
'sterling',
'section',
'bullet',
'paragraph',
'germandbls',
'registered',
'copyright',
'trademark',
'acute',
'dieresis',
'notequal',
'AE',
'Oslash',
'infinity',
'plusminus',
'lessequal',
'greaterequal',
'yen',
'mu',
'partialdiff',
'summation',
'product',
'pi',
'integral',
'ordfeminine',
'ordmasculine',
'Omega',
'ae',
'oslash',
'questiondown',
'exclamdown',
'logicalnot',
'radical',
'florin',
'approxequal',
'Delta',
'guillemotleft',
'guillemotright',
'ellipsis',
'nonbreakingspace',
'Agrave',
'Atilde',
'Otilde',
'OE',
'oe',
'endash',
'emdash',
'quotedblleft',
'quotedblright',
'quoteleft',
'quoteright',
'divide',
'lozenge',
'ydieresis',
'Ydieresis',
'fraction',
'currency',
'guilsinglleft',
'guilsinglright',
'fi',
'fl',
'daggerdbl',
'periodcentered',
'quotesinglbase',
'quotedblbase',
'perthousand',
'Acircumflex',
'Ecircumflex',
'Aacute',
'Edieresis',
'Egrave',
'Iacute',
'Icircumflex',
'Idieresis',
'Igrave',
'Oacute',
'Ocircumflex',
'apple',
'Ograve',
'Uacute',
'Ucircumflex',
'Ugrave',
'dotlessi',
'circumflex',
'tilde',
'macron',
'breve',
'dotaccent',
'ring',
'cedilla',
'hungarumlaut',
'ogonek',
'caron',
'Lslash',
'lslash',
'Scaron',
'scaron',
'Zcaron',
'zcaron',
'brokenbar',
'Eth',
'eth',
'Yacute',
'yacute',
'Thorn',
'thorn',
'minus',
'multiply',
'onesuperior',
'twosuperior',
'threesuperior',
'onehalf',
'onequarter',
'threequarters',
'franc',
'Gbreve',
'gbreve',
'Idotaccent',
'Scedilla',
'scedilla',
'Cacute',
'cacute',
'Ccaron',
'ccaron',
'dcroat'
];
function postMacNames() {
return POST_MAC_NAMES.slice();
}
// -- Export --
module.exports = Object.freeze({
xAvgCharWidth,
ulCharRanges,
ulCodePages,
containsRTL,
postMacNames
});

663
bin/otb1get.py Normal file
View File

@ -0,0 +1,663 @@
#
# Copyright (C) 2018-2020 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# pylint: disable=bad-whitespace
# -- x_avg_char_width --
WEIGHT_FACTORS = (
( 'a', 64 ),
( 'b', 14 ),
( 'c', 27 ),
( 'd', 35 ),
( 'e', 100 ),
( 'f', 20 ),
( 'g', 14 ),
( 'h', 42 ),
( 'i', 63 ),
( 'j', 3 ),
( 'k', 6 ),
( 'l', 35 ),
( 'm', 20 ),
( 'n', 56 ),
( 'o', 56 ),
( 'p', 17 ),
( 'q', 4 ),
( 'r', 49 ),
( 's', 56 ),
( 't', 71 ),
( 'u', 31 ),
( 'v', 10 ),
( 'w', 18 ),
( 'x', 3 ),
( 'y', 18 ),
( 'z', 2 ),
( ' ', 166 )
)
def x_avg_char_width(font):
x_avg_total_width = 0
for factor in WEIGHT_FACTORS:
char = next((char for char in font.chars if char.code == ord(factor[0])), None)
if char is None:
return 0
x_avg_total_width += font.scaleWidth(char) * factor[1]
return round(x_avg_total_width / 1000)
# -- ul_char_ranges --
CHAR_RANGES = (
( 0, 0x0000, 0x007F ),
( 1, 0x0080, 0x00FF ),
( 2, 0x0100, 0x017F ),
( 3, 0x0180, 0x024F ),
( 4, 0x0250, 0x02AF ),
( 4, 0x1D00, 0x1D7F ),
( 4, 0x1D80, 0x1DBF ),
( 5, 0x02B0, 0x02FF ),
( 5, 0xA700, 0xA71F ),
( 6, 0x0300, 0x036F ),
( 6, 0x1DC0, 0x1DFF ),
( 7, 0x0370, 0x03FF ),
( 8, 0x2C80, 0x2CFF ),
( 9, 0x0400, 0x04FF ),
( 9, 0x0500, 0x052F ),
( 9, 0x2DE0, 0x2DFF ),
( 9, 0xA640, 0xA69F ),
( 10, 0x0530, 0x058F ),
( 11, 0x0590, 0x05FF ),
( 12, 0xA500, 0xA63F ),
( 13, 0x0600, 0x06FF ),
( 13, 0x0750, 0x077F ),
( 14, 0x07C0, 0x07FF ),
( 15, 0x0900, 0x097F ),
( 16, 0x0980, 0x09FF ),
( 17, 0x0A00, 0x0A7F ),
( 18, 0x0A80, 0x0AFF ),
( 19, 0x0B00, 0x0B7F ),
( 20, 0x0B80, 0x0BFF ),
( 21, 0x0C00, 0x0C7F ),
( 22, 0x0C80, 0x0CFF ),
( 23, 0x0D00, 0x0D7F ),
( 24, 0x0E00, 0x0E7F ),
( 25, 0x0E80, 0x0EFF ),
( 26, 0x10A0, 0x10FF ),
( 26, 0x2D00, 0x2D2F ),
( 27, 0x1B00, 0x1B7F ),
( 28, 0x1100, 0x11FF ),
( 29, 0x1E00, 0x1EFF ),
( 29, 0x2C60, 0x2C7F ),
( 29, 0xA720, 0xA7FF ),
( 30, 0x1F00, 0x1FFF ),
( 31, 0x2000, 0x206F ),
( 31, 0x2E00, 0x2E7F ),
( 32, 0x2070, 0x209F ),
( 33, 0x20A0, 0x20CF ),
( 34, 0x20D0, 0x20FF ),
( 35, 0x2100, 0x214F ),
( 36, 0x2150, 0x218F ),
( 37, 0x2190, 0x21FF ),
( 37, 0x27F0, 0x27FF ),
( 37, 0x2900, 0x297F ),
( 37, 0x2B00, 0x2BFF ),
( 38, 0x2200, 0x22FF ),
( 38, 0x2A00, 0x2AFF ),
( 38, 0x27C0, 0x27EF ),
( 38, 0x2980, 0x29FF ),
( 39, 0x2300, 0x23FF ),
( 40, 0x2400, 0x243F ),
( 41, 0x2440, 0x245F ),
( 42, 0x2460, 0x24FF ),
( 43, 0x2500, 0x257F ),
( 44, 0x2580, 0x259F ),
( 45, 0x25A0, 0x25FF ),
( 46, 0x2600, 0x26FF ),
( 47, 0x2700, 0x27BF ),
( 48, 0x3000, 0x303F ),
( 49, 0x3040, 0x309F ),
( 50, 0x30A0, 0x30FF ),
( 50, 0x31F0, 0x31FF ),
( 51, 0x3100, 0x312F ),
( 51, 0x31A0, 0x31BF ),
( 52, 0x3130, 0x318F ),
( 53, 0xA840, 0xA87F ),
( 54, 0x3200, 0x32FF ),
( 55, 0x3300, 0x33FF ),
( 56, 0xAC00, 0xD7AF ),
( 57, 0xD800, 0xDFFF ),
( 58, 0x10900, 0x1091F ),
( 59, 0x4E00, 0x9FFF ),
( 59, 0x2E80, 0x2EFF ),
( 59, 0x2F00, 0x2FDF ),
( 59, 0x2FF0, 0x2FFF ),
( 59, 0x3400, 0x4DBF ),
( 59, 0x20000, 0x2A6DF ),
( 59, 0x3190, 0x319F ),
( 60, 0xE000, 0xF8FF ),
( 61, 0x31C0, 0x31EF ),
( 61, 0xF900, 0xFAFF ),
( 61, 0x2F800, 0x2FA1F ),
( 62, 0xFB00, 0xFB4F ),
( 63, 0xFB50, 0xFDFF ),
( 64, 0xFE20, 0xFE2F ),
( 65, 0xFE10, 0xFE1F ),
( 65, 0xFE30, 0xFE4F ),
( 66, 0xFE50, 0xFE6F ),
( 67, 0xFE70, 0xFEFF ),
( 68, 0xFF00, 0xFFEF ),
( 69, 0xFFF0, 0xFFFF ),
( 70, 0x0F00, 0x0FFF ),
( 71, 0x0700, 0x074F ),
( 72, 0x0780, 0x07BF ),
( 73, 0x0D80, 0x0DFF ),
( 74, 0x1000, 0x109F ),
( 75, 0x1200, 0x137F ),
( 75, 0x1380, 0x139F ),
( 75, 0x2D80, 0x2DDF ),
( 76, 0x13A0, 0x13FF ),
( 77, 0x1400, 0x167F ),
( 78, 0x1680, 0x169F ),
( 79, 0x16A0, 0x16FF ),
( 80, 0x1780, 0x17FF ),
( 80, 0x19E0, 0x19FF ),
( 81, 0x1800, 0x18AF ),
( 82, 0x2800, 0x28FF ),
( 83, 0xA000, 0xA48F ),
( 83, 0xA490, 0xA4CF ),
( 84, 0x1700, 0x171F ),
( 84, 0x1720, 0x173F ),
( 84, 0x1740, 0x175F ),
( 84, 0x1760, 0x177F ),
( 85, 0x10300, 0x1032F ),
( 86, 0x10330, 0x1034F ),
( 87, 0x10400, 0x1044F ),
( 88, 0x1D000, 0x1D0FF ),
( 88, 0x1D100, 0x1D1FF ),
( 88, 0x1D200, 0x1D24F ),
( 89, 0x1D400, 0x1D7FF ),
( 90, 0xF0000, 0xFFFFD ),
( 90, 0x100000, 0x10FFFD ),
( 91, 0xFE00, 0xFE0F ),
( 91, 0xE0100, 0xE01EF ),
( 92, 0xE0000, 0xE007F ),
( 93, 0x1900, 0x194F ),
( 94, 0x1950, 0x197F ),
( 95, 0x1980, 0x19DF ),
( 96, 0x1A00, 0x1A1F ),
( 97, 0x2C00, 0x2C5F ),
( 98, 0x2D30, 0x2D7F ),
( 99, 0x4DC0, 0x4DFF ),
( 100, 0xA800, 0xA82F ),
( 101, 0x10000, 0x1007F ),
( 101, 0x10080, 0x100FF ),
( 101, 0x10100, 0x1013F ),
( 102, 0x10140, 0x1018F ),
( 103, 0x10380, 0x1039F ),
( 104, 0x103A0, 0x103DF ),
( 105, 0x10450, 0x1047F ),
( 106, 0x10480, 0x104AF ),
( 107, 0x10800, 0x1083F ),
( 108, 0x10A00, 0x10A5F ),
( 109, 0x1D300, 0x1D35F ),
( 110, 0x12000, 0x123FF ),
( 110, 0x12400, 0x1247F ),
( 111, 0x1D360, 0x1D37F ),
( 112, 0x1B80, 0x1BBF ),
( 113, 0x1C00, 0x1C4F ),
( 114, 0x1C50, 0x1C7F ),
( 115, 0xA880, 0xA8DF ),
( 116, 0xA900, 0xA92F ),
( 117, 0xA930, 0xA95F ),
( 118, 0xAA00, 0xAA5F ),
( 119, 0x10190, 0x101CF ),
( 120, 0x101D0, 0x101FF ),
( 121, 0x102A0, 0x102DF ),
( 121, 0x10280, 0x1029F ),
( 121, 0x10920, 0x1093F ),
( 122, 0x1F030, 0x1F09F ),
( 122, 0x1F000, 0x1F02F )
)
def ul_char_ranges(font):
char_ranges = [0, 0, 0, 0]
for char in font.chars:
range = next((range for range in CHAR_RANGES if range[1] <= char.code <= range[2]), None)
if range is not None:
char_ranges[range[0] >> 5] |= 1 << (range[0] & 0x1F)
if font.max_code >= 0x10000:
char_ranges[57 >> 5] |= 1 << (57 & 0x1F)
return char_ranges
# -- ul_code_pages --
def ul_code_pages(font):
space_index = next((index for index, char in enumerate(font.chars) if char.code == 0x20), len(font.chars))
ascii = int(len(font.chars) >= space_index + 0x5F and font.chars[space_index + 0x5E].code == 0x7E)
findf = lambda unicode: int(next((char for char in font.chars if char.code == unicode), None) is not None)
graph = findf(0x2524)
radic = findf(0x221A)
code_pages = [0, 0]
# conditions from FontForge
for char in font.chars:
unicode = char.code
if unicode == 0x00DE:
code_pages[0] |= (ascii) << 0 # 1252 Latin1
elif unicode == 0x255A:
code_pages[1] |= (ascii) << 30 # 850 WE/Latin1
code_pages[1] |= (ascii) << 31 # 437 US
elif unicode == 0x013D:
code_pages[0] |= (ascii) << 1 # 1250 Latin 2: Eastern Europe
code_pages[1] |= (ascii & graph) << 26 # 852 Latin 2
elif unicode == 0x0411:
code_pages[0] |= 1 << 2 # 1251 Cyrillic
code_pages[1] |= (findf(0x255C) & graph) << 17 # 866 MS-DOS Russian
code_pages[1] |= (findf(0x0405) & graph) << 25 # 855 IBM Cyrillic
elif unicode == 0x0386:
code_pages[0] |= 1 << 3 # 1253 Greek
code_pages[1] |= (findf(0x00BD) & graph) << 16 # 869 IBM Greek
code_pages[1] |= (graph & radic) << 28 # 737 Greek; former 437 G
elif unicode == 0x0130:
code_pages[0] |= (ascii) << 4 # 1254 Turkish
code_pages[1] |= (ascii & graph) << 24 # 857 IBM Turkish
elif unicode == 0x05D0:
code_pages[0] |= 1 << 5 # 1255 Hebrew
code_pages[1] |= (graph & radic) << 21 # 862 Hebrew
elif unicode == 0x0631:
code_pages[0] |= 1 << 6 # 1256 Arabic
code_pages[1] |= (radic) << 19 # 864 Arabic
code_pages[1] |= (graph) << 29 # 708 Arabic; ASMO 708
elif unicode == 0x0157:
code_pages[0] |= (ascii) << 7 # 1257 Windows Baltic
code_pages[1] |= (ascii & graph) << 27 # 775 MS-DOS Baltic
elif unicode == 0x20AB:
code_pages[0] |= 1 << 8 # 1258 Vietnamese
elif unicode == 0x0E45:
code_pages[0] |= 1 << 16 # 874 Thai
elif unicode == 0x30A8:
code_pages[0] |= 1 << 17 # 932 JIS/Japan
elif unicode == 0x3105:
code_pages[0] |= 1 << 18 # 936 Chinese: Simplified chars
elif unicode == 0x3131:
code_pages[0] |= 1 << 19 # 949 Korean Wansung
elif unicode == 0x592E:
code_pages[0] |= 1 << 20 # 950 Chinese: Traditional chars
elif unicode == 0xACF4:
code_pages[0] |= 1 << 21 # 1361 Korean Johab
elif unicode == 0x2030:
code_pages[0] |= (findf(0x2211) & ascii) << 29 # Macintosh Character Set (Roman)
elif unicode == 0x2665:
code_pages[0] |= (ascii) << 30 # OEM Character Set
elif unicode == 0x00C5:
code_pages[1] |= (ascii & graph & radic) << 18 # 865 MS-DOS Nordic
elif unicode == 0x00E9:
code_pages[1] |= (ascii & graph & radic) << 20 # 863 MS-DOS Canadian French
elif unicode == 0x00F5:
code_pages[1] |= (ascii & graph & radic) << 23 # 860 MS-DOS Portuguese
elif unicode == 0x00FE:
code_pages[1] |= (ascii & graph) << 22 # 861 MS-DOS Icelandic
elif 0xF000 <= unicode <= 0xF0FF:
code_pages[0] |= 1 << 31 # Symbol Character Set
return code_pages
# -- strong_rtl_flag --
RTL_RANGES = (
( 0x05BE, 0x05BE ),
( 0x05C0, 0x05C0 ),
( 0x05C3, 0x05C3 ),
( 0x05C6, 0x05C6 ),
( 0x05D0, 0x05EA ),
( 0x05EF, 0x05F4 ),
( 0x0608, 0x0608 ),
( 0x060B, 0x060B ),
( 0x060D, 0x060D ),
( 0x061B, 0x061C ),
( 0x061E, 0x064A ),
( 0x066D, 0x066F ),
( 0x0671, 0x06D5 ),
( 0x06E5, 0x06E6 ),
( 0x06EE, 0x06EF ),
( 0x06FA, 0x070D ),
( 0x070F, 0x0710 ),
( 0x0712, 0x072F ),
( 0x074D, 0x07A5 ),
( 0x07B1, 0x07B1 ),
( 0x07C0, 0x07EA ),
( 0x07F4, 0x07F5 ),
( 0x07FA, 0x07FA ),
( 0x07FE, 0x0815 ),
( 0x081A, 0x081A ),
( 0x0824, 0x0824 ),
( 0x0828, 0x0828 ),
( 0x0830, 0x083E ),
( 0x0840, 0x0858 ),
( 0x085E, 0x085E ),
( 0x0860, 0x086A ),
( 0x08A0, 0x08B4 ),
( 0x08B6, 0x08BD ),
( 0x200F, 0x200F ),
( 0x202B, 0x202B ),
( 0x202E, 0x202E ),
( 0xFB1D, 0xFB1D ),
( 0xFB1F, 0xFB28 ),
( 0xFB2A, 0xFB36 ),
( 0xFB38, 0xFB3C ),
( 0xFB3E, 0xFB3E ),
( 0xFB40, 0xFB41 ),
( 0xFB43, 0xFB44 ),
( 0xFB46, 0xFBC1 ),
( 0xFBD3, 0xFD3D ),
( 0xFD50, 0xFD8F ),
( 0xFD92, 0xFDC7 ),
( 0xFDF0, 0xFDFC ),
( 0xFE70, 0xFE74 ),
( 0xFE76, 0xFEFC ),
( 0x10800, 0x10FFF ),
( 0x1E800, 0x1EFFF ),
(-1, 0)
)
def contains_rtl(font):
index = 0
for char in font.chars:
while char.code > RTL_RANGES[index][1]:
index += 1
if RTL_RANGES[index][0] == -1:
break
if char.code >= RTL_RANGES[index][0]:
return True
return False
# -- post_mac_names --
POST_MAC_NAMES = (
b'.notdef',
b'.null',
b'nonmarkingreturn',
b'space',
b'exclam',
b'quotedbl',
b'numbersign',
b'dollar',
b'percent',
b'ampersand',
b'quotesingle',
b'parenleft',
b'parenright',
b'asterisk',
b'plus',
b'comma',
b'hyphen',
b'period',
b'slash',
b'zero',
b'one',
b'two',
b'three',
b'four',
b'five',
b'six',
b'seven',
b'eight',
b'nine',
b'colon',
b'semicolon',
b'less',
b'equal',
b'greater',
b'question',
b'at',
b'A',
b'B',
b'C',
b'D',
b'E',
b'F',
b'G',
b'H',
b'I',
b'J',
b'K',
b'L',
b'M',
b'N',
b'O',
b'P',
b'Q',
b'R',
b'S',
b'T',
b'U',
b'V',
b'W',
b'X',
b'Y',
b'Z',
b'bracketleft',
b'backslash',
b'bracketright',
b'asciicircum',
b'underscore',
b'grave',
b'a',
b'b',
b'c',
b'd',
b'e',
b'f',
b'g',
b'h',
b'i',
b'j',
b'k',
b'l',
b'm',
b'n',
b'o',
b'p',
b'q',
b'r',
b's',
b't',
b'u',
b'v',
b'w',
b'x',
b'y',
b'z',
b'braceleft',
b'bar',
b'braceright',
b'asciitilde',
b'Adieresis',
b'Aring',
b'Ccedilla',
b'Eacute',
b'Ntilde',
b'Odieresis',
b'Udieresis',
b'aacute',
b'agrave',
b'acircumflex',
b'adieresis',
b'atilde',
b'aring',
b'ccedilla',
b'eacute',
b'egrave',
b'ecircumflex',
b'edieresis',
b'iacute',
b'igrave',
b'icircumflex',
b'idieresis',
b'ntilde',
b'oacute',
b'ograve',
b'ocircumflex',
b'odieresis',
b'otilde',
b'uacute',
b'ugrave',
b'ucircumflex',
b'udieresis',
b'dagger',
b'degree',
b'cent',
b'sterling',
b'section',
b'bullet',
b'paragraph',
b'germandbls',
b'registered',
b'copyright',
b'trademark',
b'acute',
b'dieresis',
b'notequal',
b'AE',
b'Oslash',
b'infinity',
b'plusminus',
b'lessequal',
b'greaterequal',
b'yen',
b'mu',
b'partialdiff',
b'summation',
b'product',
b'pi',
b'integral',
b'ordfeminine',
b'ordmasculine',
b'Omega',
b'ae',
b'oslash',
b'questiondown',
b'exclamdown',
b'logicalnot',
b'radical',
b'florin',
b'approxequal',
b'Delta',
b'guillemotleft',
b'guillemotright',
b'ellipsis',
b'nonbreakingspace',
b'Agrave',
b'Atilde',
b'Otilde',
b'OE',
b'oe',
b'endash',
b'emdash',
b'quotedblleft',
b'quotedblright',
b'quoteleft',
b'quoteright',
b'divide',
b'lozenge',
b'ydieresis',
b'Ydieresis',
b'fraction',
b'currency',
b'guilsinglleft',
b'guilsinglright',
b'fi',
b'fl',
b'daggerdbl',
b'periodcentered',
b'quotesinglbase',
b'quotedblbase',
b'perthousand',
b'Acircumflex',
b'Ecircumflex',
b'Aacute',
b'Edieresis',
b'Egrave',
b'Iacute',
b'Icircumflex',
b'Idieresis',
b'Igrave',
b'Oacute',
b'Ocircumflex',
b'apple',
b'Ograve',
b'Uacute',
b'Ucircumflex',
b'Ugrave',
b'dotlessi',
b'circumflex',
b'tilde',
b'macron',
b'breve',
b'dotaccent',
b'ring',
b'cedilla',
b'hungarumlaut',
b'ogonek',
b'caron',
b'Lslash',
b'lslash',
b'Scaron',
b'scaron',
b'Zcaron',
b'zcaron',
b'brokenbar',
b'Eth',
b'eth',
b'Yacute',
b'yacute',
b'Thorn',
b'thorn',
b'minus',
b'multiply',
b'onesuperior',
b'twosuperior',
b'threesuperior',
b'onehalf',
b'onequarter',
b'threequarters',
b'franc',
b'Gbreve',
b'gbreve',
b'Idotaccent',
b'Scedilla',
b'scedilla',
b'Cacute',
b'cacute',
b'Ccaron',
b'ccaron',
b'dcroat'
)
def post_mac_names():
return list(POST_MAC_NAMES)

View File

@ -1,16 +1,20 @@
//
// Copyright (c) 2019 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
/*
Copyright (C) 2017-2019 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at your option)
any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
'use strict';
@ -19,7 +23,7 @@ const fncli = require('./fncli.js');
const fnio = require('./fnio.js');
const bdf = require('./bdf.js');
// -- Params --
class Params extends fncli.Params {
constructor() {
super();
@ -29,7 +33,7 @@ class Params extends fncli.Params {
}
}
// -- Options --
const HELP = ('' +
'usage: ucstoany [-f] [-F FAMILY] [-o OUTPUT] INPUT REGISTRY ENCODING TABLE...\n' +
'Generate a BDF font subset.\n' +
@ -44,7 +48,7 @@ const HELP = ('' +
' --version display the program version and license, and exit\n' +
' --excstk display the exception stack on error\n' +
'\n' +
'The input must be a BDF 2.1 font encoded in the unicode range.\n' +
'The input must be a BDF 2.1 font with unicode encoding.\n' +
'Unlike ucs2any, all TABLE-s form a single subset of the input font.\n');
const VERSION = 'ucstoany 1.55, Copyright (C) 2019 Dimitar Toshkov Zhekov\n\n' + fnutil.GPL2PLUS_LICENSE;
@ -62,7 +66,7 @@ class Options extends fncli.Options {
break;
case '-F':
if (value.includes('-')) {
throw new Error('family name may not contain "-"');
throw new Error('FAMILY may not contain "-"');
}
params.family = value;
break;
@ -75,7 +79,7 @@ class Options extends fncli.Options {
}
}
// -- Main --
function mainProgram(nonopt, parsed) {
if (nonopt.length < 4) {
throw new Error('invalid number of arguments, try --help');
@ -91,7 +95,7 @@ function mainProgram(nonopt, parsed) {
}
// READ INPUT
let ifs = new fnio.InputStream(input);
let ifs = new fnio.InputFileStream(input);
try {
var oldFont = bdf.Font.read(ifs);
@ -103,7 +107,7 @@ function mainProgram(nonopt, parsed) {
// READ TABLES
nonopt.slice(3).forEach(name => {
ifs = new fnio.InputStream(name);
ifs = new fnio.InputFileStream(name);
try {
ifs.readLines(line => {
@ -121,8 +125,8 @@ function mainProgram(nonopt, parsed) {
}
// CREATE GLYPHS
let newFont = new bdf.Font();
let charMap = [];
const newFont = new bdf.Font();
const charMap = [];
let index = 0;
let unstart = 0;
@ -135,7 +139,7 @@ function mainProgram(nonopt, parsed) {
newCodes.forEach(code => {
let oldChar = charMap[code];
let uniFFFF = (oldChar == null);
const uniFFFF = (oldChar == null);
if (code === 0xFFFF && parsed.filter) {
index++;
@ -158,12 +162,13 @@ function mainProgram(nonopt, parsed) {
}
}
let newChar = Object.assign(new bdf.Char(), oldChar);
const newChar = Object.assign(new bdf.Char(), oldChar);
newChar.code = index >= unstart ? code : index;
index++;
newChar.props = newChar.props.clone();
newChar.props.set('ENCODING', newChar.code.toString());
newChar.props = new bdf.Props();
oldChar.props.forEach((name, value) => newChar.props.set(name, value));
newChar.props.set('ENCODING', newChar.code);
newFont.chars.push(newChar);
if (uniFFFF) {
@ -175,7 +180,7 @@ function mainProgram(nonopt, parsed) {
// CREATE HEADER
let numProps;
let family = (parsed.family !== null) ? parsed.family : oldFont.xlfd[bdf.XLFD.FAMILY_NAME];
const family = (parsed.family != null) ? parsed.family : oldFont.xlfd[bdf.XLFD.FAMILY_NAME];
oldFont.props.forEach((name, value) => {
switch (name) {
@ -200,7 +205,7 @@ function mainProgram(nonopt, parsed) {
break;
case 'DEFAULT_CHAR':
if (newFont.defaultCode !== -1) {
value = newFont.defaultCode.toString();
value = newFont.defaultCode;
} else {
numProps -= 1;
return;
@ -208,24 +213,23 @@ function mainProgram(nonopt, parsed) {
break;
case 'ENDPROPERTIES':
if (newFont.defaultCode !== -1 && newFont.props.get('DEFAULT_CHAR') == null) {
newFont.props.add('DEFAULT_CHAR', newFont.defaultCode.toString());
newFont.props.set('DEFAULT_CHAR', newFont.defaultCode);
numProps += 1;
}
newFont.props.set('STARTPROPERTIES', numProps.toString());
newFont.props.set('STARTPROPERTIES', numProps);
break;
case 'CHARS':
value = newFont.chars.length.toString();
value = newFont.chars.length;
break;
}
newFont.props.add(name, value);
newFont.props.set(name, value);
});
// COPY FIELDS
newFont.bbx = oldFont.bbx;
newFont.finis = oldFont.finis;
// WRITE OUTPUT
let ofs = new fnio.OutputStream(parsed.output);
let ofs = new fnio.OutputFileStream(parsed.output);
try {
newFont.write(ofs);
@ -236,7 +240,6 @@ function mainProgram(nonopt, parsed) {
}
}
if (require.main === module) {
fncli.start('ucstoany.js', new Options(), new Params(), mainProgram);
}

View File

@ -1,15 +1,19 @@
#
# Copyright (c) 2019 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
# Copyright (C) 2017-2020 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of
# the License, or (at your option) any later version.
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
import re
@ -20,15 +24,16 @@
import fnio
import bdf
# -- Params --
class Params(fncli.Params):
def __init__(self):
fncli.Params.__init__(self)
self.filter = False
self.family = None
self.output = None
self.filter_ffff = False
self.family_name = None
self.output_name = None
# -- Options --
HELP = ('' +
'usage: ucstoany [-f] [-F FAMILY] [-o OUTPUT] INPUT REGISTRY ENCODING TABLE...\n' +
'Generate a BDF font subset.\n' +
@ -43,11 +48,10 @@ def __init__(self):
' --version display the program version and license, and exit\n' +
' --excstk display the exception stack on error\n' +
'\n' +
'The input must be a BDF 2.1 font encoded in the unicode range.\n' +
'Any COMMENT-s are discarded, duplicate properties are collapsed.\n' +
'The input must be a BDF 2.1 font with unicode encoding.\n' +
'Unlike ucs2any, all TABLE-s form a single subset of the input font.\n')
VERSION = 'ucstoany 1.55, Copyright (C) 2019 Dimitar Toshkov Zhekov\n\n' + fnutil.GPL2PLUS_LICENSE
VERSION = 'ucstoany 1.62, Copyright (C) 2017-2020 Dimitar Toshkov Zhekov\n\n' + fnutil.GPL2PLUS_LICENSE
class Options(fncli.Options):
def __init__(self):
@ -56,25 +60,24 @@ def __init__(self):
def parse(self, name, value, params):
if name in ['-f', '--filter']:
params.filter = True
params.filter_ffff = True
elif name == '-F':
params.family = bytes(value, 'ascii')
params.family_name = bytes(value, 'ascii')
if '-' in value:
raise Exception('family name may not contain "-"')
raise Exception('FAMILY may not contain "-"')
elif name == '-o':
params.output = value
params.output_name = value
else:
self.fallback(name, params)
# -- Main --
def main_program(nonopt, parsed):
bstr = lambda number: bytes(str(number), 'ascii')
# NON-OPTIONS
if len(nonopt) < 4:
raise Exception('invalid number of arguments, try --help')
input = nonopt[0]
input_name = nonopt[0]
registry = nonopt[1]
encoding = nonopt[2]
new_codes = []
@ -83,26 +86,14 @@ def main_program(nonopt, parsed):
raise Exception('invalid registry or encoding')
# READ INPUT
ifs = fnio.InputStream(input)
try:
old_font = bdf.Font.read(ifs)
ifs.close()
except Exception as ex:
raise Exception(ifs.location() + str(ex))
old_font = fnio.read_file(input_name, bdf.Font.read)
# READ TABLES
def load_code(line):
new_codes.append(fnutil.parse_hex('unicode', line))
for name in nonopt[3:]:
ifs = fnio.InputStream(name)
try:
ifs.read_lines(load_code)
ifs.close()
except Exception as ex:
raise Exception(ifs.location() + str(ex))
for table_name in nonopt[3:]:
fnio.read_file(table_name, lambda ifs: ifs.read_lines(load_code))
if not new_codes:
raise Exception('no characters in the output font')
@ -112,13 +103,13 @@ def load_code(line):
charmap = {char.code:char for char in old_font.chars}
index = 0
unstart = 0
family = parsed.family if parsed.family is not None else old_font.xlfd[bdf.XLFD.FAMILY_NAME]
family = parsed.family_name if parsed.family_name is not None else old_font.xlfd[bdf.XLFD.FAMILY_NAME]
if parsed.filter:
if parsed.filter_ffff:
unstart = 32 if registry == 'ISO10646' else bdf.CHARS_MAX
for code in new_codes:
if code == 0xFFFF and parsed.filter:
if code == 0xFFFF and parsed.filter_ffff:
index += 1
continue
@ -141,8 +132,8 @@ def load_code(line):
new_char = copy.copy(old_char)
new_char.code = code if index >= unstart else index
index += 1
new_char.props = new_char.props.clone()
new_char.props.set('ENCODING', bstr(new_char.code))
new_char.props = copy.copy(old_char.props)
new_char.props.set('ENCODING', new_char.code)
new_font.chars.append(new_char)
if uni_ffff:
@ -171,33 +162,26 @@ def load_code(line):
value = fnutil.quote(encoding)
elif name == 'DEFAULT_CHAR':
if new_font.default_code != -1:
value = bstr(new_font.default_code)
value = new_font.default_code
else:
num_props -= 1
continue
elif name == 'ENDPROPERTIES':
if new_font.default_code != -1 and new_font.props.get('DEFAULT_CHAR') is None:
new_font.props.add('DEFAULT_CHAR', bstr(new_font.default_code))
new_font.props.set('DEFAULT_CHAR', new_font.default_code)
num_props += 1
new_font.props.set('STARTPROPERTIES', bstr(num_props))
new_font.props.set('STARTPROPERTIES', num_props)
elif name == 'CHARS':
value = bstr(len(new_font.chars))
value = len(new_font.chars)
new_font.props.add(name, value)
new_font.props.set(name, value)
# COPY FIELDS
new_font.bbx = old_font.bbx
new_font.finis = old_font.finis
# WRITE OUTPUT
ofs = fnio.OutputStream(parsed.output)
try:
new_font.write(ofs)
ofs.close()
except Exception as ex:
raise Exception(ofs.location() + str(ex) + ofs.destroy())
fnio.write_file(parsed.output_name, lambda ofs: new_font.write(ofs))
if __name__ == '__main__':

20
configure vendored
View File

@ -9,17 +9,19 @@ elif test "$1" = "--version" ; then
cat << EOT
micro configure 0.21, Copyright (C) 2015 Dimitar Toshkov Zhekov
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
Report bugs to dimitar.zhekov@gmail.com
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
EOT
elif test -z `printf "\r"` ; then
echo "$0: printf failure"

View File

@ -1,13 +1,14 @@
To assign environment variables (e.g., CC, CFLAGS...), specify them as
NAME=VALUE. See the README for description of all options and targets.
NAME=VALUE. See README for a description of all options and targets.
Defaults for the options are specified in brackets.
The default values are specified in brackets.
Configuration:
--help display this help and exit
--version display version information and exit
Installation directories:
--prefix=PREFIX directories prefix [/usr]
--prefix=PREFIX prefix for all directories [/usr/local]
--psfdir=DIR PC screen fonts directory [PREFIX/share/consolefonts]
--x11dir=DIR X11 fonts directory [PREFIX/X11R6/lib/X11/fonts/local]
--x11dir=DIR X11 fonts directory [PREFIX/share/fonts/terminus]
--otbdir=DIR TrueType/OTB fonts directory [PREFIX/share/fonts/terminus]

View File

@ -7,7 +7,7 @@ FAMILY_NAME "Terminus"
FOUNDRY "xos4"
SETWIDTH_NAME "Normal"
ADD_STYLE_NAME ""
COPYRIGHT "Copyright (C) 2019 Dimitar Toshkov Zhekov"
COPYRIGHT "Copyright (C) 2020 Dimitar Toshkov Zhekov"
NOTICE "Licensed under the SIL Open Font License, Version 1.1"
WEIGHT_NAME "Bold"
SLANT "R"
@ -24,7 +24,7 @@ FONT_ASCENT 10
FONT_DESCENT 2
DEFAULT_CHAR 65533
ENDPROPERTIES
CHARS 1354
CHARS 1356
STARTCHAR char0
ENCODING 0
SWIDTH 500 0
@ -15472,6 +15472,44 @@ F8
00
00
ENDCHAR
STARTCHAR uni21B2
ENCODING 8626
SWIDTH 500 0
DWIDTH 6 0
BBX 6 12 0 -2
BITMAP
00
00
08
08
08
28
68
F8
60
20
00
00
ENDCHAR
STARTCHAR uni21B3
ENCODING 8627
SWIDTH 500 0
DWIDTH 6 0
BBX 6 12 0 -2
BITMAP
00
00
80
80
80
A0
B0
F8
30
20
00
00
ENDCHAR
STARTCHAR carriagereturn
ENCODING 8629
SWIDTH 500 0
@ -15480,7 +15518,7 @@ BBX 6 12 0 -2
BITMAP
00
00
08
00
08
08
28

View File

@ -7,7 +7,7 @@ FAMILY_NAME "Terminus"
FOUNDRY "xos4"
SETWIDTH_NAME "Normal"
ADD_STYLE_NAME ""
COPYRIGHT "Copyright (C) 2019 Dimitar Toshkov Zhekov"
COPYRIGHT "Copyright (C) 2020 Dimitar Toshkov Zhekov"
NOTICE "Licensed under the SIL Open Font License, Version 1.1"
WEIGHT_NAME "Medium"
SLANT "R"
@ -24,7 +24,7 @@ FONT_ASCENT 10
FONT_DESCENT 2
DEFAULT_CHAR 65533
ENDPROPERTIES
CHARS 1354
CHARS 1356
STARTCHAR char0
ENCODING 0
SWIDTH 500 0
@ -15472,6 +15472,44 @@ F8
00
00
ENDCHAR
STARTCHAR uni21B2
ENCODING 8626
SWIDTH 500 0
DWIDTH 6 0
BBX 6 12 0 -2
BITMAP
00
00
08
08
08
28
68
F8
60
20
00
00
ENDCHAR
STARTCHAR uni21B3
ENCODING 8627
SWIDTH 500 0
DWIDTH 6 0
BBX 6 12 0 -2
BITMAP
00
00
80
80
80
A0
B0
F8
30
20
00
00
ENDCHAR
STARTCHAR carriagereturn
ENCODING 8629
SWIDTH 500 0
@ -15480,7 +15518,7 @@ BBX 6 12 0 -2
BITMAP
00
00
08
00
08
08
28

View File

@ -7,7 +7,7 @@ FAMILY_NAME "Terminus"
FOUNDRY "xos4"
SETWIDTH_NAME "Normal"
ADD_STYLE_NAME ""
COPYRIGHT "Copyright (C) 2019 Dimitar Toshkov Zhekov"
COPYRIGHT "Copyright (C) 2020 Dimitar Toshkov Zhekov"
NOTICE "Licensed under the SIL Open Font License, Version 1.1"
WEIGHT_NAME "Bold"
SLANT "R"
@ -24,7 +24,7 @@ FONT_ASCENT 12
FONT_DESCENT 2
DEFAULT_CHAR 65533
ENDPROPERTIES
CHARS 1354
CHARS 1356
STARTCHAR char0
ENCODING 0
SWIDTH 571 0
@ -17098,8 +17098,8 @@ BITMAP
00
00
ENDCHAR
STARTCHAR carriagereturn
ENCODING 8629
STARTCHAR uni21B2
ENCODING 8626
SWIDTH 571 0
DWIDTH 8 0
BBX 8 14 0 -2
@ -17119,6 +17119,48 @@ FE
00
00
ENDCHAR
STARTCHAR uni21B3
ENCODING 8627
SWIDTH 571 0
DWIDTH 8 0
BBX 8 14 0 -2
BITMAP
00
00
C0
C0
C0
C0
C8
CC
FE
FE
0C
08
00
00
ENDCHAR
STARTCHAR carriagereturn
ENCODING 8629
SWIDTH 571 0
DWIDTH 8 0
BBX 8 14 0 -2
BITMAP
00
00
00
00
06
06
26
66
FE
FE
60
20
00
00
ENDCHAR
STARTCHAR uni21BB
ENCODING 8635
SWIDTH 571 0

View File

@ -7,7 +7,7 @@ FAMILY_NAME "Terminus"
FOUNDRY "xos4"
SETWIDTH_NAME "Normal"
ADD_STYLE_NAME ""
COPYRIGHT "Copyright (C) 2019 Dimitar Toshkov Zhekov"
COPYRIGHT "Copyright (C) 2020 Dimitar Toshkov Zhekov"
NOTICE "Licensed under the SIL Open Font License, Version 1.1"
WEIGHT_NAME "Medium"
SLANT "R"
@ -24,7 +24,7 @@ FONT_ASCENT 12
FONT_DESCENT 2
DEFAULT_CHAR 65533
ENDPROPERTIES
CHARS 1354
CHARS 1356
STARTCHAR char0
ENCODING 0
SWIDTH 571 0
@ -17098,8 +17098,8 @@ BITMAP
00
00
ENDCHAR
STARTCHAR carriagereturn
ENCODING 8629
STARTCHAR uni21B2
ENCODING 8626
SWIDTH 571 0
DWIDTH 8 0
BBX 8 14 0 -2
@ -17119,6 +17119,48 @@ FE
00
00
ENDCHAR
STARTCHAR uni21B3
ENCODING 8627
SWIDTH 571 0
DWIDTH 8 0
BBX 8 14 0 -2
BITMAP
00
00
80
80
80
80
80
88
84
FE
04
08
00
00
ENDCHAR
STARTCHAR carriagereturn
ENCODING 8629
SWIDTH 571 0
DWIDTH 8 0
BBX 8 14 0 -2
BITMAP
00
00
00
00
02
02
02
22
42
FE
40
20
00
00
ENDCHAR
STARTCHAR uni21BB
ENCODING 8635
SWIDTH 571 0

View File

@ -7,7 +7,7 @@ FAMILY_NAME "Terminus"
FOUNDRY "xos4"
SETWIDTH_NAME "Normal"
ADD_STYLE_NAME ""
COPYRIGHT "Copyright (C) 2019 Dimitar Toshkov Zhekov"
COPYRIGHT "Copyright (C) 2020 Dimitar Toshkov Zhekov"
NOTICE "Licensed under the SIL Open Font License, Version 1.1"
WEIGHT_NAME "Bold"
SLANT "R"
@ -24,7 +24,7 @@ FONT_ASCENT 12
FONT_DESCENT 2
DEFAULT_CHAR 65533
ENDPROPERTIES
CHARS 1354
CHARS 1356
STARTCHAR char0
ENCODING 0
SWIDTH 571 0
@ -17098,8 +17098,8 @@ BITMAP
00
00
ENDCHAR
STARTCHAR carriagereturn
ENCODING 8629
STARTCHAR uni21B2
ENCODING 8626
SWIDTH 571 0
DWIDTH 8 0
BBX 8 14 0 -2
@ -17119,6 +17119,48 @@ FE
00
00
ENDCHAR
STARTCHAR uni21B3
ENCODING 8627
SWIDTH 571 0
DWIDTH 8 0
BBX 8 14 0 -2
BITMAP
00
00
C0
C0
C0
C0
C8
CC
FE
FE
0C
08
00
00
ENDCHAR
STARTCHAR carriagereturn
ENCODING 8629
SWIDTH 571 0
DWIDTH 8 0
BBX 8 14 0 -2
BITMAP
00
00
00
00
06
06
26
66
FE
FE
60
20
00
00
ENDCHAR
STARTCHAR uni21BB
ENCODING 8635
SWIDTH 571 0

View File

@ -7,7 +7,7 @@ FAMILY_NAME "Terminus"
FOUNDRY "xos4"
SETWIDTH_NAME "Normal"
ADD_STYLE_NAME ""
COPYRIGHT "Copyright (C) 2019 Dimitar Toshkov Zhekov"
COPYRIGHT "Copyright (C) 2020 Dimitar Toshkov Zhekov"
NOTICE "Licensed under the SIL Open Font License, Version 1.1"
WEIGHT_NAME "Bold"
SLANT "R"
@ -24,7 +24,7 @@ FONT_ASCENT 12
FONT_DESCENT 4
DEFAULT_CHAR 65533
ENDPROPERTIES
CHARS 1354
CHARS 1356
STARTCHAR char0
ENCODING 0
SWIDTH 500 0
@ -18724,8 +18724,8 @@ BITMAP
00
00
ENDCHAR
STARTCHAR carriagereturn
ENCODING 8629
STARTCHAR uni21B2
ENCODING 8626
SWIDTH 500 0
DWIDTH 8 0
BBX 8 16 0 -4
@ -18747,6 +18747,52 @@ FE
00
00
ENDCHAR
STARTCHAR uni21B3
ENCODING 8627
SWIDTH 500 0
DWIDTH 8 0
BBX 8 16 0 -4
BITMAP
00
00
C0
C0
C0
C0
C8
CC
FE
FE
0C
08
00
00
00
00
ENDCHAR
STARTCHAR carriagereturn
ENCODING 8629
SWIDTH 500 0
DWIDTH 8 0
BBX 8 16 0 -4
BITMAP
00
00
00
00
06
06
26
66
FE
FE
60
20
00
00
00
00
ENDCHAR
STARTCHAR uni21BB
ENCODING 8635
SWIDTH 500 0

View File

@ -7,7 +7,7 @@ FAMILY_NAME "Terminus"
FOUNDRY "xos4"
SETWIDTH_NAME "Normal"
ADD_STYLE_NAME ""
COPYRIGHT "Copyright (C) 2019 Dimitar Toshkov Zhekov"
COPYRIGHT "Copyright (C) 2020 Dimitar Toshkov Zhekov"
NOTICE "Licensed under the SIL Open Font License, Version 1.1"
WEIGHT_NAME "Medium"
SLANT "R"
@ -24,7 +24,7 @@ FONT_ASCENT 12
FONT_DESCENT 4
DEFAULT_CHAR 65533
ENDPROPERTIES
CHARS 1354
CHARS 1356
STARTCHAR char0
ENCODING 0
SWIDTH 500 0
@ -18724,8 +18724,8 @@ BITMAP
00
00
ENDCHAR
STARTCHAR carriagereturn
ENCODING 8629
STARTCHAR uni21B2
ENCODING 8626
SWIDTH 500 0
DWIDTH 8 0
BBX 8 16 0 -4
@ -18747,6 +18747,52 @@ FE
00
00
ENDCHAR
STARTCHAR uni21B3
ENCODING 8627
SWIDTH 500 0
DWIDTH 8 0
BBX 8 16 0 -4
BITMAP
00
00
80
80
80
80
80
88
84
FE
04
08
00
00
00
00
ENDCHAR
STARTCHAR carriagereturn
ENCODING 8629
SWIDTH 500 0
DWIDTH 8 0
BBX 8 16 0 -4
BITMAP
00
00
00
00
02
02
02
22
42
FE
40
20
00
00
00
00
ENDCHAR
STARTCHAR uni21BB
ENCODING 8635
SWIDTH 500 0

View File

@ -7,7 +7,7 @@ FAMILY_NAME "Terminus"
FOUNDRY "xos4"
SETWIDTH_NAME "Normal"
ADD_STYLE_NAME ""
COPYRIGHT "Copyright (C) 2019 Dimitar Toshkov Zhekov"
COPYRIGHT "Copyright (C) 2020 Dimitar Toshkov Zhekov"
NOTICE "Licensed under the SIL Open Font License, Version 1.1"
WEIGHT_NAME "Bold"
SLANT "R"
@ -24,7 +24,7 @@ FONT_ASCENT 12
FONT_DESCENT 4
DEFAULT_CHAR 65533
ENDPROPERTIES
CHARS 1354
CHARS 1356
STARTCHAR char0
ENCODING 0
SWIDTH 500 0
@ -18724,8 +18724,8 @@ BITMAP
00
00
ENDCHAR
STARTCHAR carriagereturn
ENCODING 8629
STARTCHAR uni21B2
ENCODING 8626
SWIDTH 500 0
DWIDTH 8 0
BBX 8 16 0 -4
@ -18747,6 +18747,52 @@ FE
00
00
ENDCHAR
STARTCHAR uni21B3
ENCODING 8627
SWIDTH 500 0
DWIDTH 8 0
BBX 8 16 0 -4
BITMAP
00
00
C0
C0
C0
C0
C8
CC
FE
FE
0C
08
00
00
00
00
ENDCHAR
STARTCHAR carriagereturn
ENCODING 8629
SWIDTH 500 0
DWIDTH 8 0
BBX 8 16 0 -4
BITMAP
00
00
00
00
06
06
26
66
FE
FE
60
20
00
00
00
00
ENDCHAR
STARTCHAR uni21BB
ENCODING 8635
SWIDTH 500 0

View File

@ -7,7 +7,7 @@ FAMILY_NAME "Terminus"
FOUNDRY "xos4"
SETWIDTH_NAME "Normal"
ADD_STYLE_NAME ""
COPYRIGHT "Copyright (C) 2019 Dimitar Toshkov Zhekov"
COPYRIGHT "Copyright (C) 2020 Dimitar Toshkov Zhekov"
NOTICE "Licensed under the SIL Open Font License, Version 1.1"
WEIGHT_NAME "Bold"
SLANT "R"
@ -24,7 +24,7 @@ FONT_ASCENT 15
FONT_DESCENT 3
DEFAULT_CHAR 65533
ENDPROPERTIES
CHARS 1354
CHARS 1356
STARTCHAR char0
ENCODING 0
SWIDTH 556 0
@ -1656,6 +1656,7 @@ SWIDTH 556 0
DWIDTH 10 0
BBX 10 18 0 -3
BITMAP
3000
1800
0C00
0000
@ -1673,7 +1674,6 @@ BITMAP
0000
0000
0000
0000
ENDCHAR
STARTCHAR a
ENCODING 97
@ -20350,8 +20350,8 @@ BITMAP
0000
0000
ENDCHAR
STARTCHAR carriagereturn
ENCODING 8629
STARTCHAR uni21B2
ENCODING 8626
SWIDTH 556 0
DWIDTH 10 0
BBX 10 18 0 -3
@ -20375,6 +20375,56 @@ FF80
0000
0000
ENDCHAR
STARTCHAR uni21B3
ENCODING 8627
SWIDTH 556 0
DWIDTH 10 0
BBX 10 18 0 -3
BITMAP
0000
0000
0000
C000
C000
C000
C000
C400
C600
C300
FF80
FF80
0300
0600
0400
0000
0000
0000
ENDCHAR
STARTCHAR carriagereturn
ENCODING 8629
SWIDTH 556 0
DWIDTH 10 0
BBX 10 18 0 -3
BITMAP
0000
0000
0000
0000
0000
0180
0180
1180
3180
6180
FF80
FF80
6000
3000
1000
0000
0000
0000
ENDCHAR
STARTCHAR uni21BB
ENCODING 8635
SWIDTH 556 0

View File

@ -7,7 +7,7 @@ FAMILY_NAME "Terminus"
FOUNDRY "xos4"
SETWIDTH_NAME "Normal"
ADD_STYLE_NAME ""
COPYRIGHT "Copyright (C) 2019 Dimitar Toshkov Zhekov"
COPYRIGHT "Copyright (C) 2020 Dimitar Toshkov Zhekov"
NOTICE "Licensed under the SIL Open Font License, Version 1.1"
WEIGHT_NAME "Medium"
SLANT "R"
@ -24,7 +24,7 @@ FONT_ASCENT 15
FONT_DESCENT 3
DEFAULT_CHAR 65533
ENDPROPERTIES
CHARS 1354
CHARS 1356
STARTCHAR char0
ENCODING 0
SWIDTH 556 0
@ -1656,6 +1656,7 @@ SWIDTH 556 0
DWIDTH 10 0
BBX 10 18 0 -3
BITMAP
2000
1000
0800
0000
@ -1673,7 +1674,6 @@ BITMAP
0000
0000
0000
0000
ENDCHAR
STARTCHAR a
ENCODING 97
@ -20350,8 +20350,8 @@ BITMAP
0000
0000
ENDCHAR
STARTCHAR carriagereturn
ENCODING 8629
STARTCHAR uni21B2
ENCODING 8626
SWIDTH 556 0
DWIDTH 10 0
BBX 10 18 0 -3
@ -20375,6 +20375,56 @@ FF80
0000
0000
ENDCHAR
STARTCHAR uni21B3
ENCODING 8627
SWIDTH 556 0
DWIDTH 10 0
BBX 10 18 0 -3
BITMAP
0000
0000
0000
8000
8000
8000
8000
8000
8400
8200
8100
FF80
0100
0200
0400
0000
0000
0000
ENDCHAR
STARTCHAR carriagereturn
ENCODING 8629
SWIDTH 556 0
DWIDTH 10 0
BBX 10 18 0 -3
BITMAP
0000
0000
0000
0000
0000
0080
0080
0080
1080
2080
4080
FF80
4000
2000
1000
0000
0000
0000
ENDCHAR
STARTCHAR uni21BB
ENCODING 8635
SWIDTH 556 0

View File

@ -7,7 +7,7 @@ FAMILY_NAME "Terminus"
FOUNDRY "xos4"
SETWIDTH_NAME "Normal"
ADD_STYLE_NAME ""
COPYRIGHT "Copyright (C) 2019 Dimitar Toshkov Zhekov"
COPYRIGHT "Copyright (C) 2020 Dimitar Toshkov Zhekov"
NOTICE "Licensed under the SIL Open Font License, Version 1.1"
WEIGHT_NAME "Bold"
SLANT "R"
@ -24,7 +24,7 @@ FONT_ASCENT 16
FONT_DESCENT 4
DEFAULT_CHAR 65533
ENDPROPERTIES
CHARS 1354
CHARS 1356
STARTCHAR char0
ENCODING 0
SWIDTH 500 0
@ -1786,6 +1786,7 @@ SWIDTH 500 0
DWIDTH 10 0
BBX 10 20 0 -4
BITMAP
3000
1800
0C00
0000
@ -1805,7 +1806,6 @@ BITMAP
0000
0000
0000
0000
ENDCHAR
STARTCHAR a
ENCODING 97
@ -21976,8 +21976,8 @@ BITMAP
0000
0000
ENDCHAR
STARTCHAR carriagereturn
ENCODING 8629
STARTCHAR uni21B2
ENCODING 8626
SWIDTH 500 0
DWIDTH 10 0
BBX 10 20 0 -4
@ -22003,6 +22003,60 @@ FF80
0000
0000
ENDCHAR
STARTCHAR uni21B3
ENCODING 8627
SWIDTH 500 0
DWIDTH 10 0
BBX 10 20 0 -4
BITMAP
0000
0000
0000
C000
C000
C000
C000
C000
C400
C600
C300
FF80
FF80
0300
0600
0400
0000
0000
0000
0000
ENDCHAR
STARTCHAR carriagereturn
ENCODING 8629
SWIDTH 500 0
DWIDTH 10 0
BBX 10 20 0 -4
BITMAP
0000
0000
0000
0000
0000
0180
0180
0180
1180
3180
6180
FF80
FF80
6000
3000
1000
0000
0000
0000
0000
ENDCHAR
STARTCHAR uni21BB
ENCODING 8635
SWIDTH 500 0

View File

@ -7,7 +7,7 @@ FAMILY_NAME "Terminus"
FOUNDRY "xos4"
SETWIDTH_NAME "Normal"
ADD_STYLE_NAME ""
COPYRIGHT "Copyright (C) 2019 Dimitar Toshkov Zhekov"
COPYRIGHT "Copyright (C) 2020 Dimitar Toshkov Zhekov"
NOTICE "Licensed under the SIL Open Font License, Version 1.1"
WEIGHT_NAME "Medium"
SLANT "R"
@ -24,7 +24,7 @@ FONT_ASCENT 16
FONT_DESCENT 4
DEFAULT_CHAR 65533
ENDPROPERTIES
CHARS 1354
CHARS 1356
STARTCHAR char0
ENCODING 0
SWIDTH 500 0
@ -1786,6 +1786,7 @@ SWIDTH 500 0
DWIDTH 10 0
BBX 10 20 0 -4
BITMAP
2000
1000
0800
0000
@ -1805,7 +1806,6 @@ BITMAP
0000
0000
0000
0000
ENDCHAR
STARTCHAR a
ENCODING 97
@ -21976,8 +21976,8 @@ BITMAP
0000
0000
ENDCHAR
STARTCHAR carriagereturn
ENCODING 8629
STARTCHAR uni21B2
ENCODING 8626
SWIDTH 500 0
DWIDTH 10 0
BBX 10 20 0 -4
@ -22003,6 +22003,60 @@ FF80
0000
0000
ENDCHAR
STARTCHAR uni21B3
ENCODING 8627
SWIDTH 500 0
DWIDTH 10 0
BBX 10 20 0 -4
BITMAP
0000
0000
0000
8000
8000
8000
8000
8000
8000
8400
8200
8100
FF80
0100
0200
0400
0000
0000
0000
0000
ENDCHAR
STARTCHAR carriagereturn
ENCODING 8629
SWIDTH 500 0
DWIDTH 10 0
BBX 10 20 0 -4
BITMAP
0000
0000
0000
0000
0000
0000
0080
0080
0080
1080
2080
4080
FF80
4000
2000
1000
0000
0000
0000
0000
ENDCHAR
STARTCHAR uni21BB
ENCODING 8635
SWIDTH 500 0

View File

@ -7,7 +7,7 @@ FAMILY_NAME "Terminus"
FOUNDRY "xos4"
SETWIDTH_NAME "Normal"
ADD_STYLE_NAME ""
COPYRIGHT "Copyright (C) 2019 Dimitar Toshkov Zhekov"
COPYRIGHT "Copyright (C) 2020 Dimitar Toshkov Zhekov"
NOTICE "Licensed under the SIL Open Font License, Version 1.1"
WEIGHT_NAME "Bold"
SLANT "R"
@ -24,7 +24,7 @@ FONT_ASCENT 17
FONT_DESCENT 5
DEFAULT_CHAR 65533
ENDPROPERTIES
CHARS 1354
CHARS 1356
STARTCHAR char0
ENCODING 0
SWIDTH 500 0
@ -23602,8 +23602,8 @@ BITMAP
0000
0000
ENDCHAR
STARTCHAR carriagereturn
ENCODING 8629
STARTCHAR uni21B2
ENCODING 8626
SWIDTH 500 0
DWIDTH 11 0
BBX 11 22 0 -5
@ -23631,6 +23631,64 @@ FFC0
0000
0000
ENDCHAR
STARTCHAR uni21B3
ENCODING 8627
SWIDTH 500 0
DWIDTH 11 0
BBX 11 22 0 -5
BITMAP
0000
0000
0000
C000
C000
C000
C000
C000
C000
C200
C300
C180
FFC0
FFC0
0180
0300
0200
0000
0000
0000
0000
0000
ENDCHAR
STARTCHAR carriagereturn
ENCODING 8629
SWIDTH 500 0
DWIDTH 11 0
BBX 11 22 0 -5
BITMAP
0000
0000
0000
0000
0000
0000
00C0
00C0
00C0
10C0
30C0
60C0
FFC0
FFC0
6000
3000
1000
0000
0000
0000
0000
0000
ENDCHAR
STARTCHAR uni21BB
ENCODING 8635
SWIDTH 500 0

View File

@ -7,7 +7,7 @@ FAMILY_NAME "Terminus"
FOUNDRY "xos4"
SETWIDTH_NAME "Normal"
ADD_STYLE_NAME ""
COPYRIGHT "Copyright (C) 2019 Dimitar Toshkov Zhekov"
COPYRIGHT "Copyright (C) 2020 Dimitar Toshkov Zhekov"
NOTICE "Licensed under the SIL Open Font License, Version 1.1"
WEIGHT_NAME "Medium"
SLANT "R"
@ -24,7 +24,7 @@ FONT_ASCENT 17
FONT_DESCENT 5
DEFAULT_CHAR 65533
ENDPROPERTIES
CHARS 1354
CHARS 1356
STARTCHAR char0
ENCODING 0
SWIDTH 500 0
@ -23602,8 +23602,8 @@ BITMAP
0000
0000
ENDCHAR
STARTCHAR carriagereturn
ENCODING 8629
STARTCHAR uni21B2
ENCODING 8626
SWIDTH 500 0
DWIDTH 11 0
BBX 11 22 0 -5
@ -23631,6 +23631,64 @@ FFC0
0000
0000
ENDCHAR
STARTCHAR uni21B3
ENCODING 8627
SWIDTH 500 0
DWIDTH 11 0
BBX 11 22 0 -5
BITMAP
0000
0000
0000
8000
8000
8000
8000
8000
8000
8000
8200
8100
8080
FFC0
0080
0100
0200
0000
0000
0000
0000
0000
ENDCHAR
STARTCHAR carriagereturn
ENCODING 8629
SWIDTH 500 0
DWIDTH 11 0
BBX 11 22 0 -5
BITMAP
0000
0000
0000
0000
0000
0000
0040
0040
0040
0040
1040
2040
4040
FFC0
4000
2000
1000
0000
0000
0000
0000
0000
ENDCHAR
STARTCHAR uni21BB
ENCODING 8635
SWIDTH 500 0

View File

@ -7,7 +7,7 @@ FAMILY_NAME "Terminus"
FOUNDRY "xos4"
SETWIDTH_NAME "Normal"
ADD_STYLE_NAME ""
COPYRIGHT "Copyright (C) 2019 Dimitar Toshkov Zhekov"
COPYRIGHT "Copyright (C) 2020 Dimitar Toshkov Zhekov"
NOTICE "Licensed under the SIL Open Font License, Version 1.1"
WEIGHT_NAME "Bold"
SLANT "R"
@ -24,7 +24,7 @@ FONT_ASCENT 19
FONT_DESCENT 5
DEFAULT_CHAR 65533
ENDPROPERTIES
CHARS 1354
CHARS 1356
STARTCHAR char0
ENCODING 0
SWIDTH 500 0
@ -2046,6 +2046,7 @@ SWIDTH 500 0
DWIDTH 12 0
BBX 12 24 0 -5
BITMAP
0000
1800
0C00
0600
@ -2069,7 +2070,6 @@ BITMAP
0000
0000
0000
0000
ENDCHAR
STARTCHAR a
ENCODING 97
@ -25228,8 +25228,8 @@ BITMAP
0000
0000
ENDCHAR
STARTCHAR carriagereturn
ENCODING 8629
STARTCHAR uni21B2
ENCODING 8626
SWIDTH 500 0
DWIDTH 12 0
BBX 12 24 0 -5
@ -25259,6 +25259,68 @@ FFE0
0000
0000
ENDCHAR
STARTCHAR uni21B3
ENCODING 8627
SWIDTH 500 0
DWIDTH 12 0
BBX 12 24 0 -5
BITMAP
0000
0000
0000
0000
C000
C000
C000
C000
C000
C200
C300
C180
C0C0
FFE0
FFE0
00C0
0180
0300
0200
0000
0000
0000
0000
0000
ENDCHAR
STARTCHAR carriagereturn
ENCODING 8629
SWIDTH 500 0
DWIDTH 12 0
BBX 12 24 0 -5
BITMAP
0000
0000
0000
0000
0000
0000
0060
0060
0060
0860
1860
3060
6060
FFE0
FFE0
6000
3000
1800
0800
0000
0000
0000
0000
0000
ENDCHAR
STARTCHAR uni21BB
ENCODING 8635
SWIDTH 500 0

View File

@ -7,7 +7,7 @@ FAMILY_NAME "Terminus"
FOUNDRY "xos4"
SETWIDTH_NAME "Normal"
ADD_STYLE_NAME ""
COPYRIGHT "Copyright (C) 2019 Dimitar Toshkov Zhekov"
COPYRIGHT "Copyright (C) 2020 Dimitar Toshkov Zhekov"
NOTICE "Licensed under the SIL Open Font License, Version 1.1"
WEIGHT_NAME "Medium"
SLANT "R"
@ -24,7 +24,7 @@ FONT_ASCENT 19
FONT_DESCENT 5
DEFAULT_CHAR 65533
ENDPROPERTIES
CHARS 1354
CHARS 1356
STARTCHAR char0
ENCODING 0
SWIDTH 500 0
@ -2046,6 +2046,7 @@ SWIDTH 500 0
DWIDTH 12 0
BBX 12 24 0 -5
BITMAP
0000
1000
0800
0400
@ -2069,7 +2070,6 @@ BITMAP
0000
0000
0000
0000
ENDCHAR
STARTCHAR a
ENCODING 97
@ -25228,8 +25228,8 @@ BITMAP
0000
0000
ENDCHAR
STARTCHAR carriagereturn
ENCODING 8629
STARTCHAR uni21B2
ENCODING 8626
SWIDTH 500 0
DWIDTH 12 0
BBX 12 24 0 -5
@ -25259,6 +25259,68 @@ FFE0
0000
0000
ENDCHAR
STARTCHAR uni21B3
ENCODING 8627
SWIDTH 500 0
DWIDTH 12 0
BBX 12 24 0 -5
BITMAP
0000
0000
0000
0000
8000
8000
8000
8000
8000
8000
8200
8100
8080
8040
FFE0
0040
0080
0100
0200
0000
0000
0000
0000
0000
ENDCHAR
STARTCHAR carriagereturn
ENCODING 8629
SWIDTH 500 0
DWIDTH 12 0
BBX 12 24 0 -5
BITMAP
0000
0000
0000
0000
0000
0000
0020
0020
0020
0020
0820
1020
2020
4020
FFE0
4000
2000
1000
0800
0000
0000
0000
0000
0000
ENDCHAR
STARTCHAR uni21BB
ENCODING 8635
SWIDTH 500 0

View File

@ -7,7 +7,7 @@ FAMILY_NAME "Terminus"
FOUNDRY "xos4"
SETWIDTH_NAME "Normal"
ADD_STYLE_NAME ""
COPYRIGHT "Copyright (C) 2019 Dimitar Toshkov Zhekov"
COPYRIGHT "Copyright (C) 2020 Dimitar Toshkov Zhekov"
NOTICE "Licensed under the SIL Open Font License, Version 1.1"
WEIGHT_NAME "Bold"
SLANT "R"
@ -24,7 +24,7 @@ FONT_ASCENT 22
FONT_DESCENT 6
DEFAULT_CHAR 65533
ENDPROPERTIES
CHARS 1354
CHARS 1356
STARTCHAR char0
ENCODING 0
SWIDTH 500 0
@ -2306,6 +2306,7 @@ SWIDTH 500 0
DWIDTH 14 0
BBX 14 28 0 -6
BITMAP
3800
1C00
0E00
0700
@ -2333,7 +2334,6 @@ BITMAP
0000
0000
0000
0000
ENDCHAR
STARTCHAR a
ENCODING 97
@ -28480,8 +28480,8 @@ BITMAP
0000
0000
ENDCHAR
STARTCHAR carriagereturn
ENCODING 8629
STARTCHAR uni21B2
ENCODING 8626
SWIDTH 500 0
DWIDTH 14 0
BBX 14 28 0 -6
@ -28515,6 +28515,76 @@ FFF8
0000
0000
ENDCHAR
STARTCHAR uni21B3
ENCODING 8627
SWIDTH 500 0
DWIDTH 14 0
BBX 14 28 0 -6
BITMAP
0000
0000
0000
0000
C000
C000
C000
C000
C000
C000
C100
C180
C1C0
C0E0
C070
FFF8
FFF8
0070
00E0
01C0
0180
0100
0000
0000
0000
0000
0000
0000
ENDCHAR
STARTCHAR carriagereturn
ENCODING 8629
SWIDTH 500 0
DWIDTH 14 0
BBX 14 28 0 -6
BITMAP
0000
0000
0000
0000
0000
0000
0000
0018
0018
0018
0418
0C18
1C18
3818
7018
FFF8
FFF8
7000
3800
1C00
0C00
0400
0000
0000
0000
0000
0000
0000
ENDCHAR
STARTCHAR uni21BB
ENCODING 8635
SWIDTH 500 0

View File

@ -7,7 +7,7 @@ FAMILY_NAME "Terminus"
FOUNDRY "xos4"
SETWIDTH_NAME "Normal"
ADD_STYLE_NAME ""
COPYRIGHT "Copyright (C) 2019 Dimitar Toshkov Zhekov"
COPYRIGHT "Copyright (C) 2020 Dimitar Toshkov Zhekov"
NOTICE "Licensed under the SIL Open Font License, Version 1.1"
WEIGHT_NAME "Medium"
SLANT "R"
@ -24,7 +24,7 @@ FONT_ASCENT 22
FONT_DESCENT 6
DEFAULT_CHAR 65533
ENDPROPERTIES
CHARS 1354
CHARS 1356
STARTCHAR char0
ENCODING 0
SWIDTH 500 0
@ -2306,6 +2306,7 @@ SWIDTH 500 0
DWIDTH 14 0
BBX 14 28 0 -6
BITMAP
1800
0C00
0600
0300
@ -2333,7 +2334,6 @@ BITMAP
0000
0000
0000
0000
ENDCHAR
STARTCHAR a
ENCODING 97
@ -28480,8 +28480,8 @@ BITMAP
0000
0000
ENDCHAR
STARTCHAR carriagereturn
ENCODING 8629
STARTCHAR uni21B2
ENCODING 8626
SWIDTH 500 0
DWIDTH 14 0
BBX 14 28 0 -6
@ -28515,6 +28515,76 @@ FFF8
0000
0000
ENDCHAR
STARTCHAR uni21B3
ENCODING 8627
SWIDTH 500 0
DWIDTH 14 0
BBX 14 28 0 -6
BITMAP
0000
0000
0000
0000
C000
C000
C000
C000
C000
C000
C100
C180
C0C0
C060
C030
FFF8
FFF8
0030
0060
00C0
0180
0100
0000
0000
0000
0000
0000
0000
ENDCHAR
STARTCHAR carriagereturn
ENCODING 8629
SWIDTH 500 0
DWIDTH 14 0
BBX 14 28 0 -6
BITMAP
0000
0000
0000
0000
0000
0000
0000
0018
0018
0018
0418
0C18
1818
3018
6018
FFF8
FFF8
6000
3000
1800
0C00
0400
0000
0000
0000
0000
0000
0000
ENDCHAR
STARTCHAR uni21BB
ENCODING 8635
SWIDTH 500 0

View File

@ -7,7 +7,7 @@ FAMILY_NAME "Terminus"
FOUNDRY "xos4"
SETWIDTH_NAME "Normal"
ADD_STYLE_NAME ""
COPYRIGHT "Copyright (C) 2019 Dimitar Toshkov Zhekov"
COPYRIGHT "Copyright (C) 2020 Dimitar Toshkov Zhekov"
NOTICE "Licensed under the SIL Open Font License, Version 1.1"
WEIGHT_NAME "Bold"
SLANT "R"
@ -24,7 +24,7 @@ FONT_ASCENT 26
FONT_DESCENT 6
DEFAULT_CHAR 65533
ENDPROPERTIES
CHARS 1354
CHARS 1356
STARTCHAR char0
ENCODING 0
SWIDTH 500 0
@ -2567,6 +2567,7 @@ DWIDTH 16 0
BBX 16 32 0 -6
BITMAP
0000
0000
1C00
0E00
0700
@ -2597,7 +2598,6 @@ BITMAP
0000
0000
0000
0000
ENDCHAR
STARTCHAR a
ENCODING 97
@ -31732,8 +31732,8 @@ BITMAP
0000
0000
ENDCHAR
STARTCHAR carriagereturn
ENCODING 8629
STARTCHAR uni21B2
ENCODING 8626
SWIDTH 500 0
DWIDTH 16 0
BBX 16 32 0 -6
@ -31771,6 +31771,84 @@ BITMAP
0000
0000
ENDCHAR
STARTCHAR uni21B3
ENCODING 8627
SWIDTH 500 0
DWIDTH 16 0
BBX 16 32 0 -6
BITMAP
0000
0000
0000
0000
0000
0000
7000
7000
7000
7000
7000
7000
7000
70C0
70E0
7070
7038
701C
7FFE
7FFE
7FFE
001C
0038
0070
00E0
00C0
0000
0000
0000
0000
0000
0000
ENDCHAR
STARTCHAR carriagereturn
ENCODING 8629
SWIDTH 500 0
DWIDTH 16 0
BBX 16 32 0 -6
BITMAP
0000
0000
0000
0000
0000
0000
0000
0000
0000
000E
000E
000E
000E
030E
070E
0E0E
1C0E
380E
7FFE
7FFE
7FFE
3800
1C00
0E00
0700
0300
0000
0000
0000
0000
0000
0000
ENDCHAR
STARTCHAR uni21BB
ENCODING 8635
SWIDTH 500 0

View File

@ -7,7 +7,7 @@ FAMILY_NAME "Terminus"
FOUNDRY "xos4"
SETWIDTH_NAME "Normal"
ADD_STYLE_NAME ""
COPYRIGHT "Copyright (C) 2019 Dimitar Toshkov Zhekov"
COPYRIGHT "Copyright (C) 2020 Dimitar Toshkov Zhekov"
NOTICE "Licensed under the SIL Open Font License, Version 1.1"
WEIGHT_NAME "Medium"
SLANT "R"
@ -24,7 +24,7 @@ FONT_ASCENT 26
FONT_DESCENT 6
DEFAULT_CHAR 65533
ENDPROPERTIES
CHARS 1354
CHARS 1356
STARTCHAR char0
ENCODING 0
SWIDTH 500 0
@ -2567,6 +2567,7 @@ DWIDTH 16 0
BBX 16 32 0 -6
BITMAP
0000
0000
0E00
0700
0380
@ -2597,7 +2598,6 @@ BITMAP
0000
0000
0000
0000
ENDCHAR
STARTCHAR a
ENCODING 97
@ -31732,8 +31732,8 @@ BITMAP
0000
0000
ENDCHAR
STARTCHAR carriagereturn
ENCODING 8629
STARTCHAR uni21B2
ENCODING 8626
SWIDTH 500 0
DWIDTH 16 0
BBX 16 32 0 -6
@ -31771,6 +31771,84 @@ BITMAP
0000
0000
ENDCHAR
STARTCHAR uni21B3
ENCODING 8627
SWIDTH 500 0
DWIDTH 16 0
BBX 16 32 0 -6
BITMAP
0000
0000
0000
0000
0000
0000
6000
6000
6000
6000
6000
6000
6000
6000
6180
61C0
60E0
6070
6038
7FFC
7FFC
0038
0070
00E0
01C0
0180
0000
0000
0000
0000
0000
0000
ENDCHAR
STARTCHAR carriagereturn
ENCODING 8629
SWIDTH 500 0
DWIDTH 16 0
BBX 16 32 0 -6
BITMAP
0000
0000
0000
0000
0000
0000
0000
0000
0000
000C
000C
000C
000C
000C
030C
070C
0E0C
1C0C
380C
7FFC
7FFC
3800
1C00
0E00
0700
0300
0000
0000
0000
0000
0000
0000
ENDCHAR
STARTCHAR uni21BB
ENCODING 8635
SWIDTH 500 0

View File

@ -810,6 +810,8 @@
21A4
21A6
21A8
21B2
21B3
21B5
21BB
21CB

View File

@ -6,11 +6,12 @@ UNI = ../uni
UCS2ANY = $(INT) $(BIN)/ucstoany.$(EXT)
BDF2FNT = $(INT) $(BIN)/bdftofnt.$(EXT) -fModern
RC32 = windres -F pe-i386
CC32 = i686-w64-mingw32-gcc
CFLAGS = -O2 -Wall -Wextra
LDFLAGS = -mwindows -s
FONFLAGS = -shared -nostdlib -nostartfiles
RC32 = windres -F pe-i386
RM = rm -f
REG_MS_1252 = Microsoft CP1252
REG_MS_1250 = Microsoft CP1250
@ -86,6 +87,6 @@ fcpw.exe: fcp.c
$(CC32) -DFCPW $(CFLAGS) $(LDFLAGS) -o $@ $<
clean:
@./make-clean.cmd
$(RM) ter-*.bdf ter-*.fnt *.txt ter-*.o terminus.fon fcpw.exe
.PHONY: all fnt clean
.PHONY: all fnt fnt-255 clean

View File

@ -2,7 +2,7 @@ if errorlevel 1 type nul
if not exist dup\nul mkdir dup
if errorlevel 1 exit /b
if not errorlevel 1 copy /y ..\*.bdf
if not errorlevel 1 copy /y ..\ter-*.bdf
if not errorlevel 1 make -B -j8 terminus.fon
if not errorlevel 1 move /y terminus.fon terminus.bak
@ -29,7 +29,7 @@ if not errorlevel 1 call :difftofcp hi2-ka2
if not errorlevel 1 make -B -j8 terminus.fon
if not errorlevel 1 make fcpw.exe
if not errorlevel 1 del /q *.bdf *.fnt terminus.bak ter-font.o
if not errorlevel 1 del ter-*.bdf ter-*.fnt terminus.bak ter-*.o dup\xos4-2.dup
exit /b
:difftofcp
@ -38,4 +38,4 @@ if not errorlevel 1 make -B -j8 fnt
if not errorlevel 1 make terminus.fon
if not errorlevel 1 fc /b terminus.bak terminus.fon > %1.txt
rem fc sets errorlevel 1 on differences
if not errorlevel 2 copy /y ..\*.bdf
if not errorlevel 2 copy /y ..\ter-*.bdf

View File

@ -60,20 +60,24 @@ static void error(const char *s)
#define main wrap
#endif
static const char *usage =
static const char *USAGE =
"usage: " FCP " [OFFSET] FILE PATCH\n"
"\n"
FCP " 0.10.2, Copyright (C) 2017 Dimitar Toshkov Zhekov\n"
"\n"
"This program is free software; you can redistribute it and/or\n"
"modify it under the terms of the GNU General Public License as\n"
"published by the Free Software Foundation; either version 2 of\n"
"the License, or (at your option) any later version.\n"
"This program is free software; you can redistribute it and/or modify it\n"
"under the terms of the GNU General Public License as published by the Free\n"
"Software Foundation; either version 2 of the License, or (at your option)\n"
"any later version.\n"
"\n"
"This program is distributed in the hope that it will be useful,\n"
"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
"GNU General Public License for more details.\n";
"This program is distributed in the hope that it will be useful, but\n"
"WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\n"
"or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License\n"
"for more details.\n"
"\n"
"You should have received a copy of the GNU General Public License along\n"
"with this program; if not, write to the Free Software Foundation, Inc.,\n"
"51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n";
int main(int argc, char **argv)
{
@ -94,9 +98,9 @@ int main(int argc, char **argv)
else if (argc != 3)
{
#ifdef FCPW
MessageBox(NULL, usage, FCP, MB_OK);
MessageBox(NULL, USAGE, FCP, MB_OK);
#else
fputs(usage, stderr);
fputs(USAGE, stderr);
#endif
return 1;
}

View File

@ -1,5 +0,0 @@
@echo off
if not exist ter-font.rc exit /b 1
if not exist ter-main.c exit /b 1
echo rm -f *.bdf *.fnt *.txt ter-*.o terminus.fon fcpw.exe
for %%i in (*.bdf *.fnt *.txt ter-*.o terminus.fon fcpw.exe) do if exist %%i del /q %%i

View File

@ -1,15 +1,19 @@
#
# Copyright (c) 2019 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
# Copyright (c) 2020 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of
# the License, or (at your option) any later version.
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
!include nsDialogs.nsh
@ -18,17 +22,15 @@
!include WinVer.nsh
Name "Terminus Font"
OutFile terminus-font-4.48.exe
OutFile terminus-font-4.49.exe
XPStyle on
CRCCheck force
RequestExecutionLevel admin
InstallDir "$EXEDIR\terminus-font-4.48"
InstallDir "$EXEDIR\terminus-font-4.49"
InstallButtonText "Proceed"
Var ter_dialog
Var apply_ao2
Var apply_dv1
Var apply_ge2
@ -61,44 +63,39 @@ Page custom ter_dialog_page ter_dialog_page_leave
Page instfiles
Function install_clicked
EnableWindow $directory 0
EnableWindow $browse 0
${NSD_SetText} $directory "$FONTS"
${NSD_SetText} $directory $FONTS
FunctionEnd
Function unpack_clicked
${NSD_SetText} $directory "$INSTDIR"
${NSD_SetText} $directory $INSTDIR
EnableWindow $directory 1
EnableWindow $browse 1
FunctionEnd
Function hamster_clicked
ExecShell "open" "http://terminus-font.sourceforge.net#variants"
ToolTips::Classic $hamster "http://terminus-font.sourceforge.net#variants"
FunctionEnd
Function browse_clicked
nsDialogs::SelectFolderDialog Directory $INSTDIR
Pop $0
${If} $0 != error
StrCpy $INSTDIR "$0"
${NSD_SetText} $directory "$INSTDIR"
StrCpy $INSTDIR $0
${NSD_SetText} $directory $INSTDIR
${EndIf}
FunctionEnd
Function ter_dialog_page
nsDialogs::Create 1018
Pop $ter_dialog
Pop $0
${If} $0 == error
MessageBox MB_ICONSTOP|MB_OK "Failed to create installation dialog."
Abort
${EndIf}
${NSD_CreateLink} 2% 1 11% 10u "Variants"
Pop $hamster
@ -148,19 +145,17 @@ Function ter_dialog_page
${NSD_CreateLabel} 2% 71u 96% 12u "The license is available with a \
FAQ at: http://scripts.sil.org/OFL"
${NSD_CreateLabel} 2% 83u 96% 24u "Note: the Windows code pages \
contain a total of 356 characters. All other characters \
contain a total of 384 characters. All other characters \
(math, pseudographics etc.) are not currently available."
${NSD_CreateLabel} 2% 107u 96% 12u "Terminus Font 4.48, \
Copyright (C) 2019 Dimitar Toshkov Zhekov."
${NSD_CreateLabel} 2% 107u 96% 12u "Terminus Font 4.49, \
Copyright (C) 2020 Dimitar Toshkov Zhekov."
${NSD_CreateLabel} 2% 119u 96% 12u "Report bugs to \
<dimitar.zhekov@gmail.com>"
nsDialogs::Show
FunctionEnd
Function ter_dialog_page_leave
${NSD_GetState} $apply_ao2 $0
${IfThen} $0 == ${BST_CHECKED} ${|} StrCpy $ao2 "ao2" ${|}
${NSD_GetState} $apply_dv1 $0
@ -193,13 +188,12 @@ Function ter_dialog_page_leave
Abort
${EndIf}
${EndIf}
FunctionEnd
Function patch
Pop $1
${If} $1 != ""
ClearErrors
ExecWait '"$OUTDIR\fcpw.exe" 4100 terminus.fon $1.txt' $R0
${If} ${Errors}
MessageBox MB_OK|MB_ICONEXCLAMATION "Can't run $OUTDIR\fcpw.exe"
@ -207,7 +201,6 @@ Function patch
${EndIf}
${IfThen} $R0 != 0 ${|} Abort "fcpw.exe failed with exit code $R0" ${|}
${EndIf}
FunctionEnd
!macro PATCH arg
@ -218,12 +211,11 @@ FunctionEnd
!define Patch `!insertmacro PATCH`
Section "Install"
${If} $instate == ${BST_CHECKED}
InitPluginsDir
SetOutPath "$PLUGINSDIR"
SetOutPath $PLUGINSDIR
${Else}
SetOutPath "$INSTDIR"
SetOutPath $INSTDIR
${EndIf}
File "terminus.fon"
@ -280,8 +272,8 @@ Section "Install"
${Else}
StrCpy $1 "SOFTWARE\Microsoft\Windows\CurrentVersion\Fonts"
${EndIf}
WriteRegStr HKLM "$1" "Terminus" "terminus.fon"
ReadRegStr $0 HKLM "$1" "Terminus"
WriteRegStr HKLM $1 "Terminus" "terminus.fon"
ReadRegStr $0 HKLM $1 "Terminus"
StrCpy $1 ""
${If} $0 != "terminus.fon"
@ -303,5 +295,4 @@ Section "Install"
File "..\CHANGES"
File "..\OFL.TXT"
${EndIf}
SectionEnd