english breakline, and generate try to count the text size

This commit is contained in:
Tan, Kian-ting 2023-10-30 02:18:29 +08:00
parent 796e0c20c7
commit c3dc58d74a
80 changed files with 7617 additions and 1631 deletions

1
.gitignore vendored
View file

@ -3,3 +3,4 @@ node_modules
/tests/*.js
.vscode
activate.sh
docs/.nojekyll

View file

@ -1,7 +1,8 @@
# clo
another personal draught of a typesetting language and engine.
website: https://kianting.info/wiki/w/Project:Clo
License: MIT
- another personal draught of a typesetting language and engine.
- website: https://kianting.info/wiki/w/Project:Clo
- license: MIT
- issue tracking mailing list: `clo@kianting.info`
## changing journal
- 20230904 建立 thenDo、matchRange的函數、refactor harfbuzzjs 以及libpdf 等測試界面
@ -31,6 +32,7 @@ License: MIT
- 20231023-24:fix .ttc bug.
- 20231026-27 : clo basic interface, preprocessor of stream of text,
add cjk-english splitter, etc.
- 20231029: hyphenating for english.
## 之後的做法
- 先做一個前處理註冊器,註冊下列的前處理
@ -43,15 +45,20 @@ License: MIT
- 然後算出每個Box的x, y, page
- 最後納入排版
## 排版語法
## 排版語法
使用lisp表示但其實是陣列
```lisp
(hglue 寬度 伸展值)
(vglue 高度 伸展值)
(breakpoint 原始模式 斷行模式)
(bp 原始模式 斷行模式) ; breakpoint
(nl) ; newline
(em 數字)
(ex 數字)
(span {"font-family" : "Noto Sans" , "font-size" : 16 })
(vbox 高度 內容)
```
## How to generate documents
- `typedoc /path/to/index.js [/path/to/index2.js ...]`
the generated page will be stored in `/src`.

12
b.clo
View file

@ -1,4 +1,12 @@
---
many臺中daylight
The book of the generation of Jesus Christ, the son of David, the son of Abraham.
aaa collee
Abraham begat Isaac; and Isaac begat Jacob; and Jacob begat Judas and his brethren; And Judas begat Phares and Zara of Thamar; and Phares begat Esrom; and Esrom begat Aram; And Aram begat Aminadab; and Aminadab begat Naasson; and Naasson begat Salmon; And Salmon begat Booz of Rachab; and Booz begat Obed of Ruth; and Obed begat Jesse; And Jesse begat David the king;
and David the king begat Solomon of her that had been the wife of Urias; And Solomon begat Roboam; and Roboam begat Abia; and Abia begat Asa; And Asa begat Josaphat; and Josaphat begat Joram; and Joram begat Ozias; And Ozias begat Joatham; and Joatham begat Achaz; and Achaz begat Ezekias; And Ezekias begat Manasses; and Manasses begat Amon; and Amon begat Josias; And Josias begat Jechonias and his brethren, about the time they were carried away to Babylon: And after they were brought to Babylon, Jechonias begat Salathiel; and Salathiel begat Zorobabel; And Zorobabel begat Abiud; and Abiud begat Eliakim; and Eliakim begat Azor; And Azor begat Sadoc; and Sadoc begat Achim; and Achim begat Eliud; And Eliud begat Eleazar; and Eleazar begat Matthan; and Matthan begat Jacob; And Jacob begat Joseph the husband of Mary, of whom was born Jesus, who is called Christ.
So all the generations from Abraham to David are fourteen generations; and from David until the carrying away into Babylon are fourteen generations; and from the carrying away into Babylon unto Christ are fourteen generations.
Now the birth of Jesus Christ was on this wise: When as his mother Mary was espoused to Joseph, before they came together, she was found with child of the Holy Ghost. Then Joseph her husband, being a just man, and not willing to make her a publick example, was minded to put her away privily. But while he thought on these things, behold, the angel of the Lord appeared unto him in a dream, saying, Joseph, thou son of David, fear not to take unto thee Mary thy wife: for that which is conceived in her is of the Holy Ghost. And she shall bring forth a son, and thou shalt call his name JESUS: for he shall save his people from their sins. Now all this was done, that it might be fulfilled which was spoken of the Lord by the prophet, saying, Behold, a virgin shall be with child, and shall bring forth a son, and they shall call his name Emmanuel, which being interpreted is, God with us.
Then Joseph being raised from sleep did as the angel of the Lord had bidden him, and took unto him his wife: And knew her not till she had brought forth her firstborn son: and he called his name JESUS. Now when Jesus was born in Bethlehem of Judaea in the days of Herod the king, behold, there came wise men from the east to Jerusalem, Saying, Where is he that is born King of the Jews?

13
b.js
View file

@ -9,10 +9,17 @@ let clo = new cloLib.Clo();
/* CLO: beginning of middle part*/
clo.mainStream = /* CLO: end of middle part*/
[`
`, `many臺中daylight`, `
[`The`, ` `, `book`, ` `, `of`, ` `, `the`, ` `, `generation`, ` `, `of`, ` `, `Jesus`, ` `, `Christ,`, ` `, `the`, ` `, `son`, ` `, `of`, ` `, `David,`, ` `, `the`, ` `, `son`, ` `, `of`, ` `, `Abraham.`, `
`, `aaa`, ` `, `collee`];
`, `Abraham`, ` `, `begat`, ` `, `Isaac`, `;`, ` `, `and`, ` `, `Isaac`, ` `, `begat`, ` `, `Jacob`, `;`, ` `, `and`, ` `, `Jacob`, ` `, `begat`, ` `, `Judas`, ` `, `and`, ` `, `his`, ` `, `brethren`, `;`, ` `, `And`, ` `, `Judas`, ` `, `begat`, ` `, `Phares`, ` `, `and`, ` `, `Zara`, ` `, `of`, ` `, `Thamar`, `;`, ` `, `and`, ` `, `Phares`, ` `, `begat`, ` `, `Esrom`, `;`, ` `, `and`, ` `, `Esrom`, ` `, `begat`, ` `, `Aram`, `;`, ` `, `And`, ` `, `Aram`, ` `, `begat`, ` `, `Aminadab`, `;`, ` `, `and`, ` `, `Aminadab`, ` `, `begat`, ` `, `Naasson`, `;`, ` `, `and`, ` `, `Naasson`, ` `, `begat`, ` `, `Salmon`, `;`, ` `, `And`, ` `, `Salmon`, ` `, `begat`, ` `, `Booz`, ` `, `of`, ` `, `Rachab`, `;`, ` `, `and`, ` `, `Booz`, ` `, `begat`, ` `, `Obed`, ` `, `of`, ` `, `Ruth`, `;`, ` `, `and`, ` `, `Obed`, ` `, `begat`, ` `, `Jesse`, `;`, ` `, `And`, ` `, `Jesse`, ` `, `begat`, ` `, `David`, ` `, `the`, ` `, `king`, `;`, `
`, `and`, ` `, `David`, ` `, `the`, ` `, `king`, ` `, `begat`, ` `, `Solomon`, ` `, `of`, ` `, `her`, ` `, `that`, ` `, `had`, ` `, `been`, ` `, `the`, ` `, `wife`, ` `, `of`, ` `, `Urias`, `;`, ` `, `And`, ` `, `Solomon`, ` `, `begat`, ` `, `Roboam`, `;`, ` `, `and`, ` `, `Roboam`, ` `, `begat`, ` `, `Abia`, `;`, ` `, `and`, ` `, `Abia`, ` `, `begat`, ` `, `Asa`, `;`, ` `, `And`, ` `, `Asa`, ` `, `begat`, ` `, `Josaphat`, `;`, ` `, `and`, ` `, `Josaphat`, ` `, `begat`, ` `, `Joram`, `;`, ` `, `and`, ` `, `Joram`, ` `, `begat`, ` `, `Ozias`, `;`, ` `, `And`, ` `, `Ozias`, ` `, `begat`, ` `, `Joatham`, `;`, ` `, `and`, ` `, `Joatham`, ` `, `begat`, ` `, `Achaz`, `;`, ` `, `and`, ` `, `Achaz`, ` `, `begat`, ` `, `Ezekias`, `;`, ` `, `And`, ` `, `Ezekias`, ` `, `begat`, ` `, `Manasses`, `;`, ` `, `and`, ` `, `Manasses`, ` `, `begat`, ` `, `Amon`, `;`, ` `, `and`, ` `, `Amon`, ` `, `begat`, ` `, `Josias`, `;`, ` `, `And`, ` `, `Josias`, ` `, `begat`, ` `, `Jechonias`, ` `, `and`, ` `, `his`, ` `, `brethren,`, ` `, `about`, ` `, `the`, ` `, `time`, ` `, `they`, ` `, `were`, ` `, `carried`, ` `, `away`, ` `, `to`, ` `, `Babylon:`, ` `, `And`, ` `, `after`, ` `, `they`, ` `, `were`, ` `, `brought`, ` `, `to`, ` `, `Babylon,`, ` `, `Jechonias`, ` `, `begat`, ` `, `Salathiel`, `;`, ` `, `and`, ` `, `Salathiel`, ` `, `begat`, ` `, `Zorobabel`, `;`, ` `, `And`, ` `, `Zorobabel`, ` `, `begat`, ` `, `Abiud`, `;`, ` `, `and`, ` `, `Abiud`, ` `, `begat`, ` `, `Eliakim`, `;`, ` `, `and`, ` `, `Eliakim`, ` `, `begat`, ` `, `Azor`, `;`, ` `, `And`, ` `, `Azor`, ` `, `begat`, ` `, `Sadoc`, `;`, ` `, `and`, ` `, `Sadoc`, ` `, `begat`, ` `, `Achim`, `;`, ` `, `and`, ` `, `Achim`, ` `, `begat`, ` `, `Eliud`, `;`, ` `, `And`, ` `, `Eliud`, ` `, `begat`, ` `, `Eleazar`, `;`, ` `, `and`, ` `, `Eleazar`, ` `, `begat`, ` `, `Matthan`, `;`, ` `, `and`, ` `, `Matthan`, ` `, `begat`, ` `, `Jacob`, `;`, ` `, `And`, ` `, `Jacob`, ` `, `begat`, ` `, `Joseph`, ` `, `the`, ` `, `husband`, ` `, `of`, ` `, `Mary,`, ` `, `of`, ` `, `whom`, ` `, `was`, ` `, `born`, ` `, `Jesus,`, ` `, `who`, ` `, `is`, ` `, `called`, ` `, `Christ.`, `
`, `So`, ` `, `all`, ` `, `the`, ` `, `generations`, ` `, `from`, ` `, `Abraham`, ` `, `to`, ` `, `David`, ` `, `are`, ` `, `fourteen`, ` `, `generations`, `;`, ` `, `and`, ` `, `from`, ` `, `David`, ` `, `until`, ` `, `the`, ` `, `carrying`, ` `, `away`, ` `, `into`, ` `, `Babylon`, ` `, `are`, ` `, `fourteen`, ` `, `generations`, `;`, ` `, `and`, ` `, `from`, ` `, `the`, ` `, `carrying`, ` `, `away`, ` `, `into`, ` `, `Babylon`, ` `, `unto`, ` `, `Christ`, ` `, `are`, ` `, `fourteen`, ` `, `generations.`, `
`, `Now`, ` `, `the`, ` `, `birth`, ` `, `of`, ` `, `Jesus`, ` `, `Christ`, ` `, `was`, ` `, `on`, ` `, `this`, ` `, `wise:`, ` `, `When`, ` `, `as`, ` `, `his`, ` `, `mother`, ` `, `Mary`, ` `, `was`, ` `, `espoused`, ` `, `to`, ` `, `Joseph,`, ` `, `before`, ` `, `they`, ` `, `came`, ` `, `together,`, ` `, `she`, ` `, `was`, ` `, `found`, ` `, `with`, ` `, `child`, ` `, `of`, ` `, `the`, ` `, `Holy`, ` `, `Ghost.`, ` `, `Then`, ` `, `Joseph`, ` `, `her`, ` `, `husband,`, ` `, `being`, ` `, `a`, ` `, `just`, ` `, `man,`, ` `, `and`, ` `, `not`, ` `, `willing`, ` `, `to`, ` `, `make`, ` `, `her`, ` `, `a`, ` `, `publick`, ` `, `example,`, ` `, `was`, ` `, `minded`, ` `, `to`, ` `, `put`, ` `, `her`, ` `, `away`, ` `, `privily.`, ` `, `But`, ` `, `while`, ` `, `he`, ` `, `thought`, ` `, `on`, ` `, `these`, ` `, `things,`, ` `, `behold,`, ` `, `the`, ` `, `angel`, ` `, `of`, ` `, `the`, ` `, `Lord`, ` `, `appeared`, ` `, `unto`, ` `, `him`, ` `, `in`, ` `, `a`, ` `, `dream,`, ` `, `saying,`, ` `, `Joseph,`, ` `, `thou`, ` `, `son`, ` `, `of`, ` `, `David,`, ` `, `fear`, ` `, `not`, ` `, `to`, ` `, `take`, ` `, `unto`, ` `, `thee`, ` `, `Mary`, ` `, `thy`, ` `, `wife:`, ` `, `for`, ` `, `that`, ` `, `which`, ` `, `is`, ` `, `conceived`, ` `, `in`, ` `, `her`, ` `, `is`, ` `, `of`, ` `, `the`, ` `, `Holy`, ` `, `Ghost.`, ` `, `And`, ` `, `she`, ` `, `shall`, ` `, `bring`, ` `, `forth`, ` `, `a`, ` `, `son,`, ` `, `and`, ` `, `thou`, ` `, `shalt`, ` `, `call`, ` `, `his`, ` `, `name`, ` `, `JESUS:`, ` `, `for`, ` `, `he`, ` `, `shall`, ` `, `save`, ` `, `his`, ` `, `people`, ` `, `from`, ` `, `their`, ` `, `sins.`, ` `, `Now`, ` `, `all`, ` `, `this`, ` `, `was`, ` `, `done,`, ` `, `that`, ` `, `it`, ` `, `might`, ` `, `be`, ` `, `fulfilled`, ` `, `which`, ` `, `was`, ` `, `spoken`, ` `, `of`, ` `, `the`, ` `, `Lord`, ` `, `by`, ` `, `the`, ` `, `prophet,`, ` `, `saying,`, ` `, `Behold,`, ` `, `a`, ` `, `virgin`, ` `, `shall`, ` `, `be`, ` `, `with`, ` `, `child,`, ` `, `and`, ` `, `shall`, ` `, `bring`, ` `, `forth`, ` `, `a`, ` `, `son,`, ` `, `and`, ` `, `they`, ` `, `shall`, ` `, `call`, ` `, `his`, ` `, `name`, ` `, `Emmanuel,`, ` `, `which`, ` `, `being`, ` `, `interpreted`, ` `, `is,`, ` `, `God`, ` `, `with`, ` `, `us.`, `
`, `Then`, ` `, `Joseph`, ` `, `being`, ` `, `raised`, ` `, `from`, ` `, `sleep`, ` `, `did`, ` `, `as`, ` `, `the`, ` `, `angel`, ` `, `of`, ` `, `the`, ` `, `Lord`, ` `, `had`, ` `, `bidden`, ` `, `him,`, ` `, `and`, ` `, `took`, ` `, `unto`, ` `, `him`, ` `, `his`, ` `, `wife:`, ` `, `And`, ` `, `knew`, ` `, `her`, ` `, `not`, ` `, `till`, ` `, `she`, ` `, `had`, ` `, `brought`, ` `, `forth`, ` `, `her`, ` `, `firstborn`, ` `, `son:`, ` `, `and`, ` `, `he`, ` `, `called`, ` `, `his`, ` `, `name`, ` `, `JESUS.`, ` `, `Now`, ` `, `when`, ` `, `Jesus`, ` `, `was`, ` `, `born`, ` `, `in`, ` `, `Bethlehem`, ` `, `of`, ` `, `Judaea`, ` `, `in`, ` `, `the`, ` `, `days`, ` `, `of`, ` `, `Herod`, ` `, `the`, ` `, `king,`, ` `, `behold,`, ` `, `there`, ` `, `came`, ` `, `wise`, ` `, `men`, ` `, `from`, ` `, `the`, ` `, `east`, ` `, `to`, ` `, `Jerusalem,`, ` `, `Saying,`, ` `, `Where`, ` `, `is`, ` `, `he`, ` `, `that`, ` `, `is`, ` `, `born`, ` `, `King`, ` `, `of`, ` `, `the`, ` `, `Jews?`, ` `];
/* CLO: beginning of end part*/
clo.generatePdf();
/*CLO : end of end part*/

