HonorLee 11 months ago
commit
6fc450b2a7
3 changed files with 473 additions and 0 deletions
  1. 145 0
      ImageMinify.js
  2. 301 0
      package-lock.json
  3. 27 0
      package.json

+ 145 - 0
ImageMinify.js

@@ -0,0 +1,145 @@
+#! /usr/bin/env node
+`use strict`
+
+var fs   = require('fs-extra');
+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 image 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('-o, --output <output>', 'Output folder path.Default is current image path with a subfolder named minified')
+.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,
+    isFolder:false,
+    currentDir:'',
+    outputDir:''
+}
+var ImageList = [],failureList = [];
+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(){
+    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{
+            analysisFolder(filePath);
+        }
+    }
+}
+
+function prepareTask(){
+    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';
+        }
+    }
+
+    startTask();
+}
+
+function startTask(){
+    console.log('-----------------------------------------------------------------');
+    console.log(`[ Path ] ${Config.path}`);
+    console.log(`[Folder] ${Config.isFolder}\t[Quality] ${Config.quality}\t[OutputExtension] ${Config.ext}\t[Amount] ${ImageList.length}`);
+    console.log('-----------------------------------------------------------------');
+    console.log(`[OutputDirectory] ${Config.outputDir}`);
+    console.log('-----------------------------------------------------------------');
+    processBar = new ProgressBar('Minifying: [:bar][:current/:total] [:image]', { total: ImageList.length, width: 20, complete: '*' });
+    minify();
+}
+
+function minify(){
+    if(ImageList.length==0) return finished();
+    let image = ImageList.pop();
+    let pathParse = path.parse(image);
+    let imageDir = pathParse.dir;
+    let fileName = pathParse.name;
+    let subDir = imageDir.replace(Config.currentDir,'');
+    let outputExt = (Config.ext=='auto')?pathParse.ext.replace('.',''):Config.ext;
+    let outputDir = Config.outputDir + subDir;
+    let outputFile = `${outputDir}/${fileName}.${outputExt}`;
+    fs.mkdirpSync(outputDir);
+    exec(`gm convert -strip -format '${outputExt}' -quality ${Config.quality} -depth 8 '${image}' '${outputFile}'`,function(err,stdout,stderr){
+        if(err || stdout || stderr){
+            failureList.push(image);
+        }else{
+            if(program.removeorigin) fs.removeSync(image);
+        }
+        processBar.tick(1,{'image':`${subDir}/${fileName}`});
+        minify();
+    });
+}
+function finished(){
+    if(!program.silence) console.log('\All images minified');
+}
+
+

+ 301 - 0
package-lock.json

