123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218 |
- #! /usr/bin/env node
- `use strict`
- var fs = require('fs-extra');
- var os = require('os');
- var path = require('path');
- var exec = require('child_process').exec;
- var program = require('commander');
- var readlineSync = require('readline-sync');
- var ProgressBar = require('progress');
- program
- .option('-r, --removeOrigin', 'Auto remove origin file when jobs done')
- .option('-s, --silence', 'Run in background')
- .option('-q, --quality <quality>', 'Output image quality.Default is 85')
- .option('-e, --ext <ext>', 'Output file extension.Support jpg,png,auto.Default is auto')
- .option('-E, --exceptExt <exceptExt>', 'Special extension will not be minified but move(copy) into output.Different ext delimit by ","')
- .option('-F, --exceptFolder <exceptFolder>', 'Images in excepted folder(name) will not be minified')
- .option('-o, --output <output>', 'Output folder path.Default is current image path with a subfolder named minified')
- .option('-w, --worker <worker>', 'Max minify worker at the same time.Default is max CPU Core Number')
- .usage('-q [Quality] -e [Extension] -o [Output Path] Path...')
- .arguments('[path...]')
- .parse(process.argv);
- var Config = {
- path : program.args[0],
- quality : program.quality,
- output : program.output,
- ext : program.ext,
- exceptExt : program.exceptExt,
- exceptFolder : program.exceptPath,
- worker : program.worker,
- isFolder :false,
- currentDir : '',
- outputDir : ''
- }
- var ImageList = [],failureList = [],exceptExt = {},exceptFolder = {},workerCount = 0;
- var processBar;
- if(!Config.path) return program.outputHelp();
- exec('gm -version | grep -o -E \'^GraphicsMagick ([0-9]|\.)+\'',function(err,stdout,stderr){
- if(err || !stdout) return console.error('GraphicsMagick not installed!!!')
- checkPath();
- })
- function checkPath(){
- if(Config.exceptExt){
- let arr = Config.exceptExt.split(',');
- for(let ext of arr){
- exceptExt[ext] = 1;
- }
- }
- if(Config.exceptFolder){
- let arr = Config.exceptFolder.split(',');
- for(let folder of arr){
- exceptFolder[folder] = 1;
- }
- }
- exceptFolder['minified'] = 1;
- fs.stat(Config.path,function(err,stats){
- if(err || !stats) return console.error(`No such file or directory [${Config.path}]`)
- if(stats.isFile()){
- let ext = path.extname(Config.path);
- if(!ext.match(/^.(jpg|jpeg|png|gif|bmp|raw)$/gi)){
- return console.log("ImageMinify only support image with extension name in jpg,jpeg,png,gif,bmp or raw");
- }
- ImageList.push(Config.path);
- Config.currentDir = path.parse(Config.path).dir;
- prepareTask();
- }else{
- Config.isFolder = true;
- Config.currentDir = path.resolve(Config.path);
- analysisFolder(Config.currentDir);
- prepareTask();
- }
- });
- }
- function analysisFolder(readPath){
- let currentPath = readPath;
- let fileList = fs.readdirSync(currentPath);
- for(let fileName of fileList){
- let filePath = path.join(currentPath,fileName);
- let fileStat = fs.statSync(filePath);
- if(fileStat.isFile()){
- let ext = path.extname(fileName);
- // if(ext.match(/jpg|jpeg|png|gif|bmp|raw/gi)){
- ImageList.push(filePath);
- // }
- }else{
- if(exceptFolder[path.parse(filePath).name]) continue;
- analysisFolder(filePath);
- }
- }
- }
- function prepareTask(){
- fs.removeSync(`${Config.outputDir}/error.log`);
- if(!Config.output){
- if(program.silence){
- Config.output = 'minified';
- }else{
- Config.output = readlineSync.question('Output directory [minified] : ');
- if(!Config.output) Config.output = 'minified';
- }
- }
- Config.outputDir = path.resolve(Config.currentDir,Config.output);
- if(!Config.quality){
- if(program.silence){
- Config.quality = 85;
- }else{
- Config.quality = Number(readlineSync.question('Output quality [85] : '));
- if(!Config.quality) Config.quality = 85;
- }
- }
- if(!Config.ext){
- if(program.silence){
- Config.ext = 'auto';
- }else{
- Config.ext = readlineSync.question('Output extension,only support jpg,png,gif or auto [auto] : ');
- if(!Config.ext || !Config.ext.match(/^(jpg|png|gif)$/i)) Config.ext = 'auto';
- }
- }
- if(!Config.worker){
- Config.worker = os.cpus().length;
- // if(program.silence){
- // }else{
- // Config.worker = Number(readlineSync.question('Output quality [85] : '));
- // if(!Config.worker) Config.worker = os.cpus().length;
- // }
- }
- startTask();
- }
- function startTask(){
- if(!program.silence){
- console.log('-----------------------------------------------------------------');
- console.log(`[ Path ] ${Config.path}`);
- console.log(`[Folder] ${Config.isFolder}\t[Quality] ${Config.quality}\t[OutputExtension] ${Config.ext}\t[Amount] ${ImageList.length}\t[Worker] ${Config.worker}`);
- console.log('-----------------------------------------------------------------');
- console.log(`[OutputDirectory] ${Config.outputDir}`);
- console.log('-----------------------------------------------------------------');
- processBar = new ProgressBar('Minifying: [:bar][:current/:total] [:image]', { total: ImageList.length, width: 20, complete: '*' });
- }
- for(let i = 0;i<Config.worker;i++){
- minify();
- }
- }
- function minify(){
- // if(ImageList.length==0) return finished();
- if(ImageList.length==0) return;
- workerCount++;
- let image = ImageList.pop();
- let pathParse = path.parse(image);
- let imageDir = pathParse.dir;
- let fileName = pathParse.name;
- let subDir = imageDir.replace(Config.currentDir,'');
- let imgExt = pathParse.ext.replace('.','');
- let outputExt = (Config.ext=='auto')?imgExt:Config.ext;
- let outputDir = Config.outputDir + subDir;
- let outputFile = `${outputDir}/${fileName}.${outputExt}`;
- fs.mkdirpSync(outputDir);
- if(exceptExt[imgExt] || !imgExt.match(/jpg|jpeg|png|gif|bmp|raw/gi)){
- if(program.removeOrigin){
- fs.moveSync(image,`${outputDir}/${fileName}.${imgExt}`,{overwrite:true});
- }else{
- fs.copySync(image,`${outputDir}/${fileName}.${imgExt}`,{overwrite:true});
- }
- if(!program.silence) processBar.total--;
- workerCount--;
- if(ImageList.length==1) return finished();
- return minify();
- }
- exec(`export OMP_NUM_THREADS=4 && gm convert -strip -format '${outputExt}' -quality ${Config.quality} -depth 8 "${image}" "${outputFile}"`,function(err,stdout,stderr){
- if(err || stdout || stderr){
- // console.log(err,stdout,stderr)
- failureList.push(image);
- }else{
- if(program.removeOrigin){
- try{
- fs.removeSync(image);
- }catch(e){}
- }
- }
- if(!program.silence) processBar.tick(1,{'image':`${subDir}/${fileName}.${imgExt}`});
- workerCount--;
- if(workerCount==0 && ImageList.length==0) return finished();
- minify();
- });
- }
- function finished(){
- if(!program.silence) console.log('\nAll images minified');
- if(!failureList.length) return;
- let log = '';
- log += ('\n-----------------------------------------------------------------\n');
- log += ('These image(s) minified failed!');
- log += ('-----------------------------------------------------------------\n');
- for(let image of failureList){
- log += image + '\n';
- }
- log += ('-----------------------------------------------------------------\n');
- fs.writeFileSync(`${Config.outputDir}/error.log`,log,'UTF-8');
- console.error(log);
- }
|