78
docs/assets/highlight.css Normal file
View file

@ -0,0 +1,78 @@
:root {
--light-hl-0: #000000;
--dark-hl-0: #C8C8C8;
--light-hl-1: #000000;
--dark-hl-1: #D4D4D4;
--light-hl-2: #001080;
--dark-hl-2: #9CDCFE;
--light-hl-3: #A31515;
--dark-hl-3: #CE9178;
--light-hl-4: #0070C1;
--dark-hl-4: #4FC1FF;
--light-hl-5: #008000;
--dark-hl-5: #6A9955;
--light-hl-6: #0000FF;
--dark-hl-6: #569CD6;
--light-hl-7: #098658;
--dark-hl-7: #B5CEA8;
--light-code-background: #FFFFFF;
--dark-code-background: #1E1E1E;
}
@media (prefers-color-scheme: light) { :root {
--hl-0: var(--light-hl-0);
--hl-1: var(--light-hl-1);
--hl-2: var(--light-hl-2);
--hl-3: var(--light-hl-3);
--hl-4: var(--light-hl-4);
--hl-5: var(--light-hl-5);
--hl-6: var(--light-hl-6);
--hl-7: var(--light-hl-7);
--code-background: var(--light-code-background);
} }
@media (prefers-color-scheme: dark) { :root {
--hl-0: var(--dark-hl-0);
--hl-1: var(--dark-hl-1);
--hl-2: var(--dark-hl-2);
--hl-3: var(--dark-hl-3);
--hl-4: var(--dark-hl-4);
--hl-5: var(--dark-hl-5);
--hl-6: var(--dark-hl-6);
--hl-7: var(--dark-hl-7);
--code-background: var(--dark-code-background);
} }
:root[data-theme='light'] {
--hl-0: var(--light-hl-0);
--hl-1: var(--light-hl-1);
--hl-2: var(--light-hl-2);
--hl-3: var(--light-hl-3);
--hl-4: var(--light-hl-4);
--hl-5: var(--light-hl-5);
--hl-6: var(--light-hl-6);
--hl-7: var(--light-hl-7);
--code-background: var(--light-code-background);
}
:root[data-theme='dark'] {
--hl-0: var(--dark-hl-0);
--hl-1: var(--dark-hl-1);
--hl-2: var(--dark-hl-2);
--hl-3: var(--dark-hl-3);
--hl-4: var(--dark-hl-4);
--hl-5: var(--dark-hl-5);
--hl-6: var(--dark-hl-6);
--hl-7: var(--dark-hl-7);
--code-background: var(--dark-code-background);
}
.hl-0 { color: var(--hl-0); }
.hl-1 { color: var(--hl-1); }
.hl-2 { color: var(--hl-2); }
.hl-3 { color: var(--hl-3); }
.hl-4 { color: var(--hl-4); }
.hl-5 { color: var(--hl-5); }
.hl-6 { color: var(--hl-6); }
.hl-7 { color: var(--hl-7); }
pre, code { background: var(--code-background); }

