Skip to content
Switch branches/tags

Latest commit


Git stats


Failed to load latest commit information.
Latest commit message
Commit time
PyBidi is a high-level Python 3 binding for the [GNU
FriBidi]( library. It is implemented entirely
in Python, using ctypes, and gives access to all of the FriBidi
functionality that I could usefully find.


To install PyBidi on your system, type

    python3 install

This will install the Python module named “fribidi”.

Basic Usage

All functionality comes from the one module:

    import fribidi

Within this, function names correspond to those in FriBidi, excluding
the “fribidi_” prefix. For example, to call the FriBidi function
fribidi_get_bidi_types, you use the PyBidi function fribidi.get_bidi_types.

Constants and “macro” functions are available within the FRIBIDI namespace

    from fribidi import \

These omit the “FRIBIDI_” prefix. E.g. FRIBIDI.PAR_RTL is the PyBidi
name for the FriBidi constant FRIBIDI_PAR_RTL.

Where Fribidi modifies arrays that you pass in-place, PyBidi returns
modified arrays as function results. For example, where the FriBidi
function fribidi_get_bidi_types takes the length of the string and a
pointer to the array in which to return the bidi_types,
fribidi.get_bidi_types takes only the string, from which it determines
the length of the array to allocate, the contents of which are
returned in the function result as a tuple.

For convenient application of reorderings to multiple sequences,
PyBidi provides the Reordering class. The reorder_line function can
construct an instance of this class, and the “apply” method of this
class can be used on any sequence object to return a new object of the
same type, with the elements appropriately reordered.

Example Use

First, some example text to be laid out:

    text = "\u0627\u0644\u0642\u0627\u0647\u0631\u0629" # “al-qahirah”

Next, get the bidi types and embedding levels for the text:

    bidi_types = fribidi.get_bidi_types(text)
    base_dir, embedding_levels = fribidi.get_par_embedding_levels(bidi_types, FRIBIDI.PAR_RTL)[1:]

Reorder the text:

    vis_line, map = fribidi.reorder_line \
        flags = FRIBIDI.FLAGS_DEFAULT,
        bidi_types = bidi_types,
        line_offset = 0,
        base_dir = base_dir,
        embedding_levels = embedding_levels,
        logical_str = text,
        map = Reordering.identity(text)

This is sufficient for visual display of the text in the right order.
But to actually render the text with the right contextual forms for
Arabic, you need to continue...

Reorder the bidi types and embedding levels to match:

    vis_bidi_types = map.apply(bidi_types)
    vis_embedding_levels = map.apply(embedding_levels)

Get the joining types:

    joining_types = fribidi.get_joining_types(text)
    vis1_joining_types = fribidi.join_arabic(vis_bidi_types, vis_embedding_levels, joining_types)

Reorder the joining types:

    vis1_joining_types = map.apply(vis1_joining_types)

Do the shaping, i.e. replacement of characters with appropriate contextual forms:

    vis2_joining_types, vis2_line = fribidi.shape \
        flags = FRIBIDI.FLAGS_ARABIC,
        embedding_levels = vis_embedding_levels,
        ar_props = vis1_joining_types,
        string = vis_line

At this point, “vis2_line” can be drawn, for example into a Cairo
context with Qahirah ([GitLab](,
[GitHub](, using an appropriate
Arabic-capable font.

Convenience Wrapper

The code sequence above, up to fribidi.reorder_line() and the
map.apply() calls, is so common that it can be wrapped up in a single
instantiation of the ReorderLine class:

    reorder = fribidi.ReorderLine(text, FRIBIDI.PAR_RTL, FRIBIDI.FLAGS_DEFAULT)

From this point on, the output variables “bidi_types”, “base_dir”, “vis_line”,
“map”, “vis_bidi_types” and “vis_embedding_levels” can be accessed as attributes
of the “reorder” object.


FriBidi does its shaping by substituting the Unicode codes for
“Presentation Forms” of the Arabic characters. Trouble is, not all
characters that may be in Arabic script have such forms encoded--ones
that are specific to particular non-Arabic languages might not. So the
shaping will fail for these characters.

To fix such problems, and implement more advanced layout, you need
HarfBuzz ([GitLab](,

Lawrence D'Oliveiro <>
2017 October 18


Python wrapper for FriBidi





No packages published