使用Puppeteer生成文件时Pdf高度和宽度发生变化

时间:2018-07-27 01:35:10

标签: javascript node.js pdf puppeteer google-chrome-headless

我正在尝试从我的网站页面生成pdf。 为此,我有一个运行Puppeteer的快递服务器,它做一些事情: -当用户查看页面时,采用浏览器的宽度。 -调整Chrome无头浏览器的大小。 -计算页面的高度。 -将宽度/高度信息作为参数传递到page.pdf({})

我网站的某些页面在一页上呈现得很好。但是其他的确在两页上渲染,好像某些元素将内容的高度推到高于Puppeteer上javascript中计算的高度一样。

如果确实有帮助,我想我可以在代码await page.emulateMedia('screen');的开头使用此代码段遮住我的后背。

我检查了两个假设:  -使用调试控制台,我可以在调整页面大小时获得文档的实际高度。  -我检查了此信息是否已正确传递给Puppeteer。  -通过将其转换为像素,我检查了以英寸为单位的高度是否正确。

这三个假设是正确的。

这是我的木偶代码:

    const page = await browser.newPage();
    await page.emulateMedia('screen');

    // Resize window to the width it had when the client has seen it.
    async function resizeWindow(width, height) {
      await page.setViewport({height, width});

      // Window frame - probably OS and WM dependent.
      height += 85;

      // Any tab.
      const {targetInfos: [{targetId}]} = await browser._connection.send(
        'Target.getTargets'
      );

      // Tab window.
      const {windowId} = await browser._connection.send(
        'Browser.getWindowForTarget',
        {targetId}
      );

      // Resize.
      await browser._connection.send('Browser.setWindowBounds', {
        bounds: {height, width},
        windowId
      });
    }
    resizeWindow(parseInt(req.body.evidenceWidth), 0); // Use 0 as a default height because it is required, but not relevant.
    // Wait for page width to be actually changed
    await page.mainFrame().waitForFunction(`window.innerWidth === ${parseInt(req.body.evidenceWidth)}`);

    // Go to the page and wait for all the connection on the page to be resolved
    await page.goto(`${req.body.url}`, {waitUntil: 'networkidle0'});

    // Calculate real page height
    const realPageHeight = await page.evaluate(() => {
      const body = document.body,
            html = document.documentElement;
      const pageHeight = Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight );

      return pageHeight;
    });

    // Convert size from pixel to inches to avoid rounding issues caused by Puppeteer
    const convertPixelToInches = (value) => {
      let inches = Math.ceil(value/ 96 * 1000) / 1000;

      return `${parseFloat(inches).toFixed(3)}in`; // Calculate inches value and round it up.
    }
    const pageWidth = convertPixelToInches(req.body.evidenceWidth);
    const pageHeight = convertPixelToInches(realPageHeight < req.body.evidenceHeight ? req.body.evidenceHeight : realPageHeight);


    // Send the response
    switch(req.body.format) {
      case 'html':
        const html = await page.content();

        await fs.writeFile(join(__dirname, HTML_EVIDENCE_FD, `${uuid}.html`), html, (err) => {
          if (err) {
            console.error(`Evidence html could not be generated`, err);
          } else {
            res.status(200).sendFile(join(__dirname, HTML_EVIDENCE_FD, `${uuid}.html`));
          }
        });
        break;

      case 'pdf':
        await page.pdf({
          path: join(__dirname, PDF_EVIDENCE_FD, `${uuid}.pdf`),
          height: pageHeight,
          width: pageWidth,
          printBackground: true,
        });

        res.status(200).sendFile(join(__dirname, PDF_EVIDENCE_FD, `${uuid}.pdf`));
        break;

      default:
        res.status(501).send({ error: 'The format you chose is not supported'});
        break;
    }

    await page.close();
    await browser.close();
  });

  app.on("listening", function() {
    console.log("Listening on port %d", app.port);
  });
  return app;

还!我注意到另一个问题,比如说我有一个750px的断点,并且我将800px传递给了Puppeteer,我希望这个断点不会在我的pdf文件中出现。但是在pdf中完成的呈现就像页面宽度在断点以下一样。在pdf生成期间是否添加了一些不可见的边距?

1 个答案:

答案 0 :(得分:2)

因此,经过几天的搜索,我发现了问题所在:

  • 我将rem用于CSS中的字体大小和行高,因此我将其删除了 来之不易的要素。
  • 我没有重置CSS,因此在我的顶部添加了normalize.css 样式解决了我大部分的身高问题。
  • 即使使用normalize.css,Chrome仍在周围添加了rem填充 段落中,我添加了一个以像素为单位的值。