Electron 入门项目(一)

ImageShrink

简介:一个简单的图片大小缩放工具。
先看效果:
ImageShrink
原图
缩小后
图片前后质量对比:
处理前
后:
处理后
可以看到图片的大小变小了,但是图片的质量并没有下降多少。

项目技术概述

采用Electron开发,利用node 生态中的 imagemin包来实现对图片大小的缩放;利用electron-log包实现对源文件与目标文件转换的日志记录;渲染进程通过ipcRenderer将用户上传的图片的地址、将要缩小的倍数发送到主进程,主进程通过ipcMain接收到对应的opthions利用imagemin将文件缩小,将缩小后的文件存在用户的目录下,并自动打开该文件夹。

核心细节

区分环境

1
2
3
process.env.NODE_ENV = 'production'
const isDev = process.env.NODE_ENV !== 'production' ? true : false //区分生产开发环境
const isMac = process.platform === 'darwin' ? true : false // 区分平台

我这里是采用手动的方式区分开发或者是生产环境,虽然有相应的包可以直接判断,但是我觉得这样比较简单点。

创建窗口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
function createMainWindow() {
mainWindow = new BrowserWindow({
title: 'ImageShrink',
width: isDev ? 800 : 500,
height: 600,
icon: './assets/icons/Icon_256x256.png',
resizable: isDev ? true : false,
webPreferences: {
nodeIntegration: true // 设置渲染进程是否可用node
}
})
// mainWindow.loadURL(`file://${__dirname}/app/index.html`) // 可以采用loadURL的方式,但是会有一个安全的限制 需要在html中加上这一段 meta: <meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline'">

if (isDev) {
// 如果是开发环境,就打开开发者菜单
mainWindow.webContents.openDevTools()
}
mainWindow.loadFile(`./app/index.html`)
}

// 关于页面的窗口
function createAboutWindow() {
aboutWindow = new BrowserWindow({
title: 'About ImageShrink',
width: 300,
height: 300,
icon: './assets/icons/Icon_256x256.png',
resizable: false
})
aboutWindow.loadFile(`./app/about.html`)
}

设置菜单项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
const menu = [
...(isMac ? [{
label: app.name,
submenu: [{
label: 'About',
click: createAboutWindow
}]
}] : []),
{
role: 'fileMenu'
},
...(!isMac ? [{
label: 'Help',
submenu: [{
label: 'About',
click: createAboutWindow
}]
}] : []),
...(isDev ? [{
label: 'Developer', // 开发者菜单,用内置的menu
submenu: [{
role: 'reload'
},
{
role: 'forcereload'
},
{
type: 'separator'
},
{
role: 'toggledevtools'
},
]
}] : [])
]

app.on('ready', () => {
createMainWindow()

const mainMenu = Menu.buildFromTemplate(menu)
Menu.setApplicationMenu(mainMenu)

// 全局快捷键 如果不用开发者菜单 可用自己设置全局快捷键帮助开发
// globalShortcut.register('CmdOrCtrl+R', () => mainWindow.reload()) 刷新页面
// globalShortcut.register(isMac ? 'Command+Alt+I' : 'Ctrl+Shift+I', () => mainWindow.toggleDevTools()) 打开 DevTools

mainWindow.on('ready', () => mainWindow = null)
})

图片缩小逻辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
// 利用 ipcMain ipcRenderer 实现主进程与渲染进程的通信
// options 有两个参数: url 和 quality,分别为图片的路径和缩小倍数
// 这里的dest是指转换后图片存放的地址
ipcMain.on('image:minimize', (e, options) => {
options.dest = path.join(os.homedir(), 'imageshrink')
shrinkImage(options)
})

// 图片缩小的方法
async function shrinkImage({
imgPath,
quality,
dest
}) {
try {
const pngQuality = quality / 100
// 调用方法 实现缩小图片,具体细节可在npm上搜索该包的详细信息
const files = await imagemin([slash(imgPath)], {
destination: dest,
plugins: [
imageminMozjpeg({
quality
}),
imageminPngquant({
quality: [pngQuality, pngQuality]
})
]
})
// 将这个文件写入日志文件中
log.info(files)
// 打开转换后图片的存放的文件夹
shell.openPath(dest)
// 主进程 利用webContents 主动向渲染进程发送 渲染已完成的事件
mainWindow.webContents.send('image:done')
} catch (error) {
// 如果转换出错,将错误信息存入日志文件中
log.error(error)
}
}

// 渲染进程
document.getElementById('output-path').innerText = path.join(os.homedir(), 'imageshrink')

form.addEventListener('submit', e => {
e.preventDefault()

const imgPath = img.files[0].path
const quality = slider.value

// 向主进程提交缩小图片的事件,并将图片路径和缩小倍数传过去
ipcRenderer.send('image:minimize', {
imgPath,
quality
})
})

// on done
// 图片上传完成 页面提示转换完成
ipcRenderer.on('image:done', () => {
M.toast({
html: `Image resized to ${slider.value}% quality`
})
})

欢迎交流。