如何将我的动画 SVG 转换为 GIF

问题描述 投票:0回答:1
  • 我目前没有找到任何可行的解决方案,

  • 我可以用木偶师和

    ffmpge
    来完成,但这需要时间和 也没有得到我想要的解决方案。

目前此方法通过 puppeteer 在浏览器中启动

svg
,然后以 png 格式拍摄快照,然后将这些 png 组合起来并制作 gif 但这个过程是资源密集型的,而且也没有得到我想要的解决方案

这是我目前的方法,它有效但不可行


let fs = require("fs");
let child_process = require("child_process");
const { exec } = require("child_process");

let puppeteer = require("puppeteer");

const usage = "usage: node index.js <svgPath> <duration> <fps> <outDir>";
const imgExtention = "png";
const imgType = "png";

async function main() {
  let [svgPath, duration, fps, outDir] = process.argv;

  svgPath = "react-flow-canvas.svg";
  duration = 4;
  fps = 10;
  outDir = "output";
  if (outDir === undefined) {
    console.error("outDir is not defined");
    console.log(usage);
    process.exit(2);
  }
  const svg = fs.readFileSync(svgPath, "utf-8");

  duration = parseFloat(duration);
  fps = parseInt(fps);
  console.log("duration: " + duration + " s, fps: " + fps);
  const totalFrames = Math.floor(fps * duration);
  const digits = Math.floor(Math.log10(totalFrames)) + 1;
  console.log("totalFrames: " + totalFrames);

  process.chdir(outDir);
  await createFrames(svg, fps, totalFrames, digits);
  convertToMP4(fps, totalFrames, digits);
}

async function createFrames(svg, fps, totalFrames, digits) {
  svg = svg.replace("--play-state: running;", "--play-state: paused;");

  let browser = await puppeteer.launch({
    headless: true,
    args: ["--no-sandbox", "--font-render-hinting=none"],
  });

  let page = await browser.newPage();
  await page.goto("about:blank");
  await page.setContent(svg);

  let renderSettings = {
    type: imgType,
    omitBackground: false,
  };

  console.log("creating frames");
  for (let i = 1; i <= totalFrames; ++i) {
    let result = await page.evaluate(function (startVal) {
      document
        .getElementsByTagName("svg")[0]
        .style.setProperty("--start", startVal);
    }, "" + (i - 1) / fps + "s");

    await page.waitForTimeout(1);

    let outputElem = await page.$("svg");
    let prefix = ("" + i).padStart(digits, "0");
    renderSettings.path = prefix + "." + imgExtention;
    await outputElem.screenshot(renderSettings);
    if (i % fps === 0 || i === totalFrames) {
      console.log("progress: " + prefix + " / " + totalFrames);
    }
  }

  await browser.close();
  return totalFrames, digits;
}

function convertToMP4(fps, totalFrames, digits) {
  console.log("running ffmpeg");
  let output = child_process.execFileSync(
    "ffmpeg",
    [
      "-hide_banner",
      "-loglevel",
      "warning",
      "-y",
      "-framerate",
      "" + fps,
      "-i",
      "%0" + digits + "d." + imgExtention,
      "-c:v",
      "libx264",
      "-vf",
      "fps=" + fps,
      "-pix_fmt",
      "yuv420p",
      "output.mp4",
    ],
    { encoding: "utf8" }
  );
  console.log(output);

  exec("ffmpeg -i output.mp4 -qscale 200 output.gif");
}

main();

请帮助我以有效的方式做到这一点

node.js svg image-processing animated-gif svg-animate
1个回答
0
投票

我对此有更好的解决方案

const puppeteer = require("puppeteer");
const { PuppeteerScreenRecorder } = require("puppeteer-screen-recorder");
const util = require("util");
const exec = util.promisify(require("child_process").exec);
let fs = require("fs");

const wait = (ms) => new Promise((res) => setTimeout(res, ms));

(async () => {
  const browser = await puppeteer.launch({
    headless: false,
    args: ["--no-sandbox", "--font-render-hinting=none"],
  });
  try {
    const page = await browser.newPage();
    await page.setViewport({
      width: 1920,
      height: 1080,
      deviceScaleFactor: 3,
    });
    const svg = fs.readFileSync("react-flow-canvas.svg", "utf-8");
    // await page.goto("about:blank");
    await page.setContent(svg);
    const Config = {
      fps: 25,
    };

    const recorder = new PuppeteerScreenRecorder(page, Config);

    // await page.goto("https://tailwindcss.com/");

    await recorder.start("video.mp4");
    await wait(1700);
    // await page.waitForTimeout(1);
    await recorder.stop();

    await exec("ffmpeg -i video.mp4 -qscale 0 animated.gif");
  } catch (e) {
    console.log(e);
  } finally {
    await browser.close();
  }
})();
© www.soinside.com 2019 - 2024. All rights reserved.