mirror of
https://github.com/slavfox/Cozette.git
synced 2026-03-11 08:54:33 +00:00
Finish build scripts
This commit is contained in:
parent
2969e98636
commit
a0d8de634d
15 changed files with 9312 additions and 9836 deletions
15
.github/workflows/main.yml
vendored
15
.github/workflows/main.yml
vendored
|
|
@ -14,21 +14,14 @@ jobs:
|
|||
steps:
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
pacman -Sy --noconfirm base git tar
|
||||
- uses: actions/checkout@v2
|
||||
pacman -Sy --noconfirm base git tar python python-pipenv
|
||||
- name: Install fontforge
|
||||
run: pacman -S --noconfirm fontforge
|
||||
- uses: actions/checkout@v2
|
||||
- name: Build fonts
|
||||
run: |
|
||||
fontforge -lang ff -c '\
|
||||
Open("Cozette8/Cozette8.sfd"); \
|
||||
Generate("cozette.", "otb"); \
|
||||
Generate("cozette.ttf", "otb"); \
|
||||
Generate("cozette.dfont","sbit"); \
|
||||
Generate("cozette.","fnt"); \
|
||||
Generate("cozette.","bdf"); \
|
||||
'
|
||||
pipenv install; pipenv run python build.py
|
||||
- uses: ncipollo/release-action@v1
|
||||
with:
|
||||
artifacts: "*.otb, *.ttf, *.bdf, *.dfont, *.fnt"
|
||||
artifacts: "build/*"
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
|
|
|||
47
CHANGELOG.md
47
CHANGELOG.md
|
|
@ -11,16 +11,45 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
#### Glyphs
|
||||
|
||||
- Nerdfonts:
|
||||
- ****nf-custom-folder_open (U+E5FE)****
|
||||
- ****nf-custom-c (U+E61D)****, C logo
|
||||
- **nf-custom-cpp (U+E61E)**, C++ logo
|
||||
- **nf-indent-line (U+E621)**, indentation guide
|
||||
- **nf-custom-vim (U+E62B)**
|
||||
- **nf-dev-visualstudio (U+E70C)**
|
||||
- **nf-dev-terminal (U+E795)** (black `>_` symbol)
|
||||
- **nf-dev-terminal_badge (U+E7A2)** (white `>_` symbol), also copied as
|
||||
**nf-fa-terminal (U+F120)**
|
||||
- **nf-dev-ruby (U+E739)**
|
||||
- **nf-dev-ubuntu (U+E73A)**
|
||||
- **nf-dev-php (U+E73D)**
|
||||
- **nf-dev-markdown (U+E73E)**
|
||||
- **nf-dev-erlang (U+E7AF)**
|
||||
- **nf-dev-erlang (U+E7B1)**
|
||||
- **nf-fa-h_square (U+F0FD)** \[My vim uses it for C headers\]
|
||||
- Copied some nf glyphs to code points that should be the same glyph (eg.
|
||||
nf-dev-heroku U+E77B and nf-seti-heroku U+E607)
|
||||
- **nf-linux-archlinux (U+F303)**
|
||||
|
||||
- Four variations on a `+`:
|
||||
|
||||
- U+2719 OUTLINED GREEK CROSS
|
||||
- U+271A HEAVY GREEK CROSS
|
||||
- U+271B OPEN CENTRE CROSS
|
||||
- U+271C HEAVY OPEN CENTRE CROSS
|
||||
- **U+2719 OUTLINED GREEK CROSS**
|
||||
- **U+271A HEAVY GREEK CROSS**
|
||||
- **U+271B OPEN CENTRE CROSS**
|
||||
- **U+271C HEAVY OPEN CENTRE CROSS**
|
||||
|
||||
These should come in handy for git prompts and the like.
|
||||
|
||||
#### Build scripts
|
||||
|
||||
### Fixed
|
||||
- Automatic character map generation
|
||||
- Automatic sample image generation
|
||||
- True vector .ttf font building
|
||||
|
||||
### Changed
|
||||
|
||||
- Github Actions to use the new build scripts
|
||||
|
||||
#### Glyphs
|
||||
|
||||
|
|
@ -39,8 +68,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
#### Glyphs
|
||||
|
||||
- nf-dev-linux (U+E712) for vim statusbars on Linuces
|
||||
- U+25CF BLACK CIRCLE for git prompts
|
||||
- **U+25CF BLACK CIRCLE** for git prompts
|
||||
- **nf-dev-linux (U+E712)** for vim statusbars on Linuces
|
||||
|
||||
#### Other
|
||||
|
||||
|
|
@ -52,8 +81,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
#### Glyphs
|
||||
|
||||
- nf-dev-apple (U+E711) for vim statusbars on Macs
|
||||
- nf-oct-zap (U+26A1 HIGH VOLTAGE SIGN) for term prompts
|
||||
- **nf-oct-zap (U+26A1 HIGH VOLTAGE SIGN)** for term prompts
|
||||
- **nf-dev-apple (U+E711)** for vim statusbars on Macs
|
||||
|
||||
### Changed
|
||||
|
||||
|
|
|
|||
8968
Cozette/Cozette.sfd
Normal file
8968
Cozette/Cozette.sfd
Normal file
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
2
Pipfile
2
Pipfile
|
|
@ -6,11 +6,13 @@ verify_ssl = true
|
|||
[dev-packages]
|
||||
black = "*"
|
||||
mypy = "*"
|
||||
isort = "*"
|
||||
|
||||
[packages]
|
||||
numpy = "*"
|
||||
Pillow = "*"
|
||||
fonttools = "*"
|
||||
crayons = "*"
|
||||
|
||||
[requires]
|
||||
python_version = "3.8"
|
||||
|
|
|
|||
25
Pipfile.lock
generated
25
Pipfile.lock
generated
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "11679fbbfbfe6ca9cf64b908f74c67c912a0b96bff52aa6f34ff7528e5b9f449"
|
||||
"sha256": "fbc5bf15a267368c830aa098f5765fbd1a8b70feb242039f517a2550fd29f22d"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {
|
||||
|
|
@ -16,6 +16,21 @@
|
|||
]
|
||||
},
|
||||
"default": {
|
||||
"colorama": {
|
||||
"hashes": [
|
||||
"sha256:7d73d2a99753107a36ac6b455ee49046802e59d9d076ef8e47b61499fa29afff",
|
||||
"sha256:e96da0d330793e2cb9485e9ddfd918d456036c7149416295932478192f4436a1"
|
||||
],
|
||||
"version": "==0.4.3"
|
||||
},
|
||||
"crayons": {
|
||||
"hashes": [
|
||||
"sha256:50e5fa729d313e2c607ae8bf7b53bb487652e10bd8e7a1e08c4bc8bf62755ffc",
|
||||
"sha256:8c9e4a3a607bc10e9a9140d496ecd16c6805088dd16c852c378f1f1d5db7aeb6"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.3.0"
|
||||
},
|
||||
"fonttools": {
|
||||
"hashes": [
|
||||
"sha256:0c16d5da7846a92aedcb448277d13d3b729f7de48a917768d97ebd0d17067d7f",
|
||||
|
|
@ -110,6 +125,14 @@
|
|||
],
|
||||
"version": "==7.0"
|
||||
},
|
||||
"isort": {
|
||||
"hashes": [
|
||||
"sha256:54da7e92468955c4fceacd0c86bd0ec997b0e1ee80d97f67c35a78b719dccab1",
|
||||
"sha256:6e811fcb295968434526407adb8796944f1988c5b65e8139058f2014cbe100fd"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==4.3.21"
|
||||
},
|
||||
"mypy": {
|
||||
"hashes": [
|
||||
"sha256:0a9a45157e532da06fe56adcfef8a74629566b607fa2c1ac0122d1ff995c748a",
|
||||
|
|
|
|||
37
README.md
37
README.md
|
|
@ -13,25 +13,37 @@ small - which prompted me to make Cozette.
|
|||
|
||||
# Installation
|
||||
|
||||
**Note:** vscode doesn't support bitmap fonts. Until Cozette has a vectorized
|
||||
version, it won't work in vscode.
|
||||
|
||||
[You can get Cozette over at the Releases tab](https://github.com/slavfox/Cozette/releases)!
|
||||
|
||||
If you're on Linux, the preferred format is `.otb` or `.ttf`. To install the
|
||||
font, just throw it in your fonts directory (you probably want to follow your
|
||||
distro's instructions). On Ubuntu, if you don't want to reconsider your distro
|
||||
choice, you might need to
|
||||
Cozette is distributed in two main variants: bitmap and vector.
|
||||
|
||||
Bitmap fonts are, effectively, just that - bitmaps. They scale terribly, but
|
||||
look nice and sharp (and pixel-perfect) if you use them at their intended point
|
||||
size. Vector fonts scale well, but in this case, might look ugly at
|
||||
smaller point sizes because of antialiasing issues and the like.
|
||||
|
||||
VSCode and a lot of other GUI applications don't support bitmap fonts, so you
|
||||
will want to use CozetteVector there. In applications that do support bitmap
|
||||
fonts, you will want to use the normal, bitmap Cozette (unless it's too
|
||||
small for you, in which case, CozetteVector scales better).
|
||||
|
||||
If you're on Linux, the preferred format is `.otb` (for bitmaps) or `.ttf`
|
||||
(for CozetteVector). To install the font, just throw it in your fonts directory
|
||||
(you probably want to follow your distro's instructions). On Ubuntu, if you
|
||||
don't want to reconsider your distro choice, you might need to
|
||||
[specifically enable bitmap fonts](https://bugs.launchpad.net/ubuntu/+source/fontconfig/+bug/1560114).
|
||||
|
||||
If you're on Mac, download the `.dfont` and install it with `Font Book.app`.
|
||||
Both the bitmap `Cozette.dfont` and the vector `CozetteVector.dfont` should
|
||||
work.
|
||||
|
||||
If you're on Windows,
|
||||
If you're on Windows, just grab `CozetteVector.ttf`. If you want to get the
|
||||
bitmap versions to work,
|
||||
[follow the instructions from here](https://wiki.archlinux.org/index.php/installation_guide).
|
||||
|
||||
# Unicode support
|
||||
|
||||
As of release 1.0, these are the characters included in Cozette:
|
||||
As of the current version, these are the characters included in Cozette:
|
||||
|
||||

|
||||
|
||||
|
|
@ -53,9 +65,10 @@ where Cozette is so far, in the order the features are going to be implemented:
|
|||
- [ ] Nerdfonts:
|
||||
- [x] nf-seti-*
|
||||
- [ ] nf-dev-*
|
||||
- [ ] Glyph map generation (so I don't have to keep `characters.png` up to date)
|
||||
- [ ] "True" TTF version
|
||||
- [ ] Windows support
|
||||
- [x] Glyph map generation (so I don't have to keep `characters.png` up to
|
||||
date)
|
||||
- [x] "True" TTF version
|
||||
- [x] Windows support
|
||||
- [ ] Bold version
|
||||
- [ ] Italic version
|
||||
- [ ] Ligatures
|
||||
|
|
|
|||
143
build.py
143
build.py
|
|
@ -1,22 +1,143 @@
|
|||
import os
|
||||
import subprocess
|
||||
import tempfile
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from cozette_builder.imagegen import save_sample, save_charlist, read_sample
|
||||
from shlex import quote
|
||||
from shutil import copy
|
||||
from typing import Optional, Sequence, cast
|
||||
|
||||
import crayons # type: ignore
|
||||
|
||||
from cozette_builder.imagegen import read_sample, save_charlist, save_sample
|
||||
from cozette_builder.ttfbuilder import TTFBuilder
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parent
|
||||
bdfpath = REPO_ROOT / "Cozette8" / "Cozette-10.bdf"
|
||||
BUILD_DIR = REPO_ROOT / "build"
|
||||
FONTNAME = "Cozette"
|
||||
|
||||
def save_images():
|
||||
|
||||
save_charlist(bdfpath, REPO_ROOT / "img" / "characters.png")
|
||||
@dataclass
|
||||
class Generate:
|
||||
filename: str
|
||||
bitmap_fmt: Optional[str] = None
|
||||
|
||||
save_sample(
|
||||
"Clozette",
|
||||
read_sample(REPO_ROOT / "img" / "sample.txt"),
|
||||
REPO_ROOT / "img" / "sample.png",
|
||||
def __str__(self):
|
||||
return (
|
||||
f'Generate("{self.filename}", "{self.bitmap_fmt}")'
|
||||
if self.bitmap_fmt
|
||||
else f'Generate("{self.filename}")'
|
||||
)
|
||||
|
||||
|
||||
def save_images(bdfpath):
|
||||
with tempfile.TemporaryDirectory() as tmpdirname:
|
||||
print(crayons.yellow("Making tmp fontdir"))
|
||||
tmpdirpath = Path(tmpdirname)
|
||||
copy(bdfpath, tmpdirname)
|
||||
subprocess.run(["mkfontdir", tmpdirname])
|
||||
subprocess.run(["xset", "+fp", tmpdirname])
|
||||
subprocess.run(["xset", "fp", "rehash"])
|
||||
|
||||
print(crayons.yellow("Saving character map"))
|
||||
save_charlist(FONTNAME, bdfpath, REPO_ROOT / "img" / "characters.png")
|
||||
|
||||
print(crayons.yellow("Saving sample image"))
|
||||
save_sample(
|
||||
FONTNAME,
|
||||
read_sample(REPO_ROOT / "img" / "sample.txt"),
|
||||
REPO_ROOT / "img" / "sample.png",
|
||||
)
|
||||
subprocess.run(["xset", "-fp", tmpdirname])
|
||||
subprocess.run(["xset", "fp", "rehash"])
|
||||
|
||||
|
||||
def fontforge(open: Path, generate: Sequence[Generate]):
|
||||
BUILD_DIR.mkdir(exist_ok=True)
|
||||
script = "; ".join(
|
||||
[
|
||||
f'Open("{open}")',
|
||||
'RenameGlyphs("AGL with PUA")',
|
||||
'Reencode("unicode")',
|
||||
]
|
||||
+ [str(gen) for gen in generate]
|
||||
)
|
||||
# No idea why this doesn't work without shell=True
|
||||
subprocess.run(
|
||||
[f"fontforge -lang ff -c {quote(script)}"], cwd=BUILD_DIR, shell=True
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# save_images()
|
||||
TTFBuilder.from_bdf_path(bdfpath).build("cloze.ttf")
|
||||
def rename_single(dir: Path, pattern: str, newname: str) -> Path:
|
||||
return cast(Path, next(dir.glob(pattern)).rename(dir / newname))
|
||||
|
||||
|
||||
def mkbdf() -> Path:
|
||||
print()
|
||||
fontforge(
|
||||
open=REPO_ROOT / "Cozette" / "Cozette.sfd",
|
||||
generate=[Generate("cozette.", bitmap_fmt="bdf")],
|
||||
)
|
||||
bdfpath = rename_single(BUILD_DIR, "*.bdf", "cozette.bdf")
|
||||
return bdfpath
|
||||
|
||||
|
||||
def gen_bitmap_formats(bdfpath: Path):
|
||||
fontforge(
|
||||
open=bdfpath,
|
||||
generate=[
|
||||
Generate("cozette.", "otb"),
|
||||
Generate("cozette.", "fnt"),
|
||||
Generate("cozette_bitmap.ttf", "otb"),
|
||||
Generate("cozette_bitmap.dfont", "sbit"),
|
||||
],
|
||||
)
|
||||
rename_single(BUILD_DIR, "*.fnt", "cozette.fnt")
|
||||
|
||||
|
||||
def fix_ttf(ttfpath: Path):
|
||||
outname = "CozetteVector"
|
||||
script = "; ".join(
|
||||
[
|
||||
f'Open("{ttfpath}")',
|
||||
"SelectWorthOutputting()",
|
||||
"RemoveOverlap()",
|
||||
"CorrectDirection()",
|
||||
"Simplify()",
|
||||
"Simplify(-1, 1.02)",
|
||||
'RenameGlyphs("AGL with PUA")',
|
||||
'Reencode("unicode")',
|
||||
f'Generate("{outname}.dfont")',
|
||||
f'Generate("{outname}.otf.dfont")',
|
||||
f'Generate("{outname}.otf")',
|
||||
"ScaleToEm(1024)",
|
||||
f'Generate("{outname}.ttf")',
|
||||
]
|
||||
)
|
||||
|
||||
# No idea why this doesn't work without shell=True
|
||||
subprocess.run(
|
||||
[f"fontforge -lang ff -c {quote(script)}"], cwd=BUILD_DIR, shell=True
|
||||
)
|
||||
ttfpath.unlink()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
BUILD_DIR.mkdir(exist_ok=True)
|
||||
os.chdir(BUILD_DIR)
|
||||
print(crayons.blue("Building .bdf..."))
|
||||
bdfpath = mkbdf()
|
||||
print(crayons.green("Done!", bold=True))
|
||||
print(crayons.blue("Building bitmap formats..."))
|
||||
gen_bitmap_formats(bdfpath)
|
||||
print(crayons.green("Done!", bold=True))
|
||||
print(crayons.blue("Saving sample images..."))
|
||||
save_images(bdfpath)
|
||||
print(crayons.green("Done!", bold=True))
|
||||
print(crayons.blue("Generating TTF..."))
|
||||
ttfbuilder = TTFBuilder.from_bdf_path(bdfpath)
|
||||
ttfbuilder.build("cozette-tmp.ttf")
|
||||
print(crayons.green("Done!", bold=True))
|
||||
print(crayons.blue("Fixing TTF..."))
|
||||
fix_ttf(Path("cozette-tmp.ttf"))
|
||||
print(crayons.green("Done!", bold=True))
|
||||
|
|
|
|||
|
|
@ -1,16 +1,18 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from typing import (
|
||||
Dict,
|
||||
Iterable,
|
||||
Union,
|
||||
List,
|
||||
Literal,
|
||||
NamedTuple,
|
||||
Dict,
|
||||
List,
|
||||
TextIO,
|
||||
Tuple,
|
||||
Union,
|
||||
)
|
||||
|
||||
import numpy as np # type: ignore
|
||||
from fontTools.pens.ttGlyphPen import TTGlyphPen
|
||||
from fontTools.pens.ttGlyphPen import TTGlyphPen # type: ignore
|
||||
|
||||
Bit = Union[Literal[1], Literal[0]]
|
||||
|
||||
|
|
@ -27,9 +29,7 @@ class BdfGlyph:
|
|||
|
||||
self.bbx = bbx = BBX(*[int(s) for s in meta["BBX"].split()])
|
||||
# this is probably wrong
|
||||
self.bits: np.array = np.pad(bits, [[0, 0], [bbx.x, 0]])[
|
||||
bbx.y : bbx.y + bbx.h, bbx.x : bbx.x + bbx.w
|
||||
]
|
||||
self.bits: np.array = bits[0 : bbx.h, 0 : bbx.w]
|
||||
self.metadata = meta
|
||||
|
||||
@classmethod
|
||||
|
|
@ -54,26 +54,39 @@ class BdfGlyph:
|
|||
|
||||
def draw(self, ppp: float):
|
||||
pen = TTGlyphPen(None)
|
||||
for y, row in reversed(enumerate(self.bits)):
|
||||
for y, row in enumerate(reversed(self.bits)):
|
||||
for x, col in enumerate(row):
|
||||
if col:
|
||||
pen.moveTo((x * ppp, y * ppp))
|
||||
pen.lineTo(((x + 1) * ppp, y * ppp))
|
||||
pen.lineTo(((x + 1) * ppp, (y + 1) * ppp))
|
||||
pen.lineTo((x * ppp, (y + 1) * ppp))
|
||||
pen.lineTo((x * ppp, y * ppp))
|
||||
pen.moveTo(
|
||||
((x + self.bbx.x) * ppp, (y + self.bbx.y) * ppp)
|
||||
)
|
||||
pen.lineTo(
|
||||
((x + self.bbx.x + 1) * ppp, (y + self.bbx.y) * ppp)
|
||||
)
|
||||
pen.lineTo(
|
||||
(
|
||||
(x + self.bbx.x + 1) * ppp,
|
||||
(y + self.bbx.y + 1) * ppp,
|
||||
)
|
||||
)
|
||||
pen.lineTo(
|
||||
((x + self.bbx.x) * ppp, (y + self.bbx.y + 1) * ppp)
|
||||
)
|
||||
pen.lineTo(
|
||||
((x + self.bbx.x) * ppp, (y + self.bbx.y) * ppp)
|
||||
)
|
||||
pen.closePath()
|
||||
return pen.glyph()
|
||||
|
||||
def meta(self, k) -> List[str]:
|
||||
return self.metadata[k].strip().strip('"').strip().split()
|
||||
return self.metadata[k].strip('"').strip().split()
|
||||
|
||||
|
||||
def parse_char(bdfstream: TextIO) -> Tuple[Dict[str, str], List[int]]:
|
||||
specs = {}
|
||||
while not (line := bdfstream.readline()).startswith("BITMAP"):
|
||||
parts = line.split(maxsplit=1)
|
||||
specs[parts[0]] = parts[1]
|
||||
specs[parts[0]] = parts[1].strip()
|
||||
bitmap = []
|
||||
while not (line := bdfstream.readline()).startswith("ENDCHAR"):
|
||||
bitmap.append(int(line.strip(), 16))
|
||||
|
|
@ -90,8 +103,8 @@ class BdfFont:
|
|||
metadata = {}
|
||||
while not (line := bdfstream.readline()).startswith("CHARS "):
|
||||
try:
|
||||
meta, val = line.split(maxsplit=1)
|
||||
metadata[meta] = val
|
||||
k, val = line.split(maxsplit=1)
|
||||
metadata[k] = val.strip()
|
||||
except ValueError:
|
||||
pass
|
||||
glyphs = {}
|
||||
|
|
@ -109,4 +122,4 @@ class BdfFont:
|
|||
return tuple(f"U+{i:X}" for i in self.glyphs)
|
||||
|
||||
def meta(self, k) -> List[str]:
|
||||
return self.metadata[k].strip().strip('"').strip().split()
|
||||
return self.metadata[k].strip('"').strip().split()
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
import subprocess
|
||||
from typing import Tuple, Dict, Optional, NamedTuple
|
||||
from shlex import quote
|
||||
from pathlib import Path
|
||||
from unicodedata import east_asian_width as charwidth
|
||||
from cozette_builder.bdffont import BdfFont
|
||||
import platform
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
from shlex import quote
|
||||
from typing import Dict, NamedTuple, Optional, Tuple
|
||||
from unicodedata import east_asian_width as charwidth
|
||||
|
||||
from cozette_builder.bdffont import BdfFont
|
||||
|
||||
Color = Tuple[int, int, int]
|
||||
|
||||
|
|
@ -45,7 +45,7 @@ def wrap_text(src: str, width=79) -> Sample:
|
|||
idx = 0
|
||||
linebreaks = []
|
||||
while idx < len(src):
|
||||
if running_w >= width:
|
||||
if running_w - int(src[idx] == " ") >= width:
|
||||
linebreaks.append(idx - 1)
|
||||
running_w = 0
|
||||
sample_h += 1
|
||||
|
|
@ -58,7 +58,7 @@ def wrap_text(src: str, width=79) -> Sample:
|
|||
running_w += 1 if charwidth(src[idx]) != "W" else 2
|
||||
idx += 1
|
||||
for idx in reversed(linebreaks):
|
||||
src = src[:idx] + "\n" + src[idx:]
|
||||
src = src[:idx].rstrip() + "\n" + src[idx:].lstrip()
|
||||
return Sample(src, width, sample_h)
|
||||
|
||||
|
||||
|
|
@ -73,9 +73,8 @@ def read_sample(src_path: Path) -> Sample:
|
|||
return Sample(src, w, h)
|
||||
|
||||
|
||||
# Todo: rewrite this to use files instead of a string
|
||||
def save_sample(
|
||||
font: str,
|
||||
fnt: str,
|
||||
sample: Sample,
|
||||
output_path: Path,
|
||||
fgcolor: str = "#abb2bf",
|
||||
|
|
@ -85,7 +84,6 @@ def save_sample(
|
|||
if palette is None:
|
||||
palette = default_palette
|
||||
colored = color_text(sample.text, palette)
|
||||
print(colored)
|
||||
with tempfile.NamedTemporaryFile("w", delete=False) as f:
|
||||
f.write(colored)
|
||||
fp = f.name
|
||||
|
|
@ -97,12 +95,14 @@ def save_sample(
|
|||
subprocess.run(
|
||||
[
|
||||
"xterm",
|
||||
"-en",
|
||||
"utf8",
|
||||
"-fg",
|
||||
fgcolor,
|
||||
"-bg",
|
||||
bgcolor,
|
||||
"-fa",
|
||||
font,
|
||||
fnt,
|
||||
"-geometry",
|
||||
f"{sample.width}x{sample.height}",
|
||||
"-dc",
|
||||
|
|
@ -137,15 +137,17 @@ def color_text(text: str, palette: Palette) -> str:
|
|||
return colored_text
|
||||
|
||||
|
||||
def save_charlist(bdf_font: Path, output_path: Path):
|
||||
def save_charlist(fnt: str, bdf_font: Path, output_path: Path):
|
||||
with bdf_font.open() as f:
|
||||
bdf = BdfFont.from_bdf(f)
|
||||
save_sample(
|
||||
"Clozette",
|
||||
fnt,
|
||||
wrap_text(
|
||||
"".join(
|
||||
chr(c) for c in bdf.codepoints if c >= 32 and c not in (127,)
|
||||
" ".join(
|
||||
chr(c) for c in bdf.codepoints if c > 32 and c not in (127,)
|
||||
)
|
||||
.replace("⚡ ", "⚡")
|
||||
.replace("\u03a2 ", "")
|
||||
),
|
||||
output_path,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,23 @@
|
|||
from pathlib import Path
|
||||
from fontTools.fontBuilder import FontBuilder
|
||||
from fontTools.pens.ttGlyphPen import TTGlyphPen
|
||||
from cozette_builder.bdffont import BdfFont, BdfGlyph
|
||||
|
||||
from fontTools.fontBuilder import FontBuilder # type: ignore
|
||||
|
||||
from cozette_builder.bdffont import BdfFont
|
||||
|
||||
with (Path(__file__).resolve().parent.parent / "LICENSE").open() as f:
|
||||
LICENSE_TEXT = f.read()
|
||||
|
||||
|
||||
def get_version():
|
||||
cozette_path = (
|
||||
Path(__file__).resolve().parent.parent / "Cozette" / "Cozette.sfd"
|
||||
)
|
||||
with cozette_path.open() as f:
|
||||
for line in f:
|
||||
if line.startswith("Version:"):
|
||||
_, v = line.split()
|
||||
return v
|
||||
|
||||
|
||||
class TTFBuilder:
|
||||
@classmethod
|
||||
|
|
@ -23,10 +39,11 @@ class TTFBuilder:
|
|||
self.startx = int(startx)
|
||||
self.starty = int(starty)
|
||||
|
||||
def build(self, output_path: Path):
|
||||
def build(self, output_path: str):
|
||||
glyph_names = {
|
||||
k: glyph.meta("STARTCHAR")[0] for k, glyph in
|
||||
self.bdf.glyphs.items()
|
||||
k: glyph.meta("STARTCHAR")[0]
|
||||
for k, glyph in self.bdf.glyphs.items()
|
||||
if k >= 0
|
||||
}
|
||||
ascent = round(self.ascent * self.ppp)
|
||||
descent = round(self.descent * self.ppp)
|
||||
|
|
@ -34,36 +51,46 @@ class TTFBuilder:
|
|||
self.fb.setupGlyphOrder(list(glyph_names.values()))
|
||||
self.fb.setupCharacterMap(glyph_names)
|
||||
advance_widths = {
|
||||
name: 700 for name in glyph_names.values()
|
||||
name: int(self.bdf.glyphs[k].meta("SWIDTH")[0])
|
||||
for k, name in glyph_names.items()
|
||||
}
|
||||
# copied from fontbuilder for now
|
||||
familyName = "HelloTestFont"
|
||||
styleName = "TotallyNormal"
|
||||
version = "0.1"
|
||||
family_name = "CozetteVector"
|
||||
style_name = "Regular"
|
||||
version = get_version()
|
||||
|
||||
nameStrings = dict(
|
||||
familyName=dict(en=familyName, nl="HalloTestFont"),
|
||||
styleName=dict(en=styleName, nl="TotaalNormaal"),
|
||||
uniqueFontIdentifier="fontBuilder: " + familyName + "." + styleName,
|
||||
fullName=familyName + "-" + styleName,
|
||||
psName=familyName + "-" + styleName,
|
||||
version="Version " + version,
|
||||
)
|
||||
# scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=IWS-Chapter08
|
||||
namestrings = {
|
||||
"familyName": {"en": family_name},
|
||||
"styleName": {"en": style_name},
|
||||
"uniqueFontIdentifier": f"fontBuilder: {family_name}.{style_name}",
|
||||
"fullName": family_name,
|
||||
"psName": f"{family_name}-{style_name}",
|
||||
"version": f"Version {version}",
|
||||
"copyright": "(c) 2020 Slavfox",
|
||||
"manufacturer": "Slavfox",
|
||||
"designer": "Slavfox",
|
||||
"description": "Programming bitmap font optimized for coziness",
|
||||
"vendorURL": "https://github.com/slavfox",
|
||||
"designerURL": "https://github.com/slavfox",
|
||||
"licenseDescription": LICENSE_TEXT,
|
||||
"licenseInfoURL": "https://opensource.org/licenses/MIT",
|
||||
"sampleText": "A wizard’s job is to vex chumps quickly in fog.",
|
||||
}
|
||||
self.fb.setupGlyf(
|
||||
{name: self.bdf.glyphs[k].draw(self.ppp) for k, name in
|
||||
glyph_names.items()}
|
||||
{
|
||||
name: self.bdf.glyphs[k].draw(self.ppp)
|
||||
for k, name in glyph_names.items()
|
||||
}
|
||||
)
|
||||
metrics = {}
|
||||
glyphTable = self.fb.font["glyf"]
|
||||
for name in glyph_names.values():
|
||||
metrics[name] = (700, glyphTable[name].xMin)
|
||||
metrics = {
|
||||
name: (w, self.fb.font["glyf"][name].xMin)
|
||||
for name, w in advance_widths.items()
|
||||
}
|
||||
self.fb.setupHorizontalMetrics(metrics)
|
||||
self.fb.setupHorizontalHeader(ascent=ascent, descent=-descent)
|
||||
self.fb.setupNameTable(nameStrings)
|
||||
self.fb.setupOS2(sTypoAscender=ascent, usWinAscent=ascent,
|
||||
usWinDescent=descent)
|
||||
self.fb.setupNameTable(namestrings)
|
||||
self.fb.setupOS2(
|
||||
sTypoAscender=ascent, usWinAscent=ascent, usWinDescent=descent
|
||||
)
|
||||
self.fb.setupPost()
|
||||
self.fb.save(str(output_path))
|
||||
|
||||
|
||||
|
||||
self.fb.save(output_path)
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 5 KiB |
BIN
img/sample.png
BIN
img/sample.png
Binary file not shown.
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.4 KiB |
|
|
@ -15,7 +15,7 @@ $BLUE$┏━━━━━━━━━━━━━━━━━━━━━━━
|
|||
│ , . ` ~$BLUE$ │
|
||||
╰───────────────────────────╯
|
||||
$YELLOW$
|
||||
|
||||
|
||||
$BLUE$│ $FG$╔═══════════════╗
|
||||
$BLUE$└──$FG$║ $GREEN$✓ ✔ $YELLOW$✕ ✖ $MAGENTA$✗ ✘ $FG$ ║$BLUE$▒
|
||||
$FG$║ $BLUE$ $FG$║$BLUE$▒
|
||||
|
|
|
|||
10
pyproject.toml
Normal file
10
pyproject.toml
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
[tool.isort]
|
||||
multi_line_output = 3
|
||||
include_trailing_comma = true
|
||||
force_grid_wrap = 0
|
||||
use_parentheses = true
|
||||
line_length = 79
|
||||
|
||||
[tool.black]
|
||||
target-version = ['py38']
|
||||
line_length = 79
|
||||
Loading…
Reference in a new issue