nodejs 全自动使用 Tinypng (免费版,无需任何配置)压缩图片

前端一直比较喜欢tinypng压缩图片,但是每次都要用手拖来拖去,很累.
最近不忙了,node撸了一段100行的代码,一个命令全自动压缩文件夹(包含子文件夹)里所有大小小于5MBjpgpng图片,亲测成功,再次感谢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}] \n 压缩成功,原始大小-${obj.input.size},压缩大小-${
            obj.output.size
          },优化比例-${obj.output.ratio}`
        );
      });
    });
  });
  req.on('error', e => {
    console.error(e);
  });
  req.end();
}

你可能感兴趣的:(javascript,node.js)