UNPKG

zipping-image

Version:

图片压缩工具,内部使用tinypng接口

145 lines (133 loc) 3.44 kB
const fs = require('fs') const tinify = require('tinify') const p = require('path') const FileType = require('file-type') const packageJson = require('./package.json') tinify.key = packageJson.key function getFileSize(filePath) { const stat = fs.statSync(filePath) return stat.size } function isCompressed(filePath) { return new Promise(resolve => { const rs = fs.createReadStream(filePath) let data = '' rs.on('data', chunk => { data += chunk }) rs.on('end', function () { const compressed = data.toString().includes('_compress') resolve(compressed) }) }) } function writeBuffer(filePath) { return new Promise(resolve => { const rs = fs.createReadStream(filePath) const data = [] rs.on('data', chunk => { data.push(chunk) }) rs.on('end', function () { const buf = Buffer.from('_compress') const newBuf = Buffer.concat([...data, buf]) const ws = fs.createWriteStream(filePath) ws.write(newBuf) ws.end() ws.on('finish', resolve) }) }) } function saving(max, min) { return (((max - min) / max) * 100).toFixed(2) + '%' } function toSizeFixed(size) { if (size < 1024) { return size + 'B' } if (size < 1024 * 1024) { return (size / 1024).toFixed(2) + 'KB' } return (size / 1024 / 1024).toFixed(2) + 'MB' } function getFileList(pathList) { return pathList.map(path => transferFileList(path)).flat(Infinity) } function transferFileList(path, fileList = []) { const stat = fs.statSync(path) if (stat.isDirectory()) { const files = fs.readdirSync(path) files.forEach(item => { const child = p.join(path, item) transferFileList(child, fileList) }) } else { fileList.push(path) } return fileList } async function getImageList(paths) { const list = [] for (const path of paths) { const type = await FileType.fromFile(path) if (type && /jpg|png/.test(type.ext)) { list.push(path) } } return list } /** * @param {string[]} fileList */ function getResolveList(fileList) { if (!packageJson.key) { return [Promise.reject({ err_msg: '请先阅读readme, 添加key' })] } return fileList.map(async fileName => { const cwd = process.cwd() const filePath = p.resolve(cwd, fileName) const was = getFileSize(filePath) try { // todo const compress = await isCompressed(filePath) if (!compress) { const source = tinify.fromFile(filePath) await source.toFile(filePath) await writeBuffer(filePath) } const now = getFileSize(filePath) return { path: filePath.replace(cwd + '/', ''), was: toSizeFixed(was), now: toSizeFixed(now), saving: toSizeFixed(was - now), rate: saving(was, now), } } catch (error) { const { status } = error let err_msg switch (status) { case 401: err_msg = 'Credentials are invalid' break case 429: err_msg = '您本月次数已经用完, 请更新tinify.key' default: err_msg = error break } return Promise.reject({ status, err_msg, }) } }) } module.exports = { async compress(fileList) { const pathList = getFileList(fileList) const imageList = await getImageList(pathList) return Promise.all(getResolveList(imageList)) }, writeBuffer, }