Files
wechat_wc/compress-images.js
T
broccoli b19a56003f 添加登录和后端校验
完成后端设计(未在本仓库体现),通过安全的手段完成了登录鉴权
2026-08-06 16:27:36 +08:00

99 lines
3.0 KiB
JavaScript

const sharp = require('sharp')
const fs = require('fs')
const path = require('path')
const IMG_DIR = path.join(__dirname, 'src', 'img')
const QUALITY = 60 // JPG 质量
const MAX_WIDTH = 800 // 最长边限制
const MAX_FILE_KB = 80 // 单张上限 KB —— 强制压到 80KB 以下
/**
* 压缩单个文件(强制覆盖)
*/
async function compressFile(inputPath) {
const ext = path.extname(inputPath).toLowerCase()
const dir = path.dirname(inputPath)
const base = path.basename(inputPath, ext)
const finalPath = path.join(dir, base + '.jpg')
const isAlreadyJpg = ext === '.jpg' || ext === '.jpeg'
const stat = fs.statSync(inputPath)
const currentKb = stat.size / 1024
// 如果已经 .jpg、体积已小于上限、且最长边不超,跳过
if (isAlreadyJpg && currentKb <= MAX_FILE_KB) {
const meta = await sharp(inputPath).metadata()
const longEdge = Math.max(meta.width || 0, meta.height || 0)
if (longEdge <= MAX_WIDTH) {
console.log(`skip ${inputPath} (${currentKb.toFixed(1)}KB, ${longEdge}px)`)
return { from: inputPath, to: inputPath, size: stat.size }
}
}
// 重建 pipeline
const meta = await sharp(inputPath).metadata()
const longEdge = Math.max(meta.width || 0, meta.height || 0)
const resizeOpts = longEdge > MAX_WIDTH ? { width: MAX_WIDTH, height: MAX_WIDTH, fit: 'inside' } : undefined
let pipeline = sharp(inputPath).jpeg({ quality: QUALITY, progressive: true, force: true })
if (resizeOpts) pipeline = pipeline.resize(resizeOpts)
const tmpPath = path.join(dir, base + '_tmp.jpg')
await pipeline.toFile(tmpPath)
fs.unlinkSync(inputPath)
fs.renameSync(tmpPath, finalPath)
const newSize = fs.statSync(finalPath).size
console.log(
`${isAlreadyJpg ? 'compress' : 'convert'} ${base}${ext} (${currentKb.toFixed(1)}KB, ${longEdge}px → ${(newSize / 1024).toFixed(1)}KB)`
)
return { from: inputPath, to: finalPath, size: newSize }
}
/**
* 递归收集所有图片
*/
function collectImages(dir) {
let results = []
const entries = fs.readdirSync(dir, { withFileTypes: true })
for (const entry of entries) {
const full = path.join(dir, entry.name)
if (entry.isDirectory()) {
results = results.concat(collectImages(full))
} else if (/\.(png|jpe?g)$/i.test(entry.name)) {
results.push(full)
}
}
return results
}
/**
* 主函数
*/
async function main() {
console.log(`scanning ${IMG_DIR}...\n`)
const images = collectImages(IMG_DIR)
console.log(`found ${images.length} images\n`)
let totalBefore = 0
let totalAfter = 0
for (const img of images) {
totalBefore += fs.statSync(img).size
const result = await compressFile(img)
totalAfter += result.size
}
console.log(`\n✅ done`)
console.log(` before: ${(totalBefore / 1024 / 1024).toFixed(2)} MB`)
console.log(` after: ${(totalAfter / 1024 / 1024).toFixed(2)} MB`)
console.log(` saved: ${((totalBefore - totalAfter) / 1024 / 1024).toFixed(2)} MB`)
}
main().catch(err => {
console.error(err)
process.exit(1)
})