新增 TinyPanda 图片压缩工具项目,基于 Electron 和 Tinify API 构建

This commit is contained in:
yuantao
2026-01-30 14:01:42 +08:00
parent 067636aa29
commit 167e375631
9 changed files with 7111 additions and 0 deletions

205
src/main/index.js Normal file
View File

@@ -0,0 +1,205 @@
const { app, BrowserWindow, ipcMain, dialog } = require('electron');
const path = require('path');
const tinify = require('tinify');
const fs = require('fs');
const JSZip = require('jszip');
require('dotenv').config();
let mainWindow;
let apiKey = process.env.TINIFY_API_KEY || '';
function createWindow() {
mainWindow = new BrowserWindow({
width: 1200,
height: 800,
frame: false,
transparent: false,
backgroundColor: '#FFFFFF',
vibrancy: 'acrylic',
resizable: true,
webPreferences: {
nodeIntegration: true,
contextIsolation: false
},
icon: path.join(__dirname, '../../assets/icon.png')
});
mainWindow.loadFile('src/renderer/index.html');
// 开发模式下打开开发者工具
if (process.env.NODE_ENV === 'development') {
mainWindow.webContents.openDevTools();
}
}
app.whenReady().then(createWindow);
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
// 获取当前 API Key
ipcMain.handle('get-api-key', async () => {
return { apiKey: apiKey || '' };
});
// 设置 API Key
ipcMain.handle('set-api-key', async (event, key) => {
apiKey = key;
tinify.key = key;
return { success: true };
});
// 验证 API Key
ipcMain.handle('validate-api-key', async (event, key) => {
try {
tinify.key = key;
await tinify.fromBuffer(Buffer.from('fake')).toBuffer();
return { valid: false };
} catch (error) {
if (error.message && error.message.includes('Credentials')) {
return { valid: false };
}
// 其他错误说明格式正确但不是真实图片
return { valid: true };
}
});
// 压缩单张图片
ipcMain.handle('compress-image', async (event, filePath) => {
try {
const source = tinify.fromFile(filePath);
const compressed = await source.toBuffer();
return {
success: true,
compressedData: compressed.toString('base64')
};
} catch (error) {
return {
success: false,
error: error.message
};
}
});
// 获取图片信息
ipcMain.handle('get-image-info', async (event, filePath) => {
try {
const stats = fs.statSync(filePath);
return {
size: stats.size,
success: true
};
} catch (error) {
return {
success: false,
error: error.message
};
}
});
// 保存压缩后的图片
ipcMain.handle('save-compressed-image', async (event, savePath, base64Data) => {
try {
const buffer = Buffer.from(base64Data, 'base64');
fs.writeFileSync(savePath, buffer);
return { success: true };
} catch (error) {
return {
success: false,
error: error.message
};
}
});
// 创建压缩包
ipcMain.handle('create-zip', async (event, files) => {
try {
const zip = new JSZip();
for (const file of files) {
const buffer = Buffer.from(file.data, 'base64');
zip.file(file.name, buffer);
}
const content = await zip.generateAsync({ type: 'base64' });
return {
success: true,
zipData: content
};
} catch (error) {
return {
success: false,
error: error.message
};
}
});
// 选择保存目录
ipcMain.handle('select-save-directory', async () => {
const result = await dialog.showOpenDialog({
properties: ['openDirectory']
});
if (result.canceled) {
return { canceled: true };
}
return { canceled: false, path: result.filePaths[0] };
});
// 选择文件
ipcMain.handle('select-files', async () => {
const result = await dialog.showOpenDialog({
properties: ['openFile', 'multiSelections'],
filters: [
{ name: 'Images', extensions: ['jpg', 'jpeg', 'png', 'webp'] }
]
});
if (result.canceled) {
return { canceled: true };
}
return { canceled: false, files: result.filePaths };
});
// 窗口控制
ipcMain.handle('window-minimize', async () => {
if (mainWindow) {
mainWindow.minimize();
}
});
ipcMain.handle('window-maximize', async () => {
if (mainWindow) {
if (mainWindow.isMaximized()) {
mainWindow.unmaximize();
} else {
mainWindow.maximize();
}
}
});
ipcMain.handle('window-close', async () => {
if (mainWindow) {
mainWindow.close();
}
});
ipcMain.handle('window-is-maximized', async () => {
if (mainWindow) {
return mainWindow.isMaximized();
}
return false;
});