Skip to content
Draft
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
23 changes: 22 additions & 1 deletion manim/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from __future__ import annotations

from enum import Enum
from enum import Enum, StrEnum
from typing import TypedDict

import numpy as np
Expand Down Expand Up @@ -275,6 +275,27 @@ class RendererType(Enum):
OPENGL = "opengl" #: An OpenGL-based renderer.


class TexOutputFormat(StrEnum):
DVI = ".dvi"
XDV = ".xdv"
PDF = ".pdf"


class TexCompiler(StrEnum):
LATEX = "latex"
PDFLATEX = "pdflatex"
LUALATEX = "lualatex"
XELATEX = "xelatex"
TECTONIC = "tectonic"

@property
def output_formats(self) -> list[TexOutputFormat]:
if self in (TexCompiler.XELATEX, TexCompiler.TECTONIC):
return [TexOutputFormat.PDF, TexOutputFormat.XDV]
else:
return [TexOutputFormat.DVI, TexOutputFormat.PDF]


class LineJointType(Enum):
"""Collection of available line joint types.

Expand Down
6 changes: 4 additions & 2 deletions manim/utils/tex.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
from pathlib import Path
from typing import TYPE_CHECKING, Any

from manim.constants import TexCompiler, TexOutputFormat

if TYPE_CHECKING:
from typing import Self

Expand All @@ -33,15 +35,15 @@ class TexTemplate:
_body: str = field(default="", init=False)
"""A custom body, can be set from a file."""

tex_compiler: str | list[str] = "latex"
tex_compiler: TexCompiler | list[TexCompiler] | str | list[str] = TexCompiler.LATEX
"""The TeX compiler(s) to be used. Can be a single compiler (e.g. ``"latex"``,
``"pdflatex"``, ``"lualatex"``) or a list of compilers to compile in order
(e.g. ``["lualatex", "pdflatex"]``)."""

description: str = ""
"""A description of the template"""

output_format: str = ".dvi"
output_format: TexOutputFormat | str = TexOutputFormat.DVI
"""The output format resulting from compilation, e.g. ``.dvi`` or ``.pdf``."""

documentclass: str = r"\documentclass[preview]{standalone}"
Expand Down
80 changes: 50 additions & 30 deletions manim/utils/tex_file_writing.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from re import Match
from typing import Any

from manim.constants import TexCompiler, TexOutputFormat
from manim.utils.tex import TexTemplate

from .. import config, logger
Expand Down Expand Up @@ -62,12 +63,16 @@ def tex_to_svg_file(
if svg_file.exists():
return svg_file

# convert to TexCompiler and TexOutputFormat
tex_compiler = TexCompiler(str(tex_template.tex_compiler))
output_format = TexOutputFormat(str(tex_template.output_format))

dvi_file = compile_tex(
tex_file,
tex_template.tex_compiler,
tex_template.output_format,
tex_compiler,
output_format,
)
svg_file = convert_to_svg(dvi_file, tex_template.output_format)
svg_file = convert_to_svg(dvi_file, output_format)
if not config["no_latex_cleanup"]:
delete_nonsvg_files()
return svg_file
Expand Down Expand Up @@ -116,7 +121,10 @@ def generate_tex_file(


def make_tex_compilation_command(
tex_compiler: str, output_format: str, tex_file: Path, tex_dir: Path
tex_compiler: TexCompiler,
output_format: TexOutputFormat,
tex_file: Path,
tex_dir: Path,
) -> list[str]:
"""Prepares the TeX compilation command, i.e. the TeX compiler name
and all necessary CLI flags.
Expand All @@ -137,29 +145,37 @@ def make_tex_compilation_command(
:class:`list[str]`
Compilation command according to given parameters
"""
if tex_compiler in {"latex", "pdflatex", "luatex", "lualatex"}:
if output_format not in tex_compiler.output_formats:
raise ValueError(
f"{tex_compiler} does not support output format {output_format}"
)
if tex_compiler in {TexCompiler.LATEX, TexCompiler.PDFLATEX, TexCompiler.LUALATEX}:
command = [
tex_compiler,
"-interaction=batchmode",
f"-output-format={output_format[1:]}",
"-halt-on-error",
f"-output-directory={tex_dir.as_posix()}",
f"{tex_file.as_posix()}",
"--interaction=batchmode",
f"--output-format={output_format.removeprefix('.')}",
"--halt-on-error",
f"--output-directory={tex_dir.as_posix()}",
tex_file.as_posix(),
]
elif tex_compiler == "xelatex":
if output_format == ".xdv":
outflag = ["-no-pdf"]
elif output_format == ".pdf":
outflag = []
else:
raise ValueError("xelatex output is either pdf or xdv")
elif tex_compiler == TexCompiler.XELATEX:
outflag = ["-no-pdf"] if output_format is TexOutputFormat.XDV else []
command = [
"xelatex",
tex_compiler,
*outflag,
"-interaction=batchmode",
"-halt-on-error",
f"-output-directory={tex_dir.as_posix()}",
f"{tex_file.as_posix()}",
"--interaction=batchmode",
"--halt-on-error",
f"--output-directory={tex_dir.as_posix()}",
tex_file.as_posix(),
]
elif tex_compiler is TexCompiler.TECTONIC:
command = [
tex_compiler,
"--outfmt",
output_format.removeprefix("."),
"-o",
tex_dir.as_posix(),
tex_file.as_posix(),
]
else:
raise ValueError(f"Tex compiler {tex_compiler} unknown.")
Expand All @@ -179,7 +195,9 @@ def insight_package_not_found_error(matching: Match[str]) -> Generator[str]:


def compile_tex(
tex_file: Path, tex_compiler: str | list[str], output_format: str
tex_file: Path,
tex_compiler: TexCompiler | list[TexCompiler],
output_format: TexOutputFormat = TexOutputFormat.DVI,
) -> Path:
"""Compiles a tex_file into a .dvi or a .xdv or a .pdf

Expand All @@ -189,16 +207,16 @@ def compile_tex(
File name of TeX file to be typeset.
tex_compiler
The TeX compiler(s) to be used.
Can be a single compiler (e.g. ``"latex"``, ``"pdflatex"`` ``"lualatex"``) or a list of compilers to compile in order (e.g. ``["lualatex", "pdflatex"]``).
Can be a single compiler (e.g. ``"latex"``, ``"pdflatex"``, ``"lualatex"``) or a list of compilers to compile in order (e.g. ``["lualatex", "pdflatex"]``).
output_format
String containing the output format generated by the compiler, e.g. ``.dvi`` or ``.pdf``
String containing the output format generated by the compiler, e.g. ``.dvi``, ``.pdf`` or ``.xdv``

Returns
-------
:class:`Path`
Path to generated output file in desired format (DVI, XDV or PDF).
"""
result = tex_file.with_suffix(output_format)
result = tex_file.with_suffix(str(output_format))
tex_dir = config.get_dir("tex_dir")
tex_compilers = [tex_compiler] if isinstance(tex_compiler, str) else tex_compiler
if not result.exists():
Expand All @@ -223,15 +241,17 @@ def compile_tex(
return result


def convert_to_svg(dvi_file: Path, extension: str, page: int = 1) -> Path:
def convert_to_svg(
dvi_file: Path, output_format: TexOutputFormat, page: int = 1
) -> Path:
"""Converts a .dvi, .xdv, or .pdf file into an svg using dvisvgm.

Parameters
----------
dvi_file
File name of the input file to be converted.
extension
String containing the file extension and thus indicating the file type, e.g. ``.dvi`` or ``.pdf``
output_format
String containing the file output format and thus indicating the file type, e.g. ``.dvi`` or ``.pdf``
page
Page to be converted if input file is multi-page.

Expand All @@ -244,7 +264,7 @@ def convert_to_svg(dvi_file: Path, extension: str, page: int = 1) -> Path:
if not result.exists():
command = [
"dvisvgm",
*(["--pdf"] if extension == ".pdf" else []),
*(["--pdf"] if output_format is TexOutputFormat.PDF else []),
f"--page={page}",
"--no-fonts",
"--verbosity=0",
Expand Down
58 changes: 30 additions & 28 deletions manim/utils/tex_templates.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
"TexFontTemplates",
]

from manim.constants import TexCompiler, TexOutputFormat

from .tex import *

# This file makes TexTemplateLibrary and TexFontTemplates available for use in manim Tex and MathTex objects.
Expand Down Expand Up @@ -68,8 +70,8 @@ class TexTemplateLibrary:
""" An instance of the default TeX template used by 3b1b """

ctex = TexTemplate(
tex_compiler="xelatex",
output_format=".xdv",
tex_compiler=TexCompiler.XELATEX,
output_format=TexOutputFormat.XDV,
preamble=_3b1b_preamble.replace(
r"\DisableLigatures{encoding = *, family = * }",
r"\usepackage[UTF8]{ctex}",
Expand Down Expand Up @@ -315,8 +317,8 @@ class TexTemplateLibrary:
\usepackage[defaultmathsizes]{mathastext}
""",
)
americantypewriter.tex_compiler = "xelatex"
americantypewriter.output_format = ".xdv"
americantypewriter.tex_compiler = TexCompiler.XELATEX
americantypewriter.output_format = TexOutputFormat.XDV

# Minion Pro and Myriad Pro (and TX fonts symbols)
mpmptx = _new_ams_template()
Expand All @@ -333,8 +335,8 @@ class TexTemplateLibrary:
\renewcommand\familydefault\rmdefault
""",
)
mpmptx.tex_compiler = "xelatex"
mpmptx.output_format = ".xdv"
mpmptx.tex_compiler = TexCompiler.XELATEX
mpmptx.output_format = TexOutputFormat.XDV


# New Century Schoolbook (Symbol Greek, PX math symbols)
Expand Down Expand Up @@ -436,8 +438,8 @@ class TexTemplateLibrary:
\usepackage[defaultmathsizes]{mathastext}
""",
)
applechancery.tex_compiler = "xelatex"
applechancery.output_format = ".xdv"
applechancery.tex_compiler = TexCompiler.XELATEX
applechancery.output_format = TexOutputFormat.XDV


# Zapf Chancery
Expand Down Expand Up @@ -467,8 +469,8 @@ class TexTemplateLibrary:
\usepackage[defaultmathsizes,italic]{mathastext}
""",
)
italicverdana.tex_compiler = "xelatex"
italicverdana.output_format = ".xdv"
italicverdana.tex_compiler = TexCompiler.XELATEX
italicverdana.output_format = TexOutputFormat.XDV


# URW Zapf Chancery (CM Greek)
Expand Down Expand Up @@ -504,8 +506,8 @@ class TexTemplateLibrary:
\usepackage[defaultmathsizes]{mathastext}
""",
)
comicsansms.tex_compiler = "xelatex"
comicsansms.output_format = ".xdv"
comicsansms.tex_compiler = TexCompiler.XELATEX
comicsansms.output_format = TexOutputFormat.XDV


# GFS Didot (Italic)
Expand All @@ -531,8 +533,8 @@ class TexTemplateLibrary:
\usepackage[defaultmathsizes]{mathastext}
""",
)
chalkduster.tex_compiler = "lualatex"
chalkduster.output_format = ".pdf"
chalkduster.tex_compiler = TexCompiler.LUALATEX
chalkduster.output_format = TexOutputFormat.PDF


# Minion Pro (and TX fonts symbols)
Expand All @@ -546,8 +548,8 @@ class TexTemplateLibrary:
\usepackage[defaultmathsizes]{mathastext}
""",
)
mptx.tex_compiler = "xelatex"
mptx.output_format = ".xdv"
mptx.tex_compiler = TexCompiler.XELATEX
mptx.output_format = TexOutputFormat.XDV


# GNU FreeSerif and FreeSans
Expand Down Expand Up @@ -575,8 +577,8 @@ class TexTemplateLibrary:
\renewcommand{\familydefault}{\rmdefault}
""",
)
gnufsfs.tex_compiler = "xelatex"
gnufsfs.output_format = ".xdv"
gnufsfs.tex_compiler = TexCompiler.XELATEX
gnufsfs.output_format = TexOutputFormat.XDV

