编辑器导入导出与写回
编辑器把翻译流水线生成的工程数据读进来,让你逐区域修改文字、位置、样式、蒙版和画笔/印章层;修改完成后,执行一次“导出图片”会把当前图渲染成最终图片,同时把工程数据写回磁盘。这里说明这些数据的导入格式、导出渲染与输出路径,以及 JSON、修复图等工程数据的写回机制。
右侧文件列表的增删、切页和“任务完成”进入编辑器的完整操作见布局与文件列表;顶栏“导出图片”菜单项与“切图时自动导出”开关的界面和持久化见工具栏与菜单;Ctrl+Q 等快捷键的分派见快捷键;蒙版与画笔/印章层如何进入工程文件见蒙版绘制与仿制印章。
可以做什么
- 本页负责编辑器与磁盘之间的数据边界:导入时读取哪些工程文件、导出时渲染什么、写回哪里,以及写回内容的格式。
- 不负责右侧文件列表的按钮、树形展示和行状态(归布局与文件列表);不负责“导出图片”菜单项和“切图时自动导出”开关的界面与持久化(归工具栏与菜单)。
- 编辑器导出不是重新跑完整翻译流水线:它直接渲染当前快照,不重新检测、OCR、翻译、上色或超分;蒙版视为已精炼,修复图直接复用。
- 翻译页的“导入翻译并渲染”与编辑器共用同一套
_translations.json格式,但入口不同:前者是翻译页的工作模式,后者是编辑器文件列表加载图片时自动读取工程数据。 - 不在本页展示真实用户图片、工程 JSON、密钥或私有路径;格式只以键名和脱敏结构描述。
在编辑器中操作
导入图片与工程数据
- 在编辑器右栏点击“添加文件”、“添加文件夹”或直接拖放文件/文件夹,把图片加入页面列表;列表按钮的完整操作见布局与文件列表。
- 点击列表行(或按
A/D切页)加载该图片:编辑器在后台读取关联的*_translations.json、修复图和画笔层,画布显示后即可编辑。 - 翻译任务完成后,主窗口弹出“任务完成”确认框;选择“是”会进入编辑器并打开结果对应的原图(先经
translation_map.json或本次任务的输出映射解析原图路径)。
导出当前图片
- 打开顶栏“菜单”,点击“导出图片”,或按
Ctrl+Q。 - 编辑器先冲刷浮动富文本等防抖期内的草稿,再写回工程数据并进入导出队列;导出期间显示进度 Toast,成功后显示“导出成功 … 已同步 JSON”。
- 开启“切图时自动导出”时,切到下一张图会自动先导出当前图;自动导出被拒绝会中止切图。
未保存编辑与切页
关闭“切图时自动导出”后,当前图存在未保存编辑时切页会弹出三按钮对话框(源码硬编码中文):
| 按钮 | 行为 |
|---|---|
| 导出图片 | 先导出当前图,等导出成功后再加载目标图;导出未入队或失败则不切页 |
| 不保存 | 放弃未保存的编辑,直接加载目标图 |
| 取消 | 中止切页,留在当前图 |
导入:文件与工程数据
支持加载的页面图片扩展名与主页一致:.png、.jpg、.jpeg、.jfif、.webp、.avif、.bmp、.tiff、.tif、.heic、.heif。
导入流程
flowchart LR
A["添加文件/文件夹或拖放"] --> B["文件列表后台扫描"]
B --> C["选中图片并加载"]
C --> D["translation_map.json 解析原图"]
D --> E{"editor_base 是否有效?"}
E -->|"JSON 有超分/上色标记"| F["显示 editor_base 底图"]
E -->|"无标记或已过期"| G["删除过期底图,显示原图"]
F --> H["后台并行加载工程文件"]
G --> H
H --> H1["_translations.json\nregions / mask_raw / overlays"]
H --> H2["_inpainted 修复图"]
H --> H3["paint_overlay PNG(旧版兜底)"]
H1 --> I["EditorModel 文档快照"]
H2 --> I
H3 --> I
导出:渲染、输出路径与队列
导出做了什么
“导出图片”不重新运行检测/OCR/翻译/上色/超分,而是把当前快照直接交给后端 load_text 纯渲染:translator='none'、load_text=True、save_text=False;蒙版视为已精炼(mask_is_refined),修复图直接复用;导出配置还会强制 render.disable_auto_wrap=True,因为文本框布局已由用户排布。
导出前先做两件持久化:把工程数据写回 *_translations.json(见写回:JSON 与修复图),并把当前修复图(没有修复图时用底图充当)写回 _inpainted 文件,让后端 load_text 跳过自己的修复步骤。之后才把渲染任务加入导出队列。
输出路径与文件名
输出目录按以下优先级确定:
- 该图 JSON 中记录的
last_export_dir(上次导出目录)。 cli.save_to_source_dir开启时:<原图目录>/manga_translator_work/result。app.last_output_path(存在且有效时)。- 原图所在目录。
文件名规则:cli.format 非空且不是“不指定”时使用该扩展名(小写);否则沿用原图扩展名;都没有时使用 .png。图片质量取 cli.save_quality。若开启了 cli.export_editable_psd,渲染完成后还会在 manga_translator_work/psd/ 下导出可编辑 PSD(cli.psd_script_only 时只导出脚本)。
导出队列与“已保存”语义
导出是异步单线程队列任务(ThreadPoolExecutor(max_workers=1)):
- 同一张图的自动导出会合并:新任务入队时取消该图未开始的旧自动导出;手动导出不合并。
- 工程数据写回成功后任务即入队并
mark_clean()(QUndoStack 干净状态)。因此“未保存”判定只看导出是否已入队,不看渲染是否最终成功;渲染失败时 JSON 已写回,但输出图片不会生成,界面显示失败 Toast。 - 导出期间 Toast 显示“正在导出…”或“正在导出(N 个任务)”;成功显示“导出成功\n<输出路径>\n已同步 JSON”,失败显示“<文件名> 导出失败:<原因>”。
- 关闭应用时若有未完成任务,先弹出“导出任务尚未完成”确认框;选择“是”会排空导出队列再退出,选择“否”则取消关闭。
导出流程
flowchart LR
A["菜单「导出图片」/ Ctrl+Q / 切图自动导出"] --> B["提交视图层草稿"]
B --> C["快照图片、区域、蒙版、画笔/印章层"]
C --> D["写回 JSON + 修复图"]
D --> E["加入单线程导出队列"]
E --> F["后端 load_text 纯渲染\n跳过替换 / 蒙版已精炼 / 禁用自动换行"]
F --> G["保存输出图片(原子替换)"]
G --> H["成功 Toast + mark_clean"]
F -->|"失败"| I["失败 Toast\nJSON 已写回但图片未生成"]
写回:JSON 与修复图
JSON 写回
导出时 EditorControllerExportService.save_editor_json() 把当前快照写到 find_json_path() 找到的 *_translations.json:
- 以原图绝对路径作为顶层键;
regions经_normalize_regions_for_backend规范化:补齐translation、texts、font_size、angle、target_lang、language、direction等字段,把fg_colors/fg_color元组转成font_color十六进制,把v/h转成vertical/horizontal。 - 恒写
skip_text_replacements: true:编辑器translation字段就是替换后终稿(translation_raw才是替换前),后端重渲染不能再次替换。 - 蒙版存在时写
mask_raw(base64 PNG)并标mask_is_refined: true,后端跳过蒙版优化。 - 画笔/印章层有内容时以 base64 PNG(RGBA)写入
paint_overlay/stamp_overlay。 - 保留已有 JSON 的超分/上色信息与
last_export_dir(preserve_existing_preprocess_flags),避免下次导出丢失底图来源标志。 - 写入采用“同目录临时文件 +
os.replace”的原子替换,避免半截 JSON 被后端读到。
修复图写回
save_inpainted_image() 把当前修复图(没有则用底图充当)写到 manga_translator_work/inpainted/<图片名>_inpainted.<扩展名>,质量取 cli.save_quality,同样走临时文件 + os.replace。后端渲染后若重新生成了修复图,也会回写同一路径(_persist_backend_inpainted_image),保证下次编辑看到的是最新修复结果。
写回流程
flowchart LR
A["编辑操作(QUndoCommand)"] --> B["导出时提交快照"]
B --> C["_save_regions_data_internal"]
C --> C1["regions 规范化 + skip_text_replacements"]
C --> C2["mask_raw base64 PNG + mask_is_refined"]
C --> C3["paint/stamp overlay base64 PNG"]
C --> C4["保留 upscale/colorizer/last_export_dir"]
C1 --> D["临时文件 + os.replace 原子写"]
C2 --> D
C3 --> D
C4 --> D
D --> E["*_translations.json"]
B --> F["save_inpainted_image"]
F --> G["manga_translator_work/inpainted/*_inpainted"]
限制与注意事项
- 编辑器导出强制
disable_auto_wrap=True,因此导出结果不受“启用 AI 断句”等自动换行设置影响;文本框大小和位置以编辑器为准。 translation恒为替换后终稿:导入旧 JSON 缺translation_raw时用translation回填;写回时skip_text_replacements防止二次替换。- 批量管理等外部写回会修改 JSON,但编辑器把区域常驻内存且不监听文件变化;批量面板写回后会调用
load_image_and_regions让编辑器重新加载,否则切图自动导出会用旧内存覆盖新写入。相关流程见批量管理:预览、应用与恢复。 - 切页自动导出依赖导出队列:自动导出被拒绝会中止切图;手动导出时切图等待导出完成。
editor_base只在 JSON 有超分/上色标记时有效;没有标记时编辑器删除过期底图并回退到原图,避免显示与当前 JSON 不匹配的旧底图。- JSON 不存在时导出会新建(
find_json_path无结果则get_json_path(create_dir=True));写入后位于新位置,旧版同目录 JSON 仍可读但不再作为写入目标。
