import os import subprocess from pathlib import Path import tempfile import shutil # 设置pandoc路径 PANDOC_PATH = r"D:\work\pandoc-3.6.4-windows-x86_64\pandoc-3.6.4\pandoc.exe" def check_dependencies(): """检查必要的依赖是否已安装""" # 检查 pandoc if not os.path.exists(PANDOC_PATH): raise Exception(f"未找到 pandoc,请检查路径是否正确: {PANDOC_PATH}") print(f"找到 pandoc: {PANDOC_PATH}") # 测试 pandoc 命令 try: result = subprocess.run([PANDOC_PATH, '--version'], capture_output=True, text=True, encoding='utf-8') print(f"Pandoc 版本信息:\n{result.stdout}") except Exception as e: print(f"测试 pandoc 命令时出错: {str(e)}") raise # 检查 xelatex if shutil.which('xelatex') is None: raise Exception("未找到 xelatex,请先安装 MiKTeX:https://miktex.org/download") print("找到 xelatex") # 检查 pdflatex if shutil.which('pdflatex') is None: print("警告:未找到 pdflatex") else: print("找到 pdflatex") def create_latex_template(): """创建支持中文的LaTeX模板""" template = r"""\documentclass{article} \usepackage[UTF8]{ctex} \usepackage{listings} \usepackage{color} \usepackage{enumitem} \usepackage{booktabs} \usepackage{longtable} \usepackage{hyperref} \usepackage{amsmath} % 定义tightlist命令 \newcommand{\tightlist}{% \setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}} \lstset{ basicstyle=\ttfamily, breaklines=true, frame=single, numbers=left, numberstyle=\tiny, keywordstyle=\color{blue}, commentstyle=\color{green!60!black}, stringstyle=\color{red} } \begin{document} $body$ \end{document}""" # 使用临时文件 with tempfile.NamedTemporaryFile(suffix='.tex', delete=False, mode='w', encoding='utf-8') as f: f.write(template) return f.name def markdown_to_docx(markdown_file: str, output_docx: str = None) -> str: """ 将Markdown文件转换为DOCX文件 Args: markdown_file (str): Markdown文件的路径 output_docx (str, optional): 输出的DOCX文件路径。如果为None,则使用与输入文件相同的名称 Returns: str: 生成的DOCX文件路径 """ # 获取绝对路径 markdown_file = os.path.abspath(markdown_file) print(f"输入文件绝对路径: {markdown_file}") # 检查输入文件是否存在 if not os.path.exists(markdown_file): raise FileNotFoundError(f"Markdown文件不存在: {markdown_file}") print(f"输入文件存在: {markdown_file}") # 如果没有指定输出文件,则使用与输入文件相同的名称 if output_docx is None: output_docx = os.path.splitext(markdown_file)[0] + '.docx' else: output_docx = os.path.abspath(output_docx) print(f"输出DOCX文件路径: {output_docx}") # 确保输出目录存在 output_dir = os.path.dirname(output_docx) if not os.path.exists(output_dir): os.makedirs(output_dir) print(f"创建输出目录: {output_dir}") try: # 使用pandoc将markdown转换为docx cmd = [ PANDOC_PATH, markdown_file, '-o', output_docx, '--standalone', # 生成独立的文档 '--wrap=preserve', # 保持原始换行 '--highlight-style=tango', # 代码高亮样式 '--metadata', 'lang=zh-CN' # 设置文档语言 ] print(f"\n执行转换命令: {' '.join(cmd)}") # 使用utf-8编码执行命令 result = subprocess.run(cmd, capture_output=True, text=True, encoding='utf-8') print(f"命令输出: {result.stdout}") if result.stderr: print(f"命令警告: {result.stderr}") # 检查DOCX是否生成 if os.path.exists(output_docx): print(f"DOCX文件已成功生成: {output_docx}") return output_docx else: raise Exception(f"DOCX文件未生成: {output_docx}") except subprocess.CalledProcessError as e: print(f"命令执行错误: {e}") print(f"错误输出: {e.output if hasattr(e, 'output') else '无输出'}") raise Exception(f"转换过程中出错: {str(e)}") except Exception as e: print(f"发生错误: {str(e)}") raise Exception(f"发生未知错误: {str(e)}") def markdown_to_pdf(markdown_file: str, output_pdf: str = None) -> str: """ 将Markdown文件转换为PDF文件 Args: markdown_file (str): Markdown文件的路径 output_pdf (str, optional): 输出的PDF文件路径。如果为None,则使用与输入文件相同的名称 Returns: str: 生成的PDF文件路径 """ # 检查依赖 check_dependencies() # 获取绝对路径 markdown_file = os.path.abspath(markdown_file) print(f"输入文件绝对路径: {markdown_file}") # 检查输入文件是否存在 if not os.path.exists(markdown_file): raise FileNotFoundError(f"Markdown文件不存在: {markdown_file}") print(f"输入文件存在: {markdown_file}") # 如果没有指定输出文件,则使用与输入文件相同的名称 if output_pdf is None: output_pdf = os.path.splitext(markdown_file)[0] + '.pdf' else: output_pdf = os.path.abspath(output_pdf) print(f"输出PDF文件路径: {output_pdf}") # 确保输出目录存在 output_dir = os.path.dirname(output_pdf) if not os.path.exists(output_dir): os.makedirs(output_dir) print(f"创建输出目录: {output_dir}") try: # 创建支持中文的LaTeX模板 latex_template = create_latex_template() print(f"LaTeX模板文件: {latex_template}") # 使用pandoc直接将markdown转换为pdf cmd = [ PANDOC_PATH, markdown_file, '-o', output_pdf, '--pdf-engine=xelatex', f'--template={latex_template}', '--listings', '--highlight-style=tango', '--verbose' ] print(f"\n执行转换命令: {' '.join(cmd)}") # 使用utf-8编码执行命令 result = subprocess.run(cmd, capture_output=True, text=True, encoding='utf-8') print(f"命令输出: {result.stdout}") if result.stderr: print(f"命令警告: {result.stderr}") # 检查PDF是否生成 if os.path.exists(output_pdf): print(f"PDF文件已成功生成: {output_pdf}") return output_pdf else: raise Exception(f"PDF文件未生成: {output_pdf}") except subprocess.CalledProcessError as e: print(f"命令执行错误: {e}") print(f"错误输出: {e.output if hasattr(e, 'output') else '无输出'}") raise Exception(f"转换过程中出错: {str(e)}") except Exception as e: print(f"发生错误: {str(e)}") raise Exception(f"发生未知错误: {str(e)}") finally: # 清理临时文件 if os.path.exists(latex_template): try: os.remove(latex_template) print(f"已删除临时模板文件: {latex_template}") except Exception as e: print(f"删除临时文件时出错: {str(e)}") if __name__ == "__main__": # 使用示例 try: # 获取当前脚本所在目录 current_dir = os.path.dirname(os.path.abspath(__file__)) print(f"当前工作目录: {current_dir}") # 示例:转换当前目录下的test.md文件 input_file = os.path.join(current_dir, "test.md") # 转换为DOCX docx_file = os.path.join(current_dir, "output.docx") print(f"\n开始转换为DOCX...") docx_path = markdown_to_docx(input_file, docx_file) print(f"DOCX转换成功!") print(f"DOCX文件已保存至: {docx_path}") # 转换为PDF pdf_file = os.path.join(current_dir, "output.pdf") print(f"\n开始转换为PDF...") pdf_path = markdown_to_pdf(input_file, pdf_file) print(f"PDF转换成功!") print(f"PDF文件已保存至: {pdf_path}") except Exception as e: print(f"转换失败: {str(e)}")