From f6ecddd38e234e77d06e5d103804f61df858fbb0 Mon Sep 17 00:00:00 2001 From: Shavez Date: Sat, 13 Sep 2025 16:02:39 +0530 Subject: [PATCH] fix(Latex): add latex_cache directory to resolve LaTeX compilation errors. Fixes #2390 --- manimlib/default_config.yml | 2 + manimlib/utils/tex_file_writing.py | 97 +++++++++++++++--------------- 2 files changed, 52 insertions(+), 47 deletions(-) diff --git a/manimlib/default_config.yml b/manimlib/default_config.yml index 098c6c45d5..51676848e6 100644 --- a/manimlib/default_config.yml +++ b/manimlib/default_config.yml @@ -30,6 +30,8 @@ directories: data: "data" # When downloading, say an image, where will it go? downloads: "downloads" + # For storing cached LaTeX compilation results + latex_cache: "latex_cache" # For certain object types, especially Tex and Text, manim will save information # to file to prevent the need to re-compute, e.g. recompiling the latex. By default, # it stores this saved data to whatever directory appdirs.user_cache_dir("manim") returns, diff --git a/manimlib/utils/tex_file_writing.py b/manimlib/utils/tex_file_writing.py index cfc91f4fed..6c85564e2e 100644 --- a/manimlib/utils/tex_file_writing.py +++ b/manimlib/utils/tex_file_writing.py @@ -93,53 +93,56 @@ def full_tex_to_svg(full_tex: str, compiler: str = "latex", message: str = ""): else: raise NotImplementedError(f"Compiler '{compiler}' is not implemented") - # Write intermediate files to a temporary directory - with tempfile.TemporaryDirectory() as temp_dir: - tex_path = Path(temp_dir, "working").with_suffix(".tex") - dvi_path = tex_path.with_suffix(dvi_ext) - - # Write tex file - tex_path.write_text(full_tex) - - # Run latex compiler - process = subprocess.run( - [ - compiler, - *(['-no-pdf'] if compiler == "xelatex" else []), - "-interaction=batchmode", - "-halt-on-error", - f"-output-directory={temp_dir}", - tex_path - ], - capture_output=True, - text=True - ) - - if process.returncode != 0: - # Handle error - error_str = "" - log_path = tex_path.with_suffix(".log") - if log_path.exists(): - content = log_path.read_text() - error_match = re.search(r"(?<=\n! ).*\n.*\n", content) - if error_match: - error_str = error_match.group() - raise LatexError(error_str or "LaTeX compilation failed") - - # Run dvisvgm and capture output directly - process = subprocess.run( - [ - "dvisvgm", - dvi_path, - "-n", # no fonts - "-v", "0", # quiet - "--stdout", # output to stdout instead of file - ], - capture_output=True - ) - - # Return SVG string - result = process.stdout.decode('utf-8') + # Use the custom LaTeX cache directory from the config + temp_dir = Path(manim_config.directories.latex_cache) + temp_dir.mkdir(exist_ok=True) # Create the directory if it does not already exist + + # Define paths for the intermediate TeX and DVI files + tex_path = temp_dir / "working.tex" + dvi_path = tex_path.with_suffix(dvi_ext) + + # Write tex file + tex_path.write_text(full_tex) + + # Run latex compiler + process = subprocess.run( + [ + compiler, + *(['-no-pdf'] if compiler == "xelatex" else []), + "-interaction=batchmode", + "-halt-on-error", + f"-output-directory={temp_dir}", + tex_path + ], + capture_output=True, + text=True + ) + + if process.returncode != 0: + # Handle error + error_str = "" + log_path = tex_path.with_suffix(".log") + if log_path.exists(): + content = log_path.read_text() + error_match = re.search(r"(?<=\n! ).*\n.*\n", content) + if error_match: + error_str = error_match.group() + raise LatexError(error_str or "LaTeX compilation failed") + + # Run dvisvgm and capture output directly + process = subprocess.run( + [ + "dvisvgm", + dvi_path, + "-n", # no fonts + "-v", "0", # quiet + "--stdout", # output to stdout instead of file + ], + capture_output=True + ) + + # Return SVG string + result = process.stdout.decode('utf-8') if message: print(" " * len(message), end="\r")