# GFS NeoHellenic
gfsneohellenic = _new_ams_template()
Expand Down Expand Up @@ -631,8 +633,8 @@ class TexTemplateLibrary:
\usepackage[defaultmathsizes,italic]{mathastext}
""",
)
italicbaskerville.tex_compiler = "xelatex"
italicbaskerville.output_format = ".xdv"
italicbaskerville.tex_compiler = TexCompiler.XELATEX
italicbaskerville.output_format = TexOutputFormat.XDV


# ECF JD (with TX fonts)
Expand Down Expand Up @@ -676,8 +678,8 @@ class TexTemplateLibrary:
\usepackage[defaultmathsizes]{mathastext}
""",
)
papyrus.tex_compiler = "xelatex"
papyrus.output_format = ".xdv"
papyrus.tex_compiler = TexCompiler.XELATEX
papyrus.output_format = TexOutputFormat.XDV


# GNU FreeSerif (and TX fonts symbols)
Expand All @@ -695,8 +697,8 @@ class TexTemplateLibrary:
\usepackage[defaultmathsizes]{mathastext}
""",
)
gnufstx.tex_compiler = "xelatex"
gnufstx.output_format = ".pdf"
gnufstx.tex_compiler = TexCompiler.XELATEX
gnufstx.output_format = TexOutputFormat.PDF


# ECF Skeetch (CM Greek)
Expand Down Expand Up @@ -790,8 +792,8 @@ class TexTemplateLibrary:
\usepackage[defaultmathsizes]{mathastext}
""",
)
chalkboardse.tex_compiler = "xelatex"
chalkboardse.output_format = ".xdv"
chalkboardse.tex_compiler = TexCompiler.XELATEX
chalkboardse.output_format = TexOutputFormat.XDV


# Noteworthy Light
Expand Down Expand Up @@ -878,8 +880,8 @@ class TexTemplateLibrary:
r"""\boldmath
""",
)
brushscriptxpx.tex_compiler = "xelatex"
brushscriptxpx.output_format = ".xdv"
brushscriptxpx.tex_compiler = TexCompiler.XELATEX
brushscriptxpx.output_format = TexOutputFormat.XDV


# URW Avant Garde (Symbol Greek)
Expand Down
3 changes: 3 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ jupyterlab = [
typst = [
"typst>=0.14",
]
tectonic = [
"tecto>=0.16.9",
]

[dependency-groups]
dev = [
Expand Down
Loading