59
docs/assets/main.js Normal file

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1 @@
window.navigationData = "data:application/octet-stream;base64,H4sIAAAAAAAAA42XW0/bMBSA/0ue0TYYsI230gZWoGnUZAMJocqkbuPVsaPEKa2m/fe5iZM6t+M8leZ8/hpfzvHh9a8l8F5YN1aA2A5ZZ1aMRCi/RnyVUZx+zh9/CkVEZWxL2Mq6uTizgpDQVYKZdfNaCXz54YkDxScJZllUKqpwXfb931nN8IzJJhT9iiLe7xhTfhpMmMDJGgXVPGS0MZer6/rgMY8iJCOgQ0GQ6o6z5mq0TBUDidYScqXA9RwUYReRBDC2YUjtTu4mPMgizLQFF4e40mlAw/Plx7fzq4vG3nkiwSj6xUiPrs6YjOtydXx+/POkXGcsEIQzfdIaWPdeX2rKOBPHd+hXKaCleNMk8hnetxMlfzwoUUJM4wlOg5NjhxKC3jWLIuq6r/rqxAmX256Oks2uazqFR4PAKVHyHuh5U86peD5oUhOS4Py3m6mrHFV8YOoGFKXp6RVaiXt+oQ+95fvOrFCjZRjM1UQmi0FRMpBndLmcOkv3pWtjlaZEgJ0N/mx3t5QH23TKFnijn7WWrsUavDkjC4ScHTNodRSwrvAaZVTky9Oody1tizV7Oy6VPm3PBVOzhoc4xOyOJ7Wzdkqb8sBrGFBOCszf+gnGRluBQcVJ+NzdA54CAAxpTIkYPzz+BiQVA3jEB19gkSUs9bmDPyhh0PQ6aLDYxChJcdIuNsXzYa0G32L2SPRruig2ylHF+4uNaOxacU+p8aJjr9oX1Hju+Lbjd51M5VEEcCCnM3e+gBQFYDTYttFh20aLZ5R4gMOZ+8sRNJcCMBqWvv1i1uQU4HIX83tAcgwDoz37fgbvrSJAx2w6nj/NHdCiGMBD8V7Pl5YjjwPjeSZkX2Pr2dJyVIzR8xMjs+gIGU0zslp1F/aaq8AAG4pjeji25Li7S1Q2HQOKn8JkAzDElmMm2zSKeWKUFdQwVzpMlppsDhej3pZY91WgyeiiAW+XQ4NMz0SE8hgMW8H2CNNveHgz5NQozGyLyJhTvQfu8ynQaIxlD+o8GX0FZrIN2WjDHhOm/kXyeV/Xo2wNEmo3ZNjnDx4gK5GOxuLtPxjWUt7DEAAA"

1
docs/assets/search.js Normal file

File diff suppressed because one or more lines are too long

1383
docs/assets/style.css Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

