summaryrefslogtreecommitdiffstats
path: root/lib/output2/assets-inliner.js
diff options
context:
space:
mode:
Diffstat (limited to 'lib/output2/assets-inliner.js')
-rw-r--r--lib/output2/assets-inliner.js140
1 files changed, 140 insertions, 0 deletions
diff --git a/lib/output2/assets-inliner.js b/lib/output2/assets-inliner.js
new file mode 100644
index 0000000..6f1f02d
--- /dev/null
+++ b/lib/output2/assets-inliner.js
@@ -0,0 +1,140 @@
+var util = require('util');
+var path = require('path');
+var crc = require('crc');
+
+var FolderOutput = require('./folder')();
+var Promise = require('../utils/promise');
+var fs = require('../utils/fs');
+var imagesUtil = require('../utils/images');
+var location = require('../utils/location');
+
+var DEFAULT_ASSETS_FOLDER = 'assets';
+
+/*
+Mixin to inline all the assets in a book:
+ - Outline <svg> tags
+ - Download remote images
+ - Convert .svg images as png
+*/
+
+module.exports = function assetsInliner(Base) {
+ Base = Base || FolderOutput;
+
+ function AssetsInliner() {
+ Base.apply(this, arguments);
+
+ // Map of svg already converted
+ this.svgs = {};
+ this.inlineSvgs = {};
+
+ // Map of images already downloaded
+ this.downloaded = {};
+ }
+ util.inherits(AssetsInliner, Base);
+
+ // Output a SVG buffer as a file
+ AssetsInliner.prototype.onOutputSVG = function(page, svg) {
+ this.log.debug.ln('output svg from', page.path);
+
+ // Convert svg buffer to a png file
+ return this.convertSVGBuffer(svg)
+
+ // Return relative path from the page
+ .then(function(filename) {
+ return page.relative('/' + filename);
+ });
+ };
+
+
+ // Output an image as a file
+ AssetsInliner.prototype.onOutputImage = function(page, src) {
+ var that = this;
+
+ return Promise()
+
+ // Download file if external
+ .then(function() {
+ if (!location.isExternal(src)) return;
+
+ return that.downloadAsset(src)
+ .then(function(_asset) {
+ src = '/' + _asset;
+ });
+
+ })
+ .then(function() {
+ // Resolve src to a relative filepath to the book's root
+ src = page.resolveLocal(src);
+
+ // Already a PNG/JPG/.. ?
+ if (path.extname(src).toLowerCase() != '.svg') {
+ return src;
+ }
+
+ // Convert SVG to PNG
+ return that.convertSVGFile(that.resolve(src));
+ })
+
+ // Return relative path from the page
+ .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, that.resolve(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);
+ });
+ };
+
+ return AssetsInliner;
+};