马一丁

Fix the Issue Where Dependencies for PDF Generation are Installed but not Recogn…

…ized by the Program (Perhaps?)
@@ -396,10 +396,14 @@ uv venv --python 3.11 # Create Python 3.11 environment @@ -396,10 +396,14 @@ uv venv --python 3.11 # Create Python 3.11 environment
396 brew install pango gdk-pixbuf libffi 396 brew install pango gdk-pixbuf libffi
397 397
398 # 2. Set environment variable (required) 398 # 2. Set environment variable (required)
  399 +# Apple Silicon
399 export DYLD_LIBRARY_PATH=/opt/homebrew/lib:$DYLD_LIBRARY_PATH 400 export DYLD_LIBRARY_PATH=/opt/homebrew/lib:$DYLD_LIBRARY_PATH
  401 +# Intel Mac
  402 +export DYLD_LIBRARY_PATH=/usr/local/lib:$DYLD_LIBRARY_PATH
400 403
401 # Or permanently add to ~/.zshrc 404 # Or permanently add to ~/.zshrc
402 echo 'export DYLD_LIBRARY_PATH=/opt/homebrew/lib:$DYLD_LIBRARY_PATH' >> ~/.zshrc 405 echo 'export DYLD_LIBRARY_PATH=/opt/homebrew/lib:$DYLD_LIBRARY_PATH' >> ~/.zshrc
  406 +# Intel users: echo 'export DYLD_LIBRARY_PATH=/usr/local/lib:$DYLD_LIBRARY_PATH' >> ~/.zshrc
403 source ~/.zshrc 407 source ~/.zshrc
404 ``` 408 ```
405 409
@@ -439,7 +443,18 @@ sudo yum install -y pango gdk-pixbuf2 libffi-devel cairo @@ -439,7 +443,18 @@ sudo yum install -y pango gdk-pixbuf2 libffi-devel cairo
439 # Visit: https://github.com/tschoonj/GTK-for-Windows-Runtime-Environment-Installer/releases 443 # Visit: https://github.com/tschoonj/GTK-for-Windows-Runtime-Environment-Installer/releases
440 # Download the latest .exe file and install 444 # Download the latest .exe file and install
441 445
442 -# 2. Restart command line or IDE 446 +# 2. Add the GTK installation bin directory to PATH (open a new terminal afterwards)
  447 +# Default path example (replace with your custom install path if different)
  448 +set PATH=C:\Program Files\GTK3-Runtime Win64\bin;%PATH%
  449 +
  450 +# Optional: persist the setting
  451 +setx PATH "C:\Program Files\GTK3-Runtime Win64\bin;%PATH%"
  452 +
  453 +# If installed to a custom path, replace with your actual path, or set GTK_BIN_PATH=<your-bin-path>, then reopen the terminal
  454 +
  455 +# 3. Verify in a new terminal
  456 +python -m ReportEngine.utils.dependency_check
  457 +# You should see “✓ Pango dependency check passed”
443 ``` 458 ```
444 459
445 </details> 460 </details>
@@ -389,7 +389,7 @@ conda activate your_conda_name @@ -389,7 +389,7 @@ conda activate your_conda_name
389 uv venv --python 3.11 # 创建3.11环境 389 uv venv --python 3.11 # 创建3.11环境
390 ``` 390 ```
391 391
392 -### 3. 安装 PDF 导出所需系统依赖(可选) 392 +### 2. 安装 PDF 导出所需系统依赖(可选)
393 393
394 > ⚠️ **注意**:如果您需要使用 PDF 导出功能,请按照以下步骤安装系统依赖。如果不需要 PDF 导出功能,可以跳过此步骤,系统其他功能不受影响。 394 > ⚠️ **注意**:如果您需要使用 PDF 导出功能,请按照以下步骤安装系统依赖。如果不需要 PDF 导出功能,可以跳过此步骤,系统其他功能不受影响。
395 395
@@ -404,10 +404,15 @@ brew install pango gdk-pixbuf libffi @@ -404,10 +404,15 @@ brew install pango gdk-pixbuf libffi
404 404
405 # 步骤 2: 设置环境变量(⚠️ 必须执行!) 405 # 步骤 2: 设置环境变量(⚠️ 必须执行!)
406 # 方法一:临时设置(仅当前终端会话有效) 406 # 方法一:临时设置(仅当前终端会话有效)
  407 +# Apple Silicon
