├── LICENSE ├── README.md ├── lib.typ ├── tests ├── fakebold.typ ├── fakeitalic.typ └── fakesc.typ └── typst.toml /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Cuti 2 | 3 | Cuti (/kjuːti/) is a package that simulates fake bold / fake italic / fake small captials. This package is typically used on fonts that do not have a `bold` weight, such as "SimSun". 4 | 5 | ## Usage 6 | 7 | Please refer to the [Documentation](https://csimide.github.io/cuti-docs/en/). 8 | 9 | 本 Package 提供中文文档: [中文文档](https://csimide.github.io/cuti-docs/zh-CN/)。 10 | 11 | ### Getting Started Quickly (For Chinese User) 12 | 13 | Please add the following content at the beginning of the document: 14 | 15 | ```typst 16 | #import "@preview/cuti:0.3.0": show-cn-fakebold 17 | #show: show-cn-fakebold 18 | ``` 19 | 20 | Then, the bolding for SimHei, SimSun, and KaiTi fonts should work correctly. 21 | 22 | ## Changelog 23 | 24 | ### `0.3.0` 25 | 26 | - feat: Add fake small caps feature by Tetragramm. 27 | - fix: `show-fakebold` may crash on Typst version 0.12.0. 28 | 29 | ### `0.2.1` 30 | 31 | - feat: The stroke of fake bold will use the same color as the text. 32 | - fix: Attempted to fix the issue with the spacing of punctuation in fake italic (#2), but there are still problems. 33 | 34 | ### `0.2.0` 35 | 36 | - feat: Added fake italic functionality. 37 | 38 | ### `0.1.0` 39 | 40 | - Basic fake bold functionality. 41 | 42 | ## License 43 | 44 | MIT License 45 | 46 | This package refers to the following content: 47 | 48 | - [TeX and Chinese Character Processing: Fake Bold and Fake Italic](https://zhuanlan.zhihu.com/p/19686102) 49 | - Typst issue [#394](https://github.com/typst/typst/issues/394) 50 | - Typst issue [#2749](https://github.com/typst/typst/issues/2749) (The function `_skew` comes from Enivex's code.) 51 | 52 | Thanks to Enter-tainer for the assistance. 53 | -------------------------------------------------------------------------------- /lib.typ: -------------------------------------------------------------------------------- 1 | #let fakebold(base-weight: auto, weight: auto, s, ..params) = { 2 | let t-weight = if base-weight == auto {weight} else {base-weight} 3 | assert( 4 | t-weight in (auto, none) or type(t-weight) in (str, int), 5 | message: "`base-weight`/`weight` should be `auto`, `none`, `int` or `str` type.", 6 | ) 7 | set text(weight: t-weight) if type(t-weight) in (str, int) 8 | set text(weight: "regular") if t-weight == none 9 | set text(..params) if params != () 10 | context { 11 | set text(stroke: 0.02857em + text.fill) 12 | s 13 | } 14 | } 15 | 16 | #let regex-fakebold(reg-exp: ".+", s, ..params) = { 17 | show regex(reg-exp): it => { 18 | fakebold(it, ..params) 19 | } 20 | s 21 | } 22 | 23 | #let show-fakebold(reg-exp: ".+", s, weight: none, ..params) = { 24 | show text.where(weight: "bold").or(strong): it => { 25 | regex-fakebold(reg-exp: reg-exp, it, weight: weight, ..params) 26 | } 27 | s 28 | } 29 | 30 | #let cn-fakebold(s, ..params) = { 31 | regex-fakebold(reg-exp: "[\p{script=Han}!-・〇-〰—]+", weight: "regular", s, ..params) 32 | } 33 | 34 | #let show-cn-fakebold(s, ..params) = { 35 | show-fakebold(reg-exp: "[\p{script=Han}!-・〇-〰—]+", weight: "regular", s, ..params) 36 | } 37 | 38 | #let regex-fakeitalic(reg-exp: ".+?", ang: -18.4deg, s) = { 39 | show regex(reg-exp): it => { 40 | box(skew(ax: ang, reflow: false, it)) 41 | } 42 | s 43 | } 44 | 45 | #let fakeitalic( 46 | ang: -18.4deg, 47 | s, 48 | ) = regex-fakeitalic(reg-exp: "(?:\b[^\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}!-・〇-〰—]+?\b|[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}])", ang: ang, s) 49 | 50 | #let fakesc(s, scaling: 0.75) = { 51 | show regex("\p{Ll}+"): it => { 52 | context text(scaling * 1em, stroke: 0.01em + text.fill, upper(it)) 53 | } 54 | text(s) 55 | } -------------------------------------------------------------------------------- /tests/fakebold.typ: -------------------------------------------------------------------------------- 1 | #import "../lib.typ": * 2 | #set page(margin: 2cm) 3 | #show table.cell.where(y: 0): it => {strong(it)} 4 | 5 | // Please add `set text(font: ...)` to test how text appears in different fonts when testing typography layouts. 6 | 7 | // Functional tests 8 | 9 | #[ 10 | *Regex `[aik]` Fakebold*: #regex-fakebold(reg-exp: "[aik]", lorem(10)) \ 11 | *Fakebold based on `bold`*: #fakebold(base-weight: "bold", lorem(10)) \ 12 | ] 13 | 14 | // English 15 | 16 | #[ 17 | #let en-test(s) = table( 18 | columns: (1fr, ) * 3, 19 | stroke: 0.5pt, 20 | table.header( 21 | [Original], 22 | [Bold - Font], 23 | [Fakebold - `cuti`] 24 | ), 25 | s, 26 | strong(s), 27 | fakebold(s) 28 | ) 29 | 30 | #en-test(lorem(30)) 31 | 32 | #set par(justify: true) 33 | 34 | #en-test(lorem(30)) 35 | ] 36 | 37 | // Chinese + English 38 | 39 | #[ 40 | #let cn-test(s) = table( 41 | columns: (1fr, ) * 3, 42 | stroke: 0.5pt, 43 | table.header( 44 | [Original], 45 | [Fakebold - `cuti`], 46 | [zh Fakebold + en Font Bold] 47 | ), 48 | s, 49 | fakebold(s), 50 | show-cn-fakebold(strong(s)) 51 | ) 52 | 53 | #set par(justify: true) 54 | 55 | // zh-CN 56 | #set text(lang: "cn", region: "zh") 57 | #cn-test[你说得对,但是《Typst》是一款由 Typst GmbH 与众多贡献者开发的一款开放世界冒险排版游戏。游戏发生在一个被称作「typst.app」的线上世界。在这里,后面忘了——同时,逐步发掘排版的真相。Typst,启动!] 58 | 59 | // zh-HK 60 | #set text(lang: "cn", region: "hk") 61 | #cn-test[你說得對,但是《Typst》係一款由 Typst GmbH 同眾多貢獻者開發嘅開放世界冒險排版遊戲。遊戲發生喺一個叫做「typst.app」嘅線上世界。喺呢度,後面唔記得咗——同時,逐步發掘排版嘅真相。Typst,啟動!] 62 | 63 | // zh-TW 64 | #set text(lang: "cn", region: "tw") 65 | #cn-test[你說得對,但是《Typst》是一款由 Typst GmbH 與眾多貢獻者開發的開放世界冒險排版遊戲。遊戲發生在一個被稱作「typst.app」的線上世界。在這裡,後面忘記了——同時,逐步發掘排版的真相。Typst,啟動!] 66 | ] -------------------------------------------------------------------------------- /tests/fakeitalic.typ: -------------------------------------------------------------------------------- 1 | #import "../lib.typ": * 2 | #set page(margin: 2cm) 3 | #show table.cell.where(y: 0): it => {strong(it)} 4 | 5 | // Please add `set text(font: ...)` to test how text appears in different fonts when testing typography layouts. 6 | 7 | // Functional tests 8 | 9 | #[ 10 | *Fakeitalic*: #fakeitalic(lorem(10)) 11 | ] 12 | 13 | // English 14 | 15 | #[ 16 | #let en-test(s) = table( 17 | columns: (1fr, ) * 3, 18 | stroke: 0.5pt, 19 | table.header( 20 | [Original], 21 | [Italic - Font], 22 | [Fakeitalic -18.4deg - `cuti`] 23 | ), 24 | s, 25 | emph(s), 26 | fakeitalic(s) 27 | ) 28 | 29 | #en-test(lorem(30)) 30 | 31 | #set par(justify: true) 32 | 33 | #en-test(lorem(30)) 34 | ] 35 | 36 | 37 | // Chinese + English 38 | 39 | #[ 40 | #let cn-test(s) = table( 41 | columns: (1fr, ) * 3, 42 | stroke: 0.5pt, 43 | table.header( 44 | [Original], 45 | [Fakebold - `cuti`], 46 | [zh Fakebold + en Font Bold] 47 | ), 48 | s, 49 | emph(s), 50 | fakeitalic(s) 51 | ) 52 | 53 | #set par(justify: true) 54 | 55 | // zh-CN 56 | #set text(lang: "cn", region: "zh") 57 | #cn-test[你说得对,但是《Typst》是一款由 Typst GmbH 与众多贡献者开发的一款开放世界冒险排版游戏。游戏发生在一个被称作「typst.app」的线上世界。在这里,后面忘了——同时,逐步发掘排版的真相。Typst,启动!] 58 | 59 | // zh-HK 60 | #set text(lang: "cn", region: "hk") 61 | #cn-test[你說得對,但是《Typst》係一款由 Typst GmbH 同眾多貢獻者開發嘅開放世界冒險排版遊戲。遊戲發生喺一個叫做「typst.app」嘅線上世界。喺呢度,後面唔記得咗——同時,逐步發掘排版嘅真相。Typst,啟動!] 62 | 63 | // zh-TW 64 | #set text(lang: "cn", region: "tw") 65 | #cn-test[你說得對,但是《Typst》是一款由 Typst GmbH 與眾多貢獻者開發的開放世界冒險排版遊戲。遊戲發生在一個被稱作「typst.app」的線上世界。在這裡,後面忘記了——同時,逐步發掘排版的真相。Typst,啟動!] 66 | ] -------------------------------------------------------------------------------- /tests/fakesc.typ: -------------------------------------------------------------------------------- 1 | #import "../lib.typ": * 2 | #set page(margin: 2cm) 3 | #show table.cell.where(y: 0): it => {strong(it)} 4 | 5 | // Please add `set text(font: ...)` to test how text appears in different fonts when testing typography layouts. 6 | 7 | #[ 8 | #let en-test(s) = table( 9 | columns: (1fr, ) * 3, 10 | stroke: 0.5pt, 11 | table.header( 12 | [Original], 13 | [Small Capitals - Font], 14 | [FakeSC - `cuti`] 15 | ), 16 | s, 17 | smallcaps(s), 18 | fakesc(s) 19 | ) 20 | 21 | #en-test(lorem(30)) 22 | 23 | #set par(justify: true) 24 | 25 | #en-test(lorem(30)) 26 | ] -------------------------------------------------------------------------------- /typst.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cuti" 3 | version = "0.3.0" 4 | entrypoint = "lib.typ" 5 | authors = ["csimide", "Enivex", "Tetragramm"] 6 | license = "MIT" 7 | description = "Easily simulate (fake) bold, italic and small capital characters." 8 | compiler = "0.12.0" 9 | repository = "https://github.com/csimide/cuti" 10 | exclude = ["demo-and-doc"] 11 | --------------------------------------------------------------------------------