mirror of
https://github.com/svg/svgo.git
synced 2025-07-29 20:21:14 +03:00
This commit is contained in:
26
examples/fromFile.js
Normal file
26
examples/fromFile.js
Normal file
@ -0,0 +1,26 @@
|
||||
var SVGO = require('../lib/svgo'),
|
||||
svgo = new SVGO(/*{ custom config object }*/);
|
||||
|
||||
svgo
|
||||
// optimize SVG file
|
||||
.fromFile('../examples/test.svg')
|
||||
// get optimized result
|
||||
.then(function(min) {
|
||||
|
||||
console.log(min);
|
||||
// output:
|
||||
// {
|
||||
// // optimized SVG data string
|
||||
// data: '<svg width="10" height="20">test</svg>'
|
||||
// // additional info such as width/height and start/end bytes length
|
||||
// info: {
|
||||
// width: '10',
|
||||
// height: '20',
|
||||
// startBytes: 59,
|
||||
// endBytes: 38
|
||||
// }
|
||||
// }
|
||||
|
||||
})
|
||||
// end promises chain
|
||||
.done();
|
31
examples/fromStream.js
Normal file
31
examples/fromStream.js
Normal file
@ -0,0 +1,31 @@
|
||||
var FS = require('fs'),
|
||||
PATH = require('path'),
|
||||
path = PATH.resolve(__dirname, '../examples/test.svg'),
|
||||
fileStream = FS.createReadStream(path, { encoding: 'utf8' });
|
||||
|
||||
var SVGO = require('../lib/svgo'),
|
||||
svgo = new SVGO(/*{ custom config object }*/);
|
||||
|
||||
svgo
|
||||
// optimize stream
|
||||
.fromStream(fileStream)
|
||||
// get optimized result
|
||||
.then(function(min) {
|
||||
|
||||
console.log(min);
|
||||
// output:
|
||||
// {
|
||||
// // optimized SVG data string
|
||||
// data: '<svg width="10" height="20">test</svg>'
|
||||
// // additional info such as width/height and start/end bytes length
|
||||
// info: {
|
||||
// width: '10',
|
||||
// height: '20',
|
||||
// startBytes: 59,
|
||||
// endBytes: 38
|
||||
// }
|
||||
// }
|
||||
|
||||
})
|
||||
// end promises chain
|
||||
.done();
|
26
examples/fromString.js
Normal file
26
examples/fromString.js
Normal file
@ -0,0 +1,26 @@
|
||||
var SVGO = require('../lib/svgo'),
|
||||
svgo = new SVGO(/*{ custom config object }*/);
|
||||
|
||||
svgo
|
||||
// optimize SVG data string
|
||||
.fromString('<svg version="1.1" width="10" height="20">test</svg>')
|
||||
// get optimized result
|
||||
.then(function(min) {
|
||||
|
||||
console.log(min);
|
||||
// output:
|
||||
// {
|
||||
// // optimized SVG data string
|
||||
// data: '<svg width="10" height="20">test</svg>'
|
||||
// // additional info such as width/height and start/end bytes length
|
||||
// info: {
|
||||
// width: '10',
|
||||
// height: '20',
|
||||
// startBytes: 52,
|
||||
// endBytes: 38
|
||||
// }
|
||||
// }
|
||||
|
||||
})
|
||||
// end promises chain
|
||||
.done();
|
3
examples/test.svg
Normal file
3
examples/test.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg version="1.1" width="10" height="20">
|
||||
test
|
||||
</svg>
|
After Width: | Height: | Size: 59 B |
60
lib/svgo.js
60
lib/svgo.js
@ -11,10 +11,14 @@
|
||||
*/
|
||||
|
||||
var INHERIT = require('inherit'),
|
||||
Q = require('q'),
|
||||
FS = require('fs'),
|
||||
PATH = require('path'),
|
||||
CONFIG = require('./svgo/config'),
|
||||
SVG2JS = require('./svgo/svg2js'),
|
||||
PLUGINS = require('./svgo/plugins'),
|
||||
JS2SVG = require('./svgo/js2svg');
|
||||
JS2SVG = require('./svgo/js2svg'),
|
||||
decodeSVGDatauri = require('./svgo/tools').decodeSVGDatauri;
|
||||
|
||||
/**
|
||||
* @class SVGO.
|
||||
@ -34,27 +38,61 @@ module.exports = INHERIT(/** @lends SVGO.prototype */{
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Main optimize function.
|
||||
*
|
||||
* @param {String} svgdata input data
|
||||
*
|
||||
* @return {String} output data deferred promise
|
||||
*/
|
||||
optimize: function(svgdata) {
|
||||
fromString: function(str) {
|
||||
|
||||
str = decodeSVGDatauri(str);
|
||||
|
||||
return this.config
|
||||
.then(function(config) {
|
||||
|
||||
return SVG2JS(svgdata, config.svg2js)
|
||||
return SVG2JS(str, config.svg2js)
|
||||
.then(function(jsdata) {
|
||||
|
||||
return JS2SVG(PLUGINS(jsdata, config.plugins), config.js2svg);
|
||||
var out = JS2SVG(PLUGINS(jsdata, config.plugins), config.js2svg);
|
||||
|
||||
out.info.startBytes = Buffer.byteLength(str, 'utf-8');
|
||||
out.info.endBytes = Buffer.byteLength(out.data, 'utf-8');
|
||||
|
||||
return out;
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
fromStream: function(stream) {
|
||||
|
||||
var deferred = Q.defer(),
|
||||
inputData = [],
|
||||
self = this;
|
||||
|
||||
stream.pause();
|
||||
|
||||
stream
|
||||
.on('data', function(chunk) {
|
||||
inputData.push(chunk);
|
||||
})
|
||||
.once('end', function() {
|
||||
deferred.resolve(inputData.join());
|
||||
})
|
||||
.resume();
|
||||
|
||||
return deferred.promise
|
||||
.then(function(str) {
|
||||
|
||||
return self.fromString(str);
|
||||
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
fromFile: function(path) {
|
||||
|
||||
path = PATH.resolve(__dirname, path);
|
||||
|
||||
return this.fromStream(FS.createReadStream(path, { encoding: 'utf8' }));
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
201
lib/svgo/coa.js
201
lib/svgo/coa.js
@ -1,9 +1,8 @@
|
||||
var Q = require('q'),
|
||||
FS = require('fs'),
|
||||
var FS = require('fs'),
|
||||
UTIL = require('util'),
|
||||
SVGO = require('../svgo'),
|
||||
info = JSON.parse(require('fs').readFileSync(__dirname + '/../../package.json')),
|
||||
datauriPrefix = 'data:image/svg+xml;base64,';
|
||||
encodeSVGDatauri = require('./tools').encodeSVGDatauri;
|
||||
|
||||
/**
|
||||
* Command-Option-Argument.
|
||||
@ -26,17 +25,19 @@ module.exports = require('coa').Cmd()
|
||||
})
|
||||
.end()
|
||||
.opt()
|
||||
.name('input').title('Input: stdin (default) | filename | Data URI base64 string')
|
||||
.name('input').title('Input file, "-" for STDIN')
|
||||
.short('i').long('input')
|
||||
.def(process.stdin)
|
||||
.val(function(val) {
|
||||
return val || this.reject('Option --input must have a value.');
|
||||
})
|
||||
.end()
|
||||
.opt()
|
||||
.name('output').title('Output: stdout (default) | filename')
|
||||
.name('string').title('Input SVG data string')
|
||||
.short('s').long('string')
|
||||
.end()
|
||||
.opt()
|
||||
.name('output').title('Output file (by default the same as the input), "-" for STDOUT')
|
||||
.short('o').long('output')
|
||||
.def(process.stdout)
|
||||
.val(function(val) {
|
||||
return val || this.reject('Option --output must have a value.');
|
||||
})
|
||||
@ -74,11 +75,6 @@ module.exports = require('coa').Cmd()
|
||||
.long('pretty')
|
||||
.flag()
|
||||
.end()
|
||||
.opt()
|
||||
.name('test').title('Make a visual comparison of two files (PhantomJS pre-required)')
|
||||
.long('test')
|
||||
.flag()
|
||||
.end()
|
||||
.arg()
|
||||
.name('input').title('Alias to --input')
|
||||
.end()
|
||||
@ -89,123 +85,71 @@ module.exports = require('coa').Cmd()
|
||||
|
||||
var input = args && args.input ? args.input : opts.input,
|
||||
output = args && args.output ? args.output : opts.output,
|
||||
inputData = [],
|
||||
deferred = Q.defer(),
|
||||
string = opts.string,
|
||||
startTime = Date.now(),
|
||||
endTime,
|
||||
startBytes,
|
||||
endBytes;
|
||||
svgo;
|
||||
|
||||
// https://github.com/joyent/node/issues/2130
|
||||
process.stdin.pause();
|
||||
if (
|
||||
(!input || input === '-') &&
|
||||
!string &&
|
||||
!opts.stdin &&
|
||||
process.stdin.isTTY
|
||||
) return this.usage();
|
||||
|
||||
// if value is a string and not a Data URI string
|
||||
if (typeof input === 'string' && !isDatauri(input)) {
|
||||
// then create stream
|
||||
input = FS.createReadStream(input, { encoding: 'utf8' });
|
||||
input.pause();
|
||||
// --string
|
||||
if (string) {
|
||||
svgo = new SVGO({ coa: opts }).fromString(string);
|
||||
}
|
||||
|
||||
// if run as just 'svgo' display help and exit
|
||||
if (input.isTTY) return this.usage();
|
||||
|
||||
// datauri base64 string
|
||||
if (typeof input === 'string') {
|
||||
deferred.resolve(convertDatauriInput(input));
|
||||
// stdin or file stream
|
||||
} else {
|
||||
input
|
||||
.on('data', function(chunk) {
|
||||
inputData.push(chunk);
|
||||
})
|
||||
.once('end', function() {
|
||||
deferred.resolve(convertDatauriInput(inputData.join()));
|
||||
})
|
||||
.resume();
|
||||
// STDIN
|
||||
else if (input === '-') {
|
||||
svgo = new SVGO({ coa: opts }).fromStream(process.stdin);
|
||||
}
|
||||
|
||||
return deferred.promise
|
||||
.then(function(svg) {
|
||||
startBytes = Buffer.byteLength(svg, 'utf-8');
|
||||
// file
|
||||
else if (input) {
|
||||
svgo = new SVGO({ coa: opts }).fromFile(input);
|
||||
}
|
||||
|
||||
return new SVGO({ coa: opts }).optimize(svg);
|
||||
})
|
||||
.then(function(svgmin) {
|
||||
endTime = Date.now();
|
||||
endBytes = Buffer.byteLength(svgmin.data, 'utf-8');
|
||||
return svgo.then(function(svgmin) {
|
||||
|
||||
// --datauri
|
||||
if (opts.datauri) {
|
||||
// convert to Data URI base64 string
|
||||
svgmin.data = datauriPrefix + new Buffer(svgmin.data).toString('base64');
|
||||
}
|
||||
|
||||
if (typeof output === 'string') {
|
||||
output = FS.createWriteStream(output, { encoding: 'utf8' });
|
||||
// --datauri
|
||||
if (opts.datauri) {
|
||||
// convert to Data URI base64 string
|
||||
svgmin.data = encodeSVGDatauri(svgmin.data);
|
||||
}
|
||||
|
||||
// stdout
|
||||
if (output === '-' || (input === '-' && !output)) {
|
||||
process.stdout.write(svgmin.data + '\n');
|
||||
}
|
||||
|
||||
// file
|
||||
else {
|
||||
|
||||
// if input is from file - overwrite it
|
||||
if (!output && input) {
|
||||
output = input;
|
||||
}
|
||||
|
||||
// output file
|
||||
output = FS.createWriteStream(output, { encoding: 'utf8' });
|
||||
output.write(svgmin.data);
|
||||
output.end();
|
||||
|
||||
if (output === process.stdout) {
|
||||
output.write('\n');
|
||||
} else {
|
||||
output.end();
|
||||
// print time info
|
||||
printTimeInfo(startTime, Date.now());
|
||||
|
||||
// print time info
|
||||
printTimeInfo(startTime, endTime);
|
||||
// print optimization profit info
|
||||
printProfitInfo(svgmin.info.startBytes, svgmin.info.endBytes);
|
||||
|
||||
// print optimization profit info
|
||||
printProfitInfo(startBytes, endBytes);
|
||||
}
|
||||
|
||||
// --test
|
||||
if (opts.test) {
|
||||
// make a visual comparison of two files with PhantomJS and print info
|
||||
printPhantomTestInfo(
|
||||
input.path,
|
||||
output.path,
|
||||
svgmin.info.width || 500,
|
||||
svgmin.info.height || 500
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
.done();
|
||||
})
|
||||
.done();
|
||||
|
||||
});
|
||||
|
||||
/**
|
||||
* Check if string is a Data URI base64.
|
||||
*
|
||||
* @param {String} str input string
|
||||
*
|
||||
* @return {Boolean}
|
||||
*/
|
||||
function isDatauri(str) {
|
||||
|
||||
return str.substring(0, 26) === datauriPrefix;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert Data URI base64 string to plain SVG.
|
||||
*
|
||||
* @param {String} str input string
|
||||
*
|
||||
* @return {String} output string
|
||||
*/
|
||||
function convertDatauriInput(str) {
|
||||
|
||||
// if datauri base64 string
|
||||
if (isDatauri(str)) {
|
||||
// then convert
|
||||
str = new Buffer(str.substring(26), 'base64').toString('utf8');
|
||||
}
|
||||
|
||||
return str;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Print time info.
|
||||
*
|
||||
@ -235,40 +179,3 @@ function printProfitInfo(inBytes, outBytes) {
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a visual comparison of two files with PhantomJS and print info.
|
||||
*
|
||||
* @param {String} file1 file1 path
|
||||
* @param {String} file2 file2 path
|
||||
* @param {Number} width width
|
||||
* @param {Number} height height
|
||||
*/
|
||||
function printPhantomTestInfo(file1, file2, width, height) {
|
||||
|
||||
var PHANTOM = require('./phantom');
|
||||
|
||||
UTIL.print('Visual comparison: ');
|
||||
|
||||
PHANTOM.test(file1, file2, width, height)
|
||||
.then(function(code) {
|
||||
|
||||
var answer;
|
||||
|
||||
if (code === 1) {
|
||||
answer = 'OK';
|
||||
} else if (code === 2) {
|
||||
answer = 'Oops, files are not visually identical!\n\nIf you do not see any visual differences with your eyes then ALL IS OK and there are only very minor floating-point numbers rounding errors in some browsers.\nBut if you see significant errors then things are bad :), please create an issue at https://github.com/svg/svgo/issues';
|
||||
} else if (code === 3) {
|
||||
answer = 'Error while rendering SVG\nPlease create an issue at https://github.com/svg/svgo/issues';
|
||||
} else if (code === 127) {
|
||||
answer = 'Error, you need to install PhantomJS first http://phantomjs.org/download.html';
|
||||
} else {
|
||||
answer = 'Error, something went wrong\nPlease create an issue at https://github.com/svg/svgo/issues';
|
||||
}
|
||||
|
||||
UTIL.print(answer + '\n\n');
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
@ -1,30 +0,0 @@
|
||||
var PATH = require('path'),
|
||||
Q = require('Q'),
|
||||
spawn = require('child_process').spawn;
|
||||
|
||||
/**
|
||||
* Two SVG files rendering and visually comparing with PhantomJS.
|
||||
*
|
||||
* @see http://phantomjs.org/
|
||||
* @see /lib/phantom_test.js
|
||||
*
|
||||
* @param {String} file1 file1
|
||||
* @param {String} file2 file2
|
||||
* @param {Number} width viewport width
|
||||
* @param {Number} height viewport height
|
||||
*
|
||||
* @return {Object} deferred promise with exit code
|
||||
*/
|
||||
exports.test = function(file1, file2, width, height) {
|
||||
|
||||
var phantomTestFile = PATH.resolve(__dirname, './phantom_test.js'),
|
||||
phantom = spawn('phantomjs', [phantomTestFile, file1, file2, width, height]),
|
||||
deferred = Q.defer();
|
||||
|
||||
phantom.on('exit', function(code) {
|
||||
deferred.resolve(code);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
|
||||
};
|
@ -1,40 +0,0 @@
|
||||
/**
|
||||
* Two SVG files rendering and visually comparing with PhantomJS.
|
||||
*
|
||||
* @see http://phantomjs.org/
|
||||
* @see https://github.com/ariya/phantomjs/wiki/Screen-Capture
|
||||
*/
|
||||
var page = require('webpage').create(),
|
||||
file1 = phantom.args[0],
|
||||
file2 = phantom.args[1],
|
||||
width = phantom.args[2],
|
||||
height = phantom.args[3];
|
||||
|
||||
page.viewportSize = {
|
||||
width: width,
|
||||
height: height
|
||||
};
|
||||
|
||||
open(file1, function(out1) {
|
||||
open(file2, function(out2) {
|
||||
if (out1.length === out2.length && out1 === out2) {
|
||||
phantom.exit(1);
|
||||
} else {
|
||||
phantom.exit(2);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function open(file, callback) {
|
||||
|
||||
page.open(file, function(status) {
|
||||
|
||||
if (status !== 'success') {
|
||||
phantom.exit(3);
|
||||
} else {
|
||||
callback(page.renderBase64('PNG'));
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
@ -8,12 +8,12 @@ var UTIL = require('util'),
|
||||
*
|
||||
* @module svg2js
|
||||
*
|
||||
* @param {String} svgdata input data
|
||||
* @param {String} svg input data
|
||||
* @param {Object} config sax xml parser config
|
||||
*
|
||||
* @return {Object} output data deferred promise
|
||||
*/
|
||||
module.exports = function(svgdata, config) {
|
||||
module.exports = function(svg, config) {
|
||||
|
||||
var deferred = Q.defer(),
|
||||
sax = SAX.parser(config.strict, config),
|
||||
@ -119,7 +119,7 @@ module.exports = function(svgdata, config) {
|
||||
|
||||
};
|
||||
|
||||
sax.write(svgdata).close();
|
||||
sax.write(svg).close();
|
||||
|
||||
return deferred.promise;
|
||||
|
||||
|
@ -1,3 +1,33 @@
|
||||
var datauriSVGPrefix = exports.datauriSVGPrefix = 'data:image/svg+xml;base64,';
|
||||
|
||||
/**
|
||||
* Encode plain SVG data string into Data URI base64 string.
|
||||
*
|
||||
* @param {String} str input string
|
||||
*
|
||||
* @return {String} output string
|
||||
*/
|
||||
exports.encodeSVGDatauri = function(str) {
|
||||
|
||||
return datauriSVGPrefix + new Buffer(str).toString('base64');
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Decode SVG Data URI base64 string into plain SVG data string.
|
||||
*
|
||||
* @param {string} str input string
|
||||
*
|
||||
* @return {String} output string
|
||||
*/
|
||||
exports.decodeSVGDatauri = function(str) {
|
||||
|
||||
if (str.substring(0, 26) !== datauriSVGPrefix) return str;
|
||||
|
||||
return new Buffer(str.substring(26), 'base64').toString('utf8');
|
||||
|
||||
};
|
||||
|
||||
exports.extend = require('node.extend');
|
||||
|
||||
exports.flattenOneLevel = function(array) {
|
||||
|
@ -66,7 +66,7 @@ function getResult(name, index) {
|
||||
.then(function(input) {
|
||||
mySVGO.enableOnlyOne(name);
|
||||
|
||||
return mySVGO.optimize(input.toString());
|
||||
return mySVGO.fromString(input.toString());
|
||||
})
|
||||
.then(function(min) {
|
||||
return readFile(name + '.' + index +'.should.svg')
|
||||
|
Reference in New Issue
Block a user