407 export DYLD_LIBRARY_PATH=/opt/homebrew/lib:$DYLD_LIBRARY_PATH 408 export DYLD_LIBRARY_PATH=/opt/homebrew/lib:$DYLD_LIBRARY_PATH
  409 +# Intel Mac
  410 +export DYLD_LIBRARY_PATH=/usr/local/lib:$DYLD_LIBRARY_PATH
408 411
409 # 方法二:永久设置(推荐) 412 # 方法二:永久设置(推荐)
410 echo 'export DYLD_LIBRARY_PATH=/opt/homebrew/lib:$DYLD_LIBRARY_PATH' >> ~/.zshrc 413 echo 'export DYLD_LIBRARY_PATH=/opt/homebrew/lib:$DYLD_LIBRARY_PATH' >> ~/.zshrc
  414 +# Intel 用户请改为:
  415 +# echo 'export DYLD_LIBRARY_PATH=/usr/local/lib:$DYLD_LIBRARY_PATH' >> ~/.zshrc
411 source ~/.zshrc 416 source ~/.zshrc
412 ``` 417 ```
413 418
@@ -462,7 +467,18 @@ sudo yum install -y pango gdk-pixbuf2 libffi-devel cairo @@ -462,7 +467,18 @@ sudo yum install -y pango gdk-pixbuf2 libffi-devel cairo
462 # 访问:https://github.com/tschoonj/GTK-for-Windows-Runtime-Environment-Installer/releases 467 # 访问:https://github.com/tschoonj/GTK-for-Windows-Runtime-Environment-Installer/releases
463 # 下载最新版本的 .exe 文件并安装 468 # 下载最新版本的 .exe 文件并安装
464 469
465 -# 2. 重启命令行或 IDE 470 +# 2. 将 GTK 安装目录下的 bin 添加到 PATH(安装后请重新打开终端)
  471 +# 默认路径示例(如果安装在其他目录,请替换成你的实际路径)
  472 +set PATH=C:\Program Files\GTK3-Runtime Win64\bin;%PATH%
  473 +
  474 +# 可选:永久添加到 PATH
  475 +setx PATH "C:\Program Files\GTK3-Runtime Win64\bin;%PATH%"
  476 +
  477 +# 如果安装在自定义目录,请替换为实际路径,或设置环境变量 GTK_BIN_PATH=你的bin路径,再重新打开终端
  478 +
  479 +# 3. 验证(新终端执行)
  480 +python -m ReportEngine.utils.dependency_check
  481 +# 输出包含 “✓ Pango 依赖检测通过” 表示配置正确
466 ``` 482 ```
467 483
468 </details> 484 </details>
@@ -1191,8 +1191,8 @@ def export_pdf(task_id: str): @@ -1191,8 +1191,8 @@ def export_pdf(task_id: str):
1191 return jsonify({ 1191 return jsonify({
1192 'success': False, 1192 'success': False,
1193 'error': 'PDF 导出功能不可用:缺少系统依赖', 1193 'error': 'PDF 导出功能不可用:缺少系统依赖',
1194 - 'details': '请查看根目录 README.md 第393行「PDF 导出依赖」部分了解如何安装依赖',  
1195 - 'help_url': 'https://github.com/666ghj/BettaFish#3-安装-pdf-导出所需系统依赖可选', 1194 + 'details': '请查看根目录 README.md “源码启动”的第二步(PDF 导出依赖)了解安装方法',
  1195 + 'help_url': 'https://github.com/666ghj/BettaFish#2-安装-pdf-导出所需系统依赖可选',
1196 'system_message': pango_message 1196 'system_message': pango_message
1197 }), 503 1197 }), 503
1198 1198
@@ -1280,8 +1280,8 @@ def export_pdf_from_ir(): @@ -1280,8 +1280,8 @@ def export_pdf_from_ir():
1280 return jsonify({ 1280 return jsonify({
1281 'success': False, 1281 'success': False,
1282 'error': 'PDF 导出功能不可用:缺少系统依赖', 1282 'error': 'PDF 导出功能不可用:缺少系统依赖',
1283 - 'details': '请查看根目录 README.md 第393行「PDF 导出依赖」部分了解如何安装依赖',  
1284 - 'help_url': 'https://github.com/666ghj/BettaFish#3-安装-pdf-导出所需系统依赖可选', 1283 + 'details': '请查看根目录 README.md “源码启动”的第二步(PDF 导出依赖)了解安装方法',
  1284 + 'help_url': 'https://github.com/666ghj/BettaFish#2-安装-pdf-导出所需系统依赖可选',
1285 'system_message': pango_message 1285 'system_message': pango_message
1286 }), 503 1286 }), 503
1287 1287
@@ -13,33 +13,57 @@ from pathlib import Path @@ -13,33 +13,57 @@ from pathlib import Path
13 from typing import Any, Dict 13 from typing import Any, Dict
14 from datetime import datetime 14 from datetime import datetime
15 from loguru import logger 15 from loguru import logger
  16 +from ReportEngine.utils.dependency_check import (
  17 + prepare_pango_environment,
  18 + check_pango_available,
  19 +)