@@ -0,0 +1,301 @@
+{
+  "name": "imageminify",
+  "version": "1.0.0",
+  "lockfileVersion": 1,
+  "requires": true,
+  "dependencies": {
+    "ansi-escapes": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz",
+      "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ=="
+    },
+    "ansi-regex": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+      "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg="
+    },
+    "ansi-styles": {
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+      "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+      "requires": {
+        "color-convert": "1.9.3"
+      }
+    },
+    "chalk": {
+      "version": "2.4.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+      "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+      "requires": {
+        "ansi-styles": "3.2.1",
+        "escape-string-regexp": "1.0.5",
+        "supports-color": "5.5.0"
+      }
+    },
+    "chardet": {
+      "version": "0.7.0",
+      "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
+      "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA=="
+    },
+    "cli-cursor": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz",
+      "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=",
+      "requires": {
+        "restore-cursor": "2.0.0"
+      }
+    },
+    "cli-width": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz",
+      "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk="
+    },
+    "color-convert": {
+      "version": "1.9.3",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+      "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+      "requires": {
+        "color-name": "1.1.3"
+      }
+    },
+    "color-name": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+      "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
+    },
+    "commander": {
+      "version": "2.19.0",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz",
+      "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg=="
+    },
+    "escape-string-regexp": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+      "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
+    },
+    "external-editor": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.0.3.tgz",
+      "integrity": "sha512-bn71H9+qWoOQKyZDo25mOMVpSmXROAsTJVVVYzrrtol3d4y+AsKjf4Iwl2Q+IuT0kFSQ1qo166UuIwqYq7mGnA==",
+      "requires": {
+        "chardet": "0.7.0",
+        "iconv-lite": "0.4.24",
+        "tmp": "0.0.33"
+      }
+    },
+    "figures": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz",
+      "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=",
+      "requires": {
+        "escape-string-regexp": "1.0.5"
+      }
+    },
+    "fs-extra": {
+      "version": "7.0.1",
+      "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz",
+      "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==",
+      "requires": {
+        "graceful-fs": "4.1.15",
+        "jsonfile": "4.0.0",
+        "universalify": "0.1.2"
+      }
+    },
+    "graceful-fs": {
+      "version": "4.1.15",
+      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz",
+      "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA=="
+    },
+    "has-flag": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+      "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
+    },
+    "iconv-lite": {
+      "version": "0.4.24",
+      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+      "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+      "requires": {
+        "safer-buffer": "2.1.2"
+      }
+    },
+    "inquirer": {
+      "version": "6.2.2",
+      "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.2.2.tgz",
+      "integrity": "sha512-Z2rREiXA6cHRR9KBOarR3WuLlFzlIfAEIiB45ll5SSadMg7WqOh1MKEjjndfuH5ewXdixWCxqnVfGOQzPeiztA==",
+      "requires": {
+        "ansi-escapes": "3.2.0",
+        "chalk": "2.4.2",
+        "cli-cursor": "2.1.0",
+        "cli-width": "2.2.0",
+        "external-editor": "3.0.3",
+        "figures": "2.0.0",
+        "lodash": "4.17.11",
+        "mute-stream": "0.0.7",
+        "run-async": "2.3.0",
+        "rxjs": "6.4.0",
+        "string-width": "2.1.1",
+        "strip-ansi": "5.1.0",
+        "through": "2.3.8"
+      },
+      "dependencies": {
+        "string-width": {
+          "version": "2.1.1",
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
+          "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
+          "requires": {
+            "is-fullwidth-code-point": "2.0.0",
+            "strip-ansi": "4.0.0"
+          },
+          "dependencies": {
+            "strip-ansi": {
+              "version": "4.0.0",
+              "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+              "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+              "requires": {
+                "ansi-regex": "3.0.0"
+              }
+            }
+          }
+        },
+        "strip-ansi": {
+          "version": "5.1.0",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.1.0.tgz",
+          "integrity": "sha512-TjxrkPONqO2Z8QDCpeE2j6n0M6EwxzyDgzEeGp+FbdvaJAt//ClYi6W5my+3ROlC/hZX2KACUwDfK49Ka5eDvg==",
+          "requires": {
+            "ansi-regex": "4.1.0"
+          },
+          "dependencies": {
+            "ansi-regex": {
+              "version": "4.1.0",
+              "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+              "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg=="
+            }
+          }
+        }
+      }
+    },
+    "is-fullwidth-code-point": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
+      "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8="
+    },
+    "is-promise": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz",
+      "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o="
+    },
+    "jsonfile": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
+      "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
+      "requires": {
+        "graceful-fs": "4.1.15"
+      }
+    },
+    "lodash": {
+      "version": "4.17.11",
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
+      "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg=="
+    },
+    "mimic-fn": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz",
+      "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ=="
+    },
+    "mute-stream": {
+      "version": "0.0.7",
+      "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz",
+      "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s="
+    },
+    "onetime": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz",
+      "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=",
+      "requires": {
+        "mimic-fn": "1.2.0"
+      }
+    },
+    "os-tmpdir": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
+      "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ="
+    },
+    "progress": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
+      "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA=="
+    },
+    "readline-sync": {
+      "version": "1.4.9",
+      "resolved": "https://registry.npmjs.org/readline-sync/-/readline-sync-1.4.9.tgz",
+      "integrity": "sha1-PtqOZfI80qF+YTAbHwADOWr17No="
+    },
+    "restore-cursor": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz",
+      "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=",
+      "requires": {
+        "onetime": "2.0.1",
+        "signal-exit": "3.0.2"
+      }
+    },
+    "run-async": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz",
+      "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=",
+      "requires": {
+        "is-promise": "2.1.0"
+      }
+    },
+    "rxjs": {
+      "version": "6.4.0",
+      "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.4.0.tgz",
+      "integrity": "sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw==",
+      "requires": {
+        "tslib": "1.9.3"
+      }
+    },
+    "safer-buffer": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+      "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+    },
+    "signal-exit": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
+      "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0="
+    },
+    "supports-color": {
+      "version": "5.5.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+      "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+      "requires": {
+        "has-flag": "3.0.0"
+      }
+    },
+    "through": {
+      "version": "2.3.8",
+      "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
+      "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU="
+    },
+    "tmp": {
+      "version": "0.0.33",
+      "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
+      "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
+      "requires": {
+        "os-tmpdir": "1.0.2"
+      }
+    },
+    "tslib": {
+      "version": "1.9.3",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz",
+      "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ=="
+    },
+    "universalify": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
+      "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="
+    }
+  }
+}

+ 27 - 0
package.json

@@ -0,0 +1,27 @@
+{
+  "name": "imageminify",
+  "version": "1.0.0",
+  "description": "Minify single/multi image(s),with path/list/folder path param",
+  "bin": {
+    "ImageMinify": "ImageMinify.js"
+  },
+  "preferGlobal": true,
+  "scripts": {
+    "test": "echo \"Error: no test specified\" && exit 1"
+  },
+  "keywords": [
+    "image",
+    "minify",
+    "image",
+    "minify"
+  ],
+  "author": "HonorLee <dev@honorlee.me>",
+  "license": "MIT",
+  "dependencies": {
+    "commander": "^2.19.0",
+    "fs-extra": "^7.0.1",
+    "inquirer": "^6.2.2",
+    "progress": "^2.0.3",
+    "readline-sync": "^1.4.9"
+  }
+}