109
docs/index.html Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

69
docs/modules/canva.html Normal file

File diff suppressed because one or more lines are too long

55
docs/modules/index.html Normal file

File diff suppressed because one or more lines are too long

76
docs/modules/libclo.html Normal file

File diff suppressed because one or more lines are too long

87
docs/modules/parser.html Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

3041
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -9,7 +9,7 @@
},
"repository": {
"type": "git",
"url": "git+https://github.com/Yoxem/clo.git"
"url": "git+https://git.kianting.info/src/clo"
},
"keywords": [
"typesetting"
@ -17,11 +17,12 @@
"author": "Tan Kian-ting",
"license": "MIT",
"bugs": {
"url": "https://github.com/Yoxem/clo/issues"
"url": "https://kianting.info/wiki/w/Project:Clo#Discussion"
},
"homepage": "https://github.com/Yoxem/clo#readme",
"homepage": "https://kianting.info/wiki/w/Project:Clo",
"devDependencies": {
"@types/chai": "^4.3.5",
"@types/jsdom": "^21.1.4",
"@types/mocha": "^10.0.1",
"@types/node": "^20.8.4",
"@types/pdfkit": "^0.13.1",
@ -36,10 +37,13 @@
"nyc": "^15.1.0",
"ts-node": "^10.9.1",
"tslint": "^6.1.3",
"typedoc": "^0.25.2",
"typescript": "^5.2.2"
},
"dependencies": {
"harfbuzzjs": "^0.3.3",
"canvas": "^2.11.2",
"hyphen": "^1.7.0",
"jsdom": "^22.1.0",
"minimist": "^1.2.8",
"npx": "^10.2.2",
"pdfkit": "^0.13.0",

View file

@ -23,16 +23,16 @@ export interface Clo{
/**
* Font Style Interface
* family : eg. "FreeSans"
* size : in px, not in pt.
* textWeight : TextWeight.REGULAR ,etc
* textWeight : TextStyle.ITALIC ,etc
* - family : eg. "FreeSans"
* - size : in px, not in pt.
* - textWeight : TextWeight.REGULAR ,etc
* - fontStyle : FontStyle.ITALIC ,etc
*/
export interface FontStyle{
export interface TextStyle{
family : string,
size : number,
textWeight : TextWeight,
textStyle : TextStyle,
fontStyle : FontStyle,
color? : string,
};
@ -41,7 +41,7 @@ export enum TextWeight {
BOLD,
};
export enum TextStyle{
export enum FontStyle{
NORMAL,
ITALIC,
OBLIQUE,
@ -57,10 +57,10 @@ export interface fontPathPSNamePair{
* @param style the font style
* @returns pair of the font path and postscript name.
*/
export function fontStyleTofont(style : FontStyle) : fontPathPSNamePair{
export function fontStyleTofont(style : TextStyle) : fontPathPSNamePair{
try {
let fcMatchCommand = `fc-match "${style.family}":${TextWeight[style.textWeight]}:`+
`${TextStyle[style.textStyle]}` +` postscriptname file`;
`${FontStyle[style.fontStyle]}` +` postscriptname file`;
let fcMatchOut = execSync(fcMatchCommand);
let matched = fcMatchOut
@ -93,7 +93,7 @@ export function fontStyleTofont(style : FontStyle) : fontPathPSNamePair{
* @param y base y-point from top
* @returns a new updated clo object
*/
export async function putText(clo : Clo, str : string, sty : FontStyle,
export async function putText(clo : Clo, str : string, sty : TextStyle,
pageNo : number, x : number, y : number): Promise<Clo>{
let fontInfo = fontStyleTofont(sty);

View file

@ -23,10 +23,14 @@ var __importStar = (this && this.__importStar) || function (mod) {
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.processArgv = exports.helpDesc = void 0;
var fs = require('fs');
var argv = require('minimist')(process.argv.slice(2));
const parser = __importStar(require("./parser.js"));
let helpDesc = `
/**
* help for inputing `--help` parameter.
*/
exports.helpDesc = `
clo: clo INPUT_FILE --output-js OUTPUT_JS_FILE
\ta little typesetter powered by TypeScript/Javascript.
@ -42,7 +46,7 @@ INPUT_FILE\tan input .clo file
Report bugs to: clo@kianting.info
clo home page: <https://kianting.info/wiki/w/Project:Clo>
`;
processArgv(argv, helpDesc);
processArgv(argv, exports.helpDesc);
/**
* processing the passed `argv` (arguments)
*/
@ -72,3 +76,4 @@ function processArgv(argv, helpDesc) {
});
}
}
exports.processArgv = processArgv;

View file

@ -3,8 +3,10 @@ var argv : any = require('minimist')(process.argv.slice(2));
import * as parser from "./parser.js";
let helpDesc =
/**
* help for inputing `--help` parameter.
*/
export let helpDesc =
`
clo: clo INPUT_FILE --output-js OUTPUT_JS_FILE
@ -28,7 +30,7 @@ processArgv(argv, helpDesc);
* processing the passed `argv` (arguments)
*/
function processArgv(argv : any, helpDesc : string){
export function processArgv(argv : any, helpDesc : string){
let inputFile : string[] = argv['_'];
let outputJSFile : string | true = argv['output-js'];

View file

@ -1,7 +1,8 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.a = exports.Clo = void 0;
exports.Clo = exports.calculateTextWidthHeight = exports.hyphenTkTree = exports.filterEmptyString = exports.spacesToBreakpoint = exports.hyphenForClo = exports.splitCJKV = exports.twoReturnsToNewline = exports.ptToPx = exports.cjkvRegexPattern = exports.cjkvBlocksInRegex = exports.defaultFrameStyle = exports.defaultTextStyle = exports.A4_IN_PX = exports.Direction = void 0;
const canva_1 = require("../canva");
const jsdom_1 = require("jsdom");
/**
* TYPES
*/
@ -17,32 +18,40 @@ var Direction;
Direction[Direction["RTL"] = 1] = "RTL";
Direction[Direction["TTB"] = 2] = "TTB";
Direction[Direction["BTT"] = 3] = "BTT";
})(Direction || (Direction = {}));
})(Direction || (exports.Direction = Direction = {}));
/**
* DEFAULT CONST PART
*/
const A4_IN_PX = { "width": 793.7,
exports.A4_IN_PX = { "width": 793.7,
"height": 1122.5 };
const defaultTextStyle = {
family: "FreeSans",
size: 12,
exports.defaultTextStyle = {
family: "FreeSerif",
size: ptToPx(12),
textWeight: canva_1.TextWeight.REGULAR,
textStyle: canva_1.TextStyle.ITALIC,
fontStyle: canva_1.FontStyle.ITALIC,
};
const defaultFrameStyle = {
exports.defaultFrameStyle = {
directionInsideLine: Direction.LTR,
direction: Direction.TTB,
baseLineskip: ptToPx(15),
fontStyle: defaultTextStyle,
x: A4_IN_PX.width * 0.10,
y: A4_IN_PX.height * 0.10,
width: A4_IN_PX.width * 0.80,
height: A4_IN_PX.height * 0.80,
textStyle: exports.defaultTextStyle,
x: exports.A4_IN_PX.width * 0.10,
y: exports.A4_IN_PX.height * 0.10,
width: exports.A4_IN_PX.width * 0.80,
height: exports.A4_IN_PX.height * 0.80,
content: null,
};
const cjkvBlocksInRegex = ["Hani"];
const cjkvRegexPattern = new RegExp("((?:" +
cjkvBlocksInRegex.map((x) => "\\p{Script_Extensions=" + x + "}").join("|") + ")+)", "gu");
/**
* definition for cjk scripts
* - Hani : Han Character
* - Hang : Hangul
* - Bopo : Bopomofo
* - Kana : Katakana
* - Hira : Hiragana
*/
exports.cjkvBlocksInRegex = ["Hani", "Hang", "Bopo", "Kana", "Hira"];
exports.cjkvRegexPattern = new RegExp("((?:" +
exports.cjkvBlocksInRegex.map((x) => "\\p{Script_Extensions=" + x + "}").join("|") + ")+)", "gu");
/**
* FUNCTION PART
*/
@ -52,47 +61,208 @@ const cjkvRegexPattern = new RegExp("((?:" +
* @returns the corresponding px value
*/
function ptToPx(pt) {
return pt * 4 / 3.0;
return pt * 4.0 / 3.0;
}
exports.ptToPx = ptToPx;
/**
* REGISTER PART
*/
/**
* convert '\n\n' to newline command ["nl"]
* @param arr the input `tkTree`
* @param clo the `Clo` object
* @returns the input tktree
*/
function twoReturnsToNewline(arr, clo) {
var middle = [];
for (let i = 0; i < arr.length; i++) {
var item = arr[i];
if (!Array.isArray(item)) {
middle = middle.concat(item.split(/(\n\n)/g));
}
else {
middle.push(item);
}
}
var result = [];
for (let j = 0; j < middle.length; j++) {
var item = middle[j];
if (!Array.isArray(item) && item == "\n\n") {
result.push(["nl"]); // push a newline command to the result `tkTree`
}
else {
result.push(middle[j]);
}
}
return result;
}
exports.twoReturnsToNewline = twoReturnsToNewline;
/**
* split CJKV and non-CJKV
*
* @param arr : input tkTree
* @returns
* @returns a splitted tkTree (by CJK and NonCJK)
* - Examples:
* ```
* [`many臺中daylight`] => [`many`, `臺中`, `dahylight`]
* ```
*/
function splitCJKV(arr) {
console.log(arr);
function splitCJKV(arr, clo) {
var result = [];
for (let i = 0; i < arr.length; i++) {
var item = arr[i];
if (!Array.isArray(item)) {
console.log(item.split(cjkvRegexPattern));
result = result.concat(item.split(cjkvRegexPattern));
result = result.concat(item.split(exports.cjkvRegexPattern));
}
else {
result.push(item);
}
}
console.log(result);
return result;
}
exports.splitCJKV = splitCJKV;
/**
* hyphenation for a clo document
* @param arr the array for a `tkTree`
* @param clo the Clo object
*/
function hyphenForClo(arr, clo) {
let hyphenLanguage = clo.attrs["hyphenLanguage"];
let res = hyphenTkTree(arr, hyphenLanguage);
return res;
}
exports.hyphenForClo = hyphenForClo;
/**
* convert spaces to Breakpoint
* \s+ => ["bp" [\s+] ""]
* @param arr the tkTree input text stream
* @param clo the Clo object
* @returns the converted object
*/
function spacesToBreakpoint(arr, clo) {
let spacePattern = /^([ \t]+)$/g;
var result = [];
for (let i = 0; i < arr.length; i++) {
var item = arr[i];
if (!Array.isArray(item) && item.match(spacePattern)) {
result.push(['bp', item, ""]); // push a newline command to the result `tkTree`
}
else {
result.push(item);
}
}
return result;
}
exports.spacesToBreakpoint = spacesToBreakpoint;
/**
* remove all the `` (empty string) in the arr
* @param arr the tkTree to be filtered
* @param clo the Clo file
*/
function filterEmptyString(arr, clo) {
if (Array.isArray(arr)) {
arr.filter((x) => { return x != ``; });
}
return arr;
}
exports.filterEmptyString = filterEmptyString;
/**
* OTHER FUNCTIONS
*/
/**
* hyphenate for a tkTree
* - hyphenation => ["bp", "", "-"]
* @param arr the tkTree array
* @param lang ISO 639 code for the language
*/
function hyphenTkTree(arr, lang) {
// import corresponding hyphen language data and function
let hyphen = require("hyphen/" + lang);
let result = [];
for (let i = 0; i < arr.length; i++) {
let element = arr[i];
let splitter = "分"; // a CJKV
if (!Array.isArray(element)) {
let hyphenatedElement = hyphen.hyphenateSync(element, { hyphenChar: splitter });
let hyphenatedSplitted = hyphenatedElement.split(splitter);
var newSplitted = [];
for (var j = 0; j < hyphenatedSplitted.length - 1; j++) {
newSplitted.push(hyphenatedSplitted[j]);
// "bp" for breakpoint
newSplitted.push(["bp", "", "-"]); //insert a breakable point (bp) mark
}
newSplitted.push(hyphenatedSplitted[hyphenatedSplitted.length - 1]);
result = result.concat(newSplitted);
}
else {
result.push(element);
}
}
return result;
}
exports.hyphenTkTree = hyphenTkTree;
/**
* calculate the text width and Height with a given `TextStyle`
* @param preprocessed
* @param defaultFontStyle
*/
function calculateTextWidthHeight(preprocessed, style) {
var dom = new jsdom_1.JSDOM(`<!DOCTYPE html><html><head></head>
<body><canvas id="canvas"></canvas></body></html>`);
try {
let canvas = dom.window.document.getElementById("canvas");
console.log(canvas);
/*if (!(canvas instanceof HTMLElement)){
throw new Error('the <canvas="canvas"> in the jsdom\'s DOM is not found.');
}*/
let context = canvas.getContext("2d");
console.log(context);
if (context == null) {
throw new Error('`canvas.getContext("2d");` can\'t be executed.');
}
context.font = `normal normal 10pt ${style.family}`;
console.log(context.font);
let txt = `Hello john`;
console.log(txt);
let measured = context.measureText(txt);
let width = measured.width;
let height = measured.actualBoundingBoxAscent;
let depth = measured.actualBoundingBoxDescent;
console.log("width: " + width);
console.log("height: " + height);
console.log("depth: " + depth);
}
catch (error) {
console.log("Exception " + error);
}
}
exports.calculateTextWidthHeight = calculateTextWidthHeight;
/**
* whole document-representing class
*/
class Clo {
constructor() {
this.preprocessors = [];
this.mainStream = [];
this.attributes = { "page": A4_IN_PX };
this.attrs = {
"page": exports.A4_IN_PX,
"defaultFrameStyle": exports.defaultFrameStyle,
"hyphenLanguage": 'en' // hyphenated in the language (in ISO 639)
};
// register the precessor functions
this.preprocessorRegister(splitCJKV);
this.preprocessorRegister(hyphenForClo);
this.preprocessorRegister(twoReturnsToNewline);
this.preprocessorRegister(spacesToBreakpoint);
this.preprocessorRegister(filterEmptyString);
}
setAttr(attr, val) {
Object.assign(this.attributes, attr, val);
Object.assign(this.attrs, attr, val);
}
getAttr(attr) {
if (Object.keys(this.attributes).length === 0) {
return this.attributes[attr];
if (Object.keys(this.attrs).length === 0) {
return this.attrs[attr];
}
else {
return undefined;
@ -107,14 +277,18 @@ class Clo {
}
generatePdf() {
// preprocessed
var prepro = this.mainStream;
var preprocessed = this.mainStream;
for (var i = 0; i < this.preprocessors.length; i++) {
prepro = this.preprocessors[i](prepro);
preprocessed = this.preprocessors[i](preprocessed, this);
}
// generate the width and height of the stream
let defaultFontStyle = this.attrs["defaultFrameStyle"].textStyle;
calculateTextWidthHeight(preprocessed, defaultFontStyle);
// TODO
console.log("test" + prepro);
console.log(preprocessed);
}
}
exports.Clo = Clo;
exports.a = new Clo();
exports.default = exports.a;
/*
export let a = new Clo();
export default a; */

View file

@ -1,7 +1,7 @@
import { isKeyObject, isStringObject } from "util/types";
import {tkTree} from "../parser";
import {TextStyle, FontStyle, TextWeight} from "../canva";
import { isString } from "util";
import {FontStyle, TextStyle, TextWeight} from "../canva";
import { JSDOM } from "jsdom";
/**
* TYPES
@ -13,7 +13,7 @@ import { isString } from "util";
* TTB - top to bottom
* etc.
*/
enum Direction{
export enum Direction{
LTR,
RTL,
TTB,
@ -25,18 +25,24 @@ enum Direction{
* - directionInsideLine : text direction inside a line
* - baselineskip : the distance between baselines in px
*/
interface FrameBox extends Box{
export interface FrameBox extends Box{
directionInsideLine : Direction,
baseLineskip : number | null,
}
/**
* a basic Box
* - x :
* - y :
* - textStyle :
* - direction :
* - width :
* - content :
*/
interface Box{
export interface Box{
x : number | null,
y : number | null,
fontStyle : FontStyle | null,
textStyle : TextStyle | null,
direction : Direction,
width : number,
height : number,
@ -47,21 +53,21 @@ interface Box{
/**
* DEFAULT CONST PART
*/
const A4_IN_PX = {"width" : 793.7,
export const A4_IN_PX = {"width" : 793.7,
"height" : 1122.5};
const defaultTextStyle : FontStyle = {
family : "FreeSans",
size : 12,
export const defaultTextStyle : TextStyle = {
family : "FreeSerif",
size : ptToPx(12),
textWeight : TextWeight.REGULAR,
textStyle : TextStyle.ITALIC,
fontStyle : FontStyle.ITALIC,
}
const defaultFrameStyle : FrameBox = {
export const defaultFrameStyle : FrameBox = {
directionInsideLine : Direction.LTR,
direction : Direction.TTB,
baseLineskip : ptToPx(15),
fontStyle : defaultTextStyle,
textStyle : defaultTextStyle,
x : A4_IN_PX.width * 0.10,
y : A4_IN_PX.height * 0.10,
width : A4_IN_PX.width * 0.80,
@ -69,9 +75,17 @@ const defaultFrameStyle : FrameBox = {
content : null,
};
const cjkvBlocksInRegex = ["Hani"];
/**
* definition for cjk scripts
* - Hani : Han Character
* - Hang : Hangul
* - Bopo : Bopomofo
* - Kana : Katakana
* - Hira : Hiragana
*/
export const cjkvBlocksInRegex = ["Hani", "Hang", "Bopo", "Kana", "Hira"];
const cjkvRegexPattern = new RegExp("((?:" +
export const cjkvRegexPattern = new RegExp("((?:" +
cjkvBlocksInRegex.map((x)=>"\\p{Script_Extensions="+x+"}").join("|") + ")+)", "gu");
/**
* FUNCTION PART
@ -81,8 +95,8 @@ const cjkvRegexPattern = new RegExp("((?:" +
* @param pt pt size value
* @returns the corresponding px value
*/
function ptToPx(pt : number) : number{
return pt * 4 / 3.0;
export function ptToPx(pt : number) : number{
return pt * 4.0 / 3.0;
}
@ -91,19 +105,54 @@ function ptToPx(pt : number) : number{
* REGISTER PART
*/
/**
* convert '\n\n' to newline command ["nl"]
* @param arr the input `tkTree`
* @param clo the `Clo` object
* @returns the input tktree
*/
export function twoReturnsToNewline(arr : tkTree, clo : Clo): tkTree{
var middle : tkTree = [];
for (let i = 0; i < arr.length; i++) {
var item = arr[i];
if (!Array.isArray(item)){
middle = middle.concat(item.split(/(\n\n)/g));
}
else{
middle.push(item);
}
}
var result : tkTree = [];
for (let j = 0; j < middle.length; j++){
var item = middle[j];
if (!Array.isArray(item) && item == "\n\n"){
result.push(["nl"]); // push a newline command to the result `tkTree`
}
else{
result.push(middle[j]);
}
}
return result;
}
/**
* split CJKV and non-CJKV
*
* @param arr : input tkTree
* @returns
* @returns a splitted tkTree (by CJK and NonCJK)
* - Examples:
* ```
* [`many臺中daylight`] => [`many`, `臺中`, `dahylight`]
* ```
*/
function splitCJKV(arr : tkTree): tkTree{
export function splitCJKV(arr : tkTree, clo : Clo): tkTree{
var result : tkTree = [];
for (let i = 0; i < arr.length; i++) {
var item = arr[i];
if (!Array.isArray(item)){
console.log(item.split(cjkvRegexPattern));
result = result.concat(item.split(cjkvRegexPattern));
}
else{
@ -114,30 +163,182 @@ function splitCJKV(arr : tkTree): tkTree{
return result;
}
/**
* hyphenation for a clo document
* @param arr the array for a `tkTree`
* @param clo the Clo object
*/
export function hyphenForClo(arr : tkTree, clo : Clo): tkTree{
let hyphenLanguage : string = clo.attrs["hyphenLanguage"];
let res = hyphenTkTree(arr, hyphenLanguage);
return res;
}
/**
* convert spaces to Breakpoint
* \s+ => ["bp" [\s+] ""]
* @param arr the tkTree input text stream
* @param clo the Clo object
* @returns the converted object
*/
export function spacesToBreakpoint(arr : tkTree, clo : Clo) : tkTree{
let spacePattern = /^([ \t]+)$/g;
var result : tkTree = [];
for (let i = 0; i < arr.length; i++){
var item = arr[i];
if (!Array.isArray(item) && item.match(spacePattern)){
result.push([ 'bp', item, "" ]); // push a newline command to the result `tkTree`
}
else{
result.push(item);
}
}
return result;
}
/**
* remove all the `` (empty string) in the arr
* @param arr the tkTree to be filtered
* @param clo the Clo file
*/
export function filterEmptyString(arr : tkTree, clo : Clo) : tkTree{
if (Array.isArray(arr)){
arr.filter((x)=>{return x != ``;});
}
return arr;
}
/**
* OTHER FUNCTIONS
*/
/**
* hyphenate for a tkTree
* - hyphenation => ["bp", "", "-"]
* @param arr the tkTree array
* @param lang ISO 639 code for the language
*/
export function hyphenTkTree(arr : tkTree, lang: string) : tkTree{
// import corresponding hyphen language data and function
let hyphen = require("hyphen/"+lang);
let result :tkTree[] = [];
for (let i = 0; i < arr.length; i++) {
let element = arr[i];
let splitter = "分"; // a CJKV
if (!Array.isArray(element)){
let hyphenatedElement : string = hyphen.hyphenateSync(element, {hyphenChar :splitter});
let hyphenatedSplitted : tkTree = hyphenatedElement.split(splitter);
var newSplitted : tkTree = [];
for (var j=0; j<hyphenatedSplitted.length-1;j++){
newSplitted.push(hyphenatedSplitted[j]);
// "bp" for breakpoint
newSplitted.push(["bp", "", "-"]); //insert a breakable point (bp) mark
}
newSplitted.push(hyphenatedSplitted[hyphenatedSplitted.length-1]);
result = result.concat(newSplitted);
}else{
result.push(element);
}
}
return result;
}
/**
* calculate the text width and Height with a given `TextStyle`
* @param preprocessed
* @param defaultFontStyle
*/
export function calculateTextWidthHeight(preprocessed : tkTree, style : TextStyle): void {
var dom = new JSDOM(`<!DOCTYPE html><html><head></head>
<body><canvas id="canvas"></canvas></body></html>`);
try {
let canvas = dom.window.document.getElementById("canvas");
console.log(canvas);
/*if (!(canvas instanceof HTMLElement)){
throw new Error('the <canvas="canvas"> in the jsdom\'s DOM is not found.');
}*/
let context = (<HTMLCanvasElement>canvas).getContext("2d");
console.log(context);
if (context == null){
throw new Error('`canvas.getContext("2d");` can\'t be executed.');
}
context.font = `normal normal ${style.size}px ${style.family}`;
console.log(context.font);
let txt = `Hello john`;
console.log(txt);
let measured = context.measureText(txt);
let width = measured.width;
let height = measured.actualBoundingBoxAscent;
let depth = measured.actualBoundingBoxDescent;
console.log("width: "+width);
console.log("height: "+height);
console.log("depth: "+depth);
} catch (error) {
console.log("Exception "+error);
}
}
/**
* whole document-representing class
*/
export class Clo{
/** storing the text string into the main frame */
mainStream : Array<string>;
/** array of preprocessor functions to preprocess the `mainStream` */
preprocessors : Array<Function>;
attributes: {[index: string]:any} ; // a4 size(x,y)
/** the attributes for the Clo */
attrs: {[index: string]:any} ; // a4 size(x,y)
constructor(){
this.preprocessors = [];
this.mainStream = [];
this.attributes = {"page" : A4_IN_PX};
this.attrs = {
"page" : A4_IN_PX, // default for a4. in px of [x, y]
"defaultFrameStyle" : defaultFrameStyle, // defaultFrameStyle
"hyphenLanguage" : 'en' // hyphenated in the language (in ISO 639)
};
// register the precessor functions
this.preprocessorRegister(splitCJKV);
this.preprocessorRegister(hyphenForClo);
this.preprocessorRegister(twoReturnsToNewline);
this.preprocessorRegister(spacesToBreakpoint);
this.preprocessorRegister(filterEmptyString);
}
public setAttr(attr : string, val : any):void{
Object.assign(this.attributes, attr, val);
Object.assign(this.attrs, attr, val);
}
public getAttr(attr:string) : any{
if (Object.keys(this.attributes).length === 0){
return this.attributes[attr];
if (Object.keys(this.attrs).length === 0){
return this.attrs[attr];
}else{
return undefined;
}
@ -154,16 +355,22 @@ export class Clo{
public generatePdf(){
// preprocessed
var prepro = this.mainStream;
var preprocessed = this.mainStream;
for (var i = 0; i<this.preprocessors.length; i++){
prepro = this.preprocessors[i](prepro);
preprocessed = this.preprocessors[i](preprocessed, this);
}
// generate the width and height of the stream
let defaultFontStyle : TextStyle = this.attrs["defaultFrameStyle"].textStyle;
calculateTextWidthHeight(preprocessed, defaultFontStyle);
// TODO
console.log("test"+prepro);
console.log(preprocessed);
}
}
/*
export let a = new Clo();
export default a;
export default a; */

View file

@ -33,7 +33,7 @@ export function tkTreeToSExp(t: tkTree): string{
export type tkTree = string | tkTree[];
enum TokenKind {
export enum TokenKind {
Seperator, // ---
Semicolon, // ;
Number,
@ -50,7 +50,7 @@ enum TokenKind {
/**
* Parsing
*/
const lexer = p.buildLexer([
export const lexer = p.buildLexer([
[true, /^\d+(\.\d+)?/g, TokenKind.Number],
[true, /^[\\][\\]/g, TokenKind.Op],
[true, /^\\\@/g, TokenKind.ExcapeAt],
@ -75,41 +75,42 @@ const lexer = p.buildLexer([
const PROG = p.rule<TokenKind, tkTree>();
const SEGMENT = p.rule<TokenKind, tkTree>();
const IMPORT = p.rule<TokenKind, tkTree>();
const IMPORTS = p.rule<TokenKind, tkTree>();
const SEMICOLON = p.rule<TokenKind, tkTree>();
const NOT_AT_TEXT = p.rule<TokenKind, tkTree>();
const CONTENT = p.rule<TokenKind, tkTree>();
export const PROG = p.rule<TokenKind, tkTree>();
export const SEGMENT = p.rule<TokenKind, tkTree>();
export const IMPORT = p.rule<TokenKind, tkTree>();
export const IMPORTS = p.rule<TokenKind, tkTree>();
export const SEMICOLON = p.rule<TokenKind, tkTree>();
export const NOT_AT_TEXT = p.rule<TokenKind, tkTree>();
export const CONTENT = p.rule<TokenKind, tkTree>();
function applySegment(input: [Token<TokenKind>, Token<TokenKind>[],
export function applySegment(input: [Token<TokenKind>, Token<TokenKind>[],
Token<TokenKind>]): tkTree[]{
let unpackedInnerExprs = input[1].map((x)=>{return x.text});
return ["%exprs", unpackedInnerExprs];
}
function applySemiColon(value: Token<TokenKind.Semicolon>): tkTree{
export function applySemiColon(value: Token<TokenKind.Semicolon>): tkTree{
return value.text;
}
function applyParts(first: tkTree,
second: [Token<TokenKind>, tkTree]):tkTree {
return ["%clo", first , second[1]];
export function applyParts(first: tkTree,
second: [Token<TokenKind>, Token<TokenKind>, tkTree]):tkTree {
return ["%clo", first , second[2]];
}
function applyPartsWithoutImport(parsed: [Token<TokenKind>, tkTree]):tkTree {
return ["%clo", "" , parsed[1]];
export function applyPartsWithoutImport(
parsed: [Token<TokenKind>, Token<TokenKind>, tkTree]):tkTree {
return ["%clo", "" , parsed[2]];
}
function applyComment(value: Token<TokenKind.Comment>): tkTree[]{
export function applyComment(value: Token<TokenKind.Comment>): tkTree[]{
return [value.text];
}
function applyImport(input: [Token<TokenKind>,Token<TokenKind>[], tkTree]) : tkTree{
export function applyImport(input: [Token<TokenKind>,Token<TokenKind>[], tkTree]) : tkTree{
let importTail = input[1].map(x=>x.text);
return ["import"].concat(importTail);
};
@ -123,7 +124,7 @@ function applyImportComment(input: [Token<TokenKind>,Token<TokenKind>[],
return ["import"].concat(importTail).concat(comment);
};*/
function applyImports(input : [tkTree, tkTree[]]): tkTree{
export function applyImports(input : [tkTree, tkTree[]]): tkTree{
let resultBody = [input[0]].concat(input[1]);
let resultWrapper = ["%import", resultBody];
return resultWrapper;
@ -132,29 +133,29 @@ function applyImports(input : [tkTree, tkTree[]]): tkTree{
function applyNotAtText(value : Token<TokenKind>): tkTree{
export function applyNotAtText(value : Token<TokenKind>): tkTree{
if (value.text == "\\\@"){
return '@';
}
else{return value.text;}
};
function applyText (input : tkTree): tkTree[]{
export function applyText (input : tkTree): tkTree[]{
return ["%text", input];
};
function applyContent(input : tkTree[]): tkTree[]{
export function applyContent(input : tkTree[]): tkTree[]{
return ["%content", input];
};
function applySpaceNL(value : Token<TokenKind.SpaceNL>): tkTree{
export function applySpaceNL(value : Token<TokenKind.SpaceNL>): tkTree{
return value.text;
}
/**
* IMPORTEE: Number, Op, Paren, Id, Str, Comment,
*/
let IMPORTEE = p.alt(p.tok(TokenKind.Number),
export let IMPORTEE = p.alt(p.tok(TokenKind.Number),
p.tok(TokenKind.Op),
p.tok(TokenKind.Paren),
p.tok(TokenKind.Id),
@ -162,7 +163,7 @@ let IMPORTEE = p.alt(p.tok(TokenKind.Number),
p.tok(TokenKind.SpaceNL),
p.tok(TokenKind.Comment));
let NOT_AT = p.alt(p.tok(TokenKind.Seperator),
export let NOT_AT = p.alt(p.tok(TokenKind.Seperator),
p.tok(TokenKind.Semicolon),
p.tok(TokenKind.Number),
p.tok(TokenKind.ExcapeAt),
@ -175,12 +176,12 @@ let NOT_AT = p.alt(p.tok(TokenKind.Seperator),
);
/**
* PROG : IMPORTS '---' CONTENT | '---' CONTNENT
* PROG : IMPORTS '---' NEWLINE CONTENT | '---' NEWLINE CONTNENT
*/
PROG.setPattern(
p.alt(
p.lrec_sc(IMPORTS, p.seq(p.str('---'), CONTENT), applyParts),
p.apply(p.seq(p.str('---'), CONTENT), applyPartsWithoutImport))
p.lrec_sc(IMPORTS, p.seq(p.str('---'), p.str("\n"), CONTENT), applyParts),
p.apply(p.seq(p.str('---'), p.str("\n"), CONTENT), applyPartsWithoutImport))
)
@ -242,7 +243,7 @@ CONTENT.setPattern(
/**
* the head part of the output JS code : before import
*/
let outputHead = `
export let outputHead = `
/* clo, a typesetting engine, generated JS file*/
/* CLO: beginning of head*/
@ -254,11 +255,15 @@ let clo = new cloLib.Clo();
/**
* the middle part of the output JS code : between import part and content part
*/
let outputMiddle =`
export let outputMiddle =`
/* CLO: beginning of middle part*/
clo.mainStream = /* CLO: end of middle part*/
`
let outputEnd =`
/**
* the end part of the output JS code : after content part
*/
export let outputEnd =`
/* CLO: beginning of end part*/
clo.generatePdf();
/*CLO : end of end part*/
@ -346,6 +351,9 @@ export function treeToJS(tree : tkTree): string{
* `inputText` to `tkTree` (ASTTree)
*/
export function inputTextToTree(inputText : string){
return p.expectSingleResult(
// force convert Windows newline to Linux newline
inputText = inputText.replace("\r\n", "\n");
return p.expectSingleResult(
p.expectEOF(PROG.parse(lexer.parse(inputText))));
}

View file

@ -1,33 +1,30 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.pdfGenerate = void 0;
const fs_1 = require("fs");
const pdf_lib_1 = require("pdf-lib");
/*import { readFileSync, writeFileSync } from "fs";
import { PDFDocument } from "pdfkit";
var fontkit = require('pdf-fontkit');
function pdfGenerate() {
return __awaiter(this, void 0, void 0, function* () {
const pdfDoc = yield pdf_lib_1.PDFDocument.create();
const page = pdfDoc.addPage();
export async function pdfGenerate(){
const pdfDoc = await PDFDocument.create()
const page = pdfDoc.addPage()
pdfDoc.registerFontkit(fontkit);
const fontBytes = (0, fs_1.readFileSync)("/usr/share/fonts/uming.ttf");
const font2 = yield pdfDoc.embedFont(fontBytes, { subset: true });
const fontBytes2 = (0, fs_1.readFileSync)("/usr/share/fonts/truetype/noto/NotoSansArabic-Light.ttf");
const font3 = yield pdfDoc.embedFont(fontBytes2, { subset: true });
page.drawText("x=20, y=20", { x: 20, y: 20 });
page.drawText("x:20, y:100 天地人", { x: 20, y: 100, font: font2 });
page.drawText("عربي", { x: 50, y: 150, font: font3 });
const pdfBytes = yield pdfDoc.save();
(0, fs_1.writeFileSync)('/tmp/test2.pdf', pdfBytes);
});
const fontBytes = readFileSync("/usr/share/fonts/uming.ttf");
const font2 = await pdfDoc.embedFont(fontBytes, {subset:true})
const fontBytes2 = readFileSync("/usr/share/fonts/truetype/noto/NotoSansArabic-Light.ttf")
const font3 = await pdfDoc.embedFont(fontBytes2, {subset:true})
page.drawText("x=20, y=20", {x : 20, y : 20})
page.drawText("x:20, y:100 天地人", {x : 20, y : 100, font: font2})
page.drawText("عربي", {x : 50, y : 150, font: font3})
const pdfBytes = await pdfDoc.save();
writeFileSync('/tmp/test2.pdf', pdfBytes);
}
exports.pdfGenerate = pdfGenerate;
pdfGenerate();
*/

View file

@ -1,5 +1,5 @@
import { readFileSync, writeFileSync } from "fs";
import { PDFDocument } from "pdf-lib";
/*import { readFileSync, writeFileSync } from "fs";
import { PDFDocument } from "pdfkit";
var fontkit = require('pdf-fontkit');
export async function pdfGenerate(){
@ -25,3 +25,5 @@ export async function pdfGenerate(){
}
pdfGenerate();
*/

View file

@ -6,21 +6,21 @@ let hanziFont = {
family : "Noto Sans CJK TC",
size : 12,
textWeight : canva.TextWeight.REGULAR,
textStyle : canva.TextStyle.ITALIC,
fontStyle : canva.FontStyle.ITALIC,
}
let romanFont = {
family : "FreeSans",
size : 15,
textWeight : canva.TextWeight.BOLD,
textStyle : canva.TextStyle.ITALIC,
fontStyle : canva.FontStyle.ITALIC,
}
let arabicFont = {
family : "noto sans arabic",
size : 16,
textWeight : canva.TextWeight.REGULAR,
textStyle : canva.TextStyle.NORMAL,
fontStyle : canva.FontStyle.NORMAL,
}
@ -32,7 +32,7 @@ async function foo (){
let clo = await {
mainText : ["123 一隻貓跑過來"],
mainFontStyle : hanziFont,
mainTextStyle : hanziFont,
PDFCanvas : doc,
}

View file

@ -0,0 +1,34 @@
import sys
import uharfbuzz as hb
fontfile = sys.argv[1]
text = sys.argv[2]
blob = hb.Blob.from_file_path(fontfile)
face = hb.Face(blob)
font = hb.Font(face)
px = 96
scale = 1000000.0/952997
font.scale = (px *scale* 1024, px*scale * 1024)
buf = hb.Buffer()
buf.add_str(text)
buf.guess_segment_properties()
features = {"kern": True, "liga": True}
hb.shape(font, buf, features)
infos = buf.glyph_infos
positions = buf.glyph_positions
for info, pos in zip(infos, positions):
gid = info.codepoint
cluster = info.cluster
x_advance = pos.x_advance / 1024
y_advance = pos.y_advance / 1024
x_offset = pos.x_offset / 1024
y_offset = pos.y_offset /1024
print(f"gid{gid}={cluster}@{x_advance},{y_offset}+{x_advance},{y_advance}")