diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ac8ce757..84ca2572 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -116,7 +116,7 @@ jobs: uses: actions/upload-artifact@v7 with: name: unsigned-latexsnipper-installer - path: dist/installer/LaTeXSnipperSetup-*.exe + path: dist/installer/LaTeXSnipper_*_amd64.exe if-no-files-found: error retention-days: 30 @@ -197,7 +197,7 @@ jobs: build-office-plugin-installer: name: Validate Office Plugin Installer - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Checkout uses: actions/checkout@v6 @@ -226,7 +226,7 @@ jobs: echo "Release version $version does not match VERSION $product_version." >&2 exit 1 fi - installer="office_plugin/release/OfficePluginSetup-${version}.exe" + installer="office_plugin/release/LaTeXSnipper_${version}_office_amd64.exe" checksum="${installer}.sha256" test -f "$installer" test -f "$checksum" @@ -358,7 +358,6 @@ jobs: name: latexsnipper-macos path: | dist/*.dmg - dist/*.app.zip dist/SHA256SUMS-macos.txt if-no-files-found: error retention-days: 30 @@ -398,7 +397,7 @@ jobs: publish-release-assets: name: Publish Release Assets if: ${{ always() && (startsWith(github.ref, 'refs/tags/v') || (github.event_name == 'workflow_dispatch' && inputs.publish_assets)) && needs.build-windows-installer.result == 'success' && needs.build-office-plugin-installer.result == 'success' && needs.build-linux-deb.result == 'success' && needs.build-macos-app.result == 'success' && needs.build-user-manual.result == 'success' }} - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 needs: - build-windows-installer - build-linux-deb @@ -425,30 +424,30 @@ jobs: mkdir -p publish-assets if [[ -d release-assets/signed-latexsnipper-installer ]]; then - signed_count="$(find release-assets/signed-latexsnipper-installer -type f -name 'LaTeXSnipperSetup-*.exe' | wc -l | tr -d ' ')" + signed_count="$(find release-assets/signed-latexsnipper-installer -type f -name 'LaTeXSnipper_*_amd64.exe' | wc -l | tr -d ' ')" else signed_count="0" fi if [[ "${signed_count}" != "0" ]]; then echo "Using signed Windows installer." - find release-assets/signed-latexsnipper-installer -type f -name 'LaTeXSnipperSetup-*.exe' -exec cp -v {} publish-assets/ \; + find release-assets/signed-latexsnipper-installer -type f -name 'LaTeXSnipper_*_amd64.exe' -exec cp -v {} publish-assets/ \; elif [[ -d release-assets/unsigned-latexsnipper-installer ]]; then - unsigned_count="$(find release-assets/unsigned-latexsnipper-installer -type f -name 'LaTeXSnipperSetup-*.exe' | wc -l | tr -d ' ')" + unsigned_count="$(find release-assets/unsigned-latexsnipper-installer -type f -name 'LaTeXSnipper_*_amd64.exe' | wc -l | tr -d ' ')" if [[ "${unsigned_count}" != "0" ]]; then echo "Signed Windows installer is missing; using unsigned Windows installer." - find release-assets/unsigned-latexsnipper-installer -type f -name 'LaTeXSnipperSetup-*.exe' -exec cp -v {} publish-assets/ \; + find release-assets/unsigned-latexsnipper-installer -type f -name 'LaTeXSnipper_*_amd64.exe' -exec cp -v {} publish-assets/ \; else - echo "Unsigned Windows installer artifact exists but contains no LaTeXSnipperSetup-*.exe; skipping Windows release asset." + echo "Unsigned Windows installer artifact exists but contains no LaTeXSnipper_*_amd64.exe; skipping Windows release asset." fi else echo "No signed or unsigned Windows installer artifact found; skipping Windows release asset." fi - find release-assets/office-plugin-installer -type f -name 'OfficePluginSetup-*.exe' -exec cp -v {} publish-assets/ \; + find release-assets/office-plugin-installer -type f -name 'LaTeXSnipper_*_office_amd64.exe' -exec cp -v {} publish-assets/ \; find release-assets/user-manual -type f -name 'LaTeXSnipper_User_Manual.pdf' -exec cp -v {} publish-assets/ \; find release-assets/latexsnipper-linux-deb -type f -name '*.deb' -exec cp -v {} publish-assets/ \; - find release-assets/latexsnipper-macos -type f \( -name '*.dmg' -o -name '*.app.zip' \) -exec cp -v {} publish-assets/ \; + find release-assets/latexsnipper-macos -type f -name '*.dmg' -exec cp -v {} publish-assets/ \; asset_count="$(find publish-assets -maxdepth 1 -type f | wc -l | tr -d ' ')" if [[ "${asset_count}" == "0" ]]; then diff --git a/.gitignore b/.gitignore index d15207a5..c05f2a1f 100644 --- a/.gitignore +++ b/.gitignore @@ -21,7 +21,7 @@ packaging/debian/usr # Large binary files *.exe -!office_plugin/release/OfficePluginSetup-*.exe +!office_plugin/release/LaTeXSnipper_*_office_amd64.exe office_plugin/release/InstallerAssets/ *.dll *.zip diff --git a/.signpath/artifact-configurations/windows-installer.xml b/.signpath/artifact-configurations/windows-installer.xml index c2fa20f7..0b601ba6 100644 --- a/.signpath/artifact-configurations/windows-installer.xml +++ b/.signpath/artifact-configurations/windows-installer.xml @@ -1,7 +1,7 @@ - + diff --git a/.signpath/artifact-configurations/windows-office-plugin-installer.xml b/.signpath/artifact-configurations/windows-office-plugin-installer.xml index b1bf77ac..b7e1866d 100644 --- a/.signpath/artifact-configurations/windows-office-plugin-installer.xml +++ b/.signpath/artifact-configurations/windows-office-plugin-installer.xml @@ -1,7 +1,7 @@ - + diff --git a/Inno/latexsnipper.iss b/Inno/latexsnipper.iss index 44dd120b..528a1d04 100644 --- a/Inno/latexsnipper.iss +++ b/Inno/latexsnipper.iss @@ -27,7 +27,7 @@ ChangesAssociations=no DisableProgramGroupPage=yes LicenseFile={#MyLicenseFile} OutputDir={#MyOutputDir} -OutputBaseFilename=LaTeXSnipperSetup-{#MyAppVersion} +OutputBaseFilename=LaTeXSnipper_{#MyAppVersion}_amd64 SetupIconFile={#MyRepoRoot}\src\assets\icon.ico SolidCompression=yes WizardStyle=modern diff --git a/README.zh-CN.md b/README.zh-CN.md index 66d83750..4c5b66e9 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -46,9 +46,9 @@ | 平台 | 下载文件 | 使用识别前注意 | | ------------------------ | --------------------------------- | -------------------------------------------------------- | -| **Windows** | `LaTeXSnipperSetup-.exe` | 已包含 Python 运行时,无需另装系统 Python | -| **Linux(Debian/Ubuntu)** | 对应架构的 `.deb` | 需要 Python `>=3.10,<3.14` 及 venv/pip;Wayland 可能限制截图和全局快捷键 | -| **macOS** | 对应架构的 `.dmg` 或 `.app.zip` | 需要 Python `>=3.10,<3.14` 及 venv/pip;截图需授予屏幕录制权限 | +| **Windows** | `LaTeXSnipper__amd64.exe` | 已包含 Python 运行时,无需另装系统 Python | +| **Linux(Debian/Ubuntu)** | `LaTeXSnipper__.deb` | 需要 Python `>=3.10,<3.14` 及 venv/pip;Wayland 可能限制截图和全局快捷键 | +| **macOS** | `LaTeXSnipper__.dmg` | 需要 Python `>=3.10,<3.14` 及 venv/pip;截图需授予屏幕录制权限 | > [!NOTE] > Linux/macOS 使用系统 Python 创建受管理的依赖环境,Windows 使用内置 Python 3.11 模板。`.deb` 声明了 `python3` 和 `python3-venv` 依赖;macOS 若没有可用 Python,请先安装受支持的版本。 @@ -83,7 +83,7 @@ * 支持公式编辑、更新,以及 Word 自动编号和引用。 * 本地渲染公式,通过桌面端 Automation API 调用截图识别。 -从 [Releases](https://github.com/SakuraMathcraft/LaTeXSnipper/releases/latest) 单独下载 `OfficePluginSetup-.exe`。支持 Windows 上的 32 位和 64 位 Office 2019/2021/2024、LTSC 2021/2024 及 Microsoft 365 Apps。 +从 [Releases](https://github.com/SakuraMathcraft/LaTeXSnipper/releases/latest) 单独下载 `LaTeXSnipper__office_amd64.exe`。支持 Windows 上的 32 位和 64 位 Office 2019/2021/2024、LTSC 2021/2024 及 Microsoft 365 Apps。 [安装要求与完整功能](office_plugin/README.md) · [公式工作流](docs/office_plugin_formula_workflows.md) diff --git a/VERSION b/VERSION index a0cd9f0c..fd2a0186 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.1.0 \ No newline at end of file +3.1.0 diff --git a/docs/automation_api.md b/docs/automation_api.md index 45ab7169..8d96810e 100644 --- a/docs/automation_api.md +++ b/docs/automation_api.md @@ -1,6 +1,6 @@ # Automation API v1 -LaTeXSnipper v3.0.0 exposes its resident MathCraft runtime and the external OCR model already configured in the desktop application through a versioned job API. Clients cannot provide or read upstream URLs, model names, credentials, paths, or prompts. +LaTeXSnipper exposes its resident MathCraft runtime and the external OCR model already configured in the desktop application through a versioned job API. Clients cannot provide or read upstream URLs, model names, credentials, paths, or prompts. ## Enable and discover diff --git a/docs/faq.md b/docs/faq.md index 88f54d54..04ee5e25 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -27,15 +27,15 @@ The main differences are platform integration details: | Window close / background behavior | Closing the main window hides it to the system tray; use the tray menu to exit. | Closing the main window hides it to the system tray when a tray is available; without a tray, the app asks before exiting. | Closing the main window minimizes it while the app keeps running; Dock/menu Quit exits the app. | | Permission model | No explicit screenshot permission is required for the normal capture path. | Wayland compositors can restrict global shortcuts or screenshot capture. | Screen Recording permission is required for screenshots. The native Carbon hotkey path normally does not require Accessibility permission. | | Dependency runtime | GitHub builds start from the bundled dependency root `\_internal\deps`; users may switch to another root. | Defaults to `~/.latexsnipper/deps`; users may switch to another root. | Defaults to `~/Library/Application Support/LaTeXSnipper/deps`; users may switch to another root. | -| Packaging | Inno installer from GitHub Releases. | Debian/Ubuntu `.deb`. | `.dmg` and `.app.zip`. | +| Packaging | Inno installer from GitHub Releases. | Debian/Ubuntu `.deb`. | `.dmg`. | The shortcut UI uses the platform's primary modifier: `Ctrl` on Windows/Linux and `Command` on macOS. macOS system and editing shortcuts such as `Command+Q`, `Command+H`, `Command+M`, `Command+W`, `Command+A`, `Command+C`, `Command+V`, `Command+X`, `Command+Z`, `Command+Space`, `Command+Tab`, and screenshot shortcuts are intentionally rejected; use an `Option+Command` combination when a plain Command shortcut is reserved. ## Which installer should I use? -- Windows: use `LaTeXSnipperSetup-.exe` from GitHub Releases. The release workflow prefers the signed installer; if signing is unavailable, the same filename may be published as an unsigned fallback. +- Windows: use `LaTeXSnipper__amd64.exe` from GitHub Releases. The release workflow prefers the signed installer; if signing is unavailable, the same filename may be published as an unsigned fallback. - Linux: use the `.deb` package on Debian/Ubuntu-compatible systems. -- macOS: use the `.dmg` or `.app.zip` artifact. +- macOS: use the `.dmg` artifact for your architecture. ## Why does macOS still say Screen Recording is unavailable after I enabled it? diff --git a/docs/office_plugin_formula_workflows.md b/docs/office_plugin_formula_workflows.md index cfb42cf4..7efe6b4e 100644 --- a/docs/office_plugin_formula_workflows.md +++ b/docs/office_plugin_formula_workflows.md @@ -6,8 +6,23 @@ - 新建和格式化从当前设置产生样式快照;普通编辑、重编号及转换保留公式已有快照。 - 局部字体与颜色命令优先于默认样式。默认样式在 MathJax 解析后、布局前应用。 -- Word OLE、PPT OLE / PNG 使用同一 SVG 轮廓;OMML 复用带样式 MathML,再映射 Word 属性,最终排版由 Word 管理。 -- MathLive 目前仍是编辑参考。三类字体的完整设置面板、最终效果预览与预设功能按重构方案后续阶段实施。 +- 编辑器以源码最外层 `\textcolor{#RRGGBB}{…}` 表示当前公式的全局颜色;工具栏修改该命令,源码区修改该命令则同步工具栏。提交和预览的 `Typography.Color` 从源码读取,MathLive 继承同一颜色,局部 `\textcolor` 可覆盖外层。右键局部上色立即写入源码。 +- Word OLE、PPT OLE / PNG 使用同一 SVG 轮廓;Word OMML 与 PowerPoint 文本内原生公式复用带样式 MathML,由各自宿主管理排版。 +- MathLive 提供可视化编辑;符号、数字、汉字三类字体和独立的默认字形共同构成样式快照。设置页的 JSON 导入/导出只管理当前宿主的全局公式默认属性;编辑器内调整只作用于当前公式。 + +## 用户偏好与升级保留 + +用户偏好与安装文件分开保存。Word 和 PowerPoint 共用注册表项,但使用不同的值名;两者的公式默认属性也在同一 JSON 文件内分别保存。 + +| 数据 | 存储位置 | 具体内容 | +| --- | --- | --- | +| Word 插入和编号偏好 | `HKCU\Software\LaTeXSnipper\OfficePlugin` | `WordInsertionBackend`、`NumberPlacement`、`NumberEnclosure`、`NumberIncludeChapter`、`NumberIncludeSection`、`HideChapterBoundary`、`HideSectionBoundary`、`NumberSeparator` | +| PowerPoint 插入偏好 | 同一注册表项 | `PowerPointInsertionBackend` | +| Word / PowerPoint 公式默认属性 | `%APPDATA%\LaTeXSnipper\OfficePlugin\settings.json` | 两个宿主各自的符号字体、数字字体、汉字字体、默认字形、字号、颜色和新建时跟随文字字号;JSON 导入/导出只读写对应宿主的这组属性 | +| 公式编辑器常用内容 | `%LOCALAPPDATA%\LaTeXSnipper\OfficePlugin\WordEditorWebView2` 和 `PowerPointEditorWebView2` | 各宿主 WebView2 的 `localStorage`:内置磁贴收藏、自定义公式收藏、符号库当前标签与折叠状态;两宿主不互相覆盖 | +| 文档内托管公式 | Word 文档变量与公式对象;PowerPoint OLE / PNG shape tags | 公式源码、身份及各公式自己的样式快照;随 Office 文档保存。PowerPoint 文本内原生公式由 Office 保存,不使用插件 shape tags | + +安装包在升级、重装前运行 `ForceClean.ps1`,清理旧安装目录、VSTO / ClickOnce 注册与缓存、OLE 注册,以及 `%LOCALAPPDATA%\LaTeXSnipper\OfficePlugin\WordAddIn` / `PowerPointAddIn` 渲染缓存和 PowerPoint 临时图片。脚本不删除上述用户偏好注册表项、`settings.json`、两个编辑器 WebView2 目录或 Office 文档。卸载时也调用同一清理脚本并保留这些用户数据。`TypographySettingsStore` 只在读取到损坏或不支持版本的 `settings.json` 时删除该文件并重建默认值,不执行配置迁移;此时注册表中的插入与编号偏好和编辑器常用内容仍保留。 ## 统一元数据模型 @@ -331,14 +346,17 @@ REF LaTeXSnipperEq_{equationId} \h ## PowerPoint 插入、加载、删除、转换、格式化 -PowerPoint 没有 Word 编号和引用链路,公式对象是 shape: +PowerPoint 没有 Word 编号和引用链路。插入时按当前位置选择两条路径: + +- 文本框内为折叠的文字光标:复用 MathJax 的带样式 MathML 转换,粘贴为 PowerPoint 原生公式,保留同一文本框内的前后文字与自动换行。公式字号使用本次编辑选择;启用“新建时跟随文字字号”时,初值来自文本光标。后续在 PowerPoint 内编辑该原生公式。 +- 文字区域外:按设置将 OLE 或 PNG 作为独立幻灯片对象居中插入;选中已有插件公式不妨碍新建。选中一段文字时要求先收起选区到光标。 -- 新建保存源码与样式快照,按设置插入 PNG 或 OLE;普通更新使用已有快照。 +- OLE / PNG 新建保存源码与样式快照;普通更新使用已有快照。 - 加载从 shape 元数据恢复完整信息;删除同时清理对应 PNG 临时文件。 - OLE / PNG 转换保留源码、样式和原位置 / 用户缩放。 - 所选 / 全文格式化共用样式流程;全文遍历演示文稿各页的托管公式,恢复新的自然尺寸。 -PowerPoint 编辑器固定白底黑字,Word 编辑器按系统深色模式适配。编辑参考与最终预览的进一步分工见字体重构方案。 +PowerPoint 文本内原生公式不参与插件的加载、OLE / PNG 转换和批量格式化,因为这些操作面向带插件元数据的幻灯片对象。Word 和 PowerPoint 编辑器固定使用浅色界面;编辑区继承源码中的全局颜色。最终预览按当前属性渲染,小字号在屏幕上适当放大以便检查;插入仍使用选定的实际字号。 ## 链路复杂度核对 @@ -387,12 +405,3 @@ Word 插入、更新、删除、编号、解析、转换和格式化都在必要 - OLE 对象本身或 PNG shape。 这些都是 Office 文档内的原生持久化载体,不依赖本机临时内存。PowerPoint PNG 的临时图片路径只用于本机清理文件,不影响公式元数据加载。 - -## 当前明确边界 - -- 不从编号数字反向删除公式。 -- 不把默认字体/颜色作为编辑器打开时的临时样式。 -- 不在加载所选时改写侧边栏用户草稿以外的持久源码。 -- 不在格式化全文时批量重写所有公式源码。 -- 不把解析与全文重编号耦合;解析后的全局序号校正仍由用户显式执行“重编号”。 -- 不扫描非主正文 story,也不跨已有公式、字段、受保护对象或表格单元格边界配对定界符。 diff --git a/docs/office_plugin_typography_refactor.md b/docs/office_plugin_typography_refactor.md deleted file mode 100644 index 38c60a4d..00000000 --- a/docs/office_plugin_typography_refactor.md +++ /dev/null @@ -1,569 +0,0 @@ -# Office 插件字体、编辑体验与预设重构方案 - -日期:2026-09-12 - -状态:第 1—6C 步实现完成;下一步为第 7 步预设与用户配置。第 4 步剩余 Office OLE 实机检查按用户确认并入第 8 步安装包发布验收(2026-09-25 更新)。 - -适用范围:Word / PowerPoint Office 插件;客户端共享 MathJax 运行时升级与导出边界 - -## 1. 本次更新的明确边界 - -本次统一公式字体、字号、最终效果预览、源码编辑和预设保存。保留现有 Office 宿主、MathLive 编辑器及 MathJax 渲染架构,不重写插件。 - -- **MathJax 升级阶段已完成:客户端与插件统一为 4.1.3。** 共享版本清单、配置和转换接口,按用途打包、独立运行;已删除 v3 资源。客户端资源约 6.77 MiB,插件约 5.40 MiB。维护与验证记录见 [运行时维护说明](../tools/mathjax/README.md),后续不重复进行版本选型或体积评估。 -- **OMML 与 OLE / PNG 共用样式配置及格式化入口。** OMML 适配器将可表达的字体、字号和字形属性映射到 MathML / OMML 或 Word 对象属性,最终取字、回退和排版由 Word 决定;不承诺与 MathLive 或 OLE 像素一致。 -- 字体系统覆盖 Word OMML / OLE、PowerPoint OLE / PNG;OLE / PNG 提供最终效果预览,OMML 提供参考预览。 -- 源码编辑体验适用于共享公式编辑器;OMML 模式不显示承诺与 Word 一致的字体预览。 -- 本次提供符号字体、数字字体、汉字字体、字号、颜色和预设。正体、斜体、粗体等保留为字形样式,不能与字体家族混为一项。 -- **不兼容或迁移旧文档、旧公式和 schema 2,不保留旧渲染、旧字号或旧包装逻辑分支。** 用户允许本次破坏性协议更新;用户主动提供的合法 LaTeX 仍按新链路解析。 -- 不实现完整 TeX 引擎,不自建完整 LaTeX 解析器,不追求任意系统字体替代全部数学符号。 -- 不改变公式身份、编号、引用和用户正文;未经明确指令不提交或推送改动。 - -本方案描述目标架构与分阶段实施记录。`office_plugin_formula_workflows.md` 随已落地阶段更新当前源码、样式与元数据边界。 - -## 2. 现状与已确认的问题 - -| 位置 | 当前实现 | 对本次工作的影响 | -| --- | --- | --- | -| `Abstractions/MathLiveLatexStyleNormalizer.cs` | 用 LaTeX 宏包装字体;特殊环境只有 aligned、gathered、split、multline | align、嵌套环境及复杂结构无法稳定应用样式;继续添加环境特例难以维护 | -| `WordPluginController.ApplyDefaultSourceFormatting` | 任意位置存在字体宏,即跳过整条公式默认字体 | 局部样式会阻断其他节点应用默认样式;PowerPoint 有同类逻辑 | -| `Editor/EditorAssets/editor.js` | textarea 与 MathLive 双向同步,MathLive 使用 latex-expanded 回写 | 无语法高亮;复杂源码存在被重新序列化的风险 | -| `MathLiveFormulaEditorForm` | 初始化只传源码、模式等,不传完整字体配置 | 编辑显示缺少最终字体上下文 | -| `Rendering/MathJaxRenderScriptBuilder.cs` 与共享运行时 | 调用共享 MathJax 4.1.3 Promise 接口输出 SVG / MathML | 版本升级已完成,字体样式适配仍需实施 | -| `Rendering/SvgVectorGraphicsRenderer.cs` | 文本使用系统字体回退,转轮廓时固定 Regular | 汉字字体不可配置,文字样式与浏览器可能不一致 | -| `MathJaxSvgRenderResponse` 与宿主控制器 | 固定 ex/em 换算、Word 当前字号及 FontScale 叠加 | 绝对字号、自然尺寸、显示缩放没有清晰分离 | -| `FormulaMetadata` 与 OLE 协议 | schema 2,源码携带样式,单独存 FontScale | 缺少完整样式快照;原生 OLE 明确校验版本 2 | -| `WordPluginSettings` / `PowerPointPluginSettings` | 用户注册表保存默认设置 | 已与安装目录隔离,但无命名预设,安装清理会删除旧注册表配置 | - -`\mathrm{\delta}` 已定位到 TeX 字符解析和正体字形供给两处,验证与接入决定见第 11.4 节。 - -已发现配置重置的直接代码原因:安装前执行的 `office_plugin/tools/ForceClean.ps1` 会删除 `HKCU:\Software\LaTeXSnipper\OfficePlugin`。新预设持久化必须同时调整安装清理策略,不能只更换存储格式。实际覆盖安装仍需验证。 - -## 3. 核心设计:源码与样式分离 - -### 3.1 唯一数据流 - -```text -原始源码 + 公式样式快照 + 输出上下文 - → 单一 MathJax 运行时解析 - → 节点样式解析与字体度量 - → 布局与 SVG 输出 - → 必要文本轮廓化,生成可移植的最终矢量结果 - ├─ 最终效果预览 - ├─ EMF → Word / PowerPoint OLE - └─ PNG → PowerPoint -``` - -MathLive 保留可视化编辑功能,不充当最终输出的唯一判断依据。OMML 复用源码解析与样式解析结果,走“语义 MathML → OMML → Word 属性应用”适配器;不经过 SVG 轮廓化,也不为追求相同字形引入另一套源码包装规则。 - -统一的是样式意图、优先级和操作入口;各输出后端负责表达同一意图。无需为 OMML 复制设置页或维护平行预设,也不能因为后端不同而跳过整个格式化命令。 - -### 3.2 样式优先级 - -1. 源码显式局部样式优先,例如 `\mathbf{A}`、`\mathrm{d}`、`\textcolor{red}{x}`。 -2. 公式自身的完整样式快照为未显式指定的节点提供默认值。 -3. 用户当前预设只用于创建新公式,或用户主动对已有公式应用预设。 -4. 内置默认配置仅补充缺失字段,不覆盖用户已有有效配置。 - -预设中的字体家族负责字形来源,源码中的正体、粗体、花体等负责数学样式语义;不把两者压缩为一个枚举。 - -普通“格式化所选 / 全文”更新样式快照并重新渲染,不改写原始源码,不删除局部样式。清除源码显式格式不是本次普通格式化的隐式行为;若后续提供,应是独立命令。 - -数学结构通过 MathJax 的解析树处理,不再靠在环境外包裹 `\mathrm{...}` 实现默认字体。字体处理必须在相关字形度量与布局前生效,不能只对已排版的 SVG 更换字体名称。 - -## 4. 共享数据契约 - -共享契约已在 Abstractions 实现,正式渲染及宿主已接入;后续界面和预设工作按第 11 节执行,职责不得分散到宿主控制器。 - -### 4.1 FormulaTypography - -不可变样式对象,至少包含: - -| 字段 | 含义 | -| --- | --- | -| `SymbolFontId` | 稳定的数学字体方案 ID,不使用本地化显示名称作为键 | -| `NumberFontFamily` | `null` 表示跟随符号字体,否则为独立数字字体家族;实际可用性由字体解析服务确认 | -| `CjkFontFamily` | 汉字及约定中文标点的字体家族 | -| `DefaultMathStyle` | 默认数学字形样式,与字体家族分开 | -| `FontSizePoints` | 插入时已经解析出的实际字号;产品接受 1–1638 pt 的有限数值,支持小数 | -| `Color` | 统一为 `#RRGGBB` 的默认公式颜色,显式局部颜色仍优先 | -| `TypographyVersion` | 样式契约版本 | - -持久化保存用户请求的字体;渲染结果另附实际采用的字体、缺字与回退诊断。不能因为临时缺字或当前机器缺字体就静默覆盖原设置。 - -### 4.2 新建默认值与公式快照 - -预设允许字号模式为“固定 pt”或“跟随宿主”。新建 Word OLE 时在确定插入上下文后解析 Word 字号;PowerPoint 只在存在有效文字上下文时跟随,否则使用明确的默认 pt 值,并在界面显示。 - -公式一旦插入,就保存实际 `FontSizePoints`。重新加载或更新时不得重新读取当前光标字号并改变公式。用户手动拉伸对象的比例单独作为宿主几何状态管理,不能反写为公式字号。 - -新建时允许保留用于预览的已解析上下文;若提交时宿主上下文发生变化,需要刷新最终结果,确保插入采用的字号与最后确认的预览一致。 - -### 4.3 FormulaMetadata 与渲染请求 - -- 新增完整 `Typography` 快照,目标 schema 3。 -- 保留原始 `Latex`、身份、显示模式、编号等既有字段与职责。 -- 预设 ID / 名称只作为可选来源信息;重绘不得依赖本机仍存在该预设。 -- `RenderRequest` 显式接收样式快照,宿主不再先加工一份带默认包装的源码。 -- 缓存键包含源码、显示模式、完整样式、字体资源版本、实际字体解析上下文、渲染器版本及必要输出参数。 -- 字体配置相同但本机实际字体不同,不得错误复用缓存。 -- 重新渲染判断比较完整样式,不再只比较 Latex 和 FontScale。 - -## 5. 单一 MathJax 字体实现 - -### 5.1 字体能力范围 - -- 符号字体先保留现有 TeX 数学字体作为完整基底,已有正体、粗体、无衬线等选项重新归类为字形样式。 -- 只有具备必要数学字形、度量和拉伸规则且通过验收的字体方案,才进入符号字体列表。第一版不虚构未实现的系统数学字体支持。 -- 数字字体独立处理数学数字节点;遵循局部样式、上下标缩放与布局度量。文本节点内数字仍属于文本,避免破坏普通文本语义。 -- 汉字字体覆盖汉字和明确约定的中文标点;混合文本按字符类别切分为字体运行段,保持文字顺序、空格和基线。 -- 非中文文本沿用明确的默认文本字体方案,不额外增加用户设置项。 -- 字形缺失按统一顺序回退,并通过最终预览提示实际字体;禁止静默宣称已应用不可用字体。 - -### 5.2 适配器设计 - -在 Rendering 中集中实现MathJax 4 字体适配器,利用现有解析节点及输出扩展点应用默认样式和测量结果。所有与 MathJax 内部节点、variant 或 wrapper 的耦合必须限制在此处,并固定版本和回归用例。 - -独立数字字体与 CJK 字体需要共享字体解析、文字测量及轮廓生成能力。可在现有 Windows 字体绘制基础上实现一个度量和轮廓服务,让布局使用的字符宽度与最终轮廓采用相同字体来源。缓存以字体、样式、文本运行段等为键,避免按字符频繁跨 WebView 调用。 - -不允许“浏览器按 A 字体测量、EMF 按 B 字体画字”。对于需要系统字体的文本,最终矢量结果必须使用已确定的字体和字形;轮廓化后的预览与输出共用同一份几何数据。 - -正体希腊字母采用集中、可测试的 variant 兼容规则;先观察 `\mathrm{\delta}` 的解析结果,再决定节点映射或字形选择。不能全局字符串替换所有希腊命令,也不能让普通 `\delta` 一并变成正体。 - -### 5.3 实施前的最小技术验证 - -基于已经完成升级的 MathJax 4.1.3 验证以下三个字体垂直样例,结果作为字体模块实现依据。复用现有 WebView2、Qt WebEngine 与 EMF 回归入口,只补充字体能力验证,不重复运行时升级: - -1. `align` 内默认字体覆盖、局部样式优先、嵌套矩阵结构不变。 -2. 正体 / 斜体希腊字母经过 SVG 和 EMF 后保持预期字形。 -3. 独立数字字体与两个可用中文字体切换,宽度、基线、分式和上下标不重叠、不裁切。 - -MathJax 4 已通过体积与本地资源加载验证,但尚未证明可替代所有字体适配工作。若 v4 的公开扩展点不足,只在字体适配器内补充版本限定实现;若仍不能满足某字体的排版要求,明确该字体暂不支持,并记录具体阻碍,不能用视觉替换掩盖错误。 - -## 6. 字号与输出尺寸 - -- 内部使用 pt;界面提供可编辑组合框,接受数字和中文字号别名,支持小数。 -- 标准别名集中定义:初号 42、小初 36、一号 26、小一 24、二号 22、小二 18、三号 16、小三 15、四号 14、小四 12、五号 10.5、小五 9、六号 7.5、小六 6.5、七号 5、八号 5.5。 -- 校验范围由共享契约统一定义并显示错误;不静默恢复成默认字号。拒绝 NaN、无穷和非正数。 -- 以目标 pt、渲染字体 em 度量、SVG 坐标体系统一计算自然宽高与基线;移除新链路中的固定 ex 经验值和重复倍率。 -- 多行公式的总高度由布局决定,不能通过把对象总高度设为 12pt 来实现 12pt 字号。 -- 编辑器视觉缩放、公式实际字号、宿主手动对象缩放三者分开。 -- 普通编辑保留宿主已有手动缩放;主动格式化恢复目标样式对应的自然尺寸,沿用清晰一致的命令语义。 -- PNG 的像素数由自然 pt 和输出 DPI 计算;更改 DPI 不改变插入物理尺寸。 - -## 7. 编辑器与最终预览 - -### 7.1 源码编辑 - -将 textarea 替换为本地打包的 CodeMirror 6,通过小型 `SourceEditor` 适配层封装读取、事务更新、选择、诊断与焦点控制。Word / PowerPoint 共用实现,不引入完整 IDE 或在线资源依赖。 - -统一颜色 token:命令、环境名、数学符号、数字、括号层级、对齐符 / 换行、注释、文本内容、错误。提供明暗两套主题,兼顾对比度,正文文字不做无意义彩虹着色。 - -本次包含括号匹配、自动缩进、撤销重做、查找替换、基础命令 / 环境补全及错误定位。中文输入法组合期间不执行会打断输入的源码重写。 - -### 7.2 源码与 MathLive 同步 - -- 原始源码是持久化内容依据,程序更新 MathLive 不触发反向覆盖。 -- 记录编辑来源和修订号,消除延迟同步任务覆盖较新源码的问题。 -- 只有用户实际在 MathLive 编辑时才接受其序列化结果,单纯加载、预览和失焦不改源码。 -- 对不能可靠往返的环境保留源码编辑与最终预览,禁用会破坏源码的可视化编辑并给出简短提示。 -- 源码和可视化修改共享文档修订边界;模式切换不清空撤销历史,程序同步不制造重复撤销步骤。 - -### 7.3 最终效果 - -编辑区提供“可视化编辑 / 最终效果”切换。新建公式即获得预设的完整上下文;最终效果调用共享渲染服务,显示经过字体解析和必要轮廓化的结果。 - -预览请求使用防抖、取消及修订号检查,旧请求不能覆盖新结果。提交必须使用当前源码和样式对应的有效结果,或等待同一请求完成;不得直接插入上一版预览。 - -字体回退、语法错误和当前预览过期均显示明确状态。预览错误时保留源码,不把错误占位图当成公式插入。 - -最终矢量几何相同是 OLE / PNG 一致性的标准;浏览器与 Office 的抗锯齿差异不作为字体不一致。EMF 转换仍需实际 Office 验证。 - -OMML 模式保留相同字体面板和格式化命令,预览标示“参考效果,实际排版由 Word 决定”。执行后保持 OMML 类型,不自动转换成 OLE。 - -OMML 适配器将解析后的有效样式映射到支持的节点属性或 Word 公式范围属性,避免覆盖周围正文、编号与引用。插件数学字体资源 ID 不等于 Windows 字体家族名;两者通过集中字体目录映射,无法对应时由 Word 使用其数学字体机制,不添加仿真分支。字体或字形无法表达时返回结构化的“不支持 / 由 Word 决定”结果,不伪报属性已经写入。 - -本次验证聚焦:支持的属性正确写入、公式结构与内容不变、重复格式化稳定、失败可诊断。不同 Office 版本的具体取字和视觉差异不作为插件修复或跨渲染器像素对齐目标。 - -## 8. 设置与预设 - -建议存储目录: - -```text -%APPDATA%/LaTeXSnipper/OfficePlugin/ - settings.json - typography-presets/ - .json -``` - -内置预设随程序只读发布;用户预设存于上述目录。WebView 缓存和临时渲染文件继续放 LocalAppData,不用 localStorage 保存核心字体配置。 - -- 提供保存、另存为、加载、删除用户预设、导入、导出和设为新建默认值。 -- “加载预设”只改变当前编辑草稿;“设为默认”影响后续新建;“应用所选 / 全文”才改变既有公式。 -- 预设包含字体、字号模式、颜色,不混入 Word 编号与 PowerPoint 插入方式等宿主选项。 -- 保存采用同目录临时文件与原子替换,保留可恢复备份;多个宿主写入需串行化并避免覆盖对方字段。 -- 导入校验 schema、字段类型、字号和字体描述;不接受脚本、宏注入或任意资源加载路径。 -- 未安装字体保留用户原选择并显示回退情况;不能以“导入成功”掩盖字体缺失。 -- 安装升级不覆盖用户目录,不通过注册表默认值写入清空已有配置。 -- 配置读取失败保留损坏文件并提示恢复来源,不自动用默认值覆盖唯一副本。 - -Word 与 PowerPoint 使用共享预设仓库;各自保存选中的默认预设 ID,避免在一个宿主选择新默认值时意外改变另一个宿主。 - -## 9. 单一协议与用户配置保留 - -### 9.1 公式协议一次切换 - -只支持新的 schema 3。共同更新 FormulaMetadata、Word Document.Variables JSON、PowerPoint 分块元数据及原生 OLE payload,托管层与 x86 / x64 handler 同步发布。 - -删除旧 schema 读取、FontScale 恢复、旧自然尺寸推断和源码包装迁移,不提供旧版渲染后备路径。旧数据或未知协议只在入口统一拒绝编辑并提示“不支持该公式版本”,不删除对象、不猜测转换、不静默重建。 - -新公式必须在 OLE 激活、重新编辑、复制粘贴与宿主间转换中完整保存源码、样式快照和矢量呈现。现有旧公式的显示不作为新版验收承诺;不为其增加实现分支。 - -### 9.2 用户预设跨更新保留 - -不迁移旧百分比字体设置,也不保留旧注册表到新样式的兼容桥。本次字体配置从新模型开始,之后同一契约的用户配置与命名预设由独立用户目录长期保存。 - -安装器必须从清理范围中排除新的用户设置和预设目录;升级不重写已有文件,首次启动只有文件不存在时才建立默认值。内置预设更新与用户预设保存互不覆盖。旧文档兼容不做,并不意味着允许今后的程序更新重置用户配置。 - -## 10. 模块落点与清理要求 - -| 模块 | 变更 | -| --- | --- | -| Abstractions | 样式契约、字号解析、schema 3、显式渲染请求 | -| Rendering | 单一 MathJax 字体适配器、统一字体度量与轮廓、pt 换算、缓存和诊断 | -| Editor | SourceEditor、同步协调、样式上下文、最终预览桥接 | -| 共享配置模块 | 预设文件、配置校验与原子保存;只建立一个共享实现 | -| Word / PowerPoint hosts | 解析宿主上下文、应用样式快照、保持身份及编号;OMML 适配可表达属性并交由 Word 排版 | -| OleFormulaObjectNative | 单一新协议及激活数据往返 | -| installer / release | 打包本地编辑器资源,保留用户配置,维持 x86 / x64 安装兼容 | - -移除新建和普通格式化中的源码字体包装,以及宿主间重复的默认样式处理。确认调用点后删除失去用途的函数及全部旧公式兼容分支。共享字体选项、字号表和校验定义,不在 C#、Word JS、PowerPoint JS 各维护一份列表。 - -本次避免无关目录重排、框架升级和既有功能重写。新增层应对应明确责任,不为单一函数建立额外框架。 - -## 11. 按顺序落地与验收 - -### 11.1 已完成:MathJax 运行时升级 - -固定 4.1.3、共享配置与异步转换、CHTML 配置、CDN / HTML 版本及按用途打包均已完成。运行时升级与后续字体 / 协议重构分阶段验收,当前进度见下表。真实文档插入、发布安装与跨平台验证保留到发布阶段;不把运行时升级通过等同于字体问题已解决。 - -### 11.2 实施顺序 - -以下每一步单独实施、检查差异并完成验收,再进入下一步。实施记录应写明实际修改、已执行验证和遗留问题;不得用一轮大改动同时替换协议、渲染、编辑器和设置。 - -| 顺序 | 本步交付与修改范围 | 验收门槛 | -| --- | --- | --- | -| 1. 字体技术验证(已完成) | 复用当前运行时,验证第 5.3 节三个样例,确定符号、数字、CJK 度量和字形选择的接入点;记录支持范围及明确限制,见第 11.4 节 | 能定位正体希腊字母的变化环节;复杂环境和两种中文字体的布局验证有证据;未解决的度量问题不能用后处理换字体绕过 | -| 2. 共享样式与尺寸契约(已完成) | 实现不可变 Typography、样式优先级、唯一字号表与 pt 校验、宿主上下文解析;此步不切换持久化协议或替换编辑器,见第 11.5 节 | 字号别名与数字等价;显式局部样式优先;新建时解析字号、后续重绘不再跟随光标;契约测试通过 | -| 3. 统一字体渲染(已完成) | 接入上一步契约,完成符号 / 数字 / CJK 字体、度量与轮廓、自然尺寸和基线、完整样式缓存;OMML 实现同一有效样式的属性映射,见第 11.6 节 | 多行、局部样式、希腊字母、混排、分式与上下标通过;SVG / EMF / PNG 几何一致;OMML 支持属性写入正确,不要求像素一致 | -| 4. 协议与宿主切换(实现完成) | 一次更新 schema 3 的全部生产者和消费者,包括元数据、OLE payload、x86 / x64 handler,以及 Word / PPT 新建、编辑、格式化和转换 | 已通过 Word OMML、PPT PNG 与原生存储验证;Office 内 OLE 激活及双向转换按用户确认随第 8 步安装包实测,未记为通过 | -| 5. 源码编辑与同步(已完成) | 共享 CodeMirror 编辑器、颜色主题、括号 / 环境辅助、文档修订与统一撤销、中文输入保护;不改设置存储,见第 11.8 节 | 复杂源码加载与提交、显式可视化回写、撤销重做、组合输入及过期同步回归通过;真实输入法及 Office 宿主交互留作安装包验收 | -| 6A. 编辑器布局与磁贴库(已完成) | 共享布局、底部两行分类磁贴、统一搜索和模板插入,实施记录见第 11.11 节 | 两宿主的选区包裹、占位符跳转、独立撤销及锁定回归通过;真实宿主交互随第 8 步验收 | -| 6B. 字体设置与最终预览(已完成) | 接入统一三类字体、数字 / 中文字号、颜色面板;编辑 / 最终预览切换采用同一草稿样式与渲染请求;OMML 使用参考预览 | 预览、提交采用同一源码与样式修订;取消和过期结果处理正确;无第二份字体或字号列表 | -| 6C. 编辑器交互收尾(已完成) | 完成键盘、焦点、窗口尺寸、明暗主题与输入法交互检查 | 磁贴滚动不干扰其他区域;布局无关键控件遮挡;输入法组合期间操作安全;Office 内实测项随第 8 步安装验收 | -| 7. 预设与用户配置 | 在已稳定的样式契约上实现共享预设仓库、保存 / 加载 / 导入导出、默认值与宿主选项隔离;同步修正安装清理 | 文件原子保存,多宿主写入不互相覆盖;加载与应用的边界正确;预设被删除后公式仍能独立重绘;连续覆盖升级保留用户配置 | -| 8. 发布回归与收尾 | 按第 12 节完整验收,验证实际 Word / PPT 文档和安装升级、x86 / x64,检查资源体积与离线运行;更新当前行为文档 | 构建与必要测试通过;发布包无旧协议或旧运行时分支、无临时验证文件;未通过的验收项明确列出,不记为完成 | - -第 2、3 步可通过共享模块的直接测试验证新契约与渲染能力,不提前发布未接通的设置入口。第 4 步是必要的协议整体切换边界,不能发布托管层和原生 handler 协议不同的中间版本,也不为中间状态添加长期双轨兼容。 - -### 11.3 每一步的代码质量要求 - -- 修改只覆盖本步目标及必要调用点;先复用现有共享模块,不为单个函数新增框架或另一套配置模型。 -- 明确源码、样式、字号和宿主缩放各自的所有者,禁止宿主各自增加补丁规则。 -- 本步替换的旧路径在确认调用点后随本步删除,不把死函数和兼容分支积攒到最后清理。 -- 有价值的最小复现保留为可重复回归;临时下载、截图、样例输出和试验性脚本在结论形成后删除。 -- 每一步先完成对应编译、静态检查和有意义的行为验证;失败先定位修复,不叠加下一步变更掩盖问题。 -- 未经用户指令不提交或推送。这里的分步交付指独立可检查的工作单元,不代表自动创建提交。 - -### 11.4 第 1 步实施记录(2026-09-13) - -运行时迭代点为 `41b47b641`(MathJax 4.1.3 与 Pandoc 文件导出)。本步只扩展现有 `Rendering.Smoke` 的 `--typography` 入口;生产渲染、宿主和 schema 2 保持当前行为。字体技术验证完成,共享契约实施结果见第 11.5 节。 - -**定位结果与接入决定:** - -| 问题 | 实测发现 | 正式实现的接入点 | -| --- | --- | --- | -| 多行默认字体 | `MathLiveLatexStyleNormalizer` 只专门处理少数环境,没有 `align`,最终仍依赖字体命令包装 | 使用解析后的 token 和样式上下文;在 `COMPILED` 之后、输出 wrapper 度量之前应用默认样式,与环境名称无关 | -| 正体希腊字母 | 4.1.3 的 TeX `mathchar0mi` 不读取 `env.font`,因此 `\mathrm{\delta}` 与普通 `\delta` 产生相同斜体路径;TeX 字库的 normal δ 又没有现成路径 | 在当前 TeX 实例的 token creator 中保留局部字体环境,再统一选择带度量的字形;保留已有扩展的 creator 链,所有版本耦合集中到字体适配器 | -| 数字与中文字体 | 在排版前注册字符的高度、深度、前进宽度和轮廓后,MathJax 能用这些数据完成分式、上下标与混排布局 | Windows 字体服务统一提供度量与轮廓,字体适配器注册局部 variant;先完成数据准备,再开始布局 | -| SVG 与 EMF 二次选字 | 现有 `SvgVectorGraphicsRenderer.AddTextGeometry` 会重新解析字体并固定用 `FontStyle.Regular` 描画 SVG 文本 | 最终 SVG 使用已经确定的轮廓,EMF 复用路径,不再在输出阶段为这些字形重新选字体 | - -MathJax 的阶段接入使用 [官方 renderActions 接口](https://docs.mathjax.org/en/latest/advanced/synchronize/renderactions.html)。token creator、variant 注册及字体数据结构属于固定到 4.1.3 的适配细节,升级时由本组回归检查。 - -**验证证据:** - -- .NET Framework 4.8 测试项目编译通过,零警告、零错误。 -- 真实 WebView2 完成 **11 组样例、69 项检查**:用户的三行条件概率 `align`、默认正体与粗体、嵌套矩阵、局部 `\mathbf` / `\mathrm` / `\mathit` 优先、普通 / 正体 / 粗体 δ、独立 Times New Roman 数字、宋体与微软雅黑混排。 -- 检查真实 SVG 几何在 viewBox 内,分子分母及上下标不重叠;数字字体改变会影响布局宽度,两个中文字体的独立文本高度 / 基线按实际度量变化。两种中文字体的全角字宽可以相同,不以“总宽度必须变化”作为成功标准。 -- **11 组 EMF** 均成功生成;枚举记录确认包含轮廓填充且没有依赖字体的文字输出记录。全部中间 SVG 均无 `` 回退。 - -复验: - -```powershell -dotnet run --project office_plugin/tests/LaTeXSnipper.OfficePlugin.Rendering.Smoke -- --typography -``` - -**本步边界:** 验证样例中的系统字体均做严格家族与样式匹配,未使用缺字体后的静默替代。正体 / 粗体 δ 暂以 Times New Roman 轮廓证明路径可行,这不是正式 TeX 字体方案的最终回退选择。当前按字形生成的测试数据只覆盖所列字符和样式;完整混排运行段、字距、缺字诊断、全部数学样式、拉伸符号、缓存和 OMML 属性映射在第 3 步实现,真实 Word / PPT 显示在第 8 步验收。 - -本步试验数据不进入安装资源。第 3 步已删除试验字体供给与注入实现,回归入口直接调用共享服务,当前支持范围与结果见第 11.6 节。 - -### 11.5 第 2 步实施记录(2026-09-13) - -已在现有 Abstractions 中实现四个共享入口: - -- `FormulaTypography`:不可变的完整样式快照,包括数学字体 ID、独立数字字体家族、中文字体、默认数学样式、绝对字号、颜色及样式契约版本。完整值相等比较覆盖每项样式,字体家族比较不区分大小写;字体实际可用性和回退结果留给渲染服务。 -- `FormulaMathStyle`:数学字形样式与字体家族分开表达。`Automatic` 保留节点固有样式;源码局部样式优先于快照默认样式。局部颜色先由解析层转换为 sRGB,再按同样优先级解析。 -- `FormulaFontSize`:唯一、只读的 16 项中文字号表;支持数字小数输入,统一校验 1–1638 pt。拒绝 NaN、无穷、越界、百分比与不明确的数字格式,不把非法用户输入换成默认字号。 -- `FormulaTypographyDefaults`:保存新建时的固定 / 跟随宿主选择。`ResolveForNewFormula` 产生完整快照,并报告字号来自固定设置、宿主或明确的后备值;无文字上下文、混合字号及 Office 未定义值使用配置中的后备字号。快照本身不携带“跟随宿主”开关,后续重绘直接使用快照。 - -内置默认值为 TeX 数学字体、数字跟随符号字体、微软雅黑、自动数学样式、12 pt 和黑色。默认值只用于构造新建偏好,不覆盖已经存在的快照。预设命名、存储及导入导出仍属于第 7 步。 - -新增独立的 `Typography.Tests` 契约测试项目并加入解决方案。本步 **.NET Framework 4.8 与 .NET 9 各通过 33 项测试**,覆盖全部字号名称与数值等价、区域设置、非法输入、完整样式比较、局部优先级、宿主字号变化、快照不变及后备来源诊断。双框架编译和现有构建分析规则通过;第 3 步增加 Rendering 引用以验证 OMML 映射。 - -```powershell -dotnet test office_plugin/tests/LaTeXSnipper.OfficePlugin.Typography.Tests -``` - -第 3 步已将此契约接入共享字体渲染。第 4 步同步切换 `RenderRequest`、schema 3、Word / PPT 和原生 handler;届时删除旧 `FormulaFontStyle`、源码包装及百分比字号路径,不增加新旧协议之间的样式转换层。 - -宿主接入时需要一并移除 Word 当前 `ReadPointSize` 的 `< 200` 判定和过早替换默认字号的行为,改为提交有效的单一文字字号或缺失上下文,让共享解析器决定后备值。PowerPoint 没有有效文字上下文时同样传递缺失值。当前契约测试验证这项规则;真实 COM 选区读取和文档重绘验收在第 4、8 步完成。 - -### 11.6 第 3 步实施记录(2026-09-13) - -共享 Rendering 模块新增以下职责清晰的实现: - -- `MathJaxTypographyAdapter.js`:集中处理 4.1.3 的解析样式、字体选择和排版前度量接入。局部样式优先于默认样式,保留化学扩展的私有 variant。TeX 未覆盖的字形统一尝试 STIX2 同样式数学字形补充,包含正体 δ;补充同时提供度量与轮廓,并返回诊断。 -- `SystemFontOutlineService` / `FontRunOutline`:按连续文本段生成系统字体度量与矢量路径,覆盖数字、汉字、标点、空格及局部粗斜体。检查实际字体、样式和字符覆盖;回退结果不修改用户请求的字体。所有路径在 MathJax 布局前准备完成。 -- `MathJaxSvgRenderer.Typography`:提供 `RenderTypographyAsync` 和 `ConvertTypographyToMathMlAsync`,统一请求队列、取消、超时与字体上下文恢复。输出自然 pt 尺寸和基线;SVG、EMF、PNG 复用同一轮廓。缓存键包含完整样式、源码、显示模式、运行时版本以及实际字体路径与度量,最多缓存 128 项。 -- `OmmlTypographyMapper`:将同一快照映射到新转换的 OMML。TeX / STIX2 分别映射 Cambria Math / STIX Two Math,数字和东亚文字使用各自字体,字号按 Word 半磅单位写入。局部样式由带样式 MathML 经现有 Office XSL 转换,映射器保留转换得到的局部属性;最终排版由 Word 管理。 - -字体实例与样式作用域在请求结束后恢复,不向客户端注入插件样式。初始化显式等待化学字体扩展,并在完整成功后发布字体实例,避免冷启动和失败重试留下半初始化状态。带 XML 声明的 MathML 通过共享输入适配提取数学元素后交给 MathJax。 - -**验证结果:** - -- 真实 WebView2 完成 **61 组 SVG / EMF、122 个 PNG**:两套数学字体、15 种默认数学样式、用户的多行条件概率、嵌套矩阵、局部字体与颜色、正体 / 斜体 δ、两种中文字体、数字分式与上下标、化学反应及 MathML 输入。检查实际字形差异、视口包围轮廓、分式和上下标不重叠、EMF 无文字输出记录、96 / 300 DPI 物理尺寸。 -- 覆盖缓存命中、绝对字号缩放、缺字与字体回退诊断、文本段尾随空格、粗斜体轮廓、取消和混合并发请求;实际 `MathMlToOmmlConverter` 转换与映射通过。 -- 样式及 OMML 测试在 **net48 / net9.0 各通过 35 项**;现有 Office 渲染 smoke 和 Python 共享运行时 4 项测试通过。Smoke 编译零警告、零错误。 - -**当前能力边界:** Windows 系统文本轮廓仅支持 BMP 字符,代理字符及控制字符明确报错;这不限制数学字库已有的补充平面字形。复杂数学样式的数字优先采用对应数学字形并返回诊断。正文中的拉丁文本使用 Times New Roman,汉字使用所选中文字体;未提供任意系统数学字体排版能力。没有可用轮廓时明确失败,不把不确定的文本回退嵌入最终 SVG。 - -**阶段交接:** 本步完成共享模块和直接调用回归,尚未切换编辑器界面、生产 `RenderRequest` 或文档协议。第 4 步一次切换全部宿主、schema 3 与原生 handler,并删除被替代入口;当前并存仅为分阶段实施,不是最终兼容架构。Word / PPT 文档操作和安装验收继续按第 4、8 步执行。 - -### 11.7 第 4 步实施记录(2026-09-14) - -协议与宿主已接入共享字体模块,真实 Word OMML 与 PPT PNG 验收通过。2026-09-20 用户确认结束第 4 步开发,继续编辑器重构;实际 Office 内 OLE 激活及转换并入最终安装包验收,仍不记为已通过。 - -- `FormulaMetadata` 切换 schema 3 并保存完整 `Typography`;`RenderRequest` 必须显式提供快照。已删除百分比字号、旧 SVG 响应解析 / 缓存和默认字体 / 颜色源码包装路径。 -- `FormulaTypographyFields` 统一样式序列化字段与校验。Word 文档变量保存 `typography` 对象;PPT 样式 JSON 复用源码的 UTF-8 十六进制分块编码;OLE payload 平铺同一组字段。未知协议、样式版本、缺失或损坏的样式在读取入口拒绝。 -- 原生 x86 / x64 handler 同步校验 schema 3、样式版本、字体方案、数学样式、颜色和绝对字号,原样持久化 payload。宿主仍管理公式身份与编号。 -- Word / PPT 新建、编辑、转换和格式化传递同一快照。所选 / 全文格式化共用流程,仅收集范围不同;默认样式不改写源码中的局部命令。OMML 保持原生类型,由 Word 处理最终字体行为。 -- 设置页改用绝对 pt 数值,支持新建时跟随有效文字字号,无有效上下文时使用配置字号。Word 批量解析读取各候选文字范围的字号;普通编辑和转换保留快照。用户手动缩放独立于快照,普通编辑保留缩放,主动格式化恢复自然尺寸。 -- 删除单独的 OMML 自然字号文档变量与旧恢复入口。自然字号取快照,OLE / PNG 自然宽高仍用于宿主缩放恢复。 -- 修复化学字体扩展早于数学字体注册的加载竞态:共享加载配置显式声明扩展对所用数学字体的依赖;客户端仍复用相同运行时。 -- Word 同一布局下更新公式时只替换 OMML 内容;仅行内 / 独行或编号模式变化时重建段落。避免字体更新触发段落删除,同时保留已有编号布局。 -- 每次独立公式转换重置 TeX 标签状态,包含轮廓准备与输出两个转换步骤,避免带 `\label` 的公式重绘时报重复定义。直接渲染回归覆盖重复 MathML 转换和切换样式后的 SVG 重绘。 - -已通过:托管解决方案构建,元数据安全及样式持久化 **17 项**、双框架样式测试各 **35 项**、**61 组 SVG / EMF 与 122 个 PNG**、Qt **3 组 SVG / MathML 与 5 个 CHTML 页面**、Python 共享运行时 **4 项**;原生 Release x86 / x64 构建通过。真实 Word OMML 已通过解析、取消续跑、重复解析、**33 个公式全文格式化**、保存和重开;重开后验证完整样式快照、源码、身份和文档结构,4 个预期非法输入保留。 - -补充实机与原生验收(2026-09-14): - -- [PPT 文档测试](../office_plugin/tests/LaTeXSnipper.OfficePlugin.PowerPointE2E/README.md):两页 PNG 公式的插入、选中加载、编辑、手动缩放保持、重复全文格式化、保存重开通过;完整字体快照、源码、身份和位置校验通过。测试独立注入渲染实例,不修改用户设置。 -- [原生 handler 测试](../office_plugin/tests/NativeOleHandler/README.md):x64 / Win32 直接加载正式 DLL,COM 工厂创建、schema 3 加载、EMF 提取、尺寸、存储保存重开及无效字号拒绝通过。此测试不修改 COM 注册,不能替代 Office 激活验收。 -- 本机当前注册的已安装 handler 拒绝 schema 3(`STG_E_INVALIDHEADER`)。临时切换当前用户 COM 路径的操作被自动审批规则拦截,返回 `blocked by policy`,未执行注册修改。不能用旧 handler 的结果判定新版 Office OLE 链路。 - -后续使用同时包含新版托管插件与 schema 3 handler 的安装包,检查 Office 内 OLE 激活、重编辑及 Word OMML/OLE、PPT PNG/OLE 双向转换。用户安装实测,发现问题继续修复;不再以临时 COM 注册阻塞第 5—7 步。完整安装发布与跨平台矩阵在第 8 步验收。 - -2026-09-20 迁移后续验:项目已迁移至当前仓库目录,托管解决方案重新构建通过。新增 `Test-OfficeTypographyE2E.ps1`,集中进行 64 位 Office 临时用户级注册、执行 Word OLE / PPT OLE 测试及正常退出时的清理,不覆盖已有用户级注册。两个宿主的双向转换、激活和重新编辑测试已加入并编译通过,尚未验收通过。前次运行中断后遗留测试注册,且注册脚本重复创建 key 清掉 DLL 默认值;已修复该脚本并增加注册值校验、运行阶段输出与日志保存。清理遗留测试注册的命令再次被自动审批拒绝(`blocked by policy`),此处记录当时的阻塞情况;随后用户手工清理报告相关键不存在,并确认 Office OLE 实测推迟到第 8 步安装包验收。该历史记录不构成继续第 5—7 步的前置任务。 - -### 11.8 第 5 步实施记录(2026-09-20) - -- Word/PPT 同时用共享 CodeMirror 6 替换 textarea。提供命令、环境、括号、数字、运算符、中文、注释的明暗颜色定义,以及行号、括号匹配 / 配对、环境缩进、命令 / 环境补全、查找替换和结构错误定位。 -- `SourceEditor` 统一文档与撤销历史;`SourceSync` 管理编辑来源、修订号、延迟预览和组合输入。可视化修改进入同一文档历史,提交读取当前源码;仅新建编辑会话重置历史。 -- MathLive 静默接收参考内容,单独的加载、失焦或通知不回写;无法可靠往返的源码保留源码编辑,上方只读并显示提示。符号库在源码焦点下插入源码;不会借此重建整份复杂公式。 -- 移除被替代的文本框同步与未调用的默认字体 / 颜色前端辅助函数。MathLive 提示音关闭,避免请求未发布的音频文件。 -- 构建工具与锁定依赖位于 `tools/office-editor`;运行时只有本地 bundle、共享模块、样式和许可证,沿用两个宿主及安装器的共享资源复制链路,无在线依赖。 -- 回归覆盖 11 项同步 / 结构行为和 6 项真实 Edge 页面交互;包括复杂源码、撤销重做、过期通知、组合输入事件、补全缩进、查找替换、符号插入、新会话和提交锁定。浏览器测试说明见 [源码编辑器维护入口](../tools/office-editor/README.md)。 - -本步未接入最终字体效果预览或预设存储。基础诊断只检查分组和环境,不冒充完整 TeX 语法校验;真实 Windows 输入法与 Office 内交互在第 8 步检查。下一步按第 11.9 节先实施 6A 编辑器布局与磁贴库,再进入 6B 字体设置和最终预览。 - -### 11.9 第 6 步编辑器布局与交互方案(2026-09-20 用户确认,6A 已完成) - -目标是让公式、源码与符号插入围绕同一编辑会话工作。复用第 5 步 CodeMirror、SourceSync 和已有渲染契约;先完成布局和插入交互,再接字体和预览,最后收尾交互。不另外引入大型前端框架,不重建同步机制。 - -**默认布局:** - -```text -顶部工具栏:撤销 / 重做、字体设置、字号、颜色、预设、布局 -公式区域:可视化编辑 / 最终预览切换 -可拖动分隔线 -LaTeX 源码区域:CodeMirror 与诊断 -底部符号库:分类标签与统一搜索 + 两行可滚动磁贴 -底栏:状态、取消、插入 / 更新 -``` - -- 删除长期占据左侧宽度的旧符号库布局,Word / PowerPoint 共用新布局和组件。公式与源码区域保持可拖动分隔;磁贴区可折叠,小窗口优先保留编辑空间和提交操作。 -- 磁贴分类覆盖常用、结构、微积分、矩阵、关系、希腊字母、箭头、集合逻辑、物理、化学等现有内容。简单符号使用紧凑磁贴,结构模板适当加宽,显示数学外观和占位框;悬停说明名称、命令及已定义的快捷键。 -- 鼠标位于磁贴内容区时,滚轮横向浏览当前分类;保留触控板原生横向滚动和左右翻页按钮。不拦截源码区、公式区的正常滚动;分类标签与内容滚动分别处理。 -- 合并当前全局 / 分类两个搜索框,统一按中文名称、英文名称及 LaTeX 命令搜索。分类和搜索使用同一条目目录,不维护重复列表。 -- 点击磁贴前保留最后活动的编辑器与选区。统一插入入口负责向源码或 MathLive 插入,支持以选中内容填入模板、进入第一个占位符及 Tab 跳转;每次模板插入形成一个可撤销操作。无法可视化编辑的公式仍在源码区操作;组合输入期间不打断输入法。 -- 磁贴支持键盘导航与回车插入,关闭搜索或面板后恢复合理焦点。模板插入、命令补全与磁贴共享数据定义;各编辑器只适配自己的选区和占位符接口。 -- 上方通过“编辑 / 最终预览”切换复用空间,MathLive 负责可视化编辑,最终预览复用统一渲染请求与草稿样式。复杂公式继续支持源码编辑;OMML 明确显示为参考效果,不承诺 Word 像素一致。 -- 工具栏常驻字号、颜色与字体设置入口,展开后提供符号 / 数字 / 汉字字体及字形设置。预设功能在第 7 步接通,尚未实现时不展示可点击的空入口。 -- 磁贴采用固定展示样式并缓存,按可见内容按需生成,避免一次渲染全部模板;不随用户每次字体调整重建磁贴。通过公式最终预览呈现用户字体效果,资源保持离线可用。 -- 完整公式模板库可在后续作为按需打开的侧栏扩展;本次 6A 先完成现有符号与结构模板,不以大型公式库建设作为验收前提。 - -**实施与验收顺序:** - -1. **6A 布局与磁贴库:** 共享布局、目录数据、搜索与滚动、焦点与选区保存、统一模板插入。验证源码和 MathLive 两种目标、复杂环境只读参考、选区包裹、占位符跳转、撤销重做和提交锁定;新路径接通后移除被替换的旧布局与插入逻辑。 -2. **6B 字体设置与最终预览:** 接通三类字体、中文 / 数字字号、颜色及预览切换。验证同一源码 / 样式修订、异步过期结果丢弃、取消不落盘以及插入采用当前有效状态;不复制字体列表、字号表或渲染规则。 -3. **6C 交互收尾:** 验证键盘操作、焦点恢复、窗口缩放、明暗主题、滚轮 / 触控板和输入法事件。实际 Windows 输入法与 Office WebView2 交互能测则测,尚未完成的真实宿主检查明确进入第 8 步验收,不用浏览器模拟结果代替。 - -6A、6B、6C 分别完成实现、差异审查和对应行为验证,再进入下一项。随后实施第 7 步预设与用户配置,最后统一构建安装包并验收。 - -### 11.10 新对话接续说明(2026-09-25 更新) - -- **当前工作目录:** 用户已合并 6B 到主线,并指定在主仓库目录的 `codex/office-typography` 分支继续;启动时用 `git status` 和 `git worktree list` 核实,不继续写入旧 Office worktree。命令与依赖路径相对当前仓库根目录解析,工具链通过 PATH / 标准环境配置发现。 -- **下一项唯一实施起点:第 7 步。** 6A / 6B / 6C 记录见第 11.11—11.13 节。6C 已获用户授权提交推送;后续工作先检查分支与工作树,保留现有实现。预设与用户配置按第 11.2 节单独推进,不提前把配置存储混入编辑交互。 -- 用户选择 `34516e96e`(6A 与路径修复)为回退基线,6B 从该基线重新推进,不恢复后续废弃实现。本轮获授权提交推送 6B;后续提交仍遵循用户指令。禁止死逻辑、死函数、旧版本兼容分支和墓碑测试。 -- 共享编辑器入口为 `office_plugin/src/LaTeXSnipper.OfficePlugin.Editor/EditorAssets`,构建源码与浏览器测试位于 `tools/office-editor`;两宿主页面位于各自的 `EditorAssets`。CodeMirror bundle 由构建生成,不手工编辑产物。 -- 当前验证记录:6C 的 22 项 Node 与 23 项 Edge 页面交互通过,托管解决方案零警告、零错误。6B 的 .NET 排版与真实 WebView2 渲染证据见第 11.12 节,本轮未修改渲染器,也未重跑该矩阵。继续修改按实际范围复验;操作说明见 `tools/office-editor/README.md`。 -- **不要重新启动临时 COM 注册清理 / 修改来阻塞开发。** 用户已确认 Office OLE 激活、重编辑及双向转换留待最终安装包,由用户安装实测;未通过的检查仍标为待验收。 -- 工具链:Node 通过 `PATH` 查找;Python 使用开发者自行选择的环境;Visual Studio 工具链通过安装发现或显式配置定位。实际可用性在需要时检查。 - -### 11.11 第 6A 步实施记录(2026-09-20) - -- Word / PowerPoint 的 HTML 只加载共享资源;布局集中在 `editor-layout.mjs` 与 `editor.css`。顶部接通撤销 / 重做,公式与源码保持拖动及键盘调整分隔线,底部为可折叠的两行磁贴、独立分类滚动与统一搜索,提交栏始终保留。字体、最终预览和预设入口未提前展示。 -- `symbol-library.mjs` 保存现有条目,`template-catalog.mjs` 按模板归并分类和别名,提供常用、矩阵及全部现有分类。中文、英文与命令统一搜索,补全与既有可视化快捷键从同一目录取模板。矩阵保留 1—10 行 / 列,分段和方阵的既有维度规则由共享生成器处理。 -- `symbol-panel.mjs` 仅对可见结构磁贴生成固定样式的静态数学外观,缓存最多 128 项;不为磁贴创建编辑器,不依赖在线资源。磁贴内容区将纵向滚轮转换为横向浏览,原生横向触控板滚动与翻页按钮保留;不拦截公式、源码或分类区滚动。 -- `template-insertion.mjs` 保存实际活动编辑器与可视化选区,搜索、切换分类及矩阵尺寸选择不改变插入目标。源码编辑器保留自身选区;复杂环境继续只读参考并在源码区插入。模板支持选区填充、Tab / Shift-Tab、独立撤销;源码占位符按实际位置跟随编辑,保留转义花括号、多行及类似模板语法的原始文本。 -- 磁贴支持方向键、Home / End 与回车;退出搜索或折叠面板恢复编辑焦点。MathLive 的实际鼠标 / 键盘事件也更新目标,覆盖新会话已持有焦点、未再次发出 `focusin` 的情况。组合输入和提交锁定共用状态守卫,锁定不会被延迟参考刷新解除。 -- 删除两份旧左右布局 CSS、双搜索框、旧网格和分散插入逻辑;条目、矩阵与输入模块改为明确的 ES module 导入。CodeMirror bundle 已从构建源码重新生成,未手工编辑产物。 - -**已执行验证:** - -- `tools/office-editor`:构建成功;18 项 Node 测试、14 项真实 Edge 页面交互测试全部通过。覆盖两宿主、源码 / MathLive 两种目标、空公式开始填写、复杂参考、矩阵尺寸、选区包裹、占位符前后跳转、撤销重做、补全、锁定及组合输入事件。 -- 浏览器检查包含 1180×780 明色、980×680 暗色与 640×480 小窗口;页面标识、可见内容、控制台、折叠 / 恢复、键盘导航、滚轮区域隔离、翻页及静态缓存复用均通过,并查看截图确认布局。浏览器使用本地资源路由模拟 WebView2 虚拟主机;此证据不替代真实 Office 验收。 -- `dotnet build office_plugin/LaTeXSnipper.OfficePlugin.slnx --no-restore -v:minimal` 成功,零警告、零错误;两宿主各 14 个共享资源文件均已与源码逐一核对哈希。检查修改差异及资源复制链路,未改变元数据、样式或渲染协议。 - -**后续边界:** 下一步 6B 接入三类字体、字号、颜色与最终预览;6C 继续收尾交互。真实 Windows 输入法、物理触控板和 Office WebView2 交互仍待第 8 步安装包验收。未重新进行临时 COM 注册或 Office OLE 激活操作,未提交、未推送。 - -### 11.12 第 6B 步实施记录(2026-09-23) - -- 工具栏常驻字号(数字 pt / 中文名称)、颜色、字体设置及编辑 / 最终预览切换;字体面板提供数学符号、数字(可跟随符号)、汉字和默认数学字形。未提前接入第 7 步预设存储。 -- 符号字体目录读取随包 `MathJax/config.js`;系统字体由共享编辑器枚举;中文字号、范围、字形枚举由原生契约传给前端,不在 Word / PPT 或 JS 中复制目录。旧文档指定但当前未安装的系统字体保留在选择中,实际回退由统一渲染器报告。 -- `typography-panel.mjs` 管理控件与草稿校验;`draft-preview.mjs` 管理合并请求、会话 / 修订、取消和结果筛选。源码或排版变化立即隐藏旧图;组合输入、提交锁定、取消、新会话均使待处理结果失效;提交失败后恢复当前预览。无效字号不使用旧值提交。 -- 原生桥接位于 `MathLiveFormulaEditorForm.Typography.cs`;通过注入的 `IFormulaRenderer` 复用宿主 MathJax 实例,预览采用当前完整样式、行内 / 独立模式和共享源码规范化。SVG 以自然 pt 尺寸展示,错误和字体回退警告可见;Word OMML 标明参考效果,以 Word 实际排版为准。 -- 提交事件携带不可变 Typography 快照;Word / PPT 在判断“未修改”之前应用草稿样式,避免仅改字体被忽略。编辑窗口取消不写入文档或设置;两个宿主校验会话编号并阻止重复提交。 - -**已执行验证:** - -- 22 项 Node 行为测试通过,包含源码 / 样式合并、过期结果、组合输入、取消、新会话以及提交失败恢复。 -- 17 项 Edge 页面测试通过(完整 16 项后,新增布局测试与受影响的 2 项再次通过);覆盖两宿主字体 / 中文字号 / 颜色 / 字形提交、失效结果、无效字号、渲染失败、OMML 标签、行内模式、新会话、锁定及 640×480 明暗布局;已查看截图。测试桥接响应为模拟,不能据此宣称真实宿主渲染通过。 -- net48 / net9.0 排版契约各 37 项通过,新增字体配置目录读取及独立样式快照验证;解决方案构建零警告、零错误。两个宿主各 16 个共享编辑资源与源码哈希一致。 -- 真实 WebView2 `Rendering.Smoke --typography` 通过 61 组 SVG / EMF、122 个 PNG 输出,以及 MathML、缓存、字号和字体诊断检查;未启动 Office 或临时注册 COM。 -- BrowserSkill CLI / skill 已安装;Chrome 扩展连接后完成独立会话导航、页面读取和关闭,最终会话列表为空。普通沙箱账户访问用户后台管道会被系统拒绝,本机验证使用获准的用户进程环境。 - -**接续 6C:** 重点复验字体面板和预览切换前后的键盘与焦点、模板目标 / 选区、尺寸和主题、滚轮 / 触控板及输入法事件。保留当前草稿 / 修订规则,不增加另一套渲染、字体或持久化配置。真实 Windows 输入法、Office WebView2 与 OLE 激活 / 重编辑 / 双向转换仍由第 8 步安装包验收,不记为已通过。 - -### 11.13 第 6C 步实施记录(2026-09-25) - -- 预览往返保留此前编辑目标与可视化选区;若在预览期间改动源码,则回到当前源码选区,不恢复过期可视化位置。新会话清理前一目标并聚焦源码。 -- 修复 MathLive 延迟焦点回调覆盖源码 / 工具栏焦点的问题:按实际鼠标、键盘进入意图及最近焦点所有者交接焦点;显式恢复可视化编辑通过原生元素焦点进入,不依赖定时重试。插入目标与当前工具栏焦点保持独立。 -- MathLive 支持 `Escape → Tab` / `Escape → Shift-Tab` 离开编辑器,通常的 Tab 占位符跳转保留;增加可访问说明。全局快捷键尊重已处理事件、组合输入及 IME 的 229 键码,避免截获源码编辑器的操作。 -- 字号组合输入与源码 / MathLive 组合输入共同阻止提交、预览切换、撤销和磁贴插入;未提交的中文字号不触发最终预览。字体面板在外部点击或键盘焦点离开时关闭,Escape 返回入口;小窗口限制面板高度并允许滚动。 -- 分隔线在短窗口中按可用空间限制两块编辑区域,ARIA 范围同步更新;紧凑布局减少可视化编辑区内边距与最小高度。磁贴保留像素 / 行 / 页滚轮处理,横向滚动与 Ctrl 滚轮继续交给浏览器。 - -**已执行验证:** - -- 22 项 Node 行为测试通过。23 项 Edge 页面交互通过:完整 22 项通过后,新增焦点测试及受影响的 IME / 小窗口测试定向通过。覆盖 Word / PPT、预览往返选区、源码更新、新会话、输入法事件、键盘退出与进入、延迟焦点保护及轮滚隔离。 -- 1180×780 / 980×680 / 640×480 既有明暗测试通过,新增 640×400 短窗口;已查看截图,并修正可视化公式裁切。真实触控板仅保留原生横向事件路径,未冒充物理设备实测。 -- 托管解决方案构建零警告、零错误,两个宿主各 16 个共享编辑资源与源码哈希一致;CodeMirror 构建源码未改动,未手改 bundle。 - -**后续边界:** 用户已授权提交推送本轮全部改动;下一项为第 7 步预设与用户配置。真实 Windows 输入法、Office WebView2、物理触控板及 Office OLE 激活 / 重编辑 / 转换仍留待第 8 步安装包验收,浏览器组合事件测试不能代替这些检查。 - -## 12. 验收矩阵 - -### 12.1 公式与字体 - -- 用户提供的条件概率 `align` 公式:中文说明、对齐、分式与条件符号保持正确,默认字体和批量格式化生效。 -- `align*`、`aligned`、`gathered`、`split`、`cases`、嵌套矩阵,以及带注释、转义符和换行间距的输入。 -- `\delta`、`\mathrm{\delta}`、`\mathbf{\delta}`、局部向量 / 微分符号,分别验证数学样式。 -- 一处局部字体命令不阻止其余节点应用默认字体;重复格式化不叠加源码包装。 -- 数字位于分式、上下标、矩阵时切换字体,位置与度量正确。 -- 中文和英文同在 `\text{}` 中,包含空格、中文标点和多个中文字体,显示不裁切、不重叠。 -- 缺字体 / 缺字时提示实际回退;已经嵌入文档的矢量呈现不因另一台机器缺字体而改变。 - -### 12.2 字号与一致性 - -- 中文字号名称与对应数字输入产生相同结果;验证 10.5pt、12pt、较大字号和非法输入。 -- 同一公式预览与 OLE / PNG 的字形、自然尺寸和基线一致,DPI 不改变物理大小。 -- 改变 Word 光标字号后重新打开已保存的新协议公式,其字号不漂移。 -- 普通编辑保持手动缩放;主动格式化恢复目标自然尺寸。 -- MathLive 不支持的源码可以完整保存和最终预览,不被转换成另一份源码。 - -### 12.3 编辑与预设 - -- 中文输入法、粘贴复杂公式、撤销重做、查找替换、括号匹配、明暗主题及键盘操作。 -- 快速连续输入 / 换预设时,过期预览不覆盖新结果,提交不使用旧结果。 -- 保存、另存、加载、导入导出、默认预设与单公式快照互不混淆。 -- 预设删除或改名后,文档仍可依照自身快照重绘。 -- 损坏配置、未知版本和多宿主同时保存有可恢复行为。 - -### 12.4 宿主与升级 - -- Word OLE、PowerPoint OLE / PNG:新建、重新编辑、所选 / 全文格式化、保存重开、复制粘贴与既有转换。 -- OMML 参与所选 / 全文字体格式化:验证支持属性写入及重复执行稳定,公式内容、结构、编号、引用和 OMML 类型不变;不做与 MathLive / OLE 的像素对齐验收。 -- schema 3 所有存储层往返完整;其他版本在入口拒绝编辑,不存在隐式迁移或旧渲染回退。 -- x86 / x64 OLE 激活及常用 Office 版本验证。 -- 对新配置契约执行连续覆盖升级,确认用户默认值与预设保留;验证安装清理不触及用户配置目录。 -- 发行包只包含最终选定的一代 MathJax;检查新增包只包含必要编辑器与字体资源,记录体积及冷启动 / 连续预览耗时。沿用已验证的裁剪运行资源,不重新引入完整组合包。 - -验证使用现有 .NET / 原生测试和真实 Office E2E 入口。Python 辅助脚本使用开发者自行选择的环境运行。第一阶段已执行的验证见运行时维护说明;本节中的字体重构验收仍待第二阶段完成。 - - -## 13. 客户端与插件统一升级、保留导出职责 - -### 13.1 已确认的四点结构 - -1. 一份版本锁定和声明式资源清单:MathJax、字体和扩展有固定版本与完整性记录。两端升级至同一 v4,不保留“客户端 v3、插件 v4”的长期分叉。 -2. 一套共享 JavaScript 配置基础与转换接口:统一扩展集合、字体资源定位和必要语义处理;Python / C# 仅保留各自 WebEngine / WebView2 消息桥接,不重复维护规则列表。 -3. 两个声明式打包配置:客户端包含 CHTML + SVG 及 MathML 转换能力,插件包含 SVG 及 MathML 转换能力。CHTML 属于客户端真实需求,不能直接使用插件的 SVG 精简包替换客户端目录。 -4. 两端独立安装运行:共享资源来源和构建逻辑,各安装包携带所需子集;插件运行时不依赖客户端的安装路径和版本。 - -当前客户端的普通、混合内容和智能预览加载 CHTML,导出转换使用 SVG / MathML。客户端保持现有预览输出类型,不为统一版本强制将所有预览改成 SVG。 - -当前实际资源为客户端约 6.77 MiB、插件约 5.40 MiB,包含共享适配器及资源清单;这是资源目录大小,不是安装包压缩体积。Qt WebEngine、WebView2 和 EMF 运行验证已经完成。 - -### 13.2 当前客户端导出依赖审计 - -源码依据:`src/exporting/formula_export.py`、`formula_converters.py`、`formula_format_helpers.py`、`pandoc_exporter.py` 和 `src/ui/editor_actions_controller.py`。 - -| 导出项 | 导出时的路径 | 阅读输出时是否需要 MathJax | -| --- | --- | --- | -| LaTeX 行内 / display / equation | 源码规范化外层定界符,再按格式包装;不调用 MathJax | 由接收方决定,与客户端导出无关 | -| Markdown 行内 / 块级 | 保留公式源码并加美元定界符;不调用 MathJax | 由 Markdown 阅读器决定 | -| MathML 及其 mml / m / attr 变体 | 本地 MathJax → MathML → 标准化 / 命名空间处理 | 输出不自带 MathJax,由阅读器处理 MathML | -| 普通 HTML(`html`) | 本地 MathJax → MathML → span 包装的 HTML 片段 | 片段不附带 MathJax 脚本,依赖接收方的 MathML 支持 | -| Word OMML(`omml`) | 本地 MathJax → MathML → Microsoft MML2OMML.XSL → OMML | 不需要 MathJax,由 Word 排版 | -| SVG Code(`svgcode`) | 本地 MathJax → 独立 SVG | 不需要 MathJax 运行时;外部字体或文本回退仍需按输出内容考虑 | -| Pandoc HTML 独立页 | Pandoc `--standalone --mathjax`,没有调用本地 MathJax 转换器 | 需要 MathJax 排版公式;现有脚本通常引用 CDN,不等于离线自包含 | -| Pandoc DOCX / PPTX / ODT / EPUB / Typst / plain | Pandoc 转换源码,不调用本地 MathJax 转换器 | 由输出格式与阅读器决定,不由本地 MathJax 运行时负责 | -| Pandoc PDF | Pandoc + 已配置 / 探测到的 LaTeX 引擎 | PDF 阅读不需要 MathJax | - -Pandoc 的所有格式统一进入文件保存流程,包括 HTML 独立页(`.html`)、Typst(`.typ`)与纯文本(`.txt`)。文本文件使用 UTF-8 编码;后台转换后保存,取消保存不执行转换。普通 HTML 片段继续使用原有文本导出流程。 - -普通 HTML 与 Pandoc HTML 独立页是不同的导出路径。当前 Pandoc HTML 已使用精确版本脚本参数,并由共享加载器提供 4.1.3 配置;已移除浮动 `@4` 地址。 - -### 13.3 共享运行时与样式职责 - -**共享 MathJax 不意味着共享用户样式覆盖。** 客户端导出默认不注入 Office 插件预设、当前 Word 字号、界面主题颜色或预览缩放。插件传入自身公式样式快照;客户端传入源码及自身明确的导出选项。两者使用同一转换服务,参数来源不同,不建立两份转换实现。 - -当前转换接口已经按请求输出 MathML 或 SVG;后续保留这一接口,不恢复每次强制同时转换的路径。 - -### 13.4 已完成与后续边界 - -运行时升级已经结束:两端统一 4.1.3,异步桥接、CHTML 配置、精确 CDN / HTML 版本和裁剪资源均已接入。测试与复验入口集中维护在 [运行时说明](../tools/mathjax/README.md),不再保留独立体积评估或重复的历史验收记录。 - -`mhchem` 在升级前的客户端与插件中已经启用;4.1.3 的化学字体扩展是保留既有化学公式能力的配套资源,不是仅为编辑器新增的一项功能。 - -插件重构已完成共享字体渲染、宿主与 schema 3 接入、源码编辑与同步以及 6A 编辑器布局 / 磁贴库、6B 字体设置 / 最终预览。6C 交互收尾也已完成,下一步实施独立预设;Office 内 OLE 实机检查、正式安装及跨平台矩阵随最终安装包验收完成。 diff --git a/docs/user_data_storage.md b/docs/user_data_storage.md index 0d265307..7dc9acfd 100644 --- a/docs/user_data_storage.md +++ b/docs/user_data_storage.md @@ -19,8 +19,8 @@ and temporary files. Keep new app-managed writes under the shared helpers in | Main settings | `LaTeXSnipper_config.json` | Unified application settings, including dependency root, recognition backends, external models, Automation API, theme, rendering, export, and window behavior | | Local secret key | `secret.key` on Linux/macOS; Windows uses DPAPI and does not create this file | `runtime.secret_store`; created when the first persistent secret is encrypted | | Automation API discovery | `automation-api.json` | Ephemeral local address and per-session token; created only while the API runs and removed on shutdown | -| Recognition history | `history.json` | Main window history; no user-facing path selector | -| Favorites | `favorites.json`; user-facing export writes a copy to a chosen folder without changing the app data path | Favorites window | +| Recognition history | `history.json` | Main window history | +| Favorites | `favorites.json` | Favorites window | | Single-instance lock | `instance.lock` | Runtime single-instance guard | | Release cache | `release_etag_cache.json` | Update checker | | Downloaded update package | `updates/` | Update installer and `installer_meta.json` cache; old packages are pruned | @@ -104,7 +104,7 @@ tools, and model weights. |---|---| | Windows | Before the standard Inno uninstall confirmation, the uninstaller prompts for three optional cleanup choices: app data/logs/temp, app-managed shared tools, and MathCraft model weights. After the standard uninstall confirmation is accepted, it asks Windows/Inno to close LaTeXSnipper, force-closes any remaining `LaTeXSnipper.exe`, then runs selected cleanup before the main install payload is removed. The installed `\_internal` directory is removed unconditionally as part of uninstall. User-selected external Python roots are never read from config or deleted. | | Linux `.deb` | Package removal does not delete home-directory data. Run `latexsnipper-clean-user-data --deps` and any other needed cleanup options before `apt purge`, or remove the documented user data roots manually. The script removes shared tools under the app state root and does not read or delete `install_base_dir`. | -| macOS `.dmg` / `.app.zip` | Moving the `.app` to Trash removes the app bundle only. The app bundle includes `Contents/Resources/Uninstall User Data.command`; the `.dmg` also exposes `Uninstall User Data.command` next to the app. The script follows the same current-user cleanup policy as Linux. | +| macOS `.dmg` | Moving the `.app` to Trash removes the app bundle only. The app bundle includes `Contents/Resources/Uninstall User Data.command`; the `.dmg` also exposes `Uninstall User Data.command` next to the app. The script follows the same current-user cleanup policy as Linux. | Custom `MATHCRAFT_HOME` directories are never deleted automatically because they may point outside LaTeXSnipper-owned storage. Dependency tools created by diff --git a/office_plugin/README.md b/office_plugin/README.md index 9027a615..476754f7 100644 --- a/office_plugin/README.md +++ b/office_plugin/README.md @@ -75,7 +75,7 @@ office_plugin\installer\build.bat Release The build reads the shared product version from the repository `VERSION` file. -Output: `office_plugin\release\OfficePluginSetup-3.0.0.exe` +Output: `office_plugin\release\LaTeXSnipper_3.1.0_office_amd64.exe` Run the installer as administrator. Close Word and PowerPoint before installation, upgrade, or removal. diff --git a/office_plugin/hosts/PowerPointAddIn/DynamicPowerPointApplicationAdapter.cs b/office_plugin/hosts/PowerPointAddIn/DynamicPowerPointApplicationAdapter.cs index 57f12899..bcdfd72a 100644 --- a/office_plugin/hosts/PowerPointAddIn/DynamicPowerPointApplicationAdapter.cs +++ b/office_plugin/hosts/PowerPointAddIn/DynamicPowerPointApplicationAdapter.cs @@ -29,10 +29,16 @@ public double GetCurrentFontSizePoints() { try { - double points = Convert.ToDouble(_application.ActiveWindow.Selection.TextRange.Font.Size); + dynamic selection = _application.ActiveWindow.Selection; + if (Convert.ToInt32(selection.Type) != 3) + { + return 0; + } + + double points = Convert.ToDouble(selection.TextRange.Font.Size); return FormulaFontSize.IsValid(points) ? points : 0; } - catch (Exception error) when (error is COMException || error is Microsoft.CSharp.RuntimeBinder.RuntimeBinderException) + catch (Exception error) when (error is COMException || error is ArgumentException || error is Microsoft.CSharp.RuntimeBinder.RuntimeBinderException) { return 0; } @@ -666,6 +672,78 @@ private dynamic GetActiveSlide() } } + public PowerPointTextInsertionTarget? CaptureTextInsertionTarget() + { + try + { + dynamic selection = _application.ActiveWindow.Selection; + if (Convert.ToInt32(selection.Type) != 3) return null; + if (Convert.ToInt32(selection.TextRange.Length) != 0) + throw new InvalidOperationException(PowerPointAddInText.Get("TextCaretRequired")); + + dynamic shape = selection.ShapeRange.Item(1); + if (Convert.ToInt32(shape.HasTextFrame) != MsoTrue) return null; + dynamic slide = GetActiveSlide(); + if (Convert.ToInt32(shape.Parent.SlideID) != Convert.ToInt32(slide.SlideID)) return null; + dynamic range = shape.TextFrame2.TextRange; + return new PowerPointTextInsertionTarget( + shape, + GetCurrentDocumentId(), + Convert.ToInt32(slide.SlideID), + Convert.ToInt32(shape.Id), + Convert.ToInt32(selection.TextRange2.Start), + Convert.ToInt32(range.Length), + Convert.ToString(range.Text) ?? string.Empty, + GetCurrentFontSizePoints()); + } + catch (Exception error) when (error is COMException || error is ArgumentException || error is Microsoft.CSharp.RuntimeBinder.RuntimeBinderException) + { + return null; + } + } + + public Task InsertNativeEquationAsync(PowerPointTextInsertionTarget target, string mathMl, double fontSizePoints, + CancellationToken cancellationToken) + { + cancellationToken.ThrowIfCancellationRequested(); + if (target == null) throw new ArgumentNullException(nameof(target)); + if (!string.Equals(target.DocumentId, GetCurrentDocumentId(), StringComparison.Ordinal) + || Convert.ToInt32(GetActiveSlide().SlideID) != target.SlideId) + throw new InvalidOperationException(PowerPointAddInText.Get("TextCaretChanged")); + + dynamic shape = target.Shape; + dynamic fullRange = shape.TextFrame2.TextRange; + if (Convert.ToInt32(shape.Id) != target.ShapeId + || Convert.ToInt32(shape.Parent.SlideID) != target.SlideId + || !string.Equals(Convert.ToString(fullRange.Text), target.OriginalText, StringComparison.Ordinal) + || Convert.ToInt32(fullRange.Length) != target.TextLength) + throw new InvalidOperationException(PowerPointAddInText.Get("TextCaretChanged")); + + ActivateForEditingAsync(cancellationToken).GetAwaiter().GetResult(); + shape.TextFrame.TextRange.Characters(target.Start, 0).Select(); + try + { + PowerPointMathMlClipboard.PasteAtSelection(_application.ActiveWindow.Selection, mathMl); + int insertedLength = Convert.ToInt32(shape.TextFrame2.TextRange.Length) - target.TextLength; + if (insertedLength <= 0) + throw new InvalidOperationException(PowerPointAddInText.Get("NativeEquationInsertFailed")); + dynamic inserted = shape.TextFrame2.TextRange.Characters(target.Start, insertedLength); + dynamic equation = inserted.MathZones(1, 1); + if (Convert.ToInt32(equation.Start) != target.Start) + throw new InvalidOperationException(PowerPointAddInText.Get("NativeEquationInsertFailed")); + equation.Font.Size = fontSizePoints; + } + catch + { + int insertedLength = Convert.ToInt32(shape.TextFrame2.TextRange.Length) - target.TextLength; + if (insertedLength > 0) + shape.TextFrame2.TextRange.Characters(target.Start, insertedLength).Text = string.Empty; + throw; + } + + return Task.CompletedTask; + } + private static InsertionPoint GetInsertionPoint(dynamic slide, float widthPoints, float heightPoints) { try diff --git a/office_plugin/hosts/PowerPointAddIn/EditorAssets/help.html b/office_plugin/hosts/PowerPointAddIn/EditorAssets/help.html index ad641e91..28da798d 100644 --- a/office_plugin/hosts/PowerPointAddIn/EditorAssets/help.html +++ b/office_plugin/hosts/PowerPointAddIn/EditorAssets/help.html @@ -3,338 +3,193 @@ - LaTeXSnipper Office Plugin Help + LaTeXSnipper Office 帮助
-

LaTeXSnipper Office 插件

-

在 Word 和 PowerPoint 中插入、编辑、转换和维护 LaTeXSnipper 公式。

+
LATEXSNIPPER · OFFICE
+

公式使用指南

+

从新建公式到修改、编号与批量整理,按实际操作顺序查找。

- -
-

系统要求

- - - - - - - - - -
组件要求
Windows 版本Windows 10 22H2 或更高版本 / Windows 11
Office 版本
  • Microsoft 365 应用(当前通道或月度企业通道)
  • Office 2024 / 2021 / 2019 零售版或批量许可版
  • Office LTSC 2024 / 2021
运行时.NET Framework 4.8;Microsoft Edge WebView2 Runtime(Windows 11 已内置;M365 会自动安装)
Office 体系仅支持 32 位和 64 位桌面版 Office;不支持网页版、移动版和 macOS 版 Office
LaTeXSnipper 桌面端需在本机运行并开启自动化接口;插件通过受身份验证的本机 Automation API 连接桌面端
-
- -
-

快速开始

-
-

1. 启动桌面端

打开 LaTeXSnipper 桌面端,在设置中启用 Office 插件功能。

-

2. 打开编辑器

使用 Ribbon 插入按钮打开 MathLive 编辑器,输入或选择需要插入的公式。

-

3. 插入到文档

默认使用 OLE 公式对象插入。侧边栏只负责独立草稿和新插入;更新公式只从编辑器窗口提交。

+ +
+

开始使用

+
+
1 · 打开插件在 Word 或 PowerPoint 顶部的 LaTeXSnipper 选项卡中选择插入公式。
+
2 · 写入公式在上方可视化区域输入,或在下方源码区写 LaTeX;也可以从左侧符号库选择公式。
+
3 · 插入文档确认字号和颜色后点击“插入”。选中已有公式并点击“加载所选”,可修改后点击“更新”。
-
公式编辑与渲染在插件内本地完成;截图识别需要本机 LaTeXSnipper 桌面端。
-
- -
-

编辑器快捷键

-

MathLive 输入区按 Enter 新建数学行,首次换行会自动进入多行数学环境;按 Shift+Enter 插入或更新公式。Ctrl+F、Ctrl+R、Ctrl+H、Ctrl+L、Ctrl+J 分别插入分式、根号、上标、下标和上下标。空格键插入数学薄空格。Esc 不关闭编辑器,只收回 MathLive 虚拟键盘。提交期间按钮会禁用;如果 Office 正在执行加载、删除、重编号或 OCR 等命令,编辑器会提示稍后再试,不排队等待。

-
- -
-

字体与宏包命令

-

设置页提供常用论文写作字体。下列字体既可作为新公式默认字体,也可在源码编辑框显式输入。

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
用途源码示例MathJax 扩展插件支持
TeX 原生数学字体e^{i\pi}+1=0内置默认字体选项
罗马正体\mathrm{rank}\,A内置默认字体选项;源码可用
数学斜体\mathit{ABCxyz}内置默认字体选项;源码可用
粗体字母\mathbf{x},\mathbf{A}内置默认字体选项;源码可用
粗体符号\boldsymbol{\alpha+\nabla f}boldsymbol默认字体选项;源码可用
粗斜体\mathbfit{x},\mathbfit{T}内置默认字体选项;源码可用
无衬线\mathsf{ABCxyz}内置默认字体选项;源码可用
无衬线粗体\mathbfsf{ABC}内置默认字体选项;源码可用
无衬线斜体\mathsfit{ABCxyz}内置默认字体选项;源码可用
无衬线粗斜体\mathbfsfit{ABCxyz}内置默认字体选项;源码可用
等宽\mathtt{code123}内置默认字体选项;源码可用
花体\mathcal{L},\mathcal{F}内置默认字体选项;源码可用
手写体\mathscr{F},\mathscr{O}内置/AMS 自动加载默认字体选项;源码可用
哥特体\mathfrak{g},\mathfrak{sl}_2内置/AMS 自动加载默认字体选项;源码可用
黑板粗体\mathbb{R},\mathbb{N}内置/AMS 自动加载默认字体选项;源码可用
数学文本\text{if }x>0、\textrm{Re}textmacros源码可用
直立希腊\upalpha,\uppi,\Updeltaupgreek源码可用
化学式文本\ce{H2O}、\pu{9.8 m/s2}mhchem源码可用
物理微分和向量\qty(\frac{a}{b})、\dv{f}{x}、\vb{E}physics源码可用
量子力学括号\braket{\psi|\phi}、\ketbra{0}{1}braket源码可用
分段函数\begin{cases}x^2,&x>0\\0,&x\le0\end{cases}cases源码可用
删除线与标记\cancel{x}、\bcancel{y}、\xcancel{z}cancel源码可用
长箭头A\xrightarrow[\beta]{\alpha}Bextpfeil源码可用
数学工具扩展\coloneqq、\vcentcolon、\prescript{a}{b}{X}mathtools源码可用
常用符号补充\degree、\celsius、\textdegreegensymb / textcomp源码可用
-
默认字体会保存为对应的 LaTeX 字体命令。
-
- -
-

Word 功能

-

OLE 与 OMML

-

默认使用 OLE 公式对象,公式显示由 MathJax SVG 转为 EMF+Dual 矢量预览。设置中可切换到 Word OMML。

-

加载、更新和删除

-

选中受管理公式后用 Ribbon 加载到编辑器修改。编辑器提交后更新原公式;侧边栏不会承担更新入口。编辑器提交、加载所选、删除、重编号、OCR 等 Office 命令互斥执行,正在处理时不会排队堆积新的提交。

-

侧边栏草稿

-

侧边栏是独立的新公式草稿区。加载公式到编辑器时会临时显示该公式属性;编辑器提交或取消后恢复原来的侧边栏草稿。

-

公式解析

-

“解析所选”和“解析全文”可将正文及表格单元格中完整且非空的 $...$、\(...\)、$$...$$ 和 \[...\] 转换为受管理公式。行内公式不编号;行间公式使用当前插入后端和公式设置,有效的 \tag{...} 优先作为自定义编号。已有公式及其他受保护内容会被跳过,转换失败时保留原文并继续处理;解析不会自动执行全文重编号。

-

自动编号与重编号

-

自动编号只对未编号的行间公式生效。可组合章、节、公式三级编号并选择层级分隔符;章、节边界会递归重置后续编号,也可分别隐藏。

-

转换、引用与格式化

-

“转换”会处理当前选区内的受管理公式,在 Word OMML 与 OLE 之间原位转换,不处理相邻文字或段落;多选时分批执行并在状态窗格显示进度。“引用”创建 Word REF 交叉引用,重编号时引用域同步更新。“格式化所选”恢复默认字体、颜色和自然大小,多选时同样分批执行;“格式化全文”只恢复被手动拉伸公式的自然大小。

-

带编号公式布局

-

带编号公式会将公式居中显示,并按设置把编号放在最左或最右。加载、更新和删除以公式对象或公式所在段落为稳定入口;单独选中编号数字不会反向删除公式。

-

OLE 对象尺寸

-

新公式按光标处正文大小计算自然尺寸。更新已有 OLE 公式时保留用户在 Word 中手动拉伸出的对象倍率。

-

截图识别

-

点击后等待桌面端截图结果,再次点击可取消。

+
截图识别需要打开 LaTeXSnipper 桌面端,并在桌面端设置中启用自动化接口。普通公式编辑和插入可直接在 Office 插件中完成。
- -
-

PowerPoint 功能

-

OLE 与 PNG 图片

-

默认使用 OLE 公式对象,公式显示由 MathJax SVG 转为 EMF+Dual 矢量预览。设置中可切换到 PNG 图片方式。

-

加载和删除

-

选中受管理公式后用 Ribbon 加载到同一套 MathLive 编辑器修改。编辑器提交后替换原位置公式,并保留用户在幻灯片中手动拉伸出的对象倍率。编辑器提交、加载所选、删除和 OCR 等 Office 命令互斥执行,正在处理时不会排队堆积新的提交。

-

侧边栏草稿

-

侧边栏是独立的新公式草稿区,不负责更新已有公式。

-

转换与格式化

-

“转换”会处理当前选区内的受管理公式,在 OLE 与 PNG 之间切换,不移动同页其他对象;多选时分批执行并在状态窗格显示进度。“格式化所选”恢复默认字体、颜色和自然大小,多选时同样分批执行;“格式化全文”只恢复被手动拉伸公式的自然大小。

-

OLE 对象尺寸

-

新插入的 OLE 与 PNG 使用相同的初始倍率。更新已有公式时保留用户在幻灯片中手动拉伸出的对象倍率。

-

截图识别

-

点击后等待桌面端截图结果,识别后的 LaTeX 自动填入编辑器。再次点击可取消。

+
+

编辑公式

+
    +
  • 可视化区与源码区:两者同步。源码含有可视化编辑器无法原样保留的写法时,上方只显示参考结果;继续在源码区编辑,或点击“用上方结果替换源码(可撤销)”。
  • +
  • 符号库与常用:左侧可搜索公式和符号,点击磁贴插入。右键点击磁贴可加入或移出“常用”;工具栏星形按钮可收藏当前公式。常用内容在升级后保留。
  • +
  • 字体与预览:工具栏的字体、字形、字号和颜色优先用于当前公式。全局颜色会同步到源码和可视化编辑区;右键可对选中部分上色、剪切、粘贴或全选,局部颜色会立即写入源码。“最终预览”按当前属性渲染,小字号会在屏幕上放大以便检查,插入仍使用选定字号;修改已有公式时沿用该公式保存的属性。
  • +
  • 快捷键:可视化区按 Enter 新建数学行,Shift + Enter 插入或更新,Esc 收起虚拟键盘。源码区按 Tab 在光标处缩进;补全列表按 Enter 接受。
  • +
- -
-

插件架构

+
+

设置与字体

+

在 LaTeXSnipper 选项卡点击“设置”。公式默认属性用于新建公式和主动执行的格式化;编辑器里临时选择的属性优先用于当前公式。导入、导出 JSON 可保存或应用当前 Word / PowerPoint 的公式默认属性。

- + - - - - - + + + + +
项目实现
设置作用
运行方式Windows 原生 VSTO 插件,Ribbon、侧边栏、设置和帮助页均在 Office 内打开。
Word 公式默认写入 LaTeXSnipper OLE 公式对象;OMML 是可选插入后端。
PowerPoint 公式默认写入 LaTeXSnipper OLE 公式对象;PNG 图片是可选插入后端。
连接方式公式在插件内本地渲染;截图识别通过受身份验证的本机 Automation API 连接桌面端。
编辑器WebView2 托管的 MathLive 编辑器,支持可视化编辑和实时预览。编辑器提交与 Office 命令统一串行化。
符号字体决定数学字母、符号及公式结构的字体方案。可选打包提供的 TeX 和 STIX2。
数字字体单独指定普通数字使用的系统字体;选“跟随符号字体”时与公式符号保持一致。
汉字字体指定公式内汉字使用的系统字体;列表只显示检测到汉字字形的字体。
默认字形控制数学字符的正体、斜体、粗体、花体等表现,与字体方案分别选择。“自动”保留公式原有的数学排版;源码中明确指定的局部字形优先。
字号、颜色决定新公式的默认大小和颜色。“新建时跟随文字字号”启用后优先使用光标或选区文字字号,无有效字号时使用设置中的固定值。
+

升级或重装会保留公式默认属性、插入方式、Word 编号布局和编辑器常用内容。导入公式预设只替换对应宿主的公式默认属性。

+
+
+

Word 中的常用操作

+

插入与编号

+

“插入行内公式”放在当前文字中;“插入行间公式”单独占一行;“插入带编号公式”按设置的左右位置与外框显示编号。设置中的“带编号公式默认布局”还可选择章、节编号、层级分隔符,以及是否显示章/节分隔符。

+

加载、转换和格式化

+

选中插件插入的公式后,用“加载所选”修改或用“删除所选”移除。设置中的“公式插入方式”可选 OLE 对象或 Word 原生公式;“转换为 OLE / Word 原生公式”可处理已选公式。“格式化所选 / 全文”按当前默认属性整理公式。

+

解析正文中的 LaTeX

+

“解析所选 / 全文”识别完整的 $...$、\(...\)、$$...$$ 和 \[...\]。未闭合或转换失败的内容会保留原文;行间公式中的有效 \tag{...} 可作为自定义编号。

+

重编号与引用

+

“自动编号”可给未编号的行间公式添加编号;插入章/节分隔符后,后续编号会按层级更新。“重编号”重新计算全文插件公式编号。用“插入引用”创建占位符,再选择目标编号公式或其所在段落完成引用。

+

侧边栏保留独立的新公式草稿;加载并更新已有公式请使用编辑器窗口。

+
+
+

PowerPoint 中的常用操作

+

在文本框内把光标放在文字中间并点击“插入公式”,会得到随文字排版的 PowerPoint 原生公式,可在 PowerPoint 中继续编辑。光标不在文字中时,新公式作为居中的独立幻灯片对象插入,并按设置选择 OLE 对象或 PNG 图片。

+

选中插件公式后,可“加载所选”修改、“删除所选”、在 OLE 与 PNG 间转换,或用“格式化所选 / 全文”应用当前默认属性。更新与转换会尽量保留对象在幻灯片中的位置和手动缩放。

+

侧边栏用于新公式草稿;“加载所选”、OLE / PNG 转换和批量格式化适用于插件插入的独立对象。文本内原生公式由 PowerPoint 管理。

+
+
+

社区与支持

+

项目免费开源,没有广告和内购。欢迎给仓库点 Star、反馈问题,或通过下面的二维码赞助维护并加入中文交流群。

+
+
支付宝收款码
支付宝赞助
+
微信收款码
微信赞助
+
LaTeXSnipper 中文交流群二维码
中文交流群
+
- -
-

边界说明

-
    -
  • 只有由 LaTeXSnipper 插入的受管理公式才能被插件加载、更新、删除和重编号。
  • -
  • 普通 Office 公式不会被自动转换为 LaTeXSnipper 公式。
  • -
  • 如果加载项未显示,请关闭 Office,重新运行安装包进行修复或重新安装,然后再打开 Office。
  • -
-
- - +
LaTeXSnipper Office 插件
-
-

LaTeXSnipper Office Plugin

-

Insert, edit, convert, and maintain LaTeXSnipper formulas in Word and PowerPoint.

+
LATEXSNIPPER · OFFICE
+

Formula guide

+

Find the next step, from inserting a formula to editing, numbering, and formatting it.

- -
-

System Requirements

- - - - - - - - - -
ComponentRequirement
WindowsWindows 10 22H2 or later / Windows 11
Office
  • Microsoft 365 Apps (Current or Monthly Enterprise Channel)
  • Office 2024 / 2021 / 2019 Retail or Volume License
  • Office LTSC 2024 / 2021
Runtime.NET Framework 4.8; Microsoft Edge WebView2 Runtime (built into Windows 11; auto-installed by M365)
Office Platform32-bit and 64-bit Windows desktop Office only; web, mobile, and macOS are not supported
LaTeXSnipper DesktopMust be running locally with the Office plugin feature enabled; communicates via local Bridge at 127.0.0.1:28765
-
- -
-

Quick Start

-
-

1. Start the client

Open LaTeXSnipper and enable Office plugin in settings.

-

2. Open the editor

Use Ribbon insert buttons to open the MathLive editor, then type or choose the formula to insert.

-

3. Insert into Office

OLE formula objects are the default. The side pane owns an independent draft for new insertions; formula updates are submitted only from the editor window.

+ +
+

Get started

+
+
1 · Open the pluginUse the LaTeXSnipper tab at the top of Word or PowerPoint to insert a formula.
+
2 · Write the formulaType in the visual area or the LaTeX source pane, or choose a formula from the symbol library.
+
3 · Insert itCheck the size and color, then select Insert. To change an existing formula, select it and use Load Selected, then Update.
-
Formula editing and rendering are local to the add-in. Screenshot OCR requires the local LaTeXSnipper desktop client.
-
- -
-

Editor Shortcuts

-

Press Enter in the MathLive field to start a new math row; the first line break creates a multiline math environment. Press Shift+Enter to insert or update the formula. Ctrl+F, Ctrl+R, Ctrl+H, Ctrl+L, and Ctrl+J insert a fraction, root, superscript, subscript, and combined scripts. Space inserts a mathematical thin space. Esc does not close the editor; it only retracts the MathLive virtual keyboard. Submit buttons are disabled during submission. If Office is already running load, delete, renumber, OCR, or another command, the editor reports that processing is busy instead of queueing the submit.

-
- -
-

Fonts and Macro Commands

-

The settings page includes common fonts used in academic writing. These styles can be used as new-formula defaults and as explicit source commands.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
UseSource exampleMathJax extensionAdd-in support
Native TeX mathe^{i\pi}+1=0Built inDefault font option
Roman upright\mathrm{rank}\,ABuilt inDefault font option; source command
Math italic\mathit{ABCxyz}Built inDefault font option; source command
Bold letters\mathbf{x},\mathbf{A}Built inDefault font option; source command
Bold symbols\boldsymbol{\alpha+\nabla f}boldsymbolDefault font option; source command
Bold italic\mathbfit{x},\mathbfit{T}Built inDefault font option; source command
Sans serif\mathsf{ABCxyz}Built inDefault font option; source command
Sans serif bold\mathbfsf{ABC}Built inDefault font option; source command
Sans serif italic\mathsfit{ABCxyz}Built inDefault font option; source command
Sans serif bold italic\mathbfsfit{ABCxyz}Built inDefault font option; source command
Typewriter\mathtt{code123}Built inDefault font option; source command
Calligraphic\mathcal{L},\mathcal{F}Built inDefault font option; source command
Script\mathscr{F},\mathscr{O}Built in / AMS autoloadDefault font option; source command
Fraktur\mathfrak{g},\mathfrak{sl}_2Built in / AMS autoloadDefault font option; source command
Blackboard bold\mathbb{R},\mathbb{N}Built in / AMS autoloadDefault font option; source command
Math text\text{if }x>0, \textrm{Re}textmacrosSource command
Upright Greek\upalpha,\uppi,\UpdeltaupgreekSource command
Chemical text\ce{H2O}, \pu{9.8 m/s2}mhchemSource command
Physics differentials and vectors\qty(\frac{a}{b}), \dv{f}{x}, \vb{E}physicsSource command
Quantum brackets\braket{\psi|\phi}, \ketbra{0}{1}braketSource command
Piecewise functions\begin{cases}x^2,&x>0\\0,&x\le0\end{cases}casesSource command
Cancellation marks\cancel{x}, \bcancel{y}, \xcancel{z}cancelSource command
Long arrowsA\xrightarrow[\beta]{\alpha}BextpfeilSource command
Math tools\coloneqq, \vcentcolon, \prescript{a}{b}{X}mathtoolsSource command
Additional symbols\degree, \celsius, \textdegreegensymb / textcompSource command
-
Default fonts are saved as the corresponding LaTeX font commands.
-
- -
-

Word Features

-

OLE and OMML

-

OLE formula objects are the default. MathJax SVG output is converted to an EMF+Dual vector preview. Word OMML remains available in settings.

-

Load, Update, Delete

-

Use the Ribbon to load a managed formula into the editor. Submitting the editor updates the original formula; the side pane is not an update entry point. Editor submit, load selected, delete, renumber, and OCR Office commands run through a single command gate; a busy command rejects new editor submits instead of queueing them.

-

Side Pane Draft

-

The side pane is an independent new-formula draft. Loading a formula into the editor temporarily shows that formula's properties; after editor accept or cancel, the original side pane draft is restored.

-

Formula Parsing

-

Parse Selected and Parse All convert complete, non-empty $...$, \(...\), $$...$$, and \[...\] expressions in body text and table cells into managed formulas. Inline formulas remain unnumbered; display formulas use the current insertion backend and formula settings, with a valid \tag{...} taking priority as a custom number. Existing formulas and other protected content are skipped, while failed conversions keep their source text and processing continues. Parsing does not renumber the whole document automatically.

-

Auto Numbering & Renumber

-

Auto Number only applies to unnumbered display equations. Chapter, section, and equation levels can be combined with a configurable separator; chapter and section boundaries recursively reset later counters and can be hidden independently.

-

Conversion, References & Formatting

-

Conversion processes managed formulas in the current selection in place between Word OMML and OLE without touching adjacent text or paragraphs; multi-selection runs in batches and reports progress in the status pane. References use Word REF fields and stay synchronized when formulas are renumbered. Format Selected restores the default font, color, and natural size and also runs multi-selection in batches; Format All only restores manually resized formulas to natural size.

-

Numbered Formula Layout

-

Numbered formulas center the formula and place the number on the left or right according to settings. Loading, updating, and deleting use the formula object or its paragraph as the stable target; selecting only the number text does not delete the formula.

-

OLE Object Size

-

New formulas derive their natural size from the text at the insertion point. Updating an existing OLE formula preserves the object stretch factor manually set in Word.

-

Screenshot OCR

-

Click to wait for the next desktop screenshot; click again to cancel.

+
Screenshot recognition requires the LaTeXSnipper desktop app with the Automation API enabled in its settings. Ordinary formula editing and insertion work inside the Office plugin.
- -
-

PowerPoint Features

-

OLE and PNG Image

-

OLE formula objects are the default. MathJax SVG output is converted to an EMF+Dual vector preview. PNG image insertion remains available in settings.

-

Load and Delete

-

Use the Ribbon to load a managed formula into the same MathLive editor. After editing, the new formula replaces the original at the same position and preserves the object stretch factor manually set on the slide. Editor submit, load selected, delete, and OCR Office commands run through a single command gate; a busy command rejects new editor submits instead of queueing them.

-

Side Pane Draft

-

The side pane is an independent new-formula draft and is not an update entry point.

-

Conversion and Formatting

-

Conversion processes managed formulas in the current selection between OLE and PNG without moving other slide objects; multi-selection runs in batches and reports progress in the status pane. Format Selected restores the default font, color, and natural size and also runs multi-selection in batches; Format All only restores manually resized formulas to natural size.

-

OLE Object Size

-

New OLE and PNG formulas use the same initial scale. Updating an existing formula preserves the object stretch factor manually set on the slide.

-

Screenshot OCR

-

Click to wait for the next desktop screenshot; recognized LaTeX is loaded into the editor. Click again to cancel.

+
+

Edit formulas

+
    +
  • Visual and source panes:They stay in sync. When the visual editor cannot preserve source exactly, the upper pane is a reference. Keep editing below, or choose “Replace source with result (undoable)”.
  • +
  • Library and Common:Search and click a tile to insert it. Right-click a tile to add or remove it from Common. Use the toolbar star to save the current formula. Common survives upgrades.
  • +
  • Typography and preview:Toolbar choices apply to the current formula. The formula color is synchronized with the source and visual editor. Right-click in the visual editor to color a selection, cut, paste, or select all; local colors are written to the source immediately. Final Preview enlarges small formulas on screen for inspection; insertion still uses the selected point size. Existing formulas reopen with their saved properties.
  • +
  • Keys:In the visual pane, Enter starts a math row, Shift + Enter inserts or updates, and Esc hides the virtual keyboard. In source, Tab indents at the caret and Enter accepts a completion.
  • +
- -
-

Plugin Architecture

+
+

Settings and fonts

+

Open Settings from the LaTeXSnipper tab. Default formula properties apply to new formulas and explicit Format commands. Editor choices take priority for the current formula. Import and export JSON to save or apply the current host's formula defaults.

- + - - - - - + + + + +
AreaImplementation
SettingWhat it controls
RuntimeNative Windows VSTO add-in. Ribbon, side pane, settings, and help open inside Office.
Word OutputLaTeXSnipper OLE formula objects by default; OMML is an optional backend.
PowerPoint OutputLaTeXSnipper OLE formula objects by default; PNG image insertion is an optional backend.
ConnectionFormulas render locally inside the plugin. Screenshot OCR uses the desktop client through the local Bridge at 127.0.0.1:28765.
EditorWebView2-hosted MathLive editor with visual editing and live preview. Editor submissions are serialized with Office commands.
Symbol fontThe font scheme for mathematical letters, symbols, and formula structures. The bundled choices are TeX and STIX2.
Number fontAn optional system font for ordinary digits. Follow Symbol Font keeps numbers with the mathematical symbols.
CJK fontA system font for Chinese characters within formulas. The list shows fonts found to contain Chinese glyphs.
Default math styleUpright, italic, bold, script, and other mathematical shapes, selected independently from the font scheme. Automatic preserves normal mathematical styling; explicit source styles take priority.
Size and colorDefaults for new formulas. Follow Text Size uses the text at the insertion point when available and falls back to the fixed size.
+

Upgrades and reinstalls preserve formula defaults, insertion choices, Word numbering preferences, and Common formulas. Importing a formula preset replaces only that host's formula defaults.

+
+
+

Common tasks in Word

+

Insert and number

+

Insert Inline places a formula within text. Insert Display gives it a separate line. Insert Numbered positions the number and enclosure according to settings. Default Numbered Formula Layout also controls chapter and section numbering, separators, and boundary visibility.

+

Load, convert, and format

+

Select a plugin formula to Load Selected or Delete Selected. Formula Insertion offers OLE objects or native Word equations. Convert to OLE / Word Equation changes selected formulas. Format Selected / All applies the current default properties.

+

Parse LaTeX in document text

+

Parse Selected / All recognizes complete $...$, \(...\), $$...$$, and \[...\] expressions. Incomplete or failed conversions leave the original text in place. A valid \tag{...} can provide a custom number for a display formula.

+

Renumber and reference

+

Auto Number numbers an unnumbered display formula. Chapter and section boundaries affect later numbers. Renumber recalculates plugin formula numbers across the document. Insert Reference creates a placeholder; select a numbered formula or its paragraph to complete it.

+

The side pane keeps a separate draft for a new formula. Use the editor window to update an existing one.

+
+
+

Common tasks in PowerPoint

+

Place the text caret inside a text box to insert a native PowerPoint equation that flows with the surrounding text and remains editable in PowerPoint. Outside text, Insert Formula adds a centered slide object using the OLE or PNG insertion setting.

+

Select a plugin formula to Load Selected, Delete Selected, convert between OLE and PNG, or apply Format Selected / All. Updates and conversions preserve the slide position and manual scale where possible.

+

The side pane holds a new formula draft. Load Selected, OLE / PNG conversion, and bulk formatting apply to standalone objects inserted by the plugin. PowerPoint manages equations within text.

+
+
+

Community and support

+

LaTeXSnipper is free, open source, ad-free, and has no in-app purchases. Star the repository, report an issue, support maintenance, or join the Chinese community using the QR codes below.

+
+
Alipay donation QR code
Alipay
+
WeChat Pay donation QR code
WeChat Pay
+
LaTeXSnipper community chat QR code
Community chat
+
- -
-

Boundaries

-
    -
  • Only managed formulas inserted by LaTeXSnipper can be loaded, updated, deleted, and renumbered by the plugin.
  • -
  • Plain Office equations are not automatically converted into LaTeXSnipper formulas.
  • -
  • If the add-in does not appear, close Office, run the installer again to repair or reinstall the add-in, then reopen Office.
  • -
-
- - +
LaTeXSnipper Office Plugin
- - diff --git a/office_plugin/hosts/PowerPointAddIn/EditorAssets/settings.css b/office_plugin/hosts/PowerPointAddIn/EditorAssets/settings.css index 2bed0035..d607802c 100644 --- a/office_plugin/hosts/PowerPointAddIn/EditorAssets/settings.css +++ b/office_plugin/hosts/PowerPointAddIn/EditorAssets/settings.css @@ -103,6 +103,33 @@ button:hover { gap: 6px; } +.settings-grid label.follow-host-option { + display: flex; + grid-column: 1 / -1; + gap: 8px; + align-items: center; +} + +.settings-grid .font-size-field { + grid-column: 1 / -1; +} + +.follow-host-option input { + margin: 0; + flex: none; +} + +.size-control { + display: grid; + grid-template-columns: minmax(0, 1fr) auto; + gap: 8px; + align-items: center; +} + +.size-control select { + width: 100%; +} + .color-control { grid-template-columns: 56px minmax(0, 1fr); } @@ -220,6 +247,10 @@ kbd { min-width: 92px; } +.preset-file-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 12px; } +#presetStatus { color: var(--muted); } +#presetStatus.error { color: #b42318; } + @media (max-width: 720px) { .accent-panel { grid-template-columns: 1fr; diff --git a/office_plugin/hosts/PowerPointAddIn/EditorAssets/settings.html b/office_plugin/hosts/PowerPointAddIn/EditorAssets/settings.html index eb2a33c5..0f8de10a 100644 --- a/office_plugin/hosts/PowerPointAddIn/EditorAssets/settings.html +++ b/office_plugin/hosts/PowerPointAddIn/EditorAssets/settings.html @@ -36,33 +36,31 @@

公式默认属性

+ + + -