diff --git a/README.md b/README.md index 3734ad1..be4b4e2 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Historically when drawing text microcontrollers have been limited to bitmapped f More recently the power and capacity of cheap, embeddable, microcontrollers has increased to the point where for a dollar and change you can be running at hundreds of megahertz with megabytes of flash storage alongside. -It is now viable to render filled, transformed, anti-aliased, and scalable characters that are comparable in quality to the text that we see on our computer screens every day. +It is now viable to render filled, transformed, anti-aliased, and scalable characters that are comparable in quality to the text that we see on our computer screens every day. There is, however, still a sticking point. Existing font formats are complicated beasts that define shapes as collections of curves and control points, include entire state machines for pixel hinting, have character pair specific kerning tables, and digital rights management for.. well, yeah. @@ -37,7 +37,7 @@ Features: Alright Fonts includes: -- `afinate` an extraction and encoding tool to create Alright Font (.af) files +- `afinate` an extraction and encoding tool to create Alright Font (.af) files - `python_alright_fonts` a Python library for encoding and loading Alright Fonts - `alright-fonts.hpp` a reference C++ library implementation @@ -65,13 +65,13 @@ Font data can be output either as a binary file or as source files for C(++) and - `c` generates a C(++) code file containing a const array of font data - `python` generates a Python code file containing an array of font data - `--quality`: the quality of decomposed bezier curves, either `low`, `medium`, or `high` (default: `medium` - affects file size) - + The list of characters to include can be specified in three ways: - default: full printable ASCII set (95 characters) - `--characters CHARACTERS`: a list of characters to include in the font pack - `--corpus FILE`: a text file containing all of the characters to include - + For example: ```bash @@ -118,11 +118,11 @@ This scale was chosen for a number of reasons: Let's hedge our bets. -Being an English software developer ~~it's possible~~ an absolute certainty that I don't fully understand every nuance of every language used globally - heck, I can just barely handle my own. +Being an English software developer ~~it's possible~~ an absolute certainty that I don't fully understand every nuance of every language used globally - heck, I can just barely handle my own. It's also likely that we may want, in future, to add a feature or two: -- excluding glyph bounding boxes +- excluding glyph bounding boxes - including glyph pair kerning data - allowing 4-byte character codepoints - allow a finer scale for coordinates (i.e. `-65536..65535`) @@ -192,10 +192,12 @@ Here three Alright Fonts files have been generated containing the full set of pr The differences are easier to see when viewing the images at their original size - click to open in a new tab. -### Python `render-demo` +### Python `swatch` + +To run the Python examples, install the alright fonts Python package into your virtual environment with `pip install` (either `pip install .` for a static installation, or `pip install -e .` for a development version). -You can pipe the output of `afinate` directly into the `render-demo` example script to product a swatch image. +You can pipe the output of `afinate` directly into the `swatch` example script to product a swatch image. ```bash -./afinate --font fonts/Roboto-Black.ttf --quality high - | ./render-demo +./afinate --font fonts/Roboto-Black.ttf --quality high - | examples/python/swatch ``` diff --git a/afinate b/afinate index 4635a76..46df965 100755 --- a/afinate +++ b/afinate @@ -91,9 +91,9 @@ for codepoint in character_codepoints: if glyph: print(" \\u{:04} {} : {:>2} contours / {:>3} points".format( - codepoint, - "'" + chr(codepoint) + "'", - len(glyph.contours), + codepoint, + "'" + chr(codepoint) + "'", + len(glyph.contours), sum([len(c) for c in glyph.contours]) )) printable_count += 1 @@ -141,14 +141,14 @@ with open(args.out, "wb") as outfile: for char in line: outfile.write("0x{:02x}".format(char).encode("ascii")) if i < len(result) - 1: - outfile.write(b", ") - i += 1 + outfile.write(b", ") + i += 1 outfile.write(b"\n") outfile.write(b"};\n") # python array if args.format == "python": - ooutfileut.write(b"_font = bytes([\n") + outfile.write(b"_font = bytes([\n") i = 0 while i < len(result): line = result[i:i + 12] @@ -156,8 +156,8 @@ with open(args.out, "wb") as outfile: for char in line: outfile.write("0x{:02x}".format(char).encode("ascii")) if i < len(result) - 1: - outfile.write(b", ") - i += 1 + outfile.write(b", ") + i += 1 outfile.write(b"\n") outfile.write(b"])\n") pass diff --git a/examples/python/quality b/examples/python/quality index 45bd23c..c14f1f4 100755 --- a/examples/python/quality +++ b/examples/python/quality @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # renders a demo swatch using the font provided -# +# # either pass the font file in with the `--font` argument or pipe the file to stdin # # for example: @@ -9,23 +9,15 @@ # ./examples/python/render-demo --font out/roboto-black.af # ./afinate --font fonts/Roboto-Black.tff --quality medium - | examples/python/render-demo - -# insert top level into python module search path so python_alright_fonts import works -# what's the pythonic way to achieve this kind of structure of a repo with -# a module and an isolated `examples` folder? -import sys, os, argparse -path = os.path.abspath(os.path.join(os.path.dirname(__file__), '../..')) -sys.path.insert(1, path) - from python_alright_fonts import Glyph, Point, Face, load_font -font_low = load_font("fonts/Roboto-Black-Low.af") -font_medium = load_font("fonts/Roboto-Black-Medium.af") -font_high = load_font("fonts/Roboto-Black-High.af") - from PIL import Image, ImageDraw -def draw_glyph(glyph, position, scale, colour=(255, 255, 255)): +font_low = load_font("sample-fonts/Roboto/Roboto-Black-Low.af") +font_medium = load_font("sample-fonts/Roboto/Roboto-Black-Medium.af") +font_high = load_font("sample-fonts/Roboto/Roboto-Black-High.af") + +def draw_glyph(glyph, position, scale, colour=(255, 255, 255)): point_count = 0 for contour in glyph.contours: for i in range(0, len(contour)): @@ -47,7 +39,7 @@ def text(font, text, position, size, color=(255, 255, 255)): spacing = 1 line_spacing = 0.85 for character in text: - if character == "\n": + if character == "\n": caret.x = position.x caret.y += size * line_spacing continue @@ -56,20 +48,20 @@ def text(font, text, position, size, color=(255, 255, 255)): if not glyph: continue - + draw_glyph(glyph, caret, scale) caret.x += glyph.advance * scale * spacing -image = Image.new("RGB", (1000, 1000)) +image = Image.new("RGB", (1000, 1000)) canvas = ImageDraw.Draw(image, "RGBA") canvas.rectangle((0, 0, 1000, 1000), fill=(60, 70, 80, 255)) message = """12345 67890 -!\"$% +!\\"$% ^&*()_ abcde fghij diff --git a/examples/python/swatch b/examples/python/swatch index 695407e..f81241a 100755 --- a/examples/python/swatch +++ b/examples/python/swatch @@ -1,21 +1,19 @@ #!/usr/bin/env python3 # renders a demo swatch using the font provided -# +# # either pass the font file in with the `--font` argument or pipe the file to stdin # # for example: # -# ./examples/python/render-demo --font out/roboto-black.af -# ./afinate --font fonts/Roboto-Black.tff --quality medium - | examples/python/render-demo +# ./examples/python/swatch --font out/roboto-black.af +# ./afinate --font fonts/Roboto-Black.tff --quality medium - | examples/python/swatch + +import argparse +import sys -# insert top level into python module search path so python_alright_fonts import works -# what's the pythonic way to achieve this kind of structure of a repo with -# a module and an isolated `examples` folder? -import sys, os, argparse -path = os.path.abspath(os.path.join(os.path.dirname(__file__), '../..')) -sys.path.insert(1, path) +from PIL import Image, ImageDraw from python_alright_fonts import Glyph, Point, Face, load_font @@ -33,9 +31,7 @@ else: face = load_font(data) glyph = face.get_glyph(ord("a")) -from PIL import Image, ImageDraw - -def draw(glyph, position, scale, colour=(255, 255, 255)): +def draw(glyph, position, scale, colour=(255, 255, 255)): point_count = 0 for contour in glyph.contours: for i in range(0, len(contour)): @@ -51,23 +47,23 @@ def draw(glyph, position, scale, colour=(255, 255, 255)): f = int((i / len(contour)) * 255) #canvas.ellipse([p1[0] - 1, p1[1] - 1, p1[0] + 1, p1[1] + 1], fill=(f, 255 - f, 0, 255)) -image = Image.new("RGB", (1000, 1000)) +image = Image.new("RGB", (1000, 1000)) canvas = ImageDraw.Draw(image, "RGBA") canvas.rectangle((0, 0, 1000, 1000), fill=(60, 70, 80, 255)) message = """1234567890 -!\"$%^&*()_+-=[]`\{\};'#:@~,./<>?\| +!\\"$%^&*()_+-=[]`{};'#:@~,./<>?| Prow scuttle parrel provost Sail ho shrouds spirits boom mizzenmast -yardarm. Pinnace holystone -mizzenmast quarter crow's nest -nipperkin grog yardarm hempen +yardarm. Pinnace holystone +mizzenmast quarter crow's nest +nipperkin grog yardarm hempen halter furl. -Swab barque interloper chantey -doubloon starboard grog black jack +Swab barque interloper chantey +doubloon starboard grog black jack gangway rutters. """ @@ -80,7 +76,7 @@ scale = font_size / 128 spacing = 1 line_spacing = 1 for character in message: - if character == "\n": + if character == "\n": caret.x = left_margin caret.y += font_size * line_spacing continue @@ -89,7 +85,7 @@ for character in message: if not glyph: continue - + draw(glyph, caret, scale) caret.x += glyph.advance * scale * spacing diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..bf50648 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,38 @@ +[build-system] +build-backend = "setuptools.build_meta" +requires = ["setuptools>=61.0", "wheel>=0.37.1"] + +[project] +name = "alright-fonts" +version = "0.0.1" +description = "Font format and tools for low-resource platforms" +readme = "README.md" +requires-python = ">=3.9,<4.0" +license = {file = "LICENSE"} +keywords = ["font", "microcontroller", "truetype", "opentype"] + +classifiers = [ + "Development Status :: 5 - Production/Stable", + "Environment :: Console", + "License :: OSI Approved :: MIT License", + "Natural Language :: English", + "Operating System :: MacOS", + "Operating System :: Microsoft :: Windows", + "Operating System :: POSIX", + "Operating System :: POSIX :: Linux", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: Implementation :: CPython", +] + +dependencies = [ + "freetype-py", "simplification", "pillow" +] + +[tool.setuptools.packages.find] +include = ["python_alright_fonts*"] +namespaces = false + +[project.urls] +"Homepage" = "https://github.com/lowfatcode/alright-fonts" +"Documentation" = "https://github.com/lowfatcode/alright-fonts/README.md"