安装库
import imagemin from "imagemin";
import bluebird from "bluebird";
import imageminMozjpeg from "imagemin-mozjpeg";
import imageminPngquant from "imagemin-pngquant";
//版本
"imagemin": "^7.0.1",
"imagemin-mozjpeg": "^8.0.0",
"imagemin-pngquant": "^6.0.1",
"bluebird": "^3.7.2"
普通方法
(async () => {
await imagemin(['images/*.png'], {
destination: 'build/images',
plugins: [
imageminPngquant({ quality: 50 })
]
});
console.log('Images optimized');
})();
异步方法
Promise.promisify(fs.readFile)(sourcepath)
.then((buffer) => {
return imagemin.buffer(buffer, {
plugins: [
imageminMozjpeg({quality:50,progressive:true}),
imageminPngquant({ quality: [0.6, 0.8] }),
],
});
})
.then((outBuffer) => {
fs.writeFileSync(destinpathcw, outBuffer);
})
.catch((err) => {
console.log(err);
});
//片段代码,实现上面的异步方法在node的sreeam的流实现
//参考:可以放在流的writeStream.on(“finish”, () =>{ …这里面 })
let data = groupData[index];
let inum = 0;
let error_flag = false;
//任务处理TODO
for (let i = 0, len = data.length; i < len; i++) {
let hairPiece = data[i]["target_path"].split('/');
let sourcepath = data[i]["path"].replace(/\\/g, "/");
//let destinpath = path.join(__pack, 'Model',arg.fatherName,data[i]['name']).replace(/\\/g,'/');
let destinpath = path.join(__pack, "Model", data[i]["target_path"]);
let destinpathcw = path.join(__pack, "Model", `${hairPiece[0]}_100x100/${hairPiece[1]}/${hairPiece[2]}`, );
let readStream = fs.createReadStream(sourcepath);
let writeStream = fs.createWriteStream(destinpath);
readStream.pipe(writeStream);
writeStream.on("finish", () => {
Promise.promisify(fs.readFile)(sourcepath)
.then((buffer) => {
return imagemin.buffer(buffer, {
plugins: [
imageminMozjpeg({quality:50,progressive: true}),
imageminPngquant({ quality: [0.6, 0.8] }),
],
});
})
.then((outBuffer) => {
inum++;
fs.writeFileSync(destinpathcw, outBuffer);
// auto_i++;
// if(arg.id) localStorage.setItem(arg.id, auto_i);
if (inum == len) {
if (index < Object.keys(groupData).length - 1) {
writeFile(arg, ++index, groupData);
return;
}
console.log("complete status");
//如果任务处理完成,则发送完成通知
ipcRenderer.removeAllListeners("begain-task");
ipcRenderer.send("task-complete", arg);
}
})
.catch((err) => {
console.log(err);
});
});
// 上传出错,将不再继续往下执行其他文件
writeStream.on("error", (err) => {
console.log("error", err);
ipcRenderer.send("error-during-upload", err, arg);
ipcRenderer.removeAllListeners("begain-task");
if (!error_flag) ipcRenderer.send("task-complete", arg);
error_flag = true;
});
readStream.on("error", (err) => {
console.log(err);
ipcRenderer.send("error-during-upload", err, arg);
ipcRenderer.removeAllListeners("begain-task");
if (!error_flag) ipcRenderer.send("task-complete", arg);
error_flag = true;
});
readStream.on("data", (chunk) => {
currentTotal += chunk.length;
let res = parseInt((currentTotal / arg.totalSize) * 100);
if (res != pre_num) {
ipcRenderer.send("upload-progress", res);
pre_num = res;
}
});
if (error_flag) break;
}
}
//遇到的问题
出错
- Error: write EOF
at WriteWrap.onWriteComplete [as oncomplete]
解决:
imageminPngquant({ quality: [0.6,0.8] }),
改成这个
imageminPngquant({ quality: 50 }),
官方写着quality的值是Array,实际上改成number就行了
- 用imagemin的时候electron打包遇到了:Error: spawn ENOTDIR
这个压缩图片的工具用到了 imagemin这个npm包,在开发的时候压缩图片没任何问题,但是经过electron打包,一旦压缩图片,就会报错,如图所示:
起初我是懵逼的,因为这看不到有效的报错信息啊,但是经过阅读源码网上查找解决方案,最终发现了端倪。在debugger的过程中,发现imagemin是使用二进制可执行文件来对图片进行压缩的,执行二进制的函数是child_process.spawn,这个函数对于文件路径有限制,因为electron打包后,会把依赖项压缩成一个文件,导致这个函数判断路径时报错,对于这个问题,如果是自己的代码中使用了二进制文件,则可以将child_process.spawn替换为child_process.execFile函数来执行二进制文件。
但是我这里引用的是别人的包,如果擅自修改非本源的包,可能会导致项目无法在其他的环境中运行,所以得找例外的解决方案,皇天不负苦心人,终于找到了解决方案,那就是electron打包时,不对依赖项进行压缩,那样就能得到一个正确的路径了。
解决方案
修改package.json中的build选项,这个选项是对electron打包的一系列配置。将其中的 asar 修改为false,就能让electron在打包时,不对依赖进行压缩,如下所示:
“build”: {
“appId”: “com.richard.image_compress”,
“mac”: {
“category”: “tool”
},
“extends”: null,
“files”: [“build”, “*.js”, “public”],
“asar”: false
}