16 20
17 # 在导入WeasyPrint之前,尝试补充常见的macOS Homebrew动态库路径, 21 # 在导入WeasyPrint之前,尝试补充常见的macOS Homebrew动态库路径,
18 # 避免因未设置DYLD_LIBRARY_PATH而找不到pango/cairo等依赖。 22 # 避免因未设置DYLD_LIBRARY_PATH而找不到pango/cairo等依赖。
19 if sys.platform == 'darwin': 23 if sys.platform == 'darwin':
20 - brew_lib = Path('/opt/homebrew/lib')  
21 - if brew_lib.exists():  
22 - current = os.environ.get('DYLD_LIBRARY_PATH', '')  
23 - if str(brew_lib) not in current.split(':'):  
24 - os.environ['DYLD_LIBRARY_PATH'] = f"{brew_lib}{':' + current if current else ''}" 24 + mac_libs = [Path('/opt/homebrew/lib'), Path('/usr/local/lib')]
  25 + current = os.environ.get('DYLD_LIBRARY_PATH', '')
  26 + inserts = []
  27 + for lib in mac_libs:
  28 + if lib.exists() and str(lib) not in current.split(':'):
  29 + inserts.append(str(lib))
  30 + if inserts:
  31 + os.environ['DYLD_LIBRARY_PATH'] = ":".join(inserts + ([current] if current else []))
  32 +
  33 +# Windows: 自动补充常见 GTK/Pango 运行时路径,避免 DLL 加载失败
  34 +if sys.platform.startswith('win'):
  35 + added = prepare_pango_environment()
  36 + if added:
  37 + logger.debug(f"已自动添加 GTK 运行时路径: {added}")
25 38
26 try: 39 try:
27 from weasyprint import HTML, CSS 40 from weasyprint import HTML, CSS
28 from weasyprint.text.fonts import FontConfiguration 41 from weasyprint.text.fonts import FontConfiguration
29 WEASYPRINT_AVAILABLE = True 42 WEASYPRINT_AVAILABLE = True
  43 + PDF_DEP_STATUS = "OK"
30 except (ImportError, OSError) as e: 44 except (ImportError, OSError) as e:
31 WEASYPRINT_AVAILABLE = False 45 WEASYPRINT_AVAILABLE = False
32 - # 判断错误类型以提供更友好的提示 46 + # 判断错误类型以提供更友好的提示,并尝试输出缺失依赖的详细信息
  47 + try:
  48 + _, dep_message = check_pango_available()
  49 + except Exception:
  50 + dep_message = None
  51 +
33 if isinstance(e, OSError): 52 if isinstance(e, OSError):
34 - logger.warning( 53 + msg = dep_message or (
35 "PDF 导出依赖缺失(系统库未安装或环境变量未设置)," 54 "PDF 导出依赖缺失(系统库未安装或环境变量未设置),"
36 "PDF 导出功能将不可用。其他功能不受影响。" 55 "PDF 导出功能将不可用。其他功能不受影响。"
37 ) 56 )
  57 + logger.warning(msg)
  58 + PDF_DEP_STATUS = msg
38 else: 59 else:
39 - logger.warning("WeasyPrint未安装,PDF导出功能将不可用") 60 + msg = dep_message or "WeasyPrint未安装,PDF导出功能将不可用"
  61 + logger.warning(msg)
  62 + PDF_DEP_STATUS = msg
40 except Exception as e: 63 except Exception as e:
41 WEASYPRINT_AVAILABLE = False 64 WEASYPRINT_AVAILABLE = False
42 - logger.warning(f"WeasyPrint 加载失败: {e},PDF导出功能将不可用") 65 + PDF_DEP_STATUS = f"WeasyPrint 加载失败: {e},PDF导出功能将不可用"
  66 + logger.warning(PDF_DEP_STATUS)
43 67
44 from .html_renderer import HTMLRenderer 68 from .html_renderer import HTMLRenderer
45 from .pdf_layout_optimizer import PDFLayoutOptimizer, PDFLayoutConfig 69 from .pdf_layout_optimizer import PDFLayoutOptimizer, PDFLayoutConfig
@@ -73,7 +97,11 @@ class PDFRenderer: @@ -73,7 +97,11 @@ class PDFRenderer:
73 self.layout_optimizer = layout_optimizer or PDFLayoutOptimizer() 97 self.layout_optimizer = layout_optimizer or PDFLayoutOptimizer()
74 98
75 if not WEASYPRINT_AVAILABLE: 99 if not WEASYPRINT_AVAILABLE:
76 - raise RuntimeError("WeasyPrint未安装,请运行: pip install weasyprint") 100 + raise RuntimeError(
  101 + PDF_DEP_STATUS
  102 + if 'PDF_DEP_STATUS' in globals() else
  103 + "WeasyPrint未安装,请运行: pip install weasyprint"
  104 + )
77 105
78 # 初始化图表转换器 106 # 初始化图表转换器
79 try: 107 try:
@@ -2,9 +2,12 @@ @@ -2,9 +2,12 @@
2 检测系统依赖工具 2 检测系统依赖工具
3 用于检测 PDF 生成所需的系统依赖 3 用于检测 PDF 生成所需的系统依赖
4 """ 4 """
  5 +import os
5 import sys 6 import sys
6 import platform 7 import platform
  8 +from pathlib import Path
7 from loguru import logger 9 from loguru import logger
  10 +from ctypes import util as ctypes_util
8 11
9 12
10 def _get_platform_specific_instructions(): 13 def _get_platform_specific_instructions():
@@ -24,10 +27,12 @@ def _get_platform_specific_instructions(): @@ -24,10 +27,12 @@ def _get_platform_specific_instructions():
24 "║ brew install pango gdk-pixbuf libffi ║\n" 27 "║ brew install pango gdk-pixbuf libffi ║\n"
25 "║ ║\n" 28 "║ ║\n"
26 "║ 2. 设置环境变量(重要!): ║\n" 29 "║ 2. 设置环境变量(重要!): ║\n"
27 - "║ export DYLD_LIBRARY_PATH=/opt/homebrew/lib:$DYLD_LIBRARY_PATH ║\n" 30 + "║ Apple Silicon: export DYLD_LIBRARY_PATH=/opt/homebrew/lib:$DYLD_LIBRARY_PATH ║\n"
  31 + "║ Intel Mac: export DYLD_LIBRARY_PATH=/usr/local/lib:$DYLD_LIBRARY_PATH ║\n"
28 "║ ║\n" 32 "║ ║\n"
29 "║ 3. 永久生效(推荐): ║\n" 33 "║ 3. 永久生效(推荐): ║\n"
30 "║ echo 'export DYLD_LIBRARY_PATH=/opt/homebrew/lib:$DYLD_LIBRARY_PATH' >> ~/.zshrc ║\n" 34 "║ echo 'export DYLD_LIBRARY_PATH=/opt/homebrew/lib:$DYLD_LIBRARY_PATH' >> ~/.zshrc ║\n"
  35 + "║ 或 echo 'export DYLD_LIBRARY_PATH=/usr/local/lib:$DYLD_LIBRARY_PATH' >> ~/.zshrc ║\n"
