Skip to content
Back to top
View this page

# `ImageText` module

The `ImageText` module defines a `Text` class. Instances of this class provide a way to use fonts with text strings or bytes. The result is a simple API to apply styling to pieces of text and measure or draw them.

## Example

    from PIL import Image, ImageDraw, ImageFont, ImageText
    font = ImageFont.truetype("Tests/fonts/FreeMono.ttf", 24)

    text = ImageText.Text("Hello world", font)
    text.embed_color()
    text.stroke(2, "#0f0")

    print(text.get_length())  # 154.0
    print(text.get_bbox())  # (-2, 3, 156, 22)

    im = Image.new("RGB", text.get_bbox()[2:])
    d = ImageDraw.Draw(im)
    d.text((0, 0), text, "#f00")

## Comparison

Without `ImageText.Text`:

    from PIL import Image, ImageDraw
    im = Image.new(mode, size)
    d = ImageDraw.Draw(im)

    d.textlength(text, font, direction, features, language, embedded_color)
    d.multiline_textbbox(xy, text, font, anchor, spacing, align, direction, features, language, stroke_width, embedded_color)
    d.text(xy, text, fill, font, anchor, spacing, align, direction, features, language, stroke_width, stroke_fill, embedded_color)

With `ImageText.Text`:

    from PIL import ImageText
    text = ImageText.Text(text, font, mode, spacing, direction, features, language)
    text.embed_color()
    text.stroke(stroke_width, stroke_fill)

    text.get_length()
    text.get_bbox(xy, anchor, align)

    im = Image.new(mode, size)
    d = ImageDraw.Draw(im)
    d.text(xy, text, fill, anchor=anchor, align=align)

## Methods

class PIL.ImageText.Text(text: AnyStr, font: ImageFont | FreeTypeFont | TransposedFont | None = None, mode: str = 'RGB', spacing: float = 4, direction: str | None = None, features: list[str] | None = None, language: str | None = None)
  embed_color() → None

    Use embedded color glyphs (COLR, CBDT, SBIX).

  get_bbox(xy: tuple[float, float] = (0, 0), anchor: str | None = None, align: str = 'left') → tuple[float, float, float, float]

    Returns bounding box (in pixels) of text.

    Use `get_length()` to get the offset of following text with 1/64 pixel precision. The bounding box includes extra margins for some fonts, e.g. italics or accents.

    Parameters:

      - xy – The anchor coordinates of the text.

      - anchor – The text anchor alignment. Determines the relative location of the anchor to the text. The default alignment is top left, specifically `la` for horizontal text and `lt` for vertical text. See Text anchors for details.

      - align – For multiline text, `"left"`, `"center"`, `"right"` or `"justify"` determines the relative alignment of lines. Use the `anchor` parameter to specify the alignment to `xy`.

    Returns:

      `(left, top, right, bottom)` bounding box

  get_length() → float

    Returns length (in pixels with 1/64 precision) of text.

    This is the amount by which following text should be offset. Text bounding box may extend past the length in some fonts, e.g. when using italics or accents.

    The result is returned as a float; it is a whole number if using basic layout.

    Note that the sum of two lengths may not equal the length of a concatenated string due to kerning. If you need to adjust for kerning, include the following character and subtract its length.

    For example, instead of:

        hello = ImageText.Text("Hello", font).get_length()
        world = ImageText.Text("World", font).get_length()
        helloworld = ImageText.Text("HelloWorld", font).get_length()
        assert hello + world == helloworld

    use:

        hello = (
            ImageText.Text("HelloW", font).get_length() -
            ImageText.Text("W", font).get_length()
        )  # adjusted for kerning
        world = ImageText.Text("World", font).get_length()
        helloworld = ImageText.Text("HelloWorld", font).get_length()
        assert hello + world == helloworld

    or disable kerning with (requires libraqm):

        hello = ImageText.Text("Hello", font, features=["-kern"]).get_length()
        world = ImageText.Text("World", font, features=["-kern"]).get_length()
        helloworld = ImageText.Text(
            "HelloWorld", font, features=["-kern"]
        ).get_length()
        assert hello + world == helloworld

    Returns:

      Either width for horizontal text, or height for vertical text.

  stroke(width: float = 0, fill: float | tuple[int, ...] | str | None = None) → None
    Parameters:

      - width – The width of the text stroke.

      - fill – Color to use for the text stroke when drawing. If not given, will default to the `fill` parameter from `ImageDraw.ImageDraw.text()`.

  wrap(width: int, height: int | None = None, scaling: str | tuple[str, int] | None = None) → Text | None

    Wrap text to fit within a given width.

    Parameters:

      - width – The width to fit within.

      - height – An optional height limit. Any text that does not fit within this will be returned as a new `Text` object.

      - scaling – An optional directive to scale the text, either “grow” as much as possible within the given dimensions, or “shrink” until it fits. It can also be a tuple of (direction, limit), with an integer limit to stop scaling at.

    Returns:

      An `Text` object, or None.