为什么 PDFKit 不能很好地处理边距?

Why PDFKit doesn't work well with margins?

虽然我只是不需要正常询问一些事情(互联网只是一个金矿,尤其是这个网站),这让我失望了,因为我已经花了两天时间试图让它工作而且我找不到任何有用的东西。 Link 对于类似的 post 如果发现的话将不胜感激,因为我没有找到。让我们开始吧。


我将 PDFKit 与 Python 2.7 和 Django 1.9 一起使用来生成一些 HTML 到 PDF。轻松的工作。 HTML 看起来像这样:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <style type="text/css">
    * {
      /* Box-model */
      margin: 0;
      padding: 0;
    }

    .wrapper {
      /* Box-model */
      width: 229mm;
      height: 161mm;
    }
  </style>
</head>
<body>
  {% for someone in people %}
  <div class="wrapper">
    <p><strong>{{ someone.complete_name }}</strong></p>
    <p>{{ someone.bio }}</p>
  </div>
  {% endfor %}
</body>
</html>

我的 PDFKit 选项如下所示:

{
    "page-width": "229mm",
    "page-height": "162mm",
    "paper-size": "CE5",
    "encoding": "utf-8"
}

在这两种情况下,我只是不添加任何边距或填充。我生成了 PDF,看起来很棒(毫不奇怪,一切都在它所属的地方)。 但是,如果我在 HTML and/or 选项中添加任何 margin/padding,我只会在生成 PDF 时得到一个持续的重复增量边距(举个例子,在 50 页中,第一个一个没有边距,第 50 个大约有两个手指的边距)。我尝试了边距、边距和高度的不同组合,但什么也没有:当我只添加边距或边距时,PDF 会变得很乱。

(注意:是的,page-height 比 HTML 中的 height 大 1mm,但这是必需的包装适合 PDF 页面)。

有人遇到过这个问题吗?提前致谢。

好的,我终于明白发生了什么:

假设我要打印 A4 尺寸的纸张(您有一个列表 here)。因此,将其转换为 px(因为设置 cmmm 比手动计算像素更容易),我们得到 1 mm = 3.779528 px。我们设置 CSS height: Xmm。简单。

据我所知,当 PDFKit 使用 WebKit 时出现问题,呈现 HTML:WebKit 只有 3 位小数精度点值,所以我们的 3.779528 pass 为 3.779(如果我记得的话,它会向下舍入),这不是实际大小。所以这意味着添加任何类型的 margin/padding/positioning 都会破坏事物并产生神奇的间距,因为长度不正确(即使你对这些使用相同的尺寸单位)。

好消息是不设置任何 margin/padding/positioning 不会破坏东西,所以在某些方面它已经足够好了。

但是,如果您需要添加边距或类似内容怎么办? CSS 的 page-break 属性(链接的是 page-break-after)来拯救。它确保在打印 HTML(通过渲染,通过网络浏览器)时没有设置任何魔法间距。

考虑到这一点,例如:

<!DOCTYPE html>
<html>
<head>
  <style type="text/css">
    * {
      /* Box-model */
      /* To ensure no unexpected magic spacing */
      margin: 0;
      padding: 0;
    }

    .wrapper {
      /* Box-model */
      width: 197mm; /* + 100 from horizontal padding = 297 */ 
      height: 160mm; /* + 50 from vertical padding = 210 */
      padding: 25mm 50mm;
    }

    /* The selector applies the page break after, so we have to exclude the last wrapper */
    .wrapper:not(:last-of-type) {
      /* Box-model */
      page-break-after: always;
    }
  </style>
</head>
<body>
  {% for someone in people %}
  <div class="wrapper">
    <p><strong>{{ someone.complete_name }}</strong></p>
    <p>{{ someone.bio }}</p>
  </div>
  {% endfor %}
</body>
</html>

瞧,您有一个非常适合呈现 PDF 数据的模板,没有神奇的间距。您只需确保用于 "representing" 页面(本例中为 wrapper)的元素与页面的尺寸相同。

您还可以移除 PDF 默认边距

import pdfkit 

# Remove PDF margin options = {
    'page-size': 'Letter',
    'margin-top': '0.0in',
    'margin-right': '0.0in',
    'margin-bottom': '0.0in',
    'margin-left': '0.0in' }

pdfkit.from_url('https://www.google.co.in/','shaurya.pdf', options = options)