前端一直比較喜歡tinypng
壓縮圖片,但是每次都要用手拖來拖去,很累.
最近不忙了,node
擼了一段100
行的程式碼,一個命令全自動壓縮資料夾(包含子資料夾)裡所有大小小於5MB
的jpg
和png
圖片,親測成功,再次感謝tinypng
。
大體思路:
- 遞迴獲取本地資料夾裡的檔案
- 過濾檔案,格式必須是
.jpg
.png
,大小小於5MB.(資料夾遞迴) - 每次只處理一個檔案(可以繞過20個的數量限制)
- 處理返回資料拿到遠端優化圖片地址
- 取回圖片更新本地圖片
- 純node實現不依賴任何其他程式碼片段
上程式碼:
const fs = require(`fs`);
const path = require(`path`);
const https = require(`https`);
const crypto = require(`crypto`);
const { URL } = require(`url`);
const root = `./`,
exts = [`.jpg`, `.png`],
max = 5200000; // 5MB == 5242848.754299136
const options = {
method: `POST`,
hostname: `tinypng.com`,
path: `/web/shrink`,
headers: {
rejectUnauthorized: false,
`Postman-Token`: Date.now(),
`Cache-Control`: `no-cache`,
`Content-Type`: `application/x-www-form-urlencoded`,
`User-Agent`:
`Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36`
}
};
fileList(root);
// 獲取檔案列表
function fileList(folder) {
fs.readdir(folder, (err, files) => {
if (err) console.error(err);
files.forEach(file => {
fileFilter(folder + file);
});
});
}
// 過濾檔案格式,返回所有jpg,png圖片
function fileFilter(file) {
fs.stat(file, (err, stats) => {
if (err) return console.error(err);
if (
// 必須是檔案,小於5MB,字尾 jpg||png
stats.size <= max &&
stats.isFile() &&
exts.includes(path.extname(file))
) {
fileUpload(file); // console.log(`可以壓縮:` + file);
}
if (stats.isDirectory()) fileList(file + `/`);
});
}
// 非同步API,壓縮圖片
// {"error":"Bad request","message":"Request is invalid"}
// {"input": { "size": 887, "type": "image/png" },"output": { "size": 785, "type": "image/png", "width": 81, "height": 81, "ratio": 0.885, "url": "https://tinypng.com/web/output/7aztz90nq5p9545zch8gjzqg5ubdatd6" }}
function fileUpload(img) {
var req = https.request(options, function(res) {
res.on(`data`, buf => {
let obj = JSON.parse(buf.toString());
if (obj.error) {
console.log(`[${img}]:壓縮失敗!報錯:${obj.message}`);
} else {
fileUpdate(img, obj);
}
});
});
req.write(fs.readFileSync(img), `binary`);
req.on(`error`, e => {
console.error(e);
});
req.end();
}
// 該方法被迴圈呼叫,請求圖片資料
function fileUpdate(imgpath, obj) {
let options = new URL(obj.output.url);
let req = https.request(options, res => {
let body = ``;
res.setEncoding(`binary`);
res.on(`data`, function(data) {
body += data;
});
res.on(`end`, function() {
fs.writeFile(imgpath, body, `binary`, err => {
if (err) return console.error(err);
console.log(
`[${imgpath}]
壓縮成功,原始大小-${obj.input.size},壓縮大小-${
obj.output.size
},優化比例-${obj.output.ratio}`
);
});
});
});
req.on(`error`, e => {
console.error(e);
});
req.end();
}