简体   繁体   中英

Convert a SVG to a PNG/JPEG without using canvas in a serverless function

I have a serverless function which returns a SVG based on a text sent as a query parameter.

module.exports = (req, res) => {
  const { yourName } = req.query;

  res.setHeader("Content-Type", "image/svg+xml");

  const svg = `
    <svg fill="none" viewBox="0 0 600 400" width="600" height="400" xmlns="http://www.w3.org/2000/svg">
      <foreignObject width="100%" height="100%">
        <div xmlns="http://www.w3.org/1999/xhtml">
          <style>
            .title {
              font-size: 10vh;
              font-weight: regular;
              background-color: #ffddff;
            }
          </style>
            
          <p class="title">Hello ${yourName}</p> 
          
        </div>
      </foreignObject>
    </svg>
  `;

  res.send(svg);

};

As an example, when I call /api?yourName=world , it returns me the following SVG;

hello world 由无服务器 api 提供

(Deployed URL: https://vercel-test-ruddy.vercel.app/api?world )

What I need?

I need to return the SVG as an image (PNG/JPEG). So, the my function would look like,

module.exports = (req, res) => {
  const { yourName } = req.query;

  res.setHeader("Content-Type", "image/png");

  const svg = `
    <svg fill="none" viewBox="0 0 600 400" width="600" height="400" xmlns="http://www.w3.org/2000/svg">
      <foreignObject width="100%" height="100%">
        <div xmlns="http://www.w3.org/1999/xhtml">
          <style>
            .title {
              font-size: 10vh;
              font-weight: regular;
              background-color: #ffddff;
            }
          </style>
            
          <p class="title">Hello ${yourName}</p> 
          
        </div>
      </foreignObject>
    </svg>
  `;

  res.send( svgToPng(svg) );

};

svgToPng = (svg) => {
   // not defined
}

Did I refer other SO questions?

Yes. There are few questions regarding converting SVG to PNG:

Convert SVG to image (JPEG, PNG, etc.) in the browser
How to Exporting SVG as PNG format

Almost every answer talks about converting SVG to canvas and then canvas to PNG. And also answers are much older too. Can we do it without using a canvas?

In my project I actually don't have a html document , I have only one single .js file (As I know we need HTML5 to use canvas).

Notes

I have used using Vercel to deploy my serverless function which is;

Deployed at: https://vercel-test-ruddy.vercel.app/api?yourName=YOUR_NAME_HERE
GitRepo: https://github.com/tharindusathis/vercel-test

The best way to deal with this that I have found so far is by using a headless chrome and getting a screenshot. As an example by using puppeteer I could get a screenshot of the viewport like follows,

const browser = await puppeteer.launch();
const page = await browser.newPage();

let yourName = 'world'

const svg = `
    <svg fill="none" viewBox="0 0 600 400" width="600" height="400" xmlns="http://www.w3.org/2000/svg">
      <foreignObject width="100%" height="100%">
        <div xmlns="http://www.w3.org/1999/xhtml">
          <style>
            .title {
              font-size: 10vh;
              font-weight: regular;
              background-color: #ffddff;
            }
          </style>
            
          <p class="title">Hello ${yourName}</p> 
          
        </div>
      </foreignObject>
    </svg>
  `;

await page.setViewport({ width: 2048, height: 1170 });
await page.setContent(svg);

console.log(await page.content());
await page.screenshot({path: 'screenshot.png'});
await browser.close();

Then it will be easy to send the png as the response.

Looks like your deconstructing your query param, in which case its searching for that specific object property within the query.

It should work if you explicitly use yourName as query param.

https://vercel-test-ruddy.vercel.app/api?yourName=world

or don't decouple the req.query object property.

 <iframe src="https://vercel-test-ruddy.vercel.app/api?yourName=world" width="450px" height="450px">

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM