在无服务器功能中不使用画布的情况下将SVG转换为PNG / JPEG

时间:2020-09-13 14:06:58

标签: javascript svg canvas serverless vercel

我有一个无服务器功能,该功能基于作为查询参数发送的文本返回SVG。

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);

};

例如,当我调用/api?yourName=world时,它将返回以下SVG;

hello world by a serveless api

(部署的URL:https://vercel-test-ruddy.vercel.app/api?world

我需要什么?

我需要将SVG作为图像(PNG / JPEG)返回。 所以,我的函数看起来像

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
}

我还有其他问题吗?

是的。关于将SVG转换为PNG的问题很少:

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

几乎每个答案都谈到将SVG转换为画布,然后再将画布转换为PNG。而且答案也要老得多。我们可以不使用画布就能做到吗?

在我的项目中,我实际上没有html document,只有一个.js文件(据我所知,我们需要HTML5才能使用画布)。

注释

我曾经使用Vercel来部署我的无服务器功能;

部署在:https://vercel-test-ruddy.vercel.app/api?yourName=YOUR_NAME_HERE
GitRepo:https://github.com/tharindusathis/vercel-test

2 个答案:

答案 0 :(得分:1)

到目前为止,我发现的最好的处理方法是使用无头 chrome 并获取屏幕截图。作为使用 puppeteer 的示例,我可以获得如下所示的视口屏幕截图,

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();

然后很容易发送 png 作为响应。

答案 1 :(得分:0)

就像您在解构查询参数一样,在这种情况下,它会在查询中搜索特定的对象属性。

如果您明确地将yourName用作查询参数,它应该可以工作。

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

或不要解耦req.query对象属性。

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