├── .gitignore
├── LICENSE
├── README.md
├── bin
├── command.js
├── compress.js
└── index.js
├── index.js
├── lib
├── express
│ ├── favicon.ico
│ ├── index.js
│ ├── upload
│ │ └── index.js
│ └── views
│ │ ├── index.html
│ │ └── static
│ │ ├── index.css
│ │ ├── index.js
│ │ ├── jquery
│ │ └── jquery-3.1.1.js
│ │ ├── jszip
│ │ ├── .codeclimate.yml
│ │ ├── .editorconfig
│ │ ├── .gitignore
│ │ ├── .jshintignore
│ │ ├── .jshintrc
│ │ ├── .npmignore
│ │ ├── .travis.yml
│ │ ├── CHANGES.md
│ │ ├── Gruntfile.js
│ │ ├── LICENSE.markdown
│ │ ├── README.markdown
│ │ ├── _config.yml
│ │ ├── bower.json
│ │ ├── component.json
│ │ ├── dist
│ │ │ ├── jszip.js
│ │ │ └── jszip.min.js
│ │ ├── docs
│ │ │ ├── APPNOTE.TXT
│ │ │ ├── ZIP spec.txt
│ │ │ └── references.txt
│ │ ├── documentation
│ │ │ ├── _layouts
│ │ │ │ └── default.html
│ │ │ ├── api_jszip.md
│ │ │ ├── api_jszip
│ │ │ │ ├── constructor.md
│ │ │ │ ├── external.md
│ │ │ │ ├── file_data.md
│ │ │ │ ├── file_name.md
│ │ │ │ ├── file_regex.md
│ │ │ │ ├── filter.md
│ │ │ │ ├── folder_data.md
│ │ │ │ ├── folder_regex.md
│ │ │ │ ├── for_each.md
│ │ │ │ ├── generate_async.md
│ │ │ │ ├── generate_internal_stream.md
│ │ │ │ ├── generate_node_stream.md
│ │ │ │ ├── load_async.md
│ │ │ │ ├── load_async_object.md
│ │ │ │ ├── remove.md
│ │ │ │ ├── support.md
│ │ │ │ └── version.md
│ │ │ ├── api_streamhelper.md
│ │ │ ├── api_streamhelper
│ │ │ │ ├── accumulate.md
│ │ │ │ ├── on.md
│ │ │ │ ├── pause.md
│ │ │ │ └── resume.md
│ │ │ ├── api_zipobject.md
│ │ │ ├── api_zipobject
│ │ │ │ ├── async.md
│ │ │ │ ├── internal_stream.md
│ │ │ │ └── node_stream.md
│ │ │ ├── contributing.md
│ │ │ ├── css
│ │ │ │ ├── main.css
│ │ │ │ └── pygments.css
│ │ │ ├── examples.md
│ │ │ ├── examples
│ │ │ │ ├── download-zip-file.html
│ │ │ │ ├── downloader.html
│ │ │ │ ├── downloader.js
│ │ │ │ ├── get-binary-files-ajax.html
│ │ │ │ └── read-local-file-api.html
│ │ │ ├── faq.md
│ │ │ ├── howto
│ │ │ │ ├── read_zip.md
│ │ │ │ └── write_zip.md
│ │ │ ├── limitations.md
│ │ │ └── upgrade_guide.md
│ │ ├── index.html
│ │ ├── lib
│ │ │ ├── base64.js
│ │ │ ├── compressedObject.js
│ │ │ ├── compressions.js
│ │ │ ├── crc32.js
│ │ │ ├── defaults.js
│ │ │ ├── external.js
│ │ │ ├── flate.js
│ │ │ ├── generate
│ │ │ │ ├── ZipFileWorker.js
│ │ │ │ └── index.js
│ │ │ ├── index.js
│ │ │ ├── license_header.js
│ │ │ ├── load.js
│ │ │ ├── nodejs
│ │ │ │ ├── NodejsStreamInputAdapter.js
│ │ │ │ └── NodejsStreamOutputAdapter.js
│ │ │ ├── nodejsUtils.js
│ │ │ ├── object.js
│ │ │ ├── readable-stream-browser.js
│ │ │ ├── reader
│ │ │ │ ├── ArrayReader.js
│ │ │ │ ├── DataReader.js
│ │ │ │ ├── NodeBufferReader.js
│ │ │ │ ├── StringReader.js
│ │ │ │ ├── Uint8ArrayReader.js
│ │ │ │ └── readerFor.js
│ │ │ ├── signature.js
│ │ │ ├── stream
│ │ │ │ ├── ConvertWorker.js
│ │ │ │ ├── Crc32Probe.js
│ │ │ │ ├── DataLengthProbe.js
│ │ │ │ ├── DataWorker.js
│ │ │ │ ├── GenericWorker.js
│ │ │ │ └── StreamHelper.js
│ │ │ ├── support.js
│ │ │ ├── utf8.js
│ │ │ ├── utils.js
│ │ │ ├── zipEntries.js
│ │ │ ├── zipEntry.js
│ │ │ └── zipObject.js
│ │ ├── package.json
│ │ └── vendor
│ │ │ └── FileSaver.js
│ │ ├── layui
│ │ ├── css
│ │ │ ├── layui.css
│ │ │ ├── layui.mobile.css
│ │ │ └── modules
│ │ │ │ ├── code.css
│ │ │ │ ├── laydate
│ │ │ │ ├── icon.png
│ │ │ │ └── laydate.css
│ │ │ │ └── layer
│ │ │ │ └── default
│ │ │ │ ├── icon-ext.png
│ │ │ │ ├── icon.png
│ │ │ │ ├── layer.css
│ │ │ │ ├── loading-0.gif
│ │ │ │ ├── loading-1.gif
│ │ │ │ └── loading-2.gif
│ │ ├── font
│ │ │ ├── iconfont.eot
│ │ │ ├── iconfont.svg
│ │ │ ├── iconfont.ttf
│ │ │ └── iconfont.woff
│ │ ├── images
│ │ │ └── face
│ │ │ │ ├── 0.gif
│ │ │ │ ├── 1.gif
│ │ │ │ ├── 10.gif
│ │ │ │ ├── 11.gif
│ │ │ │ ├── 12.gif
│ │ │ │ ├── 13.gif
│ │ │ │ ├── 14.gif
│ │ │ │ ├── 15.gif
│ │ │ │ ├── 16.gif
│ │ │ │ ├── 17.gif
│ │ │ │ ├── 18.gif
│ │ │ │ ├── 19.gif
│ │ │ │ ├── 2.gif
│ │ │ │ ├── 20.gif
│ │ │ │ ├── 21.gif
│ │ │ │ ├── 22.gif
│ │ │ │ ├── 23.gif
│ │ │ │ ├── 24.gif
│ │ │ │ ├── 25.gif
│ │ │ │ ├── 26.gif
│ │ │ │ ├── 27.gif
│ │ │ │ ├── 28.gif
│ │ │ │ ├── 29.gif
│ │ │ │ ├── 3.gif
│ │ │ │ ├── 30.gif
│ │ │ │ ├── 31.gif
│ │ │ │ ├── 32.gif
│ │ │ │ ├── 33.gif
│ │ │ │ ├── 34.gif
│ │ │ │ ├── 35.gif
│ │ │ │ ├── 36.gif
│ │ │ │ ├── 37.gif
│ │ │ │ ├── 38.gif
│ │ │ │ ├── 39.gif
│ │ │ │ ├── 4.gif
│ │ │ │ ├── 40.gif
│ │ │ │ ├── 41.gif
│ │ │ │ ├── 42.gif
│ │ │ │ ├── 43.gif
│ │ │ │ ├── 44.gif
│ │ │ │ ├── 45.gif
│ │ │ │ ├── 46.gif
│ │ │ │ ├── 47.gif
│ │ │ │ ├── 48.gif
│ │ │ │ ├── 49.gif
│ │ │ │ ├── 5.gif
│ │ │ │ ├── 50.gif
│ │ │ │ ├── 51.gif
│ │ │ │ ├── 52.gif
│ │ │ │ ├── 53.gif
│ │ │ │ ├── 54.gif
│ │ │ │ ├── 55.gif
│ │ │ │ ├── 56.gif
│ │ │ │ ├── 57.gif
│ │ │ │ ├── 58.gif
│ │ │ │ ├── 59.gif
│ │ │ │ ├── 6.gif
│ │ │ │ ├── 60.gif
│ │ │ │ ├── 61.gif
│ │ │ │ ├── 62.gif
│ │ │ │ ├── 63.gif
│ │ │ │ ├── 64.gif
│ │ │ │ ├── 65.gif
│ │ │ │ ├── 66.gif
│ │ │ │ ├── 67.gif
│ │ │ │ ├── 68.gif
│ │ │ │ ├── 69.gif
│ │ │ │ ├── 7.gif
│ │ │ │ ├── 70.gif
│ │ │ │ ├── 71.gif
│ │ │ │ ├── 8.gif
│ │ │ │ └── 9.gif
│ │ ├── lay
│ │ │ ├── all-mobile.js
│ │ │ ├── all.js
│ │ │ └── modules
│ │ │ │ ├── code.js
│ │ │ │ ├── element.js
│ │ │ │ ├── flow.js
│ │ │ │ ├── form.js
│ │ │ │ ├── jquery.js
│ │ │ │ ├── laydate.js
│ │ │ │ ├── layedit.js
│ │ │ │ ├── layer.js
│ │ │ │ ├── laypage.js
│ │ │ │ ├── laytpl.js
│ │ │ │ ├── mobile.js
│ │ │ │ ├── mobile
│ │ │ │ ├── layer-mobile.js
│ │ │ │ ├── layim-mobile-open.js
│ │ │ │ ├── upload-mobile.js
│ │ │ │ └── zepto.js
│ │ │ │ ├── tree.js
│ │ │ │ ├── upload.js
│ │ │ │ └── util.js
│ │ └── layui.js
│ │ ├── vue
│ │ ├── vue.js
│ │ ├── vue.min.js
│ │ └── vue.router.js
│ │ └── webuploader
│ │ ├── Uploader.swf
│ │ └── webuploader.min.js
├── imagemin
│ └── index.js
├── index.js
├── log
│ └── index.js
└── runServer.js
├── package.json
└── readmeFile
├── 0.0.1_test.gif
├── 0.0.2_test.gif
├── 0.0.4_test.gif
├── 0.0.5.test.gif
├── 1.0.0-cli-test.png
└── 2017-05-08-i1.png
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .vscode
3 | test
4 | temp
5 | compass
6 | package-lock.json
7 | yarn.lock
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 zoeDylan
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # z_img
2 |
3 | 图片压缩工具【持续更新中】
4 |
5 | # 重要更新
6 |
7 | [2017-11-28](#2017-11-28)
8 |
9 | ### 命令行
10 |
11 | 1. `npm i -g zimg`
12 |
13 | 2. 定位文件夹,然后执行:`zimg`
14 |
15 | > `zimg` 压缩当前文件夹所有图片
16 |
17 | > `zimg *.png *.jpg` 压缩指定图片
18 |
19 | ### 作为压缩网站:
20 |
21 | 1. `npm i -g zimg`
22 |
23 | 2. `zimg -r`或者`zimg -r 3000`
24 |
25 | > 自动打开浏览器窗口
26 |
27 | ### 作为项目调用
28 |
29 | 1. `npm i zimg --save`
30 |
31 | 2. `const zimg = require('zimg');`
32 |
33 | 3. `zimg(输入文件(arr或者string),输出文件夹路径);`
34 |
35 | # 功能说明
36 |
37 | 1. `cli`命令
38 |
39 | 
40 |
41 | 2. 网页压缩图片
42 |
43 | 
44 |
45 |
46 | # 流程说明
47 |
48 | * 图片压缩说明:
49 |
50 | 1. 用户每次打开新的页面都会生成一个`session`
51 |
52 | 2. 用户上传第一张图片时,生成`session`对应的文件夹,文件夹位于 `lib/express/compass`
53 |
54 | 3. 同时生成2个文件夹`lib/express/compass/{{文件名}}`(存放源文件)和`lib/express/compass/{{文件名}}/compass`(存放压缩文件)
55 |
56 | 4. 压缩后会返回图片的`base64`字符串,并添加了`data:image/**;base64,`数据头:`lib/express/upload.js => (v.data = 'data:' + contentType + ';base64,' + v.data;)`
57 |
58 | 5. 数据返回用户后,`lib/express/static/index.js => _zip.add(res.name, res.data);`添加压缩文件
59 |
60 | *提示:由于jszip压缩的base64字符串不需要文件头,所以去掉文件头信息 `lib/express/static/index.js => data.replace(/data.+base64,/, '')`*
61 |
62 | # `lib/imagemin`
63 |
64 | 图片压缩核心
65 | 仅对[imagemin](https://www.npmjs.com/package/imagemin)包进行了再次包装。
66 |
67 | **依赖包**
68 |
69 | >> [imagemin](https://www.npmjs.com/package/imagemin)
70 |
71 | **使用方式**
72 |
73 | `cosnt imagemin = require('./lib/imagemin');`
74 |
75 | **API**
76 |
77 | 文件路径问题详情查看:[imagemin](https://www.npmjs.com/package/imagemin)
78 |
79 | ```
80 | cosnt imagemin = require('./lib/imagemin');
81 |
82 | //imagemin.compass(input,output);
83 |
84 | // input: 文件目录或者文件地址, './image/*.{jpg,png}' || './image/1.jpg' || ['./image/*.{jpg,png}','./image/1.jpg']
85 |
86 | // output: 文件输出目录 './image/compass' 默认:'imagemin/temp'
87 |
88 | imagemin.compass('./image/*.{jpg,png}','./image/compass')
89 | .then(v =>{
90 | if(v.status){
91 | console.log(v.data); //[{ data: buffer数据, path:图片路径 }] 路径为output所填路径加图片名称 './image/compass/1.jpg'
92 | }else{
93 | console.log(v.error); //错误消息
94 | }
95 | });
96 |
97 | ```
98 |
99 | # 日志(时间倒叙)
100 |
101 | 2019-03-31
102 |
103 | 1. 添加命令行队列处理,解决卡死问题
104 |
105 | 2. 优化命令处理逻辑
106 |
107 | 2018-04-11
108 |
109 | 1. 修改协议为`MIT`
110 |
111 | ### 2017-11-28
112 |
113 | 1. 取消定位到文件夹进行网页压缩功能
114 |
115 | 2. 增加命令行启动网页压缩功能
116 |
117 | 3. 增加外部项目调用压缩功能
118 |
119 | 2017-09-19
120 |
121 | 1. 添加`cli`命令处理
122 |
123 | 2017-09-15
124 |
125 | 1. 新增`GIF`压缩
126 |
127 | 2017-09-14
128 |
129 | 1. 清除多余包
130 |
131 | 2. 取消`co`库,改为`async await`
132 |
133 | 2017-09-07
134 |
135 | 1. 添加上传成功、失败提示
136 |
137 | 2. 优化上传失败展示文案
138 |
139 | 3. 修复图片上传报错问题
140 |
141 | #### 2017-05-08
142 |
143 | 1. 添加数据展示信息
144 |
145 | **
146 |
147 | 2. 优化用户文件夹创建时间,之前是在用户访问页面时创建文件夹,现在修改为用户上传第一张图片的时候创建,避免用户一直刷新。
148 |
149 | 3. 用户已打开页面,但是服务器重启过,导致用户`session`失效,bug修复。
150 |
151 | 4. 添加图片预览,添加图片后点击列表中的图片可以在独立标签打开页面预览图片。
152 |
153 | 5. 图片限制`30M`,并发修改为`1`
--------------------------------------------------------------------------------
/bin/command.js:
--------------------------------------------------------------------------------
1 | const
2 | runCommand = (() => {
3 | function version() {
4 | console.log('\nversion', require('../package.json').version, '\n');
5 | }
6 |
7 | function help() {
8 |
9 | console.log(`
10 | command:
11 | -c ---compress file
12 | default = '-c' , You don't need this parameter '-c'
13 | 'zimg': Compress the current folder img files
14 | 'zimg [img file]': Compress the img file
15 | 'zimg [file] [file]': Compress the two files
16 | 'zimg [file] [file] ...': Compress more specified files
17 | -v ---show version
18 | -h ---show help
19 | -r ---run server
20 | 'zimg -r': run server at port : 3000
21 | 'zimg -r [port]' run server at port : set port
22 | `);
23 |
24 | }
25 |
26 | function run(port) {
27 | require('../lib/runServer')(port);
28 | }
29 | return {
30 | 'v': version,
31 | 'h': help,
32 | 'r': run
33 | }
34 |
35 | })();
36 |
37 |
38 |
39 | //如果是命令处理就运行命令
40 | function isCommand(arr) {
41 | let
42 | com = arr.toString().split('-');
43 | com[0].length === 0 && com.shift();
44 | com = com[0];
45 | if (/^v/.test(com)) {
46 | runCommand.v();
47 | } else if (/^h|^\?/.test(com)) {
48 | runCommand.h();
49 | } else if (/^r/.test(com)) {
50 | runCommand.r(com.split(',')[1] || 3000);
51 | } else if (/^c/.test(com)) {
52 | return com.replace('c,', '').replace(/^c/, '');
53 | } else {
54 | return com.split(',');
55 | }
56 | }
57 |
58 |
59 |
60 | module.exports = {
61 | isCommand: isCommand
62 | };
--------------------------------------------------------------------------------
/bin/compress.js:
--------------------------------------------------------------------------------
1 | const
2 | fs = require('fs'),
3 | glob = require('glob'),
4 | dir = process.cwd(),
5 | imagemin = require('../lib/imagemin');
6 |
7 |
8 | const queueList = [];
9 | let maxQueueRun = 3;
10 | let nowQueueRun = 0;
11 |
12 | function runQueue(fn) {
13 | fn && queueList.push(fn);
14 | if (nowQueueRun < maxQueueRun && queueList.length > 0) {
15 | nowQueueRun += 1;
16 | queueList[0]().then(() => {
17 | nowQueueRun -= 1;
18 | runQueue();
19 | });
20 | queueList.shift();
21 | runQueue();
22 | }
23 | }
24 |
25 |
26 |
27 | module.exports = (files) => {
28 | files = files || glob.sync(dir + '/*.?(jpg|png|jpeg|gif)');
29 | function cInfo() {
30 | let
31 | numRatio = (files.length - succNum - errNum) / files.length,
32 | txt = `
33 | ┏┓
34 | ┃
35 | ┣ ${getChar('■', 20 - Math.floor(numRatio * 20))}${getChar('□', Math.floor(numRatio * 20))}(${(100 - numRatio * 100).toFixed(2)}%)'
36 | ┃
37 | ┣ 完成:${succNum + errNum}
38 | ┃
39 | ┣ 剩余:${files.length - (succNum + errNum)}
40 | ┃
41 | ┣ 错误:${errNum}
42 | ┃
43 | ┣ 共计:${files.length}
44 | ┃
45 | ┣ 总大小:${(allSourceSize / 1024).toFixed(2)}KB
46 | ┃
47 | ┣ 压缩后大小:${(allSize / 1024).toFixed(2)}KB
48 | ┃
49 | ┣ 压缩率:${((allSourceSize - allSize) / allSourceSize * 100).toFixed(3)}%
50 | ┃
51 | ┗┛`;
52 | console.clear();
53 | console.log(txt);
54 | }
55 |
56 | function getChar(txt, num) {
57 | let val = '';
58 | for (let i = 0; i < num; i++) {
59 | val += txt;
60 | }
61 | return val;
62 | }
63 | let
64 | //完成数量
65 | succNum = 0,
66 | //出错数量
67 | errNum = 0,
68 | //总大小
69 | allSourceSize = 0,
70 | //总处理后大小
71 | allSize = 0;
72 |
73 | files.forEach(path => {
74 | runQueue(() => {
75 | return imagemin.compass(path, dir + '/zimg')
76 | .then(d => {
77 | const
78 | source = fs.statSync(path);
79 | succNum++;
80 | allSourceSize += source.size;
81 | allSize += d.data[0].data.length;
82 | cInfo();
83 | })
84 | .catch(() => {
85 | errNum++;
86 | cInfo();
87 | }).then(() => {
88 | return true;
89 | })
90 | });
91 | });
92 | }
--------------------------------------------------------------------------------
/bin/index.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | process.title = 'zimg'
4 |
5 | const
6 | com = require('./command'),
7 | cmp = require('./compress');
8 |
9 | let argv = process.argv;
10 |
11 | //删除前两个用不到的变量
12 | argv.splice(0, 2);
13 | if (argv.length <= 0) {
14 | cmp();
15 | } else {
16 | let files = com.isCommand(argv);
17 | if (files) {
18 | cmp(files);
19 | } else if (files === '') {
20 | cmp();
21 | }
22 | }
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | module.exports = require('./lib');
--------------------------------------------------------------------------------
/lib/express/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ulidev9527/z_img/849441fe6486b551591d1e3d14e0dde9115455be/lib/express/favicon.ico
--------------------------------------------------------------------------------
/lib/express/index.js:
--------------------------------------------------------------------------------
1 | const
2 | express = require('express'),
3 | app = express(),
4 | session = require('express-session'),
5 | md5 = require('md5'),
6 | fs = require('fs');
7 |
8 | //compass文件夹检查
9 | if (!fs.existsSync(__dirname + '/compass')) {
10 | fs.mkdirSync(__dirname + '/compass');
11 | }
12 |
13 | app.use(session({
14 | resave: false,
15 | saveUninitialized: true,
16 | secret: 'z-img',
17 | cookie: {
18 | maxAge: 1000 * 60 * 60 * 2
19 | }
20 | }))
21 |
22 | app.use("/static", express.static(__dirname + "/views/static"));
23 |
24 | app.get('/', (req, res) => {
25 | //添加文件夹名称-每次打开页面生成一个新的文件夹
26 | req.session.dir = md5(new Date().getTime());
27 |
28 | res.sendFile(__dirname + "/views/index.html");
29 | });
30 |
31 | app.all('/favicon.ico', function(req, res) {
32 | res.sendFile(__dirname + '/favicon.ico');
33 | });
34 |
35 | app.use('/upload', require('./upload'));
36 |
37 | module.exports = app;
--------------------------------------------------------------------------------
/lib/express/upload/index.js:
--------------------------------------------------------------------------------
1 | const
2 | express = require('express'),
3 | app = express(),
4 | multiparty = require('multiparty'),
5 | imagemin = require('../../imagemin'),
6 | fs = require('fs'),
7 | path = require('path'),
8 | log = require('../../log');
9 |
10 | /**
11 | * 文件上传
12 | * @return {
13 | * status: true|false
14 | * [false => error: string]
15 | * [true => data: Object]
16 | * message: string
17 | * }
18 | */
19 | app.post('/', (req, res) => {
20 | if (req.session.dir) {
21 |
22 | let
23 | //当前用户文件夹
24 | fileDir = path.join(__dirname, '..', 'compass', req.session.dir),
25 | form = new multiparty.Form({ uploadDir: fileDir });
26 |
27 | //创建文件夹
28 | if (!fs.existsSync(fileDir)) {
29 | fs.mkdirSync(fileDir);
30 | fs.mkdirSync(fileDir + '/compass');
31 | }
32 |
33 | form.parse(req, (err, fields, files) => {
34 | if (err) {
35 | res.send({
36 | status: false,
37 | error: err.toString(),
38 | message: '文件上传失败!'
39 | });
40 | } else {
41 | //文件信息处理
42 | let
43 | //上传的文件
44 | inputFile = files.file[0],
45 | //上传文件的路径
46 | uploadedPath = inputFile.path,
47 | //压缩文件夹路径
48 | compassDir = fileDir + '/compass',
49 | //重命名文件 originalFilename为文件名称
50 | newPath = fileDir + '/' + inputFile.originalFilename,
51 | //文件头:image/***
52 | contentType = inputFile.headers['content-type'],
53 | //重命名
54 | newFile = rename(uploadedPath, newPath);
55 |
56 | //判断重命名状态
57 | if (newFile.status) {
58 | //压缩
59 | compass(newPath, compassDir)
60 | .then(v => {
61 | v.name = inputFile.originalFilename;
62 | //添加文件头
63 | v.data = 'data:' + contentType + ';base64,' + v.data;
64 | res.send(v);
65 | })
66 | .catch(e => {
67 | console.log(e);
68 | res.send({
69 | status: false,
70 | error: e.toString(),
71 | message: '压缩接口断开'
72 | });
73 | });
74 | } else {
75 | res.send(newFile);
76 | }
77 | }
78 | });
79 | } else {
80 | res.send({
81 | status: false,
82 | error: 'server 500 error',
83 | message: '服务器主动取消,请刷新页面重试。'
84 | });
85 | }
86 | });
87 |
88 |
89 | /**
90 | * 压缩
91 | * @param {*string||array} input 文件路径
92 | * @param {*string} output 压缩后文件路径
93 | * @return {
94 | * status: true|false
95 | * (true => size: number)文件压缩后的大小
96 | * (true => data: 文件的base64字符串,未添加文件信息头)
97 | * (false => (imagemin.compass)) lib/imagemin包里面的返回
98 | * }
99 | */
100 | async function compass(input, output) {
101 | return await imagemin.compass(input, output)
102 | .then(v => {
103 | if (v.status) {
104 | //这里面每次压缩都是一个文件 所以直接 v.data[0]
105 | let file = v.data[0];
106 |
107 | return {
108 | status: true,
109 | size: file.data.length,
110 | data: file.data.toString('base64')
111 | }
112 | } else {
113 | return {
114 | status: false,
115 | message: '文件压缩出错,日志:' + log(v.error)
116 | };
117 | }
118 | })
119 | }
120 |
121 | /**
122 | * 文件重命名
123 | * @param {string} oldPath 旧目录
124 | * @param {string} newPath 新目录
125 | *
126 | * @return {
127 | * status: true|false,
128 | * [false => error: string]
129 | * [true => data: (newPath)]
130 | * message: string
131 | * }
132 | */
133 | function rename(oldPath, newPath) {
134 | let file = fs.renameSync(oldPath, newPath);
135 | return file ? {
136 | status: false,
137 | error: file.toString(),
138 | message: '文件重命名失败'
139 | } : {
140 | status: true,
141 | data: newPath,
142 | message: '文件重命名成功'
143 | };
144 | }
145 |
146 |
147 |
148 | module.exports = app;
--------------------------------------------------------------------------------
/lib/express/views/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | z-img
17 |
18 |
19 |
20 |
21 |
22 |
23 |
30 |
31 | 已添加【{{add}}】
32 | 上传中【{{upload}}】
33 | 完成【{{success}}】
34 | 失败【{{error}}】
35 | 处理结束【{{end}}】
36 |
37 |
38 |
78 |
79 |
80 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
--------------------------------------------------------------------------------
/lib/express/views/static/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | padding: 60px 10px;
3 | padding-top: 120px;
4 | }
5 |
6 | #__uploader {
7 | position: fixed;
8 | width: 100%;
9 | left: 0;
10 | top: 0;
11 | padding: 10px 10px 20px;
12 | background: #fff;
13 | z-index: 1;
14 | }
15 |
16 | #__uploader fieldset {
17 | width: 97%;
18 | }
19 | #__uploader legend i{
20 | font-size: 30px;
21 | line-height: 30px;
22 | vertical-align: middle;
23 | }
24 |
25 | #__uploader div {
26 | position: relative;
27 | }
28 |
29 | #__uploader div.pick {
30 | position: absolute;
31 | left: 0;
32 | top: 0;
33 | width: 100%;
34 | height: 100%;
35 | opacity: 0;
36 | }
37 |
38 | #__uploader div.pick div {
39 | height: 100%;
40 | }
41 |
42 | #__uploader p.msg {
43 | position: absolute;
44 | bottom: 10px;
45 | left: 10px;
46 | width: 95%;
47 | text-align: right;
48 | }
49 |
50 | #__imgList tbody img {
51 | width: 40px;
52 | height: auto;
53 | transition: all .3s;
54 | }
55 |
56 | #__imgList tbody .img {
57 | height: 40px;
58 | overflow: hidden;
59 | }
60 |
61 | #__imgList tbody tr.success td{
62 | background-color: #dff0d8;
63 | }
64 | #__imgList tbody tr.danger td{
65 | background-color: #f2dede;
66 | }
67 |
68 | #__btnGroup {
69 | position: fixed;
70 | z-index: 1;
71 | width: 100%;
72 | height: 40px;
73 | background: #2F4056;
74 | left: 0;
75 | bottom: 0;
76 | text-align: right;
77 | color: #fff;
78 | }
--------------------------------------------------------------------------------
/lib/express/views/static/jszip/.codeclimate.yml:
--------------------------------------------------------------------------------
1 | ---
2 | engines:
3 | duplication:
4 | enabled: true
5 | config:
6 | languages:
7 | - javascript
8 | eslint:
9 | enabled: true
10 | fixme:
11 | enabled: true
12 | ratings:
13 | paths:
14 | - "lib/*.js"
15 | exclude_paths:
16 | - "dist/*"
17 |
--------------------------------------------------------------------------------
/lib/express/views/static/jszip/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | end_of_line = lf
5 | insert_final_newline = true
6 | charset = utf-8
7 | indent_style = space
8 | indent_size = 4
9 |
--------------------------------------------------------------------------------
/lib/express/views/static/jszip/.gitignore:
--------------------------------------------------------------------------------
1 | *~
2 | node_modules
3 | sauce_connect.log
4 | .c9revisions
--------------------------------------------------------------------------------
/lib/express/views/static/jszip/.jshintignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/lib/express/views/static/jszip/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "curly": true,
3 | "eqeqeq": true,
4 | "nonew": true,
5 | "noarg": true,
6 | "forin": true,
7 | "futurehostile": true,
8 | "freeze": true,
9 | "undef": true,
10 | "strict": true,
11 | "sub": true,
12 | "esversion": 3,
13 |
14 | "globals": {
15 | "TextEncoder": false,
16 | "TextDecoder": false
17 | },
18 | "browser": true,
19 | "node": true
20 | }
21 |
--------------------------------------------------------------------------------
/lib/express/views/static/jszip/.npmignore:
--------------------------------------------------------------------------------
1 | _config.yml
2 | bower.json
3 | component.json
4 | docs
5 | documentation
6 | Gruntfile.js
7 | index.html
8 | test
9 |
--------------------------------------------------------------------------------
/lib/express/views/static/jszip/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | sudo: false
3 | matrix:
4 | include:
5 | - node_js: "stable"
6 | env: COMMAND=lint
7 | - node_js: "0.10"
8 | env: COMMAND=test-node
9 | - node_js: "0.12"
10 | env: COMMAND=test-node
11 | - node_js: "4.4"
12 | env: COMMAND=test-node
13 | - node_js: "stable"
14 | env: COMMAND=test-node
15 | - node_js: "stable"
16 | env: COMMAND=test-browser
17 | env:
18 | global:
19 | - secure: MhA8GHU42X3GWTUMaqdZVvarx4BMjhQCUGNi3kvuD/iCmKVb7gMwj4jbds7AcJdsCRsRk8bBGzZs/E7HidBJMPDa5DhgLKy9EV1s42JlHq8lVzbJeWIGgrtyJvhVUkGRy2OJjnDSgh3U6elkQmvDn74jreSQc6m/yGoPFF1nqq8=
20 | - secure: qREw6aUu2DnB+2reMuHgygSkumRiJvt7Z5Fz4uEVoraqbe65e4PGhtzypr9uIgCN43vxS2D5tAIeDbfid5VQrWFUQnrC9O5Z5qgVPsKN94zZ1tvYurXI4wRlAg58nNjkfGXWhLI3VUjjDTp5gYcMqgfe5hpEFYUPnUQkKGnaqAk=
21 | script: npm run $COMMAND
22 |
--------------------------------------------------------------------------------
/lib/express/views/static/jszip/README.markdown:
--------------------------------------------------------------------------------
1 | JSZip [](http://travis-ci.org/Stuk/jszip) [](https://codeclimate.com/github/Stuk/jszip)
2 | =====
3 |
4 | [](https://saucelabs.com/u/jszip)
5 |
6 | A library for creating, reading and editing .zip files with Javascript, with a
7 | lovely and simple API.
8 |
9 | See https://stuk.github.io/jszip for all the documentation.
10 |
11 | ```javascript
12 | var zip = new JSZip();
13 |
14 | zip.file("Hello.txt", "Hello World\n");
15 |
16 | var img = zip.folder("images");
17 | img.file("smile.gif", imgData, {base64: true});
18 |
19 | zip.generateAsync({type:"blob"}).then(function(content) {
20 | // see FileSaver.js
21 | saveAs(content, "example.zip");
22 | });
23 |
24 | /*
25 | Results in a zip containing
26 | Hello.txt
27 | images/
28 | smile.gif
29 | */
30 | ```
31 | License
32 | -------
33 |
34 | JSZip is dual-licensed. You may use it under the MIT license *or* the GPLv3
35 | license. See [LICENSE.markdown](LICENSE.markdown).
36 |
--------------------------------------------------------------------------------
/lib/express/views/static/jszip/_config.yml:
--------------------------------------------------------------------------------
1 | # will be overwritten by github, see https://help.github.com/articles/using-jekyll-with-pages
2 | lsi: false
3 | safe: true
4 | source: ./
5 | incremental: false
6 | highlighter: rouge
7 | gist:
8 | noscript: false
9 | # /overwritten
10 |
11 | baseurl: /jszip
12 |
13 | layouts_dir: ./documentation/_layouts
14 | permalink: none
15 | exclude: ['bin', 'README.md', 'node_modules']
16 |
17 |
18 | kramdown:
19 | input: GFM
20 | hard_wrap: false
21 | gems:
22 | - jekyll-coffeescript
23 | - jekyll-paginate
24 |
25 |
--------------------------------------------------------------------------------
/lib/express/views/static/jszip/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "jszip",
3 | "homepage": "http://stuartk.com/jszip",
4 | "authors": [
5 | "Stuart Knightley "
6 | ],
7 | "description": "Create, read and edit .zip files with Javascript http://stuartk.com/jszip",
8 | "main": "dist/jszip.js",
9 | "keywords": [
10 | "zip",
11 | "deflate",
12 | "inflate"
13 | ],
14 | "license": "MIT or GPLv3",
15 | "ignore": [
16 | "**/.*",
17 | "node_modules",
18 | "bower_components",
19 | "test",
20 | "tests"
21 | ]
22 | }
23 |
--------------------------------------------------------------------------------
/lib/express/views/static/jszip/component.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "jszip",
3 | "repo": "Stuk/jszip",
4 | "description": "Create, read and edit .zip files with Javascript http://stuartk.com/jszip",
5 | "version": "3.1.3",
6 | "keywords": [
7 | "zip",
8 | "deflate",
9 | "inflate"
10 | ],
11 | "main": "dist/jszip.js",
12 | "license": "MIT or GPLv3",
13 | "scripts": [
14 | "dist/jszip.js"
15 | ]
16 | }
17 |
--------------------------------------------------------------------------------
/lib/express/views/static/jszip/docs/ZIP spec.txt:
--------------------------------------------------------------------------------
1 | Here are the notes I made while working through the ZIP file specification.
2 |
3 | For each file:
4 |
5 | local file header signature 4 bytes (0x04034b50)
6 | version needed to extract 2 bytes
7 | general purpose bit flag 2 bytes
8 | compression method 2 bytes
9 | last mod file time 2 bytes
10 | last mod file date 2 bytes
11 | crc-32 4 bytes
12 | compressed size 4 bytes
13 | uncompressed size 4 bytes
14 | file name length 2 bytes
15 | extra field length 2 bytes
16 |
17 | |sig |v |g |c |t |d |crc |csz |usz |n |x |
18 | PK.. ## 00 00 ?? ?? xxxx ???? ???? ?? 00
19 |
20 |
21 | Central directory:
22 |
23 | central file header signature 4 bytes (0x02014b50)
24 | version made by 2 bytes
25 | version needed to extract 2 bytes *
26 | general purpose bit flag 2 bytes *
27 | compression method 2 bytes *
28 | last mod file time 2 bytes *
29 | last mod file date 2 bytes *
30 | crc-32 4 bytes *
31 | compressed size 4 bytes *
32 | uncompressed size 4 bytes *
33 | file name length 2 bytes *
34 | extra field length 2 bytes *
35 | file comment length 2 bytes
36 | disk number start 2 bytes
37 | internal file attributes 2 bytes
38 | external file attributes 4 bytes
39 | relative offset of local header 4 bytes
40 |
41 | file name (variable size)
42 | extra field (variable size)
43 | file comment (variable size)
44 |
45 | |sig |vm|vx|g |c |d |t |crc |csz |usz |n |x |cm|dn|ia|xa |roff|
46 | PK.. ## ## 00 00 ?? ?? xxxx ???? ???? ?? 00 00 00 00 xxxx ????
47 |
48 | End of central directory:
49 |
50 | end of central dir signature 4 bytes (0x06054b50)
51 | number of this disk 2 bytes
52 | number of the disk with the
53 | start of the central directory 2 bytes
54 | total number of entries in the
55 | central directory on this disk 2 bytes
56 | total number of entries in
57 | the central directory 2 bytes
58 | size of the central directory 4 bytes
59 | offset of start of central
60 | directory with respect to
61 | the starting disk number 4 bytes
62 | .ZIP file comment length 2 bytes
63 | .ZIP file comment (variable size)
64 |
65 | |sig |n1|n2|e |ne|size|off |cm|
66 | PK.. 00 00 ?? ?? ???? ???? 00
67 |
--------------------------------------------------------------------------------
/lib/express/views/static/jszip/docs/references.txt:
--------------------------------------------------------------------------------
1 | Zip format
2 | ----------
3 | http://www.pkware.com/support/zip-application-note
4 | http://www.xxcopy.com/xxcopy06.htm
5 |
6 | Data URL
7 | --------
8 | https://developer.mozilla.org/en/The_data_URL_scheme
9 | http://msdn.microsoft.com/en-us/library/cc848897(VS.85).aspx
10 | http://www.phpied.com/mhtml-when-you-need-data-uris-in-ie7-and-under/
11 |
12 | http://www.motobit.com/util/base64-decoder-encoder.asp
13 |
14 | Saving files
15 | ------------
16 | http://msdn.microsoft.com/en-us/library/ms536676(VS.85).aspx
17 | http://msdn.microsoft.com/en-us/library/ms536419(VS.85).aspx
18 | http://msdn.microsoft.com/en-us/library/ms537418(VS.85).aspx
19 |
--------------------------------------------------------------------------------
/lib/express/views/static/jszip/documentation/api_jszip.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "JSZip API"
3 | layout: default
4 | section: api
5 | ---
6 |
7 | An instance of JSZip represents a set of files. You can add them, remove them,
8 | modify them. You can also import an existing zip file or generate one.
9 |
10 | ### Attributes
11 |
12 | attribute name | type | description
13 | ---------------------|-------------|-------------
14 | `files` | object | the [ZipObject]({{site.baseurl}}/documentation/api_zipobject.html)s inside the zip with the name as key. See [file(name)]({{site.baseurl}}/documentation/api_jszip/file_name.html).
15 | `comment` | string | the comment of the zip file.
16 |
--------------------------------------------------------------------------------
/lib/express/views/static/jszip/documentation/api_jszip/constructor.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "new JSZip() or JSZip()"
3 | layout: default
4 | section: api
5 | ---
6 |
7 | __Description__ : Create a new JSZip instance.
8 |
9 | __Arguments__ : None
10 |
11 | __Returns__ : A new JSZip.
12 |
13 | __Throws__ : Nothing.
14 |
15 |
16 |
17 | __Example__
18 |
19 | ```js
20 | var zip = new JSZip();
21 | // same as
22 | var zip = JSZip();
23 | ```
24 |
--------------------------------------------------------------------------------
/lib/express/views/static/jszip/documentation/api_jszip/external.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "JSZip.external"
3 | layout: default
4 | section: api
5 | ---
6 |
7 | JSZip uses objects that may not exist on every platform, in which case it uses
8 | a shim.
9 | Accessing or replacing these objects can sometimes be useful. JSZip.external
10 | contains the following properties :
11 |
12 | * `Promise` : the [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) implementation used.
13 |
14 | The global object is prefered when available.
15 |
16 | __Example__
17 |
18 | ```js
19 | // use bluebird instead
20 | JSZip.external.Promise = Bluebird;
21 |
22 | // use the native Promise object:
23 | JSZip.external.Promise = Promise;
24 | ```
25 |
26 |
--------------------------------------------------------------------------------
/lib/express/views/static/jszip/documentation/api_jszip/file_data.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "file(name, data [,options])"
3 | layout: default
4 | section: api
5 | ---
6 |
7 | __Description__ : Add (or update) a file to the zip file.
8 |
9 | __Arguments__
10 |
11 | name | type | description
12 | --------------------|---------|------------
13 | name | string | the name of the file. You can specify folders in the name : the folder separator is a forward slash ("/").
14 | data | String/ArrayBuffer/Uint8Array/Buffer/Blob/Promise/Nodejs stream | the content of the file.
15 | options | object | the options.
16 |
17 | Content of `options` :
18 |
19 | name | type | default | description
20 | ------------|---------|---------|------------
21 | base64 | boolean | `false` | set to `true` if the data is base64 encoded. For example image data from a `