Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
146 changes: 65 additions & 81 deletions manim/mobject/svg/text_mobject.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""Mobjects used for displaying (non-LaTeX) text."""

__all__ = ["Text", "Paragraph", "PangoText", "CairoText"]
__all__ = ["Text", "Paragraph", "CairoText"]


import copy
Expand Down Expand Up @@ -533,10 +533,10 @@ def change_alignment_for_a_line(self, alignment, line_no):
)


class PangoText(SVGMobject):
class Text(SVGMobject):
r"""Display (non-LaTeX) text rendered using `Pango <https://pango.gnome.org/>`_.

PangoText objects behave like a :class:`.VGroup`-like iterable of all characters
Text objects behave like a :class:`.VGroup`-like iterable of all characters
in the given text. In particular, slicing is possible.

Parameters
Expand All @@ -546,27 +546,74 @@ class PangoText(SVGMobject):

Returns
-------
:class:`PangoText`
:class:`Text`
The mobject like :class:`.VGroup`.

Examples
---------

.. manim:: Example1Text
:save_last_frame:

class Example1Text(Scene):
def construct(self):
text = Text('Hello world').scale(3)
self.add(text)

.. manim:: TextColorExample
:save_last_frame:

class TextColorExample(Scene):
def construct(self):
text1 = Text('Hello world', color=BLUE).scale(3)
text2 = Text('Hello world', gradient=(BLUE, GREEN)).scale(3).next_to(text1, DOWN)
self.add(text1, text2)

.. manim:: TextItalicAndBoldExample
:save_last_frame:

class TextItalicAndBoldExample(Scene):
def construct(self):
text0 = Text('Hello world', slant=ITALIC)
text1 = Text('Hello world', t2s={'world':ITALIC})
text2 = Text('Hello world', weight=BOLD)
text3 = Text('Hello world', t2w={'world':BOLD})
self.add(text0,text1, text2,text3)
for i,mobj in enumerate(self.mobjects):
mobj.shift(DOWN*(i-1))


.. manim:: TextMoreCustomization
:save_last_frame:

class TextMoreCustomization(Scene):
def construct(self):
text1 = Text(
'Google',
t2c={'[:1]': '#3174f0', '[1:2]': '#e53125',
'[2:3]': '#fbb003', '[3:4]': '#3174f0',
'[4:5]': '#269a43', '[5:]': '#e53125'}, size=1.2).scale(3)
self.add(text1)

As :class:`Text` uses Pango to render text, rendering non-English
characters is easily possible:

.. manim:: MultipleFonts
:save_last_frame:

