diff options
author | Samy Pessé <samypesse@gmail.com> | 2016-02-13 15:04:18 +0100 |
---|---|---|
committer | Samy Pessé <samypesse@gmail.com> | 2016-02-13 15:04:18 +0100 |
commit | d2aad34935cb243dcdaeabfc28dce150c68f6340 (patch) | |
tree | e681361847e64762935465c1fbc81e9a9d72d122 | |
parent | d8ed34beba05bde85af420cc4e42a065021653dc (diff) | |
download | gitbook-d2aad34935cb243dcdaeabfc28dce150c68f6340.zip gitbook-d2aad34935cb243dcdaeabfc28dce150c68f6340.tar.gz gitbook-d2aad34935cb243dcdaeabfc28dce150c68f6340.tar.bz2 |
Improve performance of svg conversion
-rw-r--r-- | lib/output/assets-inliner.js | 95 | ||||
-rw-r--r-- | lib/output/folder.js | 18 | ||||
-rw-r--r-- | lib/utils/fs.js | 2 | ||||
-rw-r--r-- | test/assets-inliner.js | 5 |
4 files changed, 94 insertions, 26 deletions
diff --git a/lib/output/assets-inliner.js b/lib/output/assets-inliner.js index 2156bef..fb348b4 100644 --- a/lib/output/assets-inliner.js +++ b/lib/output/assets-inliner.js @@ -1,6 +1,6 @@ -var _ = require('lodash'); var util = require('util'); var path = require('path'); +var crc = require('crc'); var FolderOutput = require('./folder'); var Promise = require('../utils/promise'); @@ -13,52 +13,50 @@ var DEFAULT_ASSETS_FOLDER = 'assets'; /* Utility mixin to inline all the assets in a book: - Outline <svg> tags - - Convert svg images as png - Download remote images + - Convert .svg images as png */ function AssetsInliner() { FolderOutput.apply(this, arguments); + + // Map of svg already converted + this.svgs = {}; + this.inlineSvgs = {}; + + // Map of images already downloaded + this.downloaded = {}; } util.inherits(AssetsInliner, FolderOutput); // Output a SVG buffer as a file AssetsInliner.prototype.onOutputSVG = function(page, svg) { this.log.debug.ln('output svg from', page.path); - var filename = _.uniqueId('svg_') + '.png'; // Convert svg buffer to a png file - return imagesUtil.convertSVGBufferToPNG(svg, this.resolve(filename)) + return this.convertSVGBuffer(svg) // Return relative path from the page - .thenResolve(function() { + .then(function(filename) { return page.relative('/' + filename); }); }; + // Output an image as a file AssetsInliner.prototype.onOutputImage = function(page, src) { var that = this; - var isSVG = false; - var ext = path.extname(src).toLowerCase(); - if (ext == '.svg') { - isSVG = false; - ext = '.png'; - } return Promise() - // Allocate a new file - .then(function() { - - return that. - }) - // Download file if external .then(function() { if (!location.isExternal(src)) return; - return fs.download(src, ) + return that.downloadAsset(src) + .then(function(_asset) { + src = '/' + _asset; + }); }) .then(function() { @@ -67,16 +65,69 @@ AssetsInliner.prototype.onOutputImage = function(page, src) { } // Convert SVG to PNG - var filename = _.uniqueId('svg_') + '.png'; - return imagesUtil.convertSVGToPNG(page.resolve(src), this.resolve(filename)) - .thenResolve('/' + filename); + return that.convertSVGFile(page.resolve(src)); }) // Return relative path from the page - .thenResolve(function(filename) { + .then(function(filename) { return page.relative('/' + filename); }); }; +// Download an asset if not already download; returns the output file +AssetsInliner.prototype.downloadAsset = function(src) { + if (this.downloaded[src]) return Promise(this.downloaded[src]); + + var that = this; + var ext = path.extname(src); + var hash = crc.crc32(src).toString(16); + + // Create new file + return this.createNewFile(DEFAULT_ASSETS_FOLDER, hash + ext) + .then(function(filename) { + that.downloaded[src] = filename; + + that.log.debug.ln('downloading asset', src); + return fs.download(src, filename) + .thenResolve(filename); + }); +}; + +// Convert a .svg into an .png +// Return the output filename for the .png +AssetsInliner.prototype.convertSVGFile = function(src) { + if (this.svgs[src]) return Promise(this.svgs[src]); + + var that = this; + var hash = crc.crc32(src).toString(16); + + // Create new file + return this.createNewFile(DEFAULT_ASSETS_FOLDER, hash + '.png') + .then(function(filename) { + that.svgs[src] = filename; + + return imagesUtil.convertSVGToPNG(src, that.resolve(filename)) + .thenResolve(filename); + }); +}; + +// Convert an inline svg into an .png +// Return the output filename for the .png +AssetsInliner.prototype.convertSVGBuffer = function(buf) { + var that = this; + var hash = crc.crc32(buf).toString(16); + + // Already converted? + if (this.inlineSvgs[hash]) return Promise(this.inlineSvgs[hash]); + + return this.createNewFile(DEFAULT_ASSETS_FOLDER, hash + '.png') + .then(function(filename) { + that.inlineSvgs[hash] = filename; + + return imagesUtil.convertSVGBufferToPNG(buf, that.resolve(filename)) + .thenResolve(filename); + }); +}; + module.exports = AssetsInliner; diff --git a/lib/output/folder.js b/lib/output/folder.js index aabdcc4..8b899f6 100644 --- a/lib/output/folder.js +++ b/lib/output/folder.js @@ -34,7 +34,7 @@ FolderOutput.prototype.prepare = function() { // ----- Utility methods ----- // Return path to the root folder -FolderOutput.prototype.root = function(filename) { +FolderOutput.prototype.root = function() { return path.resolve(process.cwd(), this.book.config.get('output')); }; @@ -74,10 +74,26 @@ FolderOutput.prototype.writeFile = function(filename, buf) { }); }; +// Return true if a file exists in the output folder +FolderOutput.prototype.hasFile = function(filename) { + var that = this; + + return Promise() + .then(function() { + return fs.exists(that.resolve(filename)); + }); +}; + + // Create a new unique file // Returns its filename FolderOutput.prototype.createNewFile = function(base, filename) { + if (!filename) { + filename = path.basename(filename); + base = path.dirname(base); + } + return fs.uniqueFilename(this.resolve(base), filename); }; diff --git a/lib/utils/fs.js b/lib/utils/fs.js index bf5e51d..3f1c11f 100644 --- a/lib/utils/fs.js +++ b/lib/utils/fs.js @@ -80,7 +80,7 @@ function uniqueFilename(base, filename) { i = i + 1; } - return path.relative(base, _filename); + return Promise(path.relative(base, _filename)); } module.exports = { diff --git a/test/assets-inliner.js b/test/assets-inliner.js index cb02e42..76b04f6 100644 --- a/test/assets-inliner.js +++ b/test/assets-inliner.js @@ -14,7 +14,8 @@ describe('Assets Inliner Output', function() { return mock.outputDefaultBook(AssetsInliner, { 'README.md': '', 'inline.md': 'This is a svg: '+SVG, - 'test.svg': '<?xml version="1.0" encoding="UTF-8"?>' + SVG + 'test.svg': '<?xml version="1.0" encoding="UTF-8"?>' + SVG, + 'SUMMARY.md': '* [inline](inline.md)\n\n' }) .then(function(_output) { output = _output; @@ -35,7 +36,7 @@ describe('Assets Inliner Output', function() { }); it('should correctly inline SVG convert to PNG', function() { - var page = output.book.addPage('README.md'); + var page = output.book.getPage('inline.md'); var $ = cheerio.load(page.content); // Is there an image? |