- 任务右键菜单:实现打开输出目录(inputs/outputs/.cache 结构)、
复制资源链接、重新编辑、再次生成、拉取结果、重新下载、收藏、删除记录
- 主进程下载:通过 Electron net 模块绕过 CORS,支持 CDN 媒体文件下载
- sharp 缩略图:替换 nativeImage,支持 4K/8K+ 大尺寸素材的流式处理
- IPC 精简:40+ 冗余通道 → 15 个分组通道,移除未使用的 preload 桥接方法
- 任务存储:新增收藏字段、schema 迁移、task-store 持久化
- 清理废弃模块:canvas-ipc / updater / request / pricing
refactor: IPC/Preload/Services 模块化拆分 — 单一职责 + 向后兼容
主要变更:
- shared/constants/ipc-channels.ts → ipc/ 模块 (base/storage/canvas/updater)
- electron/preload.ts → preload/ 模块 (base/safe-storage/file-storage/canvas)
- electron/main/ipc/canvas-ipc.ts → canvas/ 模块 (types/walk/sidecar/mime/thumbnail)
- electron/main/ipc/storage-ipc.ts → 提取 utils/ (path/download/thumbnail)
- electron/main/updater.ts → updater/ 模块 (provider/platform-updaters)
- src/services/request.ts → request/ 模块 (token/interceptors/methods)
- src/shared/utils/pricing.ts → pricing/ 模块 (types/helpers/format/calculate/fields)
- src/modules/home/center/views/ModelInputForm.tsx → 提取 utils + DependentFormItem
架构优化:
- 所有拆分均保持向后兼容(旧导入路径仍可用)
- TypeScript 编译通过 ✓
- 每个模块单一职责,平均 ~130 行
61 lines
1.9 KiB
TypeScript
61 lines
1.9 KiB
TypeScript
// ============================================================
|
||
// thumbnail.ts — 缩略图生成工具函数
|
||
//
|
||
// 职责:
|
||
// - 使用 sharp 库生成图片缩略图
|
||
// - 内存优化配置
|
||
//
|
||
// 依赖:
|
||
// - sharp (libvips) - 可选依赖,用于高效图片处理
|
||
// ============================================================
|
||
|
||
import fs from 'node:fs';
|
||
import path from 'node:path';
|
||
import sharp from 'sharp';
|
||
import { ensureDir } from './path';
|
||
|
||
// ---------- sharp/libvips 内存优化 ----------
|
||
|
||
// 单块内存上限 128MB(默认 512MB,降低以适配 Electron 单进程内存压力)
|
||
sharp.cache({ memory: 128, items: 100 });
|
||
// libvips 并发数 1(减少大图并发处理时的内存峰值)
|
||
sharp.concurrency(1);
|
||
|
||
/**
|
||
* 生成图片缩略图(sharp 流式管线)
|
||
*
|
||
* 特性:
|
||
* - shrinkOnLoad:PNG/JPEG/WebP/TIFF 解码器直接降采样,8000px 原图解码即降至 ~512px
|
||
* - sequentialRead:顺序读取减少随机 I/O 内存开销
|
||
* - limitInputPixels:默认 268MP(16384²),覆盖 8K+ 素材
|
||
*
|
||
* @param srcPath - 源文件路径
|
||
* @param destPath - 目标文件路径
|
||
* @param maxWidth - 最大宽度(默认 256)
|
||
* @param quality - JPEG 质量(默认 60)
|
||
* @returns 目标文件路径
|
||
*/
|
||
export async function generateThumbnail(
|
||
srcPath: string,
|
||
destPath: string,
|
||
maxWidth: number = 256,
|
||
quality: number = 60,
|
||
): Promise<string> {
|
||
if (!fs.existsSync(srcPath)) {
|
||
throw new Error('源文件不存在');
|
||
}
|
||
|
||
ensureDir(path.dirname(destPath));
|
||
|
||
await sharp(srcPath, {
|
||
animated: false, // 只取第一帧(GIF/APNG 等多帧格式)
|
||
sequentialRead: true,
|
||
limitInputPixels: 268402689,
|
||
})
|
||
.resize({ width: maxWidth, withoutEnlargement: true, fit: 'inside' })
|
||
.jpeg({ quality, mozjpeg: true }) // mozjpeg 压缩率更优
|
||
.toFile(destPath);
|
||
|
||
return destPath;
|
||
}
|