31 "║ source ~/.zshrc ║\n" 36 "║ source ~/.zshrc ║\n"
32 ) 37 )
33 elif system == "Linux": 38 elif system == "Linux":
@@ -40,13 +45,24 @@ def _get_platform_specific_instructions(): @@ -40,13 +45,24 @@ def _get_platform_specific_instructions():
40 "║ ║\n" 45 "║ ║\n"
41 "║ CentOS/RHEL: ║\n" 46 "║ CentOS/RHEL: ║\n"
42 "║ sudo yum install pango gdk-pixbuf2 libffi-devel cairo ║\n" 47 "║ sudo yum install pango gdk-pixbuf2 libffi-devel cairo ║\n"
  48 + "║ ║\n"
  49 + "║ 若仍提示缺库:export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH ║\n"
  50 + "║ sudo ldconfig ║\n"
43 ) 51 )
44 elif system == "Windows": 52 elif system == "Windows":
45 return ( 53 return (
46 "║ 🪟 Windows 系统解决方案: ║\n" 54 "║ 🪟 Windows 系统解决方案: ║\n"
47 "║ ║\n" 55 "║ ║\n"
48 - "║ 下载并安装 GTK3 Runtime: ║\n"  
49 - "║ https://github.com/tschoonj/GTK-for-Windows-Runtime-Environment-Installer/releases ║\n" 56 + "║ 1. 安装 GTK3 Runtime: ║\n"
  57 + "║ https://github.com/tschoonj/GTK-for-Windows-Runtime-Environment-Installer/releases ║\n"
  58 + "║ ║\n"
  59 + "║ 2. 将 GTK 安装目录下的 bin 加入 PATH(需新开终端): ║\n"
  60 + "║ set PATH=C:\\Program Files\\GTK3-Runtime Win64\\bin;%PATH% \n"
  61 + "║ (若自定义路径,请替换为实际安装路径) ║\n"
  62 + "║ ║\n"
  63 + "║ 3. 验证:在新终端运行 ║\n"
  64 + "║ python -m ReportEngine.utils.dependency_check ║\n"
  65 + "║ 看到 ✓ 提示即表示 PDF 导出可用 ║\n"
50 ) 66 )
51 else: 67 else:
52 return ( 68 return (
@@ -54,6 +70,158 @@ def _get_platform_specific_instructions(): @@ -54,6 +70,158 @@ def _get_platform_specific_instructions():
54 ) 70 )
55 71
56 72
  73 +def _ensure_windows_gtk_paths():
  74 + """
  75 + 为 Windows 自动补充 GTK/Pango 运行时搜索路径,解决 DLL 未找到问题。
  76 +
  77 + Returns:
  78 + str | None: 成功添加的路径(没有命中则为 None)
  79 + """
  80 + if platform.system() != "Windows":
  81 + return None
  82 +
  83 + candidates = []
  84 + seen = set()
  85 +
  86 + def _add_candidate(path_like):
  87 + if not path_like:
  88 + return
  89 + p = Path(path_like)
  90 + # 如果传入的是安装根目录,尝试拼接 bin
  91 + if p.is_dir() and p.name.lower() == "bin":
  92 + key = str(p.resolve()).lower()
  93 + if key not in seen:
  94 + seen.add(key)
  95 + candidates.append(p)
  96 + else:
  97 + for maybe in (p, p / "bin"):
  98 + key = str(maybe.resolve()).lower()
  99 + if maybe.exists() and key not in seen:
  100 + seen.add(key)
  101 + candidates.append(maybe)
  102 +
  103 + # 用户自定义提示优先
  104 + for env_var in ("GTK3_RUNTIME_PATH", "GTK_RUNTIME_PATH", "GTK_BIN_PATH", "GTK_BIN_DIR", "GTK_PATH"):
  105 + _add_candidate(os.environ.get(env_var))
  106 +
  107 + program_files = os.environ.get("ProgramFiles", r"C:\\Program Files")
  108 + program_files_x86 = os.environ.get("ProgramFiles(x86)", r"C:\\Program Files (x86)")
  109 + default_dirs = [
  110 + Path(program_files) / "GTK3-Runtime Win64",
  111 + Path(program_files_x86) / "GTK3-Runtime Win64",
  112 + Path(program_files) / "GTK3-Runtime Win32",
  113 + Path(program_files_x86) / "GTK3-Runtime Win32",
  114 + Path(program_files) / "GTK3-Runtime",
  115 + Path(program_files_x86) / "GTK3-Runtime",
  116 + ]
  117 +
  118 + # 常见自定义安装位置(其他盘符 / DevelopSoftware 目录)
  119 + common_drives = ["C", "D", "E", "F"]
  120 + common_names = ["GTK3-Runtime Win64", "GTK3-Runtime Win32", "GTK3-Runtime"]
  121 + for drive in common_drives:
  122 + root = Path(f"{drive}:/")
  123 + for name in common_names:
  124 + default_dirs.append(root / name)
  125 + default_dirs.append(root / "DevelopSoftware" / name)
  126 +
  127 + # 扫描 Program Files 下所有以 GTK 开头的目录,适配自定义安装目录名
  128 + for root in (program_files, program_files_x86):
  129 + root_path = Path(root)
  130 + if root_path.exists():
  131 + for child in root_path.glob("GTK*"):
  132 + default_dirs.append(child)
  133 +
  134 + for d in default_dirs:
  135 + _add_candidate(d)
  136 +
  137 + # 如果用户已把自定义路径加入 PATH,也尝试识别
  138 + path_entries = os.environ.get("PATH", "").split(os.pathsep)
  139 + for entry in path_entries:
  140 + if not entry:
  141 + continue
  142 + # 粗筛包含 gtk 或 pango 的目录
  143 + if "gtk" in entry.lower() or "pango" in entry.lower():
  144 + _add_candidate(entry)
  145 +
  146 + for path in candidates:
  147 + if not path or not path.exists():
  148 + continue
  149 + if not any(path.glob("pango*-1.0-*.dll")) and not (path / "pango-1.0-0.dll").exists():
  150 + continue
  151 +
  152 + try:
  153 + if hasattr(os, "add_dll_directory"):
  154 + os.add_dll_directory(str(path))
  155 + except Exception:
  156 + # 如果添加失败,继续尝试 PATH 方式
  157 + pass
  158 +
  159 + current_path = os.environ.get("PATH", "")
  160 + if str(path) not in current_path.split(";"):
  161 + os.environ["PATH"] = f"{path};{current_path}"
  162 +
  163 + return str(path)
  164 +
  165 + return None
  166 +
  167 +
  168 +def prepare_pango_environment():
  169 + """
  170 + 初始化运行所需的本地依赖搜索路径(当前主要针对 Windows 和 macOS)。
  171 +
  172 + Returns:
  173 + str | None: 成功添加的路径(没有命中则为 None)
  174 + """
  175 + system = platform.system()
  176 + if system == "Windows":
  177 + return _ensure_windows_gtk_paths()
  178 + if system == "Darwin":
  179 + # 自动补全 DYLD_LIBRARY_PATH,兼容 Apple Silicon 与 Intel
  180 + candidates = [Path("/opt/homebrew/lib"), Path("/usr/local/lib")]
  181 + current = os.environ.get("DYLD_LIBRARY_PATH", "")
  182 + added = []
  183 + for c in candidates:
  184 + if c.exists() and str(c) not in current.split(":"):
  185 + added.append(str(c))
  186 + if added:
  187 + os.environ["DYLD_LIBRARY_PATH"] = ":".join(added + ([current] if current else []))
  188 + return os.environ["DYLD_LIBRARY_PATH"]
  189 + return None
  190 +
  191 +
  192 +def _probe_native_libs():
  193 + """
  194 + 使用 ctypes 查找关键原生库,帮助定位缺失组件。
  195 +
  196 + Returns:
  197 + list[str]: 未找到的库标识
  198 + """
  199 + system = platform.system()
  200 + targets = []
  201 +
  202 + if system == "Windows":
  203 + targets = [
  204 + ("pango", ["pango-1.0-0"]),
  205 + ("gobject", ["gobject-2.0-0"]),
  206 + ("gdk-pixbuf", ["gdk_pixbuf-2.0-0"]),
  207 + ("cairo", ["cairo-2"]),
  208 + ]
  209 + else:
  210 + targets = [
  211 + ("pango", ["pango-1.0"]),
  212 + ("gobject", ["gobject-2.0"]),
  213 + ("gdk-pixbuf", ["gdk_pixbuf-2.0"]),
  214 + ("cairo", ["cairo", "cairo-2"]),
  215 + ]
  216 +
  217 + missing = []
  218 + for key, variants in targets:
  219 + found = any(ctypes_util.find_library(v) for v in variants)
  220 + if not found:
  221 + missing.append(key)
  222 + return missing
  223 +
  224 +
