UNPKG

librsvg-prebuilt

Version:

Prebuilt librsvg binding. Parse SVG files and render them as PNG, PDF, SVG, or raw memory buffer images.

288 lines (258 loc) 8.73 kB
'use strict'; var Writable = require('stream').Writable; var sinon = require('sinon'); var Rsvg = require('..').Rsvg; var fs = require('fs'); var path = require('path'); describe('Rsvg', function() { describe('Rsvg()', function() { it('can be constructed with a SVG', function() { // Use buffer. var svg = new Rsvg(new Buffer('<svg width="5" height="7"></svg>')); svg.should.be.an.instanceof(Rsvg); svg.width.should.equal(5); svg.height.should.equal(7); // Use string. svg = new Rsvg('<svg width="3" height="8"></svg>'); svg.width.should.equal(3); svg.height.should.equal(8); // Not writable anymore var onerror = sinon.spy(); svg.on('error', onerror); svg.write('<svg width="3" height="2"></svg>'); onerror.should.have.been.calledOnce; onerror.lastCall.args.should.have.length(1); onerror.lastCall.args[0].should.match(/write failure/i); }); it('can be a writable stream', function() { // Default constructor. var svg = new Rsvg(); svg.should.be.an.instanceof(Writable); svg.width.should.equal(0); svg.height.should.equal(0); // Write to stream and basic test. svg.write('<svg width="4" height="6">').should.be.true; svg.width.should.equal(4); svg.height.should.equal(6); // Stream options. svg = new Rsvg({ highWaterMark: 16 }); svg.write('<svg width="4" height="6">').should.be.false; }); it('emits load event when ready - from stream', function(done) { var onload = sinon.spy(); var svg = new Rsvg(); svg.on('load', onload); svg.write('<svg width="4" height="6">'); svg.write('</svg>'); onload.should.not.have.been.called; svg.end(); process.nextTick(function() { onload.should.have.been.calledOnce; onload.should.have.been.calledWithExactly(); done(); }); }); it('emits load event when ready - from svg', function(done) { var onload = sinon.spy(); var svg = new Rsvg(); svg.on('load', onload); onload = sinon.spy(); svg = new Rsvg('<svg width="2" height="3"></svg>'); svg.on('load', onload); onload.should.not.have.been.called; process.nextTick(function() { onload.should.have.been.calledOnce; onload.should.have.been.calledWithExactly(); done(); }); }); it('gives an error for invalid SVG content', function() { // Stream. var onerror = sinon.spy(); var svg = new Rsvg(); svg.on('error', onerror); svg.write('this is not a SVG file'); onerror.should.have.been.calledOnce; svg.write('this is not a SVG file'); onerror.should.have.been.calledTwice; onerror.lastCall.args.should.have.length(1); onerror.lastCall.args[0].should.match(/write failure/); // Constructed with SVG. function loadInvalidSVG() { /*jshint -W031 */ new Rsvg('this is not a SVG file'); /*jshint +W031 */ } loadInvalidSVG.should.throw(/load failure/i); // Regression test on 2014-01-16. onerror = sinon.spy(); svg = new Rsvg(); svg.on('error', onerror); svg.end('<svg width="100" height="100"></svg>invalid'); onerror.should.have.been.calledOnce; onerror.lastCall.args.should.have.length(1); onerror.lastCall.args[0].should.match(/write failure/); }); }); describe('baseURI', function() { it('allows to reference external SVGs'); }); describe('width', function() { it('gives the horizontal size', function() { new Rsvg('<svg width="314" height="1"/>').width.should.equal(314); new Rsvg('<svg width="257" height="2"/>').width.should.equal(257); }); }); describe('height', function() { it('gives the vertical size', function() { new Rsvg('<svg width="1" height="413"/>').height.should.equal(413); new Rsvg('<svg width="2" height="752"/>').height.should.equal(752); }); }); describe('dimensions()', function() { it('gives the size of the whole image', function() { new Rsvg('<svg width="314" height="257"/>').dimensions().should.deep.equal({ x: 0, y: 0, width: 314, height: 257 }); new Rsvg('<svg width="17" height="19"/>').dimensions().should.deep.equal({ x: 0, y: 0, width: 17, height: 19 }); }); it('gives the size and position of specific elements', function() { var svg = new Rsvg(); svg.write('<svg width="12" height="10">'); svg.write('<rect x="-2" y="3" width="7" height="5" id="r1"/>'); svg.write('<rect x="8" y="4" width="4" height="6" id="r2"/>'); svg.write('<circle cx="8" cy="3" r="3" id="circ"/>'); svg.write('</svg>'); svg.end(); svg.dimensions().should.deep.equal({ x: 0, y: 0, width: 12, height: 10 }); svg.dimensions(null).should.deep.equal(svg.dimensions()); svg.dimensions('#r1').should.deep.equal({ x: -2, y: 3, width: 7, height: 5 }); svg.dimensions('#r2').should.deep.equal({ x: 8, y: 4, width: 4, height: 6 }); svg.dimensions('#circ').should.deep.equal({ x: 5, y: 0, width: 6, height: 6 }); }); }); describe('hasElement()', function() { it('determines whether an element with the given ID exists', function() { var svg = new Rsvg(); svg.write('<svg width="12" height="10">'); svg.write('<rect x="-2" y="3" width="7" height="5" id="r1"/>'); svg.write('<rect x="8" y="4" width="4" height="6" id="r2"/>'); svg.write('<circle cx="8" cy="3" r="3" id="circ"/>'); svg.write('</svg>'); svg.end(); svg.hasElement().should.be.false; svg.hasElement(null).should.be.false; svg.hasElement('#r1').should.be.true; svg.hasElement('#r2').should.be.true; svg.hasElement('#circ').should.be.true; svg.hasElement('#foo').should.be.false; svg.hasElement('r1').should.be.false; }); }); describe('autocrop()', function() { it('finds the drawing area of the SVG'); }); describe('render()', function() { it('does nothing for an empty SVG document'); it('renders as a raw memory buffer'); it('renders as a PNG image'); it('renders as a PDF document'); it('renders as a PDF document'); it('renders in various image sizes'); it('can render specific SVG elements'); it('can render a specific area [future]'); it('can trim the image to a given rect [future]'); it('can resize to fit inside box [future]'); it('can resize to fit outside box [future]'); it('can resize while ignoring aspect ratio [future]'); it('can resize with a focus point [future]'); it('can add a background color [future]'); }); describe('toString()', function() { it('gives a string representation', function() { var svg = new Rsvg(); svg.toString().should.equal('{ [Rsvg] width: 0, height: 0 }'); svg = new Rsvg('<svg width="3" height="7"></svg>'); svg.toString().should.equal('{ [Rsvg] width: 3, height: 7 }'); }); }); describe('reference rendering', function () { var items = fs.readdirSync('./test/svg/'); // sinon.assert.pass = function (message) { console.log(message); }; items.forEach(function (testcase) { if (testcase.slice(-4) === '.svg') { it('png image should match the reference image "' + testcase + '"', function () { var fn = testcase.slice(0, -4); var input = fs.readFileSync('./test/svg/' + fn + '.svg'); var svg = new Rsvg(input); var rendering = new Buffer(svg.render({ format: 'png', width: svg.width, height: svg.height }).data); var compare = function (rendering, referenceFn) { var reference = fs.readFileSync('./test/png/' + referenceFn + '.png'); try{ return Buffer.compare(reference, rendering); } catch (e){ // TODO: Remove workaround after support for node 0.10 was dropped if ( JSON.stringify(reference) === JSON.stringify(rendering) ) { return 0; } else { return -1; } } }; if( compare(rendering, fn) === 0 ){ return; } else { var i = 1; while (fs.existsSync('./test/png/' + fn + '-variant' + i + '.png')){ if ( compare(rendering, fn + '-variant' + i ) === 0){ sinon.assert.pass(fn + ' passed using variant ' + i); return; } i++; } } var base64 = 'data:image/png;base64,' + rendering.toString('base64'); sinon.assert.fail('Image does not match reference!\n' + 'To view the image convert the base64 encoded string to an actual image.\n' + 'You can use a online decoder like' + ' http://www.askapache.com/online-tools/base64-image-converter\n' + 'un-check "Compress Image (png and jpeg)" to get a result that can be used as reference.\n' + 'If you think the rendering result looks good save it as\n' + path.resolve('./test/png') + '/' + fn + '-variant' + i + '.png\n'+ base64); }); } }); }); });