(imagePath: string)
| 15 | } |
| 16 | |
| 17 | export async function analyzeImage(imagePath: string): Promise<ImageAnalysisResult> { |
| 18 | try { |
| 19 | // 1. 处理不同格式的图片输入 |
| 20 | let imageBuffer: Buffer |
| 21 | if (imagePath.startsWith('ztools-icon://')) { |
| 22 | // 动态生成的应用图标,不做颜色分析,直接返回默认值 |
| 23 | // 避免尝试作为文件读取导致 ENOENT 错误 |
| 24 | return { isSimpleIcon: false, mainColor: null, isDark: false, needsAdaptation: false } |
| 25 | } else if (imagePath.startsWith('data:image/')) { |
| 26 | // Base64 格式 |
| 27 | const base64Data = imagePath.split(',')[1] |
| 28 | imageBuffer = Buffer.from(base64Data, 'base64') |
| 29 | } else if (imagePath.startsWith('http://') || imagePath.startsWith('https://')) { |
| 30 | // URL 格式 - 暂不支持 |
| 31 | return { isSimpleIcon: false, mainColor: null, isDark: false, needsAdaptation: false } |
| 32 | } else { |
| 33 | // 文件路径格式 |
| 34 | let filePath = imagePath |
| 35 | |
| 36 | // 处理 file:// 协议 |
| 37 | if (filePath.startsWith('file:')) { |
| 38 | try { |
| 39 | // 使用 fileURLToPath 安全地将 file:// URL 转换为文件路径 |
| 40 | filePath = fileURLToPath(filePath) |
| 41 | } catch (error) { |
| 42 | console.error('[ImageAnalysis] 无效的 file:// URL:', filePath, error) |
| 43 | return { isSimpleIcon: false, mainColor: null, isDark: false, needsAdaptation: false } |
| 44 | } |
| 45 | } |
| 46 | |
| 47 | // 处理相对路径 |
| 48 | const appPath = app.getAppPath() |
| 49 | |
| 50 | // 在 Windows 上,以 / 开头的路径会被 path.isAbsolute 认为是绝对路径 |
| 51 | // 但对于 Vite 资源路径(如 /src/assets/...),我们需要特殊处理 |
| 52 | if (filePath.startsWith('/src/')) { |
| 53 | // 开发模式:资源在 src/renderer/src/ 目录下 |
| 54 | const relativePath = filePath.substring(1) // 去掉开头的 / |
| 55 | filePath = path.join(appPath, 'src', 'renderer', relativePath) |
| 56 | } else if (filePath.startsWith('./assets/') || filePath.startsWith('assets/')) { |
| 57 | // 生产模式:Vite 打包后的资源路径(如 ./assets/default-xxx.png) |
| 58 | // 资源通常在 out/renderer/assets/ 目录下 |
| 59 | const assetPath = filePath.replace(/^\.\//, '') // 移除开头的 ./ |
| 60 | if (is.dev) { |
| 61 | // 开发模式:先尝试 dist 目录(如果存在) |
| 62 | const distPath = path.join(appPath, 'out', 'renderer', assetPath) |
| 63 | try { |
| 64 | await fs.access(distPath) |
| 65 | filePath = distPath |
| 66 | } catch { |
| 67 | // 如果 dist 不存在,尝试 src 目录 |
| 68 | filePath = path.join(appPath, 'src', 'renderer', assetPath) |
| 69 | } |
| 70 | } else { |
| 71 | // 生产模式:资源在 out/renderer/ 目录下(asar 包内或外) |
| 72 | filePath = path.join(appPath, 'out', 'renderer', assetPath) |
| 73 | } |
| 74 | } else if (!path.isAbsolute(filePath)) { |
no test coverage detected