Skip to content

DrEssam97/khatt

Repository files navigation

خَطّ — Khatt

PyPI CI License: MIT Python Fonts: OFL

Render Arabic text as ASCII/Unicode-block art — the Arabic FIGlet that FIGlet can't be.

⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⡄
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢺⣿⣿⣄
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⠟
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⣿⣿
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢻⣿⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣤⣄⡀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⡗
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠛⢿⣿⠟
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⣀⣠⣄⣀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⡏⠀⠀⠀⠀⣀⣤⣶⣿⣿⣿⣿⣿⣷⡄⠀⠀⠀⠀⣠⣶⣿⣿⣷⣶⣤⣄⣀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⠇⠀⣀⣴⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⢠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⣦⣤⣀⣀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣤⣾⣿⠟⠋⠉⠀⠀⠀⠀⠙⢿⣿⣿⡟⠀⠀⠘⠉⠉⠉⠉⠉⠉⠙⠛⠿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣶⣶⣶⣶⣶⡶
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣴⣿⠟⠋⠀⠀⠀⠀⠀⠀⣀⣠⣤⣶⣿⡿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣤⣽⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠁
⣀⣀⣀⣀⡀⠀⣀⣀⣀⣴⣿⣿⣥⣤⣤⣤⣴⣶⣶⣿⣿⣿⣿⣿⣿⣋⣀⡀⠀⠀⣀⣀⣀⣀⣤⣤⣶⣾⣿⣿⣿⡿⠿⠛⠋⠉⠁⠀⠀⠀⠀⠀⠀⠈
⠈⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠟⠋⠉
⠀⠀⠙⠿⢿⣿⣿⣿⣿⣿⣿⣿⣿⠿⠿⠿⠿⠿⠛⠛⠉⠛⠛⠻⠿⠿⠿⠿⠿⠿⠿⠿⠟⠛⠉⠁

(that's «خط» — "khatt", meaning line/script/calligraphy — Amiri font, braille style)

                              -%+.
       :@.           =:       *+--  =@   *#                       =@
       -@.           +:        +=   =@   #%                       +@
   %+  -@.   =%   =**+***:     @#   =@   *%       -*****%+   -%.  +@
   @*  -@.   +@         +@.    %*   =@   *%      -@-    @*   -@.  +@
   @+  -@.   +@         .@-    %*   =@   *%      +@     @*   -@.  +@
   @+  -@.   +@         :@-    %#   =@   #%      :@-    @*   -@.  +@
   @*  :%****##**********%: +**%#***#%   +#       -*****%#**+*%   =%
  .@=        :-                                             :- -.
+*%+         -*                                             =+ *:

(«ايه الأخبار» — "What's the news?" — Cairo font, ascii style)

Why FIGlet can't do this

FIGlet fonts map one character to one fixed glyph. Arabic doesn't work that way:

  • Every letter has up to four positional forms (isolated / initial / medial / final).
  • Some letter pairs form mandatory ligatures — ل + ا must become لا.
  • The script is cursive: letters connect, and the connections carry the word's shape.
  • Text runs right-to-left, and real text mixes RTL words with LTR numbers and names.

Khatt sidesteps glyph tables entirely with a rasterize-then-map pipeline:

text ──► HarfBuzz shaping ──► FreeType rasterization ──► density mapping ──► art
         (positional forms,    (real Arabic fonts,        (blocks / ascii /
          ligatures, bidi)      hi-res grayscale)          braille ramps)

The result is genuine calligraphic letterforms — from real fonts — approximated in terminal characters.

Install

pip install khatt        # or: uv add khatt

From source:

git clone https://github.com/DrEssam97/khatt.git && cd khatt
uv sync

Quickstart

Python API

import khatt

print(khatt.render("مرحبا"))                          # blocks style, 80 columns
print(khatt.render("خط", style="braille", width=60))  # high effective resolution
print(khatt.render("القاهرة", font="cairo", style="ascii", threshold=0.4))

khatt.list_fonts()   # ['amiri', 'cairo', 'noto-naskh', 'rubik']
khatt.list_styles()  # ['ascii', 'blocks', 'braille']

CLI

khatt "مرحبا"                          # render to the terminal
khatt "خط" --style braille --width 60
khatt "القاهرة" -f cairo -s ascii -t 0.4
echo "سلام" | khatt                    # stdin
khatt "خط" --output art.txt            # save the art
khatt "خط" --output khatt.png          # save the rendered text as an image
khatt --list-fonts
khatt --list-styles

Arabic diacritics (tashkeel) are stripped by default — they're illegible at character-grid resolution. Pass --keep-tashkeel (API: keep_tashkeel=True) to render them.

Gradio app

uv sync --extra app
uv run python app.py

Bundled fonts and styles

Font Family Character
amiri (default) Amiri Classical naskh, rich calligraphic detail
cairo Cairo Geometric, modern, bold strokes
noto-naskh Noto Naskh Arabic Clean, highly legible naskh
rubik Rubik Strong Latin + Arabic pairing for mixed text

All fonts are licensed under the SIL Open Font License 1.1, preserved verbatim in khatt/fonts/LICENSES/.

Style Ramp Notes
blocks ░ ▒ ▓ █ Default; reads well at any size
ascii . : - = + * # % @ Pure ASCII, maximum compatibility
braille ⠁ … ⣿ 2×4 dots per cell — 8× the effective resolution

Deploy the app to a Hugging Face Space

app.py follows the Spaces convention (single file at the repo root), so the whole repository deploys unchanged with one command:

uv run --extra app gradio deploy

About

خط — Render Arabic text as ASCII/Unicode-block art with real HarfBuzz shaping. The Arabic FIGlet.

Topics

Resources

License

Contributing

Stars

3 stars

Watchers

1 watching

Forks

Packages

 
 
 

Contributors