Socket
Socket
Sign inDemoInstall

svg2png

Package Overview
Dependencies
Maintainers
1
Versions
13
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

svg2png - npm Package Compare versions

Comparing version 2.1.0 to 3.0.0

bin/svg2png-cli.js

142

lib/converter.js

@@ -8,13 +8,16 @@ "use strict";

if (system.args.length !== 4) {
console.error("Usage: converter.js source dest resize");
var PREFIX = "data:image/svg+xml;base64,";
if (system.args.length !== 2) {
console.error("Usage: converter.js resize");
phantom.exit();
} else {
convert(system.args[1], system.args[2], system.args[3]);
convert(system.args[1]);
}
function convert(source, dest, resize) {
function convert(resize) {
var page = webpage.create();
var sourceBase64 = system.stdin.readLine();
page.open(source, function (status) {
page.open(PREFIX + sourceBase64, function (status) {
if (status !== "success") {

@@ -27,39 +30,21 @@ console.error("Unable to load the source file.");

try {
if (resize[0] === "{") {
if (resize !== "undefined") {
resize = JSON.parse(resize);
var width = resize.width;
var height = resize.height;
if (width === undefined || height === undefined) {
var dims = getSvgDimensions(page);
if (width === undefined && height === undefined) {
width = dims.width;
height = dims.height;
} else if (width === undefined) {
var widthScale = height / dims.height;
width = dims.width * widthScale;
} else if (height === undefined) {
var heightScale = width / dims.width;
height = dims.height * heightScale;
}
}
width = Math.round(width);
height = Math.round(height);
page.viewportSize = {
width: width,
height: height
};
setSvgDimensions(page, width, height);
} else {
var scale = Number(resize);
var dimensions = getSvgDimensions(page);
page.viewportSize = {
width: Math.round(dimensions.width * scale),
height: Math.round(dimensions.height * scale)
};
if (dimensions.shouldScale) {
page.zoomFactor = scale;
}
setSVGDimensions(page, resize.width, resize.height);
}
var dimensions = getSVGDimensions(page);
if (!dimensions) {
console.error("Width or height could not be determined from either the source file or the supplied " +
"dimensions");
phantom.exit();
return;
}
page.viewportSize = {
width: dimensions.width,
height: dimensions.height
};
} catch (e) {
console.error("Unable to calculate dimensions.");
console.error("Unable to calculate or set dimensions.");
console.error(e);

@@ -70,11 +55,13 @@ phantom.exit();

// This delay is I guess necessary for the resizing to happen?
setTimeout(function () {
page.render(dest, { format: "png" });
phantom.exit();
}, 0);
var result = "data:image/png;base64," + page.renderBase64("PNG");
system.stdout.write(result);
phantom.exit();
});
}
function setSvgDimensions(page, width, height) {
function setSVGDimensions(page, width, height) {
if (width === undefined && height === undefined) {
return;
}
return page.evaluate(function (width, height) {

@@ -84,21 +71,17 @@ /* global document: true */

var viewBoxWidth = el.viewBox.animVal.width;
var viewBoxHeight = el.viewBox.animVal.height;
var usesViewBox = viewBoxWidth && viewBoxHeight;
if (width !== undefined) {
el.setAttribute("width", width + "px");
} else {
el.removeAttribute("width");
}
if (!usesViewBox) {
var bbox = el.getBBox();
var bX = Math.round(bbox.x);
var bY = Math.round(bbox.y);
var bWidth = Math.round(bbox.width);
var bHeight = Math.round(bbox.height);
el.setAttribute("viewBox", bX + " " + bY + " " + bWidth + " " + bHeight);
if (height !== undefined) {
el.setAttribute("height", height + "px");
} else {
el.removeAttribute("height");
}
el.setAttribute("width", width + "px");
el.setAttribute("height", height + "px");
}, width, height);
}
function getSvgDimensions(page) {
function getSVGDimensions(page) {
return page.evaluate(function () {

@@ -108,44 +91,25 @@ /* global document: true */

var el = document.documentElement;
var bbox = el.getBBox();
var width = parseFloat(el.getAttribute("width"));
var widthIsPercent = /%\s*$/.test(el.getAttribute("width") || ""); // Phantom doesn't have endsWith
var height = parseFloat(el.getAttribute("height"));
var heightIsPercent = /%\s*$/.test(el.getAttribute("height") || "");
var width = !widthIsPercent && parseFloat(el.getAttribute("width"));
var height = !heightIsPercent && parseFloat(el.getAttribute("height"));
var hasWidthOrHeight = width || height;
if (width && height) {
return { width: width, height: height };
}
var viewBoxWidth = el.viewBox.animVal.width;
var viewBoxHeight = el.viewBox.animVal.height;
var usesViewBox = viewBoxWidth && viewBoxHeight;
if (usesViewBox) {
if (widthIsPercent) {
width = viewBoxWidth / 100 * width;
}
if (heightIsPercent) {
height = viewBoxHeight / 100 * height;
}
if (width && !height) {
height = width * viewBoxHeight / viewBoxWidth;
}
if (height && !width) {
width = height * viewBoxWidth / viewBoxHeight;
}
if (!width && !height) {
width = viewBoxWidth;
height = viewBoxHeight;
}
if (width && viewBoxHeight) {
return { width: width, height: width * viewBoxHeight / viewBoxWidth };
}
if (!width) {
width = bbox.width + bbox.x;
if (height && viewBoxWidth) {
return { width: height * viewBoxWidth / viewBoxHeight, height: height };
}
if (!height) {
height = bbox.height + bbox.y;
}
var shouldScale = (hasWidthOrHeight && !widthIsPercent && !heightIsPercent) || !usesViewBox;
return { width: width, height: height, shouldScale: shouldScale };
return null;
});
}
"use strict";
const path = require("path");
const childProcess = require("pn/child_process");
var path = require("path");
var execFile = require("child_process").execFile;
const phantomjsCmd = require("phantomjs").path;
const converterFileName = path.resolve(__dirname, "./converter.js");
var phantomjsCmd = require("phantomjs").path;
var converterFileName = path.resolve(__dirname, "./converter.js");
const PREFIX = "data:image/png;base64,";
module.exports = function svgToPng(sourceFileName, destFileName, resize, cb) {
if (typeof resize === "function") {
cb = resize;
resize = 1.0;
} else if (typeof resize === "object") {
resize = JSON.stringify(resize);
module.exports = (sourceBuffer, resize) => {
const cp = childProcess.execFile(phantomjsCmd, getPhantomJSArgs(resize), { maxBuffer: Infinity });
writeBufferInChunks(cp.stdin, sourceBuffer);
return cp.promise.then(processResult);
};
module.exports.sync = (sourceBuffer, resize) => {
const result = childProcess.spawnSync(phantomjsCmd, getPhantomJSArgs(resize), {
input: sourceBuffer.toString("base64")
});
return processResult(result);
}
function getPhantomJSArgs(resize) {
return [
converterFileName,
resize === undefined ? "undefined" : JSON.stringify(resize)
];
}
function writeBufferInChunks(writableStream, buffer) {
const asString = buffer.toString("base64");
const INCREMENT = 1024;
writableStream.cork();
for (let offset = 0; offset < asString.length; offset += INCREMENT) {
writableStream.write(asString.substring(offset, offset + INCREMENT));
}
writableStream.end("\n"); // so that the PhantomJS side can use readLine()
}
var args = [converterFileName, sourceFileName, destFileName, resize];
execFile(phantomjsCmd, args, function (err, stdout, stderr) {
if (err) {
cb(err);
} else if (stdout.length > 0) { // PhantomJS always outputs to stdout.
cb(new Error(stdout.toString().trim()));
} else if (stderr.length > 0) { // But hey something else might get to stderr.
cb(new Error(stderr.toString().trim()));
} else {
cb(null);
}
});
};
function processResult(result) {
const stdout = result.stdout.toString();
if (stdout.startsWith(PREFIX)) {
return new Buffer(stdout.substring(PREFIX.length), "base64");
}
if (stdout.length > 0) {
// PhantomJS always outputs to stdout.
throw new Error(stdout.replace(/\r/g, "").trim());
}
const stderr = result.stderr.toString();
if (stderr.length > 0) {
// But hey something else might get to stderr.
throw new Error(stderr.replace(/\r/g, "").trim());
}
throw new Error("No data received from the PhantomJS child process");
}
{
"name": "svg2png",
"description": "A SVG to PNG converter, using PhantomJS",
"version": "2.1.0",
"description": "Converts SVGs to PNGs, using PhantomJS",
"version": "3.0.0",
"author": "Domenic Denicola <d@domenic.me> (https://domenic.me)",

@@ -9,4 +9,6 @@ "license": "WTFPL",

"main": "lib/svg2png.js",
"bin": "bin/svg2png-cli.js",
"files": [
"lib/"
"lib/",
"bin/"
],

@@ -19,9 +21,14 @@ "scripts": {

"dependencies": {
"phantomjs": "^1.9.18"
"phantomjs": "^1.9.19",
"pn": "^1.0.0",
"yargs": "^3.31.0"
},
"devDependencies": {
"chai": "^3.4.1",
"chai-as-promised": "^5.2.0",
"jshint": "^2.8.0",
"mocha": "^2.3.3"
"mkdirp": "^0.5.1",
"mocha": "^2.3.4",
"rimraf": "^2.5.0"
}
}

@@ -6,30 +6,27 @@ # SVG-to-PNG Converter Using PhantomJS

```js
svg2png("source.svg", "dest.png", function (err) {
// PNGs for everyone!
});
const pn = require("pn"); // https://www.npmjs.com/package/pn
const svg2png = require("svg2png");
pn.readFile("source.svg")
.then(svg2png)
.then(buffer => fs.writeFile("dest.png", buffer))
.catch(e => console.error(e));
```
Maybe you need to scale the image while converting? We can do that too:
In the above example, we use the `width` and `height` attributes specified in the SVG file to automatically determine the size of the SVG. You can also explicitly set the size:
```js
svg2png("source.svg", "dest.png", 1.2, function (err) {
// 1.2×-sized PNGs for everyone!
});
svg2png(sourceBuffer, { width: 300, height: 400 })
.then(buffer => ...)
.catch(e => console.error(e));
```
The scale factor is relative to the SVG's `viewbox` or `width`/`height` attributes, for the record.
Maybe you need an image with exact dimensions:
This is especially useful for images without `width` or `height`s. You can even specify just one of them and (if the image has an appropriate `viewBox`) the other will be set to scale.
```js
svg2png("source.svg", "dest.png", { width: 200, height: 150 }, function (err) {
// 200x150 pixel sized PNGs for everyone!
});
```
## Sync variant
The image will be centered and zoomed to best-fit but not stretched. You can also provide just a single dimension and the other one will be inferred automatically:
There's also a sync variant, for use in your shell scripts:
```js
svg2png("source.svg", "dest.png", { width: 300 }, function (err) {
// 300 pixel-wide PNGs for everyone!
});
const outputBuffer = svg2png.sync(sourceBuffer, optionalWidthAndOrHeight);
```

@@ -39,15 +36,38 @@

svg2png is built on the latest in [PhantomJS][] technology to render your SVGs using a headless WebKit instance. I have
found this to produce much more accurate renderings than other solutions like GraphicsMagick or Inkscape. Plus, it's
easy to install cross-platform due to the excellent [phantomjs][package] npm package—you don't even need to have
PhantomJS in your `PATH`.
svg2png is built on the latest in [PhantomJS](http://phantomjs.org/) technology to render your SVGs using a headless WebKit instance. I have found this to produce much more accurate renderings than other solutions like GraphicsMagick or Inkscape. Plus, it's easy to install cross-platform due to the excellent [phantomjs](https://npmjs.org/package/phantomjs) npm package—you don't even need to have PhantomJS in your `PATH`.
[PhantomJS]: http://phantomjs.org/
[package]: https://npmjs.org/package/phantomjs
Rendering isn't perfect; we have a number of issues that are [blocked on PhantomJS](https://github.com/domenic/svg2png/labels/blocked%20on%20phantomjs) getting its act together and releasing a cross-platform version with updated WebKit.
## Exact resizing behavior
Previous versions of svg2png attempted to infer a good size based on the `width`, `height`, and `viewBox` attributes. As of our 3.0 release, we attempt to stick as close to the behavior of loading a SVG file in your browser as possible. The rules are:
- Any `width` or `height` attributes that are in percentages are ignored and do not count for the subsequent rules.
- The dimensions option `{ width, height }` overrides any `width` or `height` attributes in the SVG file, including for the subsequent rules. If a key is missing from the dimensions object (i.e. `{ width }` or `{ height }`) the corresponding attribute in the SVG file will be deleted.
- `with` and `height` attributes without a `viewBox` attribute cause the output to be of those dimensions; this might crop the image or expand it with empty space to the bottom and to the right.
- `width` and/or `height` attributes with a `viewBox` attribute cause the image to scale to those dimensions. If the ratio does not match the `viewBox`'s aspect ratio, the image will be expanded and centered with empty space in the extra dimensions. When a `viewBox` is present, one of either `width` or `height` can be omitted, with the missing one inferred from the `viewBox`'s aspect ratio.
- When there are neither `width` nor `height` attributes, the promise rejects.
One thing to note is that svg2png does not and cannot stretch your images to new aspect ratios.
## CLI
[@skyzyx][] made [a CLI version][] of this; you should go check it out if you're into using the command line.
This package comes with a CLI version as well; you can install it globally with `npm install svg2png -g`. Use it as follows:
[@skyzyx]: https://github.com/skyzyx
[a CLI version]: https://github.com/skyzyx/svg2png-cli
```
$ svg2png --help
Converts SVGs to PNGs, using PhantomJS
svg2png input.svg [--output=output.png] [--width=300] [--height=150]
Options:
-o, --output The output filename; if not provided, will be inferred [string]
-w, --width The output file width, in pixels [string]
-h, --height The output file height, in pixels [string]
--help Show help [boolean]
--version Show version number [boolean]
```
## Node.js requirements
svg2png uses the latest in ES2015 features, and as such requires a recent version of Node.js. Only the 5.x series is supported; anything lower than 5.0.0 which happens to work might break in any patch revision of svg2png and should not be used.
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc