UNPKG

7.59 kBJavaScriptView Raw
1/*
2 * Copyright (C) 2017 Alasdair Mercer, !ninja
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in all
12 * copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 * SOFTWARE.
21 */
22
23'use strict';
24
25const omit = require('lodash.omit');
26const pick = require('lodash.pick');
27
28const Converter = require('./Converter');
29
30const _provider = Symbol('provider');
31
32/**
33 * The application programming interface for a SVG converter {@link Provider}.
34 *
35 * @public
36 */
37class API {
38
39 /**
40 * Creates an instance of {@link API} using the specified <code>provider</code>.
41 *
42 * @param {Provider} provider - the {@link Provider} to be used
43 * @public
44 */
45 constructor(provider) {
46 this[_provider] = provider;
47
48 // Workaround for #22 by ensuring all public methods are bound to this instance
49 this.convert = this.convert.bind(this);
50 this.convertFile = this.convertFile.bind(this);
51 this.createConverter = this.createConverter.bind(this);
52 }
53
54 /**
55 * Converts the specified <code>input</code> SVG into another format using the <code>options</code> provided via a
56 * headless Chromium instance.
57 *
58 * <code>input</code> can either be a SVG buffer or string.
59 *
60 * If the width and/or height cannot be derived from <code>input</code> then they must be provided via their
61 * corresponding options. This method attempts to derive the dimensions from <code>input</code> via any
62 * <code>width</code>/<code>height</code> attributes or its calculated <code>viewBox</code> attribute.
63 *
64 * This method is resolved with the converted output buffer.
65 *
66 * An error will occur if both the <code>baseFile</code> and <code>baseUrl</code> options have been provided,
67 * <code>input</code> does not contain an SVG element or no <code>width</code> and/or <code>height</code> options were
68 * provided and this information could not be derived from <code>input</code>.
69 *
70 * @param {Buffer|string} input - the SVG input to be converted to another format
71 * @param {API~ConvertOptions} [options] - the options to be used
72 * @return {Promise.<Buffer, Error>} A <code>Promise</code> that is resolved with the converted output buffer.
73 * @public
74 */
75 async convert(input, options) {
76 const converter = this.createConverter(pick(options, 'puppeteer'));
77 let output;
78
79 try {
80 output = await converter.convert(input, omit(options, 'puppeteer'));
81 } finally {
82 await converter.destroy();
83 }
84
85 return output;
86 }
87
88 /**
89 * Converts the SVG file at the specified path into another format using the <code>options</code> provided and writes
90 * it to the output file.
91 *
92 * The output file is derived from <code>inputFilePath</code> unless the <code>outputFilePath</code> option is
93 * specified.
94 *
95 * If the width and/or height cannot be derived from the input file then they must be provided via their corresponding
96 * options. This method attempts to derive the dimensions from the input file via any
97 * <code>width</code>/<code>height</code> attributes or its calculated <code>viewBox</code> attribute.
98 *
99 * This method is resolved with the path of the converted output file for reference.
100 *
101 * An error will occur if both the <code>baseFile</code> and <code>baseUrl</code> options have been provided, the
102 * input file does not contain an SVG element, no <code>width</code> and/or <code>height</code> options were provided
103 * and this information could not be derived from input file, or a problem arises while reading the input file or
104 * writing the output file.
105 *
106 * @param {string} inputFilePath - the path of the SVG file to be converted to another file format
107 * @param {API~ConvertFileOptions} [options] - the options to be used
108 * @return {Promise.<string, Error>} A <code>Promise</code> that is resolved with the output file path.
109 * @public
110 */
111 async convertFile(inputFilePath, options) {
112 const converter = this.createConverter(pick(options, 'puppeteer'));
113 let outputFilePath;
114
115 try {
116 outputFilePath = await converter.convertFile(inputFilePath, omit(options, 'puppeteer'));
117 } finally {
118 await converter.destroy();
119 }
120
121 return outputFilePath;
122 }
123
124 /**
125 * Creates an instance of {@link Converter} using the <code>options</code> provided.
126 *
127 * It is important to note that, after the first time either {@link Converter#convert} or
128 * {@link Converter#convertFile} are called, a headless Chromium instance will remain open until
129 * {@link Converter#destroy} is called. This is done automatically when using the {@link API} convert methods,
130 * however, when using {@link Converter} directly, it is the responsibility of the caller. Due to the fact that
131 * creating browser instances is expensive, this level of control allows callers to reuse a browser for multiple
132 * conversions. For example; one could create a {@link Converter} and use it to convert a collection of SVG files to
133 * files in another format and then destroy it afterwards. It's not recommended to keep an instance around for too
134 * long, as it will use up resources.
135 *
136 * @param {API~CreateConverterOptions} [options] - the options to be used
137 * @return {Converter} A newly created {@link Converter} instance.
138 * @public
139 */
140 createConverter(options) {
141 return new Converter(this.provider, options);
142 }
143
144 /**
145 * Returns the {@link Provider} for this {@link Converter}.
146 *
147 * @return {Provider} The provider.
148 * @public
149 */
150 get provider() {
151 return this[_provider];
152 }
153
154 /**
155 * Returns the current version of the SVG converter provider.
156 *
157 * @return {string} The version.
158 * @public
159 */
160 get version() {
161 return this.provider.getVersion();
162 }
163
164}
165
166module.exports = API;
167
168/**
169 * The options that can be passed to {@link API#convertFile}.
170 *
171 * @typedef {Converter~ConvertFileOptions} API~ConvertFileOptions
172 * @property {Object} [puppeteer] - The options that are to be passed directly to <code>puppeteer.launch</code> when
173 * creating the <code>Browser</code> instance.
174 */
175
176/**
177 * The options that can be passed to {@link API#convert}.
178 *
179 * @typedef {Converter~ConvertOptions} API~ConvertOptions
180 * @property {Object} [puppeteer] - The options that are to be passed directly to <code>puppeteer.launch</code> when
181 * creating the <code>Browser</code> instance.
182 */
183
184/**
185 * The options that can be passed to {@link API#createConverter}.
186 *
187 * @typedef {Converter~Options} API~CreateConverterOptions
188 * @property {Object} [puppeteer] - The options that are to be passed directly to <code>puppeteer.launch</code> when
189 * creating the <code>Browser</code> instance.
190 */