Manim集成Typst排版时分式水平线不显示问题求助
Manim集成Typst排版时分式水平线不显示问题求助
大家好,我正在给Manim开发Typst排版的支持模块,目前基本功能能跑起来,但遇到一个头疼的问题——像(z^2)/(w^2)这样的分式,分子和分母之间的水平线完全不显示,试了好几种方式都没解决。下面是我写的完整代码,麻烦各位帮忙看看哪里出问题了?
from manim import * import os import shutil import subprocess # Define a temporary directory for Typst output TYPST_TEMP_DIR = "typst_temp_files" def str_to_valid_filename(s: str) -> str: """Converts a string to a valid filename.""" return "".join((c for c in s if c.isalnum() or c in "._-")).strip() def common_str_to_typst_str(common_str: str, font_size_pt: int = 50, color_hex: str = "#FFFFFF") -> str: """ Generates a Typst string with specified font size and color. The font_size_pt here is the actual font size Typst will render at. """ template = rf"""#set page(fill: none) #set text(fill: rgb("{color_hex}"), size: {font_size_pt}pt) // Set page width to auto to prevent excessive padding, allowing Typst to fit content #set page(width: auto, height: auto) {common_str}""" return template def math_str_to_common_str(math_str: str) -> str: """Wraps a math string in Typst's inline math delimiters.""" return f"$ {math_str} $" def typst_str_to_typ(typst_str: str, typst_file_name: str, folder: str = TYPST_TEMP_DIR) -> str: """Writes the Typst content to a .typ file.""" os.makedirs(folder, exist_ok=True) # Use exist_ok=True to avoid error if folder exists file_path = os.path.join(folder, typst_file_name) with open(file_path, "w", encoding="utf-8") as f: f.write(typst_str) return file_path def typ_to_svg(typ_file_path: str) -> str: """Compiles a .typ file to an SVG file using the Typst CLI.""" svg_file_path = typ_file_path.replace(".typ", ".svg") if os.path.exists(svg_file_path): return svg_file_path # Return existing SVG for caching, avoiding re-compilation command = [ 'typst', 'compile', '--format', 'svg', typ_file_path, svg_file_path ] try: result = subprocess.run(command, check=True, capture_output=True, text=True, encoding="utf-8") if result.stdout: print(f"Typst stdout: {result.stdout}") if result.stderr: print(f"Typst stderr: {result.stderr}") except subprocess.CalledProcessError as e: print(f"Error compiling Typst file: {typ_file_path}") print(f"Typst stderr: {e.stderr}") raise RuntimeError(f"Typst compilation failed: {e.stderr}") from e except FileNotFoundError: raise RuntimeError("Typst command not found. Please ensure Typst is installed and in your system's PATH.") if not os.path.exists(svg_file_path): raise RuntimeError(f"SVG file not generated at expected path: {svg_file_path}") return svg_file_path def common_str_to_svg(common_str: str, font_size_pt: int = 50, color_hex: str = "#FFFFFF", folder: str = TYPST_TEMP_DIR) -> str: """ Converts a common string to an SVG file path by rendering it with Typst. This function will generate temporary .typ and .svg files. """ unique_filename = f"{str_to_valid_filename(common_str)}_{hash(common_str) % 100000}.typ" typst_str = common_str_to_typst_str(common_str, font_size_pt, color_hex) typ_file_path = typst_str_to_typ(typst_str, unique_filename, folder) svg_file_path = typ_to_svg(typ_file_path) return svg_file_path class Typst(SVGMobject): def __init__(self, common_str: str, font_size: float = 0.7, color: ManimColor | str = WHITE, folder: str = TYPST_TEMP_DIR, **kwargs): TYPST_RENDER_FONT_SIZE_PT = 200 # Render Typst at a large, fixed point size for quality # Ensure color is a hex string for Typst if isinstance(color, ManimColor): color_hex = color.to_hex() # <-- FIX IS HERE: changed .hex to .to_hex() else: color_hex = color self.svg_file_path = common_str_to_svg(common_str, TYPST_RENDER_FONT_SIZE_PT, color_hex, folder) self._common_str = common_str self._font_size = font_size self._color = color self._folder = folder self._kwargs = kwargs if "stroke_width" not in kwargs: kwargs["stroke_width"] = 0 super().__init__(self.svg_file_path, **kwargs) if self.height > 1e-9: self.scale(font_size / self.height) else: self.set_height(font_size) self.set_color(self._color) @property def font_size(self) -> float: return self._font_size @font_size.setter def font_size(self, new_font_size: float): if new_font_size <= 0: raise ValueError("Font size must be greater than 0.") self.set_height(new_font_size) self._font_size = new_font_size def set_content(self, common_str: str, font_size: float = None, color: ManimColor | str = None, folder: str = None): """ Updates the content of the Typst mobject. Removes the old SVG file and generates a new one. """ if os.path.exists(self.svg_file_path): os.remove(self.svg_file_path) # 后续更新逻辑待补充
我自己排查了几个方向,但都没找到原因:
- 检查过Typst的模板设置,页面是透明背景,文字颜色设为白色,应该不会和背景重合
- 尝试过直接用Typst CLI渲染单独的分式,水平线是正常显示的,但通过代码生成的SVG导入Manim后就没了
- 也调整过渲染的字号大小,还是看不到水平线
有没有大佬遇到过类似的问题,或者能帮我指出代码里的疏漏?
内容来源于stack exchange
相关产品推荐
相关产品推荐

