Fix the Issue Where Dependencies for PDF Generation are Installed but not Recognized by the Program (Perhaps?)
This commit is contained in:
+16
-1
@@ -396,10 +396,14 @@ uv venv --python 3.11 # Create Python 3.11 environment
|
|||||||
brew install pango gdk-pixbuf libffi
|
brew install pango gdk-pixbuf libffi
|
||||||
|
|
||||||
# 2. Set environment variable (required)
|
# 2. Set environment variable (required)
|
||||||
|
# Apple Silicon
|
||||||
export DYLD_LIBRARY_PATH=/opt/homebrew/lib:$DYLD_LIBRARY_PATH
|
export DYLD_LIBRARY_PATH=/opt/homebrew/lib:$DYLD_LIBRARY_PATH
|
||||||
|
# Intel Mac
|
||||||
|
export DYLD_LIBRARY_PATH=/usr/local/lib:$DYLD_LIBRARY_PATH
|
||||||
|
|
||||||
# Or permanently add to ~/.zshrc
|
# Or permanently add to ~/.zshrc
|
||||||
echo 'export DYLD_LIBRARY_PATH=/opt/homebrew/lib:$DYLD_LIBRARY_PATH' >> ~/.zshrc
|
echo 'export DYLD_LIBRARY_PATH=/opt/homebrew/lib:$DYLD_LIBRARY_PATH' >> ~/.zshrc
|
||||||
|
# Intel users: echo 'export DYLD_LIBRARY_PATH=/usr/local/lib:$DYLD_LIBRARY_PATH' >> ~/.zshrc
|
||||||
source ~/.zshrc
|
source ~/.zshrc
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -439,7 +443,18 @@ sudo yum install -y pango gdk-pixbuf2 libffi-devel cairo
|
|||||||
# Visit: https://github.com/tschoonj/GTK-for-Windows-Runtime-Environment-Installer/releases
|
# Visit: https://github.com/tschoonj/GTK-for-Windows-Runtime-Environment-Installer/releases
|
||||||
# Download the latest .exe file and install
|
# Download the latest .exe file and install
|
||||||
|
|
||||||
# 2. Restart command line or IDE
|
# 2. Add the GTK installation bin directory to PATH (open a new terminal afterwards)
|
||||||
|
# Default path example (replace with your custom install path if different)
|
||||||
|
set PATH=C:\Program Files\GTK3-Runtime Win64\bin;%PATH%
|
||||||
|
|
||||||
|
# Optional: persist the setting
|
||||||
|
setx PATH "C:\Program Files\GTK3-Runtime Win64\bin;%PATH%"
|
||||||
|
|
||||||
|
# If installed to a custom path, replace with your actual path, or set GTK_BIN_PATH=<your-bin-path>, then reopen the terminal
|
||||||
|
|
||||||
|
# 3. Verify in a new terminal
|
||||||
|
python -m ReportEngine.utils.dependency_check
|
||||||
|
# You should see “✓ Pango dependency check passed”
|
||||||
```
|
```
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|||||||
@@ -389,7 +389,7 @@ conda activate your_conda_name
|
|||||||
uv venv --python 3.11 # 创建3.11环境
|
uv venv --python 3.11 # 创建3.11环境
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3. 安装 PDF 导出所需系统依赖(可选)
|
### 2. 安装 PDF 导出所需系统依赖(可选)
|
||||||
|
|
||||||
> ⚠️ **注意**:如果您需要使用 PDF 导出功能,请按照以下步骤安装系统依赖。如果不需要 PDF 导出功能,可以跳过此步骤,系统其他功能不受影响。
|
> ⚠️ **注意**:如果您需要使用 PDF 导出功能,请按照以下步骤安装系统依赖。如果不需要 PDF 导出功能,可以跳过此步骤,系统其他功能不受影响。
|
||||||
|
|
||||||
@@ -404,10 +404,15 @@ brew install pango gdk-pixbuf libffi
|
|||||||
|
|
||||||
# 步骤 2: 设置环境变量(⚠️ 必须执行!)
|
# 步骤 2: 设置环境变量(⚠️ 必须执行!)
|
||||||
# 方法一:临时设置(仅当前终端会话有效)
|
# 方法一:临时设置(仅当前终端会话有效)
|
||||||
|
# Apple Silicon
|
||||||
export DYLD_LIBRARY_PATH=/opt/homebrew/lib:$DYLD_LIBRARY_PATH
|
export DYLD_LIBRARY_PATH=/opt/homebrew/lib:$DYLD_LIBRARY_PATH
|
||||||
|
# Intel Mac
|
||||||
|
export DYLD_LIBRARY_PATH=/usr/local/lib:$DYLD_LIBRARY_PATH
|
||||||
|
|
||||||
# 方法二:永久设置(推荐)
|
# 方法二:永久设置(推荐)
|
||||||
echo 'export DYLD_LIBRARY_PATH=/opt/homebrew/lib:$DYLD_LIBRARY_PATH' >> ~/.zshrc
|
echo 'export DYLD_LIBRARY_PATH=/opt/homebrew/lib:$DYLD_LIBRARY_PATH' >> ~/.zshrc
|
||||||
|
# Intel 用户请改为:
|
||||||
|
# echo 'export DYLD_LIBRARY_PATH=/usr/local/lib:$DYLD_LIBRARY_PATH' >> ~/.zshrc
|
||||||
source ~/.zshrc
|
source ~/.zshrc
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -462,7 +467,18 @@ sudo yum install -y pango gdk-pixbuf2 libffi-devel cairo
|
|||||||
# 访问:https://github.com/tschoonj/GTK-for-Windows-Runtime-Environment-Installer/releases
|
# 访问:https://github.com/tschoonj/GTK-for-Windows-Runtime-Environment-Installer/releases
|
||||||
# 下载最新版本的 .exe 文件并安装
|
# 下载最新版本的 .exe 文件并安装
|
||||||
|
|
||||||
# 2. 重启命令行或 IDE
|
# 2. 将 GTK 安装目录下的 bin 添加到 PATH(安装后请重新打开终端)
|
||||||
|
# 默认路径示例(如果安装在其他目录,请替换成你的实际路径)
|
||||||
|
set PATH=C:\Program Files\GTK3-Runtime Win64\bin;%PATH%
|
||||||
|
|
||||||
|
# 可选:永久添加到 PATH
|
||||||
|
setx PATH "C:\Program Files\GTK3-Runtime Win64\bin;%PATH%"
|
||||||
|
|
||||||
|
# 如果安装在自定义目录,请替换为实际路径,或设置环境变量 GTK_BIN_PATH=你的bin路径,再重新打开终端
|
||||||
|
|
||||||
|
# 3. 验证(新终端执行)
|
||||||
|
python -m ReportEngine.utils.dependency_check
|
||||||
|
# 输出包含 “✓ Pango 依赖检测通过” 表示配置正确
|
||||||
```
|
```
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|||||||
@@ -1191,8 +1191,8 @@ def export_pdf(task_id: str):
|
|||||||
return jsonify({
|
return jsonify({
|
||||||
'success': False,
|
'success': False,
|
||||||
'error': 'PDF 导出功能不可用:缺少系统依赖',
|
'error': 'PDF 导出功能不可用:缺少系统依赖',
|
||||||
'details': '请查看根目录 README.md 第393行「PDF 导出依赖」部分了解如何安装依赖',
|
'details': '请查看根目录 README.md “源码启动”的第二步(PDF 导出依赖)了解安装方法',
|
||||||
'help_url': 'https://github.com/666ghj/BettaFish#3-安装-pdf-导出所需系统依赖可选',
|
'help_url': 'https://github.com/666ghj/BettaFish#2-安装-pdf-导出所需系统依赖可选',
|
||||||
'system_message': pango_message
|
'system_message': pango_message
|
||||||
}), 503
|
}), 503
|
||||||
|
|
||||||
@@ -1280,8 +1280,8 @@ def export_pdf_from_ir():
|
|||||||
return jsonify({
|
return jsonify({
|
||||||
'success': False,
|
'success': False,
|
||||||
'error': 'PDF 导出功能不可用:缺少系统依赖',
|
'error': 'PDF 导出功能不可用:缺少系统依赖',
|
||||||
'details': '请查看根目录 README.md 第393行「PDF 导出依赖」部分了解如何安装依赖',
|
'details': '请查看根目录 README.md “源码启动”的第二步(PDF 导出依赖)了解安装方法',
|
||||||
'help_url': 'https://github.com/666ghj/BettaFish#3-安装-pdf-导出所需系统依赖可选',
|
'help_url': 'https://github.com/666ghj/BettaFish#2-安装-pdf-导出所需系统依赖可选',
|
||||||
'system_message': pango_message
|
'system_message': pango_message
|
||||||
}), 503
|
}), 503
|
||||||
|
|
||||||
|
|||||||
@@ -13,33 +13,57 @@ from pathlib import Path
|
|||||||
from typing import Any, Dict
|
from typing import Any, Dict
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
|
from ReportEngine.utils.dependency_check import (
|
||||||
|
prepare_pango_environment,
|
||||||
|
check_pango_available,
|
||||||
|
)
|
||||||
|
|
||||||
# 在导入WeasyPrint之前,尝试补充常见的macOS Homebrew动态库路径,
|
# 在导入WeasyPrint之前,尝试补充常见的macOS Homebrew动态库路径,
|
||||||
# 避免因未设置DYLD_LIBRARY_PATH而找不到pango/cairo等依赖。
|
# 避免因未设置DYLD_LIBRARY_PATH而找不到pango/cairo等依赖。
|
||||||
if sys.platform == 'darwin':
|
if sys.platform == 'darwin':
|
||||||
brew_lib = Path('/opt/homebrew/lib')
|
mac_libs = [Path('/opt/homebrew/lib'), Path('/usr/local/lib')]
|
||||||
if brew_lib.exists():
|
current = os.environ.get('DYLD_LIBRARY_PATH', '')
|
||||||
current = os.environ.get('DYLD_LIBRARY_PATH', '')
|
inserts = []
|
||||||
if str(brew_lib) not in current.split(':'):
|
for lib in mac_libs:
|
||||||
os.environ['DYLD_LIBRARY_PATH'] = f"{brew_lib}{':' + current if current else ''}"
|
if lib.exists() and str(lib) not in current.split(':'):
|
||||||
|
inserts.append(str(lib))
|
||||||
|
if inserts:
|
||||||
|
os.environ['DYLD_LIBRARY_PATH'] = ":".join(inserts + ([current] if current else []))
|
||||||
|
|
||||||
|
# Windows: 自动补充常见 GTK/Pango 运行时路径,避免 DLL 加载失败
|
||||||
|
if sys.platform.startswith('win'):
|
||||||
|
added = prepare_pango_environment()
|
||||||
|
if added:
|
||||||
|
logger.debug(f"已自动添加 GTK 运行时路径: {added}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from weasyprint import HTML, CSS
|
from weasyprint import HTML, CSS
|
||||||
from weasyprint.text.fonts import FontConfiguration
|
from weasyprint.text.fonts import FontConfiguration
|
||||||
WEASYPRINT_AVAILABLE = True
|
WEASYPRINT_AVAILABLE = True
|
||||||
|
PDF_DEP_STATUS = "OK"
|
||||||
except (ImportError, OSError) as e:
|
except (ImportError, OSError) as e:
|
||||||
WEASYPRINT_AVAILABLE = False
|
WEASYPRINT_AVAILABLE = False
|
||||||
# 判断错误类型以提供更友好的提示
|
# 判断错误类型以提供更友好的提示,并尝试输出缺失依赖的详细信息
|
||||||
|
try:
|
||||||
|
_, dep_message = check_pango_available()
|
||||||
|
except Exception:
|
||||||
|
dep_message = None
|
||||||
|
|
||||||
if isinstance(e, OSError):
|
if isinstance(e, OSError):
|
||||||
logger.warning(
|
msg = dep_message or (
|
||||||
"PDF 导出依赖缺失(系统库未安装或环境变量未设置),"
|
"PDF 导出依赖缺失(系统库未安装或环境变量未设置),"
|
||||||
"PDF 导出功能将不可用。其他功能不受影响。"
|
"PDF 导出功能将不可用。其他功能不受影响。"
|
||||||
)
|
)
|
||||||
|
logger.warning(msg)
|
||||||
|
PDF_DEP_STATUS = msg
|
||||||
else:
|
else:
|
||||||
logger.warning("WeasyPrint未安装,PDF导出功能将不可用")
|
msg = dep_message or "WeasyPrint未安装,PDF导出功能将不可用"
|
||||||
|
logger.warning(msg)
|
||||||
|
PDF_DEP_STATUS = msg
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
WEASYPRINT_AVAILABLE = False
|
WEASYPRINT_AVAILABLE = False
|
||||||
logger.warning(f"WeasyPrint 加载失败: {e},PDF导出功能将不可用")
|
PDF_DEP_STATUS = f"WeasyPrint 加载失败: {e},PDF导出功能将不可用"
|
||||||
|
logger.warning(PDF_DEP_STATUS)
|
||||||
|
|
||||||
from .html_renderer import HTMLRenderer
|
from .html_renderer import HTMLRenderer
|
||||||
from .pdf_layout_optimizer import PDFLayoutOptimizer, PDFLayoutConfig
|
from .pdf_layout_optimizer import PDFLayoutOptimizer, PDFLayoutConfig
|
||||||
@@ -73,7 +97,11 @@ class PDFRenderer:
|
|||||||
self.layout_optimizer = layout_optimizer or PDFLayoutOptimizer()
|
self.layout_optimizer = layout_optimizer or PDFLayoutOptimizer()
|
||||||
|
|
||||||
if not WEASYPRINT_AVAILABLE:
|
if not WEASYPRINT_AVAILABLE:
|
||||||
raise RuntimeError("WeasyPrint未安装,请运行: pip install weasyprint")
|
raise RuntimeError(
|
||||||
|
PDF_DEP_STATUS
|
||||||
|
if 'PDF_DEP_STATUS' in globals() else
|
||||||
|
"WeasyPrint未安装,请运行: pip install weasyprint"
|
||||||
|
)
|
||||||
|
|
||||||
# 初始化图表转换器
|
# 初始化图表转换器
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -2,9 +2,12 @@
|
|||||||
检测系统依赖工具
|
检测系统依赖工具
|
||||||
用于检测 PDF 生成所需的系统依赖
|
用于检测 PDF 生成所需的系统依赖
|
||||||
"""
|
"""
|
||||||
|
import os
|
||||||
import sys
|
import sys
|
||||||
import platform
|
import platform
|
||||||
|
from pathlib import Path
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
|
from ctypes import util as ctypes_util
|
||||||
|
|
||||||
|
|
||||||
def _get_platform_specific_instructions():
|
def _get_platform_specific_instructions():
|
||||||
@@ -24,10 +27,12 @@ def _get_platform_specific_instructions():
|
|||||||
"║ brew install pango gdk-pixbuf libffi ║\n"
|
"║ brew install pango gdk-pixbuf libffi ║\n"
|
||||||
"║ ║\n"
|
"║ ║\n"
|
||||||
"║ 2. 设置环境变量(重要!): ║\n"
|
"║ 2. 设置环境变量(重要!): ║\n"
|
||||||
"║ export DYLD_LIBRARY_PATH=/opt/homebrew/lib:$DYLD_LIBRARY_PATH ║\n"
|
"║ Apple Silicon: export DYLD_LIBRARY_PATH=/opt/homebrew/lib:$DYLD_LIBRARY_PATH ║\n"
|
||||||
|
"║ Intel Mac: export DYLD_LIBRARY_PATH=/usr/local/lib:$DYLD_LIBRARY_PATH ║\n"
|
||||||
"║ ║\n"
|
"║ ║\n"
|
||||||
"║ 3. 永久生效(推荐): ║\n"
|
"║ 3. 永久生效(推荐): ║\n"
|
||||||
"║ echo 'export DYLD_LIBRARY_PATH=/opt/homebrew/lib:$DYLD_LIBRARY_PATH' >> ~/.zshrc ║\n"
|
"║ echo 'export DYLD_LIBRARY_PATH=/opt/homebrew/lib:$DYLD_LIBRARY_PATH' >> ~/.zshrc ║\n"
|
||||||
|
"║ 或 echo 'export DYLD_LIBRARY_PATH=/usr/local/lib:$DYLD_LIBRARY_PATH' >> ~/.zshrc ║\n"
|
||||||
"║ source ~/.zshrc ║\n"
|
"║ source ~/.zshrc ║\n"
|
||||||
)
|
)
|
||||||
elif system == "Linux":
|
elif system == "Linux":
|
||||||
@@ -40,13 +45,24 @@ def _get_platform_specific_instructions():
|
|||||||
"║ ║\n"
|
"║ ║\n"
|
||||||
"║ CentOS/RHEL: ║\n"
|
"║ CentOS/RHEL: ║\n"
|
||||||
"║ sudo yum install pango gdk-pixbuf2 libffi-devel cairo ║\n"
|
"║ sudo yum install pango gdk-pixbuf2 libffi-devel cairo ║\n"
|
||||||
|
"║ ║\n"
|
||||||
|
"║ 若仍提示缺库:export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH ║\n"
|
||||||
|
"║ sudo ldconfig ║\n"
|
||||||
)
|
)
|
||||||
elif system == "Windows":
|
elif system == "Windows":
|
||||||
return (
|
return (
|
||||||
"║ 🪟 Windows 系统解决方案: ║\n"
|
"║ 🪟 Windows 系统解决方案: ║\n"
|
||||||
"║ ║\n"
|
"║ ║\n"
|
||||||
"║ 下载并安装 GTK3 Runtime: ║\n"
|
"║ 1. 安装 GTK3 Runtime: ║\n"
|
||||||
"║ https://github.com/tschoonj/GTK-for-Windows-Runtime-Environment-Installer/releases ║\n"
|
"║ https://github.com/tschoonj/GTK-for-Windows-Runtime-Environment-Installer/releases ║\n"
|
||||||
|
"║ ║\n"
|
||||||
|
"║ 2. 将 GTK 安装目录下的 bin 加入 PATH(需新开终端): ║\n"
|
||||||
|
"║ set PATH=C:\\Program Files\\GTK3-Runtime Win64\\bin;%PATH% ║\n"
|
||||||
|
"║ (若自定义路径,请替换为实际安装路径) ║\n"
|
||||||
|
"║ ║\n"
|
||||||
|
"║ 3. 验证:在新终端运行 ║\n"
|
||||||
|
"║ python -m ReportEngine.utils.dependency_check ║\n"
|
||||||
|
"║ 看到 ✓ 提示即表示 PDF 导出可用 ║\n"
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
return (
|
return (
|
||||||
@@ -54,6 +70,158 @@ def _get_platform_specific_instructions():
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _ensure_windows_gtk_paths():
|
||||||
|
"""
|
||||||
|
为 Windows 自动补充 GTK/Pango 运行时搜索路径,解决 DLL 未找到问题。
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str | None: 成功添加的路径(没有命中则为 None)
|
||||||
|
"""
|
||||||
|
if platform.system() != "Windows":
|
||||||
|
return None
|
||||||
|
|
||||||
|
candidates = []
|
||||||
|
seen = set()
|
||||||
|
|
||||||
|
def _add_candidate(path_like):
|
||||||
|
if not path_like:
|
||||||
|
return
|
||||||
|
p = Path(path_like)
|
||||||
|
# 如果传入的是安装根目录,尝试拼接 bin
|
||||||
|
if p.is_dir() and p.name.lower() == "bin":
|
||||||
|
key = str(p.resolve()).lower()
|
||||||
|
if key not in seen:
|
||||||
|
seen.add(key)
|
||||||
|
candidates.append(p)
|
||||||
|
else:
|
||||||
|
for maybe in (p, p / "bin"):
|
||||||
|
key = str(maybe.resolve()).lower()
|
||||||
|
if maybe.exists() and key not in seen:
|
||||||
|
seen.add(key)
|
||||||
|
candidates.append(maybe)
|
||||||
|
|
||||||
|
# 用户自定义提示优先
|
||||||
|
for env_var in ("GTK3_RUNTIME_PATH", "GTK_RUNTIME_PATH", "GTK_BIN_PATH", "GTK_BIN_DIR", "GTK_PATH"):
|
||||||
|
_add_candidate(os.environ.get(env_var))
|
||||||
|
|
||||||
|
program_files = os.environ.get("ProgramFiles", r"C:\\Program Files")
|
||||||
|
program_files_x86 = os.environ.get("ProgramFiles(x86)", r"C:\\Program Files (x86)")
|
||||||
|
default_dirs = [
|
||||||
|
Path(program_files) / "GTK3-Runtime Win64",
|
||||||
|
Path(program_files_x86) / "GTK3-Runtime Win64",
|
||||||
|
Path(program_files) / "GTK3-Runtime Win32",
|
||||||
|
Path(program_files_x86) / "GTK3-Runtime Win32",
|
||||||
|
Path(program_files) / "GTK3-Runtime",
|
||||||
|
Path(program_files_x86) / "GTK3-Runtime",
|
||||||
|
]
|
||||||
|
|
||||||
|
# 常见自定义安装位置(其他盘符 / DevelopSoftware 目录)
|
||||||
|
common_drives = ["C", "D", "E", "F"]
|
||||||
|
common_names = ["GTK3-Runtime Win64", "GTK3-Runtime Win32", "GTK3-Runtime"]
|
||||||
|
for drive in common_drives:
|
||||||
|
root = Path(f"{drive}:/")
|
||||||
|
for name in common_names:
|
||||||
|
default_dirs.append(root / name)
|
||||||
|
default_dirs.append(root / "DevelopSoftware" / name)
|
||||||
|
|
||||||
|
# 扫描 Program Files 下所有以 GTK 开头的目录,适配自定义安装目录名
|
||||||
|
for root in (program_files, program_files_x86):
|
||||||
|
root_path = Path(root)
|
||||||
|
if root_path.exists():
|
||||||
|
for child in root_path.glob("GTK*"):
|
||||||
|
default_dirs.append(child)
|
||||||
|
|
||||||
|
for d in default_dirs:
|
||||||
|
_add_candidate(d)
|
||||||
|
|
||||||
|
# 如果用户已把自定义路径加入 PATH,也尝试识别
|
||||||
|
path_entries = os.environ.get("PATH", "").split(os.pathsep)
|
||||||
|
for entry in path_entries:
|
||||||
|
if not entry:
|
||||||
|
continue
|
||||||
|
# 粗筛包含 gtk 或 pango 的目录
|
||||||
|
if "gtk" in entry.lower() or "pango" in entry.lower():
|
||||||
|
_add_candidate(entry)
|
||||||
|
|
||||||
|
for path in candidates:
|
||||||
|
if not path or not path.exists():
|
||||||
|
continue
|
||||||
|
if not any(path.glob("pango*-1.0-*.dll")) and not (path / "pango-1.0-0.dll").exists():
|
||||||
|
continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
if hasattr(os, "add_dll_directory"):
|
||||||
|
os.add_dll_directory(str(path))
|
||||||
|
except Exception:
|
||||||
|
# 如果添加失败,继续尝试 PATH 方式
|
||||||
|
pass
|
||||||
|
|
||||||
|
current_path = os.environ.get("PATH", "")
|
||||||
|
if str(path) not in current_path.split(";"):
|
||||||
|
os.environ["PATH"] = f"{path};{current_path}"
|
||||||
|
|
||||||
|
return str(path)
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def prepare_pango_environment():
|
||||||
|
"""
|
||||||
|
初始化运行所需的本地依赖搜索路径(当前主要针对 Windows 和 macOS)。
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str | None: 成功添加的路径(没有命中则为 None)
|
||||||
|
"""
|
||||||
|
system = platform.system()
|
||||||
|
if system == "Windows":
|
||||||
|
return _ensure_windows_gtk_paths()
|
||||||
|
if system == "Darwin":
|
||||||
|
# 自动补全 DYLD_LIBRARY_PATH,兼容 Apple Silicon 与 Intel
|
||||||
|
candidates = [Path("/opt/homebrew/lib"), Path("/usr/local/lib")]
|
||||||
|
current = os.environ.get("DYLD_LIBRARY_PATH", "")
|
||||||
|
added = []
|
||||||
|
for c in candidates:
|
||||||
|
if c.exists() and str(c) not in current.split(":"):
|
||||||
|
added.append(str(c))
|
||||||
|
if added:
|
||||||
|
os.environ["DYLD_LIBRARY_PATH"] = ":".join(added + ([current] if current else []))
|
||||||
|
return os.environ["DYLD_LIBRARY_PATH"]
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def _probe_native_libs():
|
||||||
|
"""
|
||||||
|
使用 ctypes 查找关键原生库,帮助定位缺失组件。
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list[str]: 未找到的库标识
|
||||||
|
"""
|
||||||
|
system = platform.system()
|
||||||
|
targets = []
|
||||||
|
|
||||||
|
if system == "Windows":
|
||||||
|
targets = [
|
||||||
|
("pango", ["pango-1.0-0"]),
|
||||||
|
("gobject", ["gobject-2.0-0"]),
|
||||||
|
("gdk-pixbuf", ["gdk_pixbuf-2.0-0"]),
|
||||||
|
("cairo", ["cairo-2"]),
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
targets = [
|
||||||
|
("pango", ["pango-1.0"]),
|
||||||
|
("gobject", ["gobject-2.0"]),
|
||||||
|
("gdk-pixbuf", ["gdk_pixbuf-2.0"]),
|
||||||
|
("cairo", ["cairo", "cairo-2"]),
|
||||||
|
]
|
||||||
|
|
||||||
|
missing = []
|
||||||
|
for key, variants in targets:
|
||||||
|
found = any(ctypes_util.find_library(v) for v in variants)
|
||||||
|
if not found:
|
||||||
|
missing.append(key)
|
||||||
|
return missing
|
||||||
|
|
||||||
|
|
||||||
def check_pango_available():
|
def check_pango_available():
|
||||||
"""
|
"""
|
||||||
检测 Pango 库是否可用
|
检测 Pango 库是否可用
|
||||||
@@ -61,6 +229,9 @@ def check_pango_available():
|
|||||||
Returns:
|
Returns:
|
||||||
tuple: (is_available: bool, message: str)
|
tuple: (is_available: bool, message: str)
|
||||||
"""
|
"""
|
||||||
|
added_path = prepare_pango_environment()
|
||||||
|
missing_native = _probe_native_libs()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# 尝试导入 weasyprint 并初始化 Pango
|
# 尝试导入 weasyprint 并初始化 Pango
|
||||||
from weasyprint import HTML
|
from weasyprint import HTML
|
||||||
@@ -74,6 +245,21 @@ def check_pango_available():
|
|||||||
# Pango 库未安装或无法加载
|
# Pango 库未安装或无法加载
|
||||||
error_msg = str(e)
|
error_msg = str(e)
|
||||||
platform_instructions = _get_platform_specific_instructions()
|
platform_instructions = _get_platform_specific_instructions()
|
||||||
|
windows_hint = ""
|
||||||
|
if platform.system() == "Windows":
|
||||||
|
path_display = added_path or "未找到默认路径"
|
||||||
|
# 控制长度,避免破坏提示框宽度
|
||||||
|
if len(path_display) > 38:
|
||||||
|
path_display = path_display[:35] + "..."
|
||||||
|
windows_hint = f"║ 已尝试自动添加 GTK 路径: {path_display:<38}║\n"
|
||||||
|
arch_note = "║ 🔍 若已安装仍报错:确认 Python/GTK 位数一致,重开终端 ║\n"
|
||||||
|
else:
|
||||||
|
arch_note = ""
|
||||||
|
|
||||||
|
missing_note = ""
|
||||||
|
if missing_native:
|
||||||
|
missing_str = ", ".join(missing_native)
|
||||||
|
missing_note = f"║ 未识别到的依赖: {missing_str:<46}║\n"
|
||||||
|
|
||||||
if 'gobject' in error_msg.lower() or 'pango' in error_msg.lower() or 'gdk' in error_msg.lower():
|
if 'gobject' in error_msg.lower() or 'pango' in error_msg.lower() or 'gdk' in error_msg.lower():
|
||||||
return False, (
|
return False, (
|
||||||
@@ -82,12 +268,15 @@ def check_pango_available():
|
|||||||
"║ ║\n"
|
"║ ║\n"
|
||||||
"║ 📄 PDF 导出功能将不可用(其他功能不受影响) ║\n"
|
"║ 📄 PDF 导出功能将不可用(其他功能不受影响) ║\n"
|
||||||
"║ ║\n"
|
"║ ║\n"
|
||||||
|
f"{windows_hint}"
|
||||||
|
f"{arch_note}"
|
||||||
|
f"{missing_note}"
|
||||||
f"{platform_instructions}"
|
f"{platform_instructions}"
|
||||||
"║ ║\n"
|
"║ ║\n"
|
||||||
"║ 📖 完整文档:根目录 README.md 第393行「PDF 导出依赖」 ║\n"
|
"║ 📖 完整文档:根目录 README.md ‘源码启动’的第二步 ║\n"
|
||||||
"╚════════════════════════════════════════════════════════════════╝"
|
"╚════════════════════════════════════════════════════════════════╝"
|
||||||
)
|
)
|
||||||
return False, f"⚠ PDF 依赖加载失败: {error_msg}"
|
return False, f"⚠ PDF 依赖加载失败: {error_msg};缺失/未识别: {', '.join(missing_native) if missing_native else '未知'}"
|
||||||
except ImportError as e:
|
except ImportError as e:
|
||||||
# weasyprint 未安装
|
# weasyprint 未安装
|
||||||
return False, (
|
return False, (
|
||||||
|
|||||||
Reference in New Issue
Block a user