字
字节笔记本
2026年2月23日
Upscayl 源码解读:Electron 主进程架构分析
本文介绍 Upscayl 项目的 Electron 主进程入口文件 index.ts,深入分析这款开源 AI 图片放大工具的应用架构和核心实现逻辑。Upscayl 是一个基于 Real-ESRGAN 的跨平台桌面应用,支持 Windows、macOS 和 Linux 系统。
项目概述
Upscayl 是一款使用 AI 技术进行图片无损放大的开源工具,它在 GitHub 上已获得超过 4.3 万 stars。该项目采用 Electron + Next.js 技术栈构建,通过调用 Real-ESRGAN 模型实现高质量的图片放大效果。
代码结构分析
依赖导入模块
typescript
import prepareNext from "electron-next";
import { autoUpdater } from "electron-updater";
import log from "electron-log";
import { app, ipcMain, protocol } from "electron";
import { ELECTRON_COMMANDS } from "../common/electron-commands";
import logit from "./utils/logit";
import openFolder from "./commands/open-folder";
import stop from "./commands/stop";
import selectFolder from "./commands/select-folder";
import selectFile from "./commands/select-file";
import getModelsList from "./commands/get-models-list";
import customModelsSelect from "./commands/custom-models-select";
import imageUpscayl from "./commands/image-upscayl";
import { createMainWindow } from "./main-window";
import electronIsDev from "electron-is-dev";
import { execPath, modelsPath } from "./utils/get-resource-paths";
import batchUpscayl from "./commands/batch-upscayl";
import doubleUpscayl from "./commands/double-upscayl";
import autoUpdate from "./commands/auto-update";
import { FEATURE_FLAGS } from "../common/feature-flags";
import settings from "electron-settings";
import pasteImage from "./commands/paste-image";
import path from "path";从导入的依赖可以看出,Upscayl 的核心架构特点:
- electron-next: 用于在 Electron 中集成 Next.js 渲染进程
- electron-updater: 实现自动更新功能
- electron-log: 日志记录工具
- electron-settings: 应用配置持久化存储
- 模块化命令设计: 将不同功能拆分为独立的命令模块
应用初始化
typescript
// INITIALIZATION
log.initialize({ preload: true });
app.on("ready", async () => {
await prepareNext("./renderer");
// ...
});应用在 ready 事件中进行初始化:
- 日志系统初始化: 使用
electron-log记录应用运行日志 - Next.js 准备: 调用
prepareNext初始化渲染进程的 Next.js 应用
自定义协议注册
typescript
app.whenReady().then(() => {
protocol.registerFileProtocol("file", (request, callback) => {
const pathname = decodeURI(request.url.replace("file:///", ""));
callback(pathname);
});
protocol.registerFileProtocol("public", (request, callback) => {
const filePath = decodeURI(request.url.replace("public:///", ""));
const asarPath = path.join(
app.getAppPath(),
"renderer",
process.env.NODE_ENV === "development" ? "public" : "out",
filePath,
);
callback(asarPath);
});
logit("🚃 App Path: ", app.getAppPath());
});这里注册了两个自定义协议:
- file 协议: 处理本地文件访问,解码 URL 并返回文件路径
- public 协议: 处理应用资源文件,根据环境(开发/生产)动态选择资源目录
主窗口创建与配置
typescript
createMainWindow();
log.info(
"🆙 Upscayl version:",
app.getVersion(),
FEATURE_FLAGS.APP_STORE_BUILD ? "MAC-APP-STORE" : "FOSS",
);
log.info("🚀 UPSCAYL EXEC PATH: ", execPath);
log.info("🚀 MODELS PATH: ", modelsPath);创建主窗口后,记录关键运行信息:
- 应用版本号
- 构建类型(Mac App Store 或 FOSS 开源版)
- Upscayl 可执行文件路径
- AI 模型文件路径
macOS App Store 安全权限处理
typescript
let closeAccess;
const folderBookmarks = await settings.get("folder-bookmarks");
if (FEATURE_FLAGS.APP_STORE_BUILD && folderBookmarks) {
logit("🚨 Folder Bookmarks: ", folderBookmarks);
try {
closeAccess = app.startAccessingSecurityScopedResource(
folderBookmarks as string,
);
} catch (error) {
logit("📁 Folder Bookmarks Error: ", error);
}
}针对 macOS App Store 版本的特殊处理:
- 使用安全作用域书签(Security-Scoped Bookmarks)访问用户选择的文件夹
- 这是 macOS 沙盒机制的要求,用于获取跨会话的文件夹访问权限
应用生命周期管理
typescript
// Quit the app once all windows are closed
app.on("window-all-closed", () => {
app.quit();
});
// ! ENABLE THIS FOR MACOS APP STORE BUILD
if (FEATURE_FLAGS.APP_STORE_BUILD) {
logit("🚀 APP STORE BUILD ENABLED");
app.commandLine.appendSwitch("in-process-gpu");
}- 窗口关闭处理: 所有窗口关闭时退出应用
- GPU 进程配置: App Store 版本启用 in-process GPU 模式
IPC 通信命令注册
typescript
ipcMain.on(ELECTRON_COMMANDS.STOP, stop);
ipcMain.on(ELECTRON_COMMANDS.OPEN_FOLDER, openFolder);
ipcMain.handle(ELECTRON_COMMANDS.SELECT_FOLDER, selectFolder);
ipcMain.handle(ELECTRON_COMMANDS.SELECT_FILE, selectFile);
ipcMain.on(ELECTRON_COMMANDS.GET_MODELS_LIST, getModelsList);
ipcMain.handle(
ELECTRON_COMMANDS.SELECT_CUSTOM_MODEL_FOLDER,
customModelsSelect,
);
ipcMain.on(ELECTRON_COMMANDS.UPSCAYL, imageUpscayl);
ipcMain.on(ELECTRON_COMMANDS.FOLDER_UPSCAYL, batchUpscayl);
ipcMain.on(ELECTRON_COMMANDS.DOUBLE_UPSCAYL, doubleUpscayl);
ipcMain.on(ELECTRON_COMMANDS.PASTE_IMAGE, pasteImage);Upscayl 定义了丰富的 IPC 命令来处理各种用户操作:
| 命令 | 类型 | 功能 |
|---|---|---|
STOP | on | 停止当前处理任务 |
OPEN_FOLDER | on | 打开输出文件夹 |
SELECT_FOLDER | handle | 选择输入文件夹 |
SELECT_FILE | handle | 选择图片文件 |
GET_MODELS_LIST | on | 获取可用模型列表 |
SELECT_CUSTOM_MODEL_FOLDER | handle | 选择自定义模型文件夹 |
UPSCAYL | on | 单张图片放大处理 |
FOLDER_UPSCAYL | on | 批量文件夹处理 |
DOUBLE_UPSCAYL | on | 双倍放大处理 |
PASTE_IMAGE | on | 粘贴图片处理 |
系统信息查询接口
typescript
ipcMain.handle("get-gpu-info", async () => {
try {
return await app.getGPUInfo("complete");
} catch (error) {
console.error("Failed to get GPU info:", error);
return null;
}
});
ipcMain.handle("get-app-version", () => {
return `${app.getVersion()} ${
FEATURE_FLAGS.APP_STORE_BUILD ? "MAC-APP-STORE" : "FOSS"
}`;
});提供给渲染进程查询系统信息的接口:
- GPU 信息: 获取完整的 GPU 硬件信息用于性能诊断
- 应用版本: 返回带构建类型的版本字符串
自动更新机制
typescript
if (!FEATURE_FLAGS.APP_STORE_BUILD) {
autoUpdater.on("update-downloaded", autoUpdate);
}非 App Store 版本启用自动更新功能:
- 使用
electron-updater监听更新下载完成事件 - App Store 版本通过 Mac App Store 自己的更新机制,因此禁用此功能
架构设计亮点
1. 模块化命令设计
将不同功能拆分为独立的命令模块,每个模块职责单一,便于维护和测试。
2. 多平台适配
通过 FEATURE_FLAGS 区分不同构建版本(FOSS / Mac App Store),实现平台特定的逻辑处理。
3. 协议扩展
自定义 file 和 public 协议,灵活处理本地文件和资源访问需求。
4. 完善的日志系统
使用 electron-log 记录应用运行状态,便于问题排查。
技术栈总结
| 技术 | 用途 |
|---|---|
| Electron | 跨平台桌面应用框架 |
| Next.js | React 渲染进程框架 |
| TypeScript | 类型安全的 JavaScript |
| Real-ESRGAN | AI 图片放大模型 |
| electron-updater | 自动更新功能 |
| electron-log | 日志记录 |
项目链接
- GitHub 仓库: https://github.com/upscayl/upscayl
- 官方网站: https://upscayl.org/
- 下载地址: https://upscayl.org/#download
分享: