Dependencies TeX Live Install from website Easy install - tug.org Provides pdflatex to compile LaTeX source to PDF Provides texfot to filter pdflatex stdout to only relevant messages , see CTAN: Package texdoc Provides pdfcrop to trim PDF of whitespace border, see CTAN: Package pdfcrop pdf2svg Clone repository dawbarton/pdf2svg Add dist-64bits subfolder to PATH environment variable Convert PDF to SVG Execute Code Install Obsidian extension via Comminity plugins, Webstore Generate LaTeX figure from Obsidian code block Python Python Install from website Downloads - python.org Execute tools from Obsidian code blocks Setup Execute Code Open Language-Specific Settings > Python Inject python code import os, contextlib def save_source_to_file(latex_source, destination): file_path = os.path.join(destination,'figure.tex') with open(file_path, 'w') as source_file: print(latex_source, file=source_file) return file_path @contextlib.contextmanager def temporary_working_directory(path): current_dir = os.getcwd() try: os.chdir(path) yield finally: os.chdir(current_dir) def is_standalone_class(latex_source): import re return re.search(r'\\documentclass\s*(?:\[[^\]]*\])?\s*\{standalone\}', latex_source) def compile_and_crop_figure(latex_source, attachments_folder, compiler="pdflatex", escape_shell=False, rerun=0): import subprocess, tempfile intermediates_folder = tempfile.mkdtemp() input_file = save_source_to_file(latex_source, intermediates_folder) with temporary_working_directory(attachments_folder): subprocess.run(['texfot', 'pdflatex', f'-output-directory={intermediates_folder}', input_file]) for _ in range(rerun): subprocess.run(['texfot', 'pdflatex', f'-output-directory={intermediates_folder}', input_file]) with temporary_working_directory(intermediates_folder): if not is_standalone_class(latex_source): os.rename('figure.pdf', 'figure_precrop.pdf') subprocess.run('pdfcrop figure_precrop.pdf figure.pdf', shell=True) subprocess.run('pdf2svg figure.pdf figure.svg', shell=True) return intermediates_folder def print_figure(filename, folder, vault_temporary_folder): import shutil, uuid source_file = os.path.join(folder, filename) vault_filename = str(uuid.uuid4()) + '.svg' vault_relative_file = f'/{vault_temporary_folder}/{vault_filename}' shutil.copy2(source_file, @vault_path + vault_relative_file) @html('<img src="' + @vault_url + vault_relative_file + '"/>') def export_figure(filename, new_filename, source_folder, destination_folder): import shutil _, source_ext = os.path.splitext(filename) new_basename, filter_ext = os.path.splitext(new_filename) if filter_ext and source_ext != filter_ext: return copy_from = os.path.join(source_folder, filename) copy_to = os.path.join(destination_folder, new_basename + source_ext) try: shutil.copy2(copy_from, copy_to) print(f"Figure exported as: {copy_to}") except IOError as e: print(f"Error exporting figure: {e}") def delete_figure(folder_path): files_to_delete = ['figure.tex', 'figure.aux', 'figure.log', 'figure.out', 'figure.lot', 'figure_precrop.pdf', 'figure.pdf', 'figure.svg'] for filename in files_to_delete: file_path = os.path.join(folder_path, filename) if os.path.exists(file_path): os.remove(file_path) os.rmdir(folder_path) def generate_latex_figure(latex_source, compiler="pdflatex", escape_shell=False, outfile=None, keep_intermediates=False, rerun=0): assets_folder = os.path.join(@vault_path, 'attachments/') figure_folder = compile_and_crop_figure(latex_source, assets_folder, rerun=rerun) if outfile: export_figure('figure.svg', outfile, figure_folder, assets_folder) export_figure('figure.pdf', outfile, figure_folder, assets_folder) print_figure('figure.svg', figure_folder, '.temp') if not keep_intermediates: delete_figure(figure_folder) generate_latex_figure(r""" \documentclass{standalone} \begin{document} Hello World! \end{document} """) Minimal example \documentclass{standalone} \begin{document} Hello World! \end{document} Save figure as figure hello world.svg \documentclass{standalone} \begin{document} Hello World! \end{document} Rerun to get cross-references right \documentclass{article} \pagestyle{empty} \usepackage{mathtools} \begin{document} I use \eqref{eq:einstein} a lot. \[ E = mc^2 \tag{1}\label{eq:einstein} \] \end{document} Regular python code import uuid print("figure_" + str(uuid.uuid4())) @show(@vault_url + '/attachments/.temp.svg') def check_file_for_patterns(file_path): import re patterns = [ r"Rerun to get cross-references right", r"Rerun to get outlines right", r"Label\(s\) may have changed\. Rerun" ] with open(file_path, 'r') as file: content = file.read() for pattern in patterns: if re.search(pattern, content): return True return False if check_file_for_patterns(r'C:\Users\anton\AppData\Local\Temp\tmpxnojtw_g\figure.log'): print("Rerun needed. Will compile again.") else: print("No rerun needed. Compilation complete.") Sources: Related: Tags: TeX Live pdf2svg Python