57 def check_pango_available(): 225 def check_pango_available():
58 """ 226 """
59 检测 Pango 库是否可用 227 检测 Pango 库是否可用
@@ -61,6 +229,9 @@ def check_pango_available(): @@ -61,6 +229,9 @@ def check_pango_available():
61 Returns: 229 Returns:
62 tuple: (is_available: bool, message: str) 230 tuple: (is_available: bool, message: str)
63 """ 231 """
  232 + added_path = prepare_pango_environment()
  233 + missing_native = _probe_native_libs()
  234 +
64 try: 235 try:
65 # 尝试导入 weasyprint 并初始化 Pango 236 # 尝试导入 weasyprint 并初始化 Pango
66 from weasyprint import HTML 237 from weasyprint import HTML
@@ -74,6 +245,21 @@ def check_pango_available(): @@ -74,6 +245,21 @@ def check_pango_available():
74 # Pango 库未安装或无法加载 245 # Pango 库未安装或无法加载
75 error_msg = str(e) 246 error_msg = str(e)
76 platform_instructions = _get_platform_specific_instructions() 247 platform_instructions = _get_platform_specific_instructions()
  248 + windows_hint = ""
  249 + if platform.system() == "Windows":
  250 + path_display = added_path or "未找到默认路径"
  251 + # 控制长度,避免破坏提示框宽度
  252 + if len(path_display) > 38:
  253 + path_display = path_display[:35] + "..."
  254 + windows_hint = f"║ 已尝试自动添加 GTK 路径: {path_display:<38}║\n"
  255 + arch_note = "║ 🔍 若已安装仍报错:确认 Python/GTK 位数一致,重开终端 ║\n"
  256 + else:
  257 + arch_note = ""
  258 +
  259 + missing_note = ""
  260 + if missing_native:
  261 + missing_str = ", ".join(missing_native)
  262 + missing_note = f"║ 未识别到的依赖: {missing_str:<46}║\n"
