import fs from 'node:fs'; import path from 'node:path'; import { app, nativeImage } from 'electron'; let resolved = false; let cached: Electron.NativeImage | undefined; /** ICO рядом с exe (вне asar): надёжно для `nativeImage` / панели задач на Windows. */ function getPackagedBrandingIcoPath(): string | undefined { if (!app.isPackaged) return undefined; const p = path.join(process.resourcesPath, 'branding', 'icon.ico'); try { if (fs.existsSync(p)) return p; } catch { /* ignore */ } return undefined; } function brandingPngPaths(): string[] { const root = app.getAppPath(); const relPack = path.join('dist', 'renderer', 'app-pack-icon.png'); const relWindow = path.join('dist', 'renderer', 'app-window-icon.png'); const paths: string[] = []; if (app.isPackaged) { const unpacked = path.join(process.resourcesPath, 'app.asar.unpacked'); paths.push(path.join(unpacked, relPack), path.join(unpacked, relWindow)); } paths.push( path.join(root, relPack), path.join(root, relWindow), path.join(root, 'build', 'icon.png'), path.join(root, 'app', 'renderer', 'public', 'app-window-icon.png'), ); return paths; } function tryLoadImageFile(filePath: string): Electron.NativeImage | undefined { try { const buf = fs.readFileSync(filePath); const fromBuf = nativeImage.createFromBuffer(buf); if (!fromBuf.isEmpty()) return fromBuf; } catch { /* ignore */ } try { const fromPath = nativeImage.createFromPath(filePath); if (!fromPath.isEmpty()) return fromPath; } catch { /* ignore */ } return undefined; } function tryLoadSvgFile(filePath: string): Electron.NativeImage | undefined { try { const fromPath = nativeImage.createFromPath(filePath); if (!fromPath.isEmpty()) return fromPath; } catch { /* ignore */ } return undefined; } function tryDarwinSvgPaths(): Electron.NativeImage | undefined { if (process.platform !== 'darwin') return undefined; const root = app.getAppPath(); for (const p of [ path.join(root, 'dist', 'renderer', 'app-logo.svg'), path.join(root, 'app', 'renderer', 'public', 'app-logo.svg'), ]) { if (!fs.existsSync(p)) continue; const img = tryLoadSvgFile(p); if (img) return img; } return undefined; } /** * Иконка окна / дока. Сначала ICO из `extraResources` (реальный путь на диске), затем PNG * через буфер — `createFromPath` к файлам внутри `app.asar` на Windows часто даёт пустой `NativeImage`. */ export function loadBrandingWindowIcon(): Electron.NativeImage | undefined { if (resolved) return cached; resolved = true; const ico = getPackagedBrandingIcoPath(); if (ico) { const img = tryLoadImageFile(ico); if (img) { cached = img; return cached; } } for (const p of brandingPngPaths()) { if (!fs.existsSync(p)) continue; const img = tryLoadImageFile(p); if (img) { cached = img; return cached; } } const svgIcon = tryDarwinSvgPaths(); if (svgIcon) { cached = svgIcon; return cached; } cached = undefined; return undefined; }