利用tingPng接口壓縮,支持壓縮失敗從新壓縮,支持命令行調用,支持npm 安裝調用。話很少說,開幹。javascript
Listr
提供終端可執行的任務列表
cli-table'
容許從node.js腳本在命令行上呈現unicode輔助表(也就是表格呈現結果)chalk
命令行上呈現不一樣顏色的文字minimist
解析命令行參數commander
生成命令行命令。java
project
│ README.md
│ package.json
│ .gitignore
└───bin
│ │ esigntiny
└───demo
| │ images
| │ index.js
└───lib
| │ index.js
| │ initTiny.js
| │ esigntiny.js
| │ compressTiny.js
| │ compressFailedImg.js
| │ resultToChalk.js
| │ utils.js
複製代碼
bin
用來存放可執行的node文件,用於在命令行調用方式。demo
提供了可直接運行的腳本和須要壓縮的圖片。lib
是代碼源文件。node
#!/usr/bin/env node //node環境下執行
const program = require('commander')
const esigntiny = require('../lib')
const path = require('path')
const argv = require('minimist')(process.argv.slice(2))
let input = argv.i || argv.input
let output = argv.o || argv.output
const { getCwd } = require('../lib/utils.js')
// 命令行提示
program
.version(require('../package.json').version, '-v --version')
.usage('<command> [options]')
.option('-i, --input', 'input directory [require]')
.option('-o, --output', 'output directory')
// 註冊start命令
program.command('start').description('start compress images').action(start)
// 解析命令行
program.parse(process.argv)
// 命令行輸入 esigntiny start執行此函數
function start() {
if (!input) {
console.log('require input directory')
return
}
input = path.resolve(getCwd(), input)
if (!!output) output = path.resolve(getCwd(), output)
esigntiny({
input: input,
output: output,
})
}
if (!program.args.length) {
program.outputHelp()
}
複製代碼
實現的邏輯很是簡單,首先遞歸獲取
input
的image
地址,而後調用tinyPng
的接口壓縮拿到壓縮後的圖片地址,而後請求圖片地址寫入目標文件。git
const { normalizeOptions } = require('./utils.js')
const initTiny = require('./initTiny.js')
const compressTiny = require('./compressTiny.js')
const esigntiny = async function (options) {
// 初始化用戶傳參
options = normalizeOptions(options)
// 1.初始化程序,遞歸拿到圖片地址
// 2.壓縮圖片
const taskExample = compressTiny(initTiny(options))
taskExample.run().catch((err) => console.log(err))
}
module.exports = esigntiny
複製代碼
index.js
主要是標準化參數,建立listr
實例,建立獲取圖片,壓縮圖片的task
。github
const Listr = require('listr')
// 遞歸獲取image地址
const { getImsges } = require('./utils.js')
module.exports = function (options) {
const taskExample = new Listr()
taskExample.add(getFiles(options))
return taskExample
}
function getFiles(options) {
return {
title: '獲取全部圖片數量',
task: (ctx, task) => {
ctx.options = options
ctx.images = getImsges(options.input)
task.title = `共找到${ctx.images.length}張圖`
if (ctx.images.length === 0) {
Promise.reject('未找到圖片')
}
},
}
}
複製代碼
const resultToChalk = require('./resultToChalk.js')
const compressFailedImg = require('./compressFailedImg.js')
const { tinyFun } = require('./utils.js')
module.exports = function (taskExample) {
taskExample.add({
title: '壓縮圖片',
task: async (ctx, task) => {
// 獲取全部的圖片的壓縮結果
const imagesRsult = await Promise.all(tinyFun(ctx))
// 在次壓縮失敗的圖片
const failedList = await resultToChalk(imagesRsult)
await compressFailedImg(failedList, ctx.options)
},
})
return taskExample
}
複製代碼
獲取全部圖片的壓縮結果,而後繪製結果表格,而後開啓圖片的再次壓縮。npm
/** * 將每一個文件壓縮返回promise * compressFile包裝每個請求連接 */
const tinyFun = (ctx) => {
const { images, options } = ctx
return images.map((item) => {
return compressFile(item, options)
})
}
/** * 壓縮文件 */
const compressFile = (filePath, options) => {
return new Promise((resolve, reject) => {
createReadStream(filePath).pipe(
request(parms, (res) => {
res.on('data', async (info) => {
try {
info = JSON.parse(info.toString())
// console.log('[[[[[]]]]]', info)
if (/^\s*</g.test(info) || info.error) {
resolve(
getMessage({
info,
filePath,
msg: '壓縮失敗',
code: 500,
})
)
return
}
resolve(await getImageData(info, options, filePath))
} catch (e) {
// console.log(e, '))0')
resolve(
getMessage({
info,
filePath,
msg: '接口請求被拒絕',
code: 500,
})
)
}
})
})
)
})
}
/** * 讀取圖片,寫入文件 */
const getImageData = (imageInfo, options, filePath) => {
let output = options.output
const input = options.input
const imageUrl = imageInfo.output.url
const oldSize = (imageInfo.input.size / 1024).toFixed(2)
const newSize = (imageInfo.output.size / 1024).toFixed(2)
return new Promise((resolve, reject) => {
get(imageUrl, (res) => {
const outDir = path.dirname(output)
output = filePath.replace(input, output)
if (!existsSync(outDir)) {
mkdirSync(outDir)
}
res.pipe(createWriteStream(output))
res.on('end', function () {
resolve(
getMessage({
code: 200,
filePath,
msg: '壓縮成功',
info: {
oldSize,
newSize,
imageUrl,
},
})
)
})
})
})
}
/** * 接口的文案提示 */
const getMessage = ({ msg, code, info, filePath }) => {
return {
code: code || 400,
msg: msg || '成功',
data: {
filePath,
info,
},
}
}
複製代碼
將每一個文件壓縮返回
promise
,compressFile
包裝每個請求連接,建立可讀流請求tinyPng
壓縮圖片,注意這裏要將全部的結果都resolve
出去,錯誤處理交給resultToChalk
函數,壓縮成功會返回壓縮成功以後的圖片地址,建立請求寫入指定的文件地址。json
const Table = require('cli-table')
const chalk = require('chalk')
const path = require('path')
const { sleep } = require('./utils.js')
const headArr = {
head: ['name', 'status', 'old-size(kb)', 'new-size(kb)', 'compress ratio(%)'],
}
// const table = new Table({
// head: ,
// })
// 獲取要打印的數據
const getSuccessInfo = (result) => {
const data = result.data
const info = data.info
const fileName = path.basename(data.filePath)
const compressRatio = parseFloat(
((info.oldSize - info.newSize) / info.oldSize) * 100
).toFixed(2)
return [fileName, 'success', info.oldSize, info.newSize, compressRatio]
}
module.exports = async function (imagesRsult) {
let totalNewSize = 0,
totalOldSize = 0,
successNum = 0,
failedNum = 0,
failedList = [],
table = new Table(headArr)
if (imagesRsult && imagesRsult.length) {
imagesRsult.forEach((result) => {
const filePath = result.data.filePath
if (result.code === 200) {
totalNewSize += +result.data.info.newSize
totalOldSize += +result.data.info.oldSize
successNum += 1
table.push(getSuccessInfo(result))
} else {
const fileName = path.basename(filePath)
failedNum += 1
failedList.push(filePath)
table.push([fileName, 'failed'])
}
})
}
await sleep(1000)
console.log(table.toString())
const resStr = `圖片總數量:${ imagesRsult.length }, 壓縮成功:${successNum}, 壓縮失敗:${failedNum}, 壓縮比:${ ((totalOldSize - totalNewSize) / totalOldSize).toFixed(2) * 100 } (%)`
console.log(chalk.red(resStr))
// 2秒後開啓失敗的壓縮
await sleep(2000)
return failedList
}
複製代碼
const { tinyFun } = require('./utils.js')
const Listr = require('listr')
const resultToChalk = require('./resultToChalk.js')
let compressTimes = 1
// 開啓新的Listr,建立圖片壓縮task
module.exports = async function compressFailedImg(failedList, options) {
const taskExample = new Listr()
if (compressTimes-- > 0) {
taskExample.add({
title: '再次壓縮失敗圖片',
task: async (ctx, task) => {
const imagesRsult = await Promise.all(
tinyFun({
images: failedList,
options,
})
)
// 在次壓縮失敗的圖片
await resultToChalk(imagesRsult)
},
})
taskExample.run().catch((err) => {
console.log(err)
})
}
}
複製代碼
compressFailedImg
開啓新的壓縮Listr
,一樣調用tinyFun
獲取壓縮後的結果,而後交給resultToChalk
處理。promise
好了基本上就完成了壓縮小工具,gitHub地址 但願你們能喜歡。markdown