77 263
78 if 'gobject' in error_msg.lower() or 'pango' in error_msg.lower() or 'gdk' in error_msg.lower(): 264 if 'gobject' in error_msg.lower() or 'pango' in error_msg.lower() or 'gdk' in error_msg.lower():
79 return False, ( 265 return False, (
@@ -82,12 +268,15 @@ def check_pango_available(): @@ -82,12 +268,15 @@ def check_pango_available():
82 "║ ║\n" 268 "║ ║\n"
83 "║ 📄 PDF 导出功能将不可用(其他功能不受影响) ║\n" 269 "║ 📄 PDF 导出功能将不可用(其他功能不受影响) ║\n"
84 "║ ║\n" 270 "║ ║\n"
  271 + f"{windows_hint}"
  272 + f"{arch_note}"
  273 + f"{missing_note}"
85 f"{platform_instructions}" 274 f"{platform_instructions}"
86 "║ ║\n" 275 "║ ║\n"
87 - "║ 📖 完整文档:根目录 README.md 第393行「PDF 导出依赖」\n" 276 + "║ 📖 完整文档:根目录 README.md ‘源码启动’的第二步 \n"
88 "╚════════════════════════════════════════════════════════════════╝" 277 "╚════════════════════════════════════════════════════════════════╝"
89 ) 278 )
90 - return False, f"⚠ PDF 依赖加载失败: {error_msg}" 279 + return False, f"⚠ PDF 依赖加载失败: {error_msg};缺失/未识别: {', '.join(missing_native) if missing_native else '未知'}"
91 except ImportError as e: 280 except ImportError as e:
92 # weasyprint 未安装 281 # weasyprint 未安装
93 return False, ( 282 return False, (