class MultipleFonts(Scene):
def construct(self):
morning = PangoText("வணக்கம்", font="sans-serif")
chin = PangoText(
morning = Text("வணக்கம்", font="sans-serif")
chin = Text(
"見 角 言 谷 辛 辰 辵 邑 酉 釆 里!", t2c={"見 角 言": BLUE}
) # works same as ``Text``.
mess = PangoText("Multi-Language", style=BOLD)
russ = PangoText("Здравствуйте मस नम म ", font="sans-serif")
hin = PangoText("नमस्ते", font="sans-serif")
arb = PangoText(
mess = Text("Multi-Language", style=BOLD)
russ = Text("Здравствуйте मस नम म ", font="sans-serif")
hin = Text("नमस्ते", font="sans-serif")
arb = Text(
"صباح الخير \n تشرفت بمقابلتك", font="sans-serif"
) # don't mix RTL and LTR languages nothing shows up then ;-)
japanese = PangoText("臂猿「黛比」帶著孩子", font="sans-serif")
japanese = Text("臂猿「黛比」帶著孩子", font="sans-serif")
self.add(morning,chin,mess,russ,hin,arb,japanese)
for i,mobj in enumerate(self.mobjects):
mobj.shift(DOWN*(i-3))
Expand All @@ -577,16 +624,16 @@ def construct(self):

class PangoRender(Scene):
def construct(self):
morning = PangoText("வணக்கம்", font="sans-serif")
morning = Text("வணக்கம்", font="sans-serif")
self.play(Write(morning))
self.wait(2)

Tests
-----

Check that the creation of :class:`~.PangoText` works::
Check that the creation of :class:`~.Text` works::

>>> PangoText('The horse does not eat cucumber salad.')
>>> Text('The horse does not eat cucumber salad.')
Text('The horse does not eat cucumber salad.')

.. WARNING::
Expand Down Expand Up @@ -622,6 +669,10 @@ def construct(self):
}

def __init__(self, text: str, **config): # pylint: disable=redefined-outer-name
logger.info(
"Text now uses Pango for rendering. "
"In case of problems, the old implementation is available as CairoText."
)
self.full2short(config)
digest_config(self, config)
self.original_text = text
Expand Down Expand Up @@ -872,70 +923,3 @@ def text2svg(self):
offset_x += layout.get_extents()[0].x
surface.finish()
return file_name


class Text(CairoText):
"""Display (non-LaTeX) text.

Text objects behave like a :class:`.VGroup`-like iterable of all characters
in the given text. In particular, slicing is possible.

Examples
--------
.. manim:: Example1Text
:save_last_frame:

class Example1Text(Scene):
def construct(self):
text = Text('Hello world').scale(3)
self.add(text)

.. manim:: TextColorExample
:save_last_frame:

class TextColorExample(Scene):
def construct(self):
text1 = Text('Hello world', color=BLUE).scale(3)
text2 = Text('Hello world', gradient=(BLUE, GREEN)).scale(3).next_to(text1, DOWN)
self.add(text1, text2)

.. manim:: TextItalicAndBoldExample
:save_last_frame:

class TextItalicAndBoldExample(Scene):
def construct(self):
text0 = Text('Hello world', slant=ITALIC)
text1 = Text('Hello world', t2s={'world':ITALIC})
text2 = Text('Hello world', weight=BOLD)
text3 = Text('Hello world', t2w={'world':BOLD})
self.add(text0,text1, text2,text3)
for i,mobj in enumerate(self.mobjects):
mobj.shift(DOWN*(i-1))


.. manim:: TextMoreCustomization
:save_last_frame:

class TextMoreCustomization(Scene):
def construct(self):
text1 = Text(
'Google',
t2c={'[:1]': '#3174f0', '[1:2]': '#e53125',
'[2:3]': '#fbb003', '[3:4]': '#3174f0',
'[4:5]': '#269a43', '[5:]': '#e53125'}, size=1.2).scale(3)
self.add(text1)

.. WARNING::

Using a :class:`.Transform` on text with leading whitespace can look
`weird <https://github.com/3b1b/manim/issues/1067>`_. Consider using
:meth:`remove_invisible_chars` to resolve this issue.

"""

def __init__(self, text, **config):
logger.warning(
"Using Text uses Cairo Toy API to Render Text."
"Using PangoText is recommended and soon Text would point to PangoText"
)
CairoText.__init__(self, text, **config)
18 changes: 9 additions & 9 deletions tests/test_pango.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
"""Tests :class:`PangoText` by comparing SVG files created.
"""Tests :class:`Text` by comparing SVG files created.
"""
import os
import re

import cairocffi
import pangocairocffi
import pangocffi
from manim import START_X, START_Y, PangoText, SVGMobject
from manim import START_X, START_Y, Text, SVGMobject

RTL_TEXT: str = """صباح الخير
مرحبا جميعا"""
Expand All @@ -27,9 +27,9 @@ def remove_last_M(file_path: str) -> None: # pylint: disable=invalid-name


def compare_SVGObject_with_PangoText( # pylint: disable=invalid-name
text: PangoText, svg_path: str
text: Text, svg_path: str
) -> bool:
"""Checks for the path_string formed by PangoText and Formed SVG file.
"""Checks for the path_string formed by Text and Formed SVG file.
Uses SVGMobject as it parses the SVG and returns the path_string
"""
remove_last_M(svg_path) # to prevent issue displaying
Expand All @@ -53,7 +53,7 @@ def test_general_text_svgobject() -> None:
"""
text = "hello"
size = 1
temp_pango_text = PangoText(text, size=size)
temp_pango_text = Text(text, size=size)
surface = cairocffi.SVGSurface(filename, WIDTH, HEIGTH)
context = cairocffi.Context(surface)
context.move_to(START_X, START_Y)
Expand All @@ -73,7 +73,7 @@ def test_rtl_text_to_svgobject() -> None:
called using ``SVGMobject``"""
size = 1
text = RTL_TEXT.replace("\n", "")
temp_pango_text = PangoText(text, size=1)
temp_pango_text = Text(text, size=1)
surface = cairocffi.SVGSurface(filename, WIDTH, HEIGTH)
context = cairocffi.Context(surface)
context.move_to(START_X, START_Y)
Expand All @@ -93,7 +93,7 @@ def test_font_face() -> None:
size = 1
text = RTL_TEXT.replace("\n", "")
font_face = "sans"
temp_pango_text = PangoText(text, size=1, font=font_face)
temp_pango_text = Text(text, size=1, font=font_face)
surface = cairocffi.SVGSurface(filename, WIDTH, HEIGTH)
context = cairocffi.Context(surface)
context.move_to(START_X, START_Y)
Expand All @@ -111,7 +111,7 @@ def test_font_face() -> None:

def test_whether_svg_file_created() -> None:
"""Checks Whether SVG file is created in desired location"""
temp_pango_text = PangoText("hello", size=1)
temp_pango_text = Text("hello", size=1)
theo_path = os.path.abspath(
os.path.join(folder, temp_pango_text.text2hash() + ".svg")
)
Expand All @@ -123,7 +123,7 @@ def test_tabs_replace() -> None:
"""Checks whether are there in end svg image.
Pango should handle tabs and line breaks."""
size = 1
temp_pango_text = PangoText("hello\thi\nf")
temp_pango_text = Text("hello\thi\nf")
assert temp_pango_text.text == "hellohif"
surface = cairocffi.SVGSurface(filename, WIDTH, HEIGTH)
context = cairocffi.Context(surface)
Expand Down