能否让WeasyPrint自动适应纸张大小

5

我曾经在一家使用Prince XML生成HTML文档的PDF的组织工作。但是那个组织已经倒闭了,我不再拥有Prince许可证。由于我找不到四千美元的许可费用,因此我一直在尝试使用WeasyPrint将HTML发票呈现为PDF。我的HTML和CSS都非常简单,因此Weasy可以准确地呈现它们,只有一个问题。我无法像在Prince中使用的那样自动将页面缩小到纸张大小:

@page {
prince-shrink-to-fit:auto;
}

有人知道Weasy是否支持任何类似的命令吗?在重新制作整个站点的CSS以生成更小的文档之前,请先确认一下。

3个回答

4

2
这可能有助于您打印Pandas DataFrame。
from typing import Callable
import pandas as pd
import weasyprint as wp


def html_basic(df: pd.DataFrame) -> str:
    # Using df.style.render outputs an id in every cell,
    # whilst using df.to_html doesn't.
    return df.style.render()


def write_pdf_autofit(df: pd.DataFrame,
                      preamble: str,
                      fn_df_to_html: Callable[[pd.DataFrame], str]=html_basic
                      ) -> bytes:
    template = f"""<html><body>{preamble}{{table}}</body></html>"""

    # Render on a very long page so that there's no pagination.
    # Width doesn't matter, because overflow is allowed on width.
    mycss = wp.CSS(string=(
        "@page longpage {\n"
        "    size: 210mm 10000mm;\n"
        "}"
        "body {\n"
        "   page: longpage;\n"
        "}\n"
    ))

    # Create a copy of the dataframe with a dummy final column,
    # so that we can get the position of the left side of the
    # dummy column which is the right side of the final real column.
    # Then do a test render to find the positions of stuff.
    df_tmp = df.copy()
    df_tmp['x'] = np.nan
    test_html = template.format(table=fn_df_to_html(df_tmp))
    test_render = wp.HTML(string=test_html).render(stylesheets=[mycss])
    test_page1: wp.Page = test_render.pages[0]

    # I'm not sure why only need to subtract one margin,
    # but seems to work.
    printable_width = test_page1.width - test_page1._page_box.margin_left
    printable_height = 11.7 * 96 - test_page1._page_box.margin_top

    # All the cells in the html rendered DataFrame
    # have an id so are anchors, so just find the
    # max x and y from all the anchors.
    max_x, max_y = map(max, *test_page1.anchors.values())
    zoom_pct = 1
    if max_x > printable_width or max_y > printable_height:
        zoom_pct = min([printable_width / max_x,
                        printable_height / max_y])

    # Increase the page size to fit the table, then
    # we will zoom out the write_pdf to fit standard page size.
    # A4 = 210mm x 297mm
    mycss = wp.CSS(string=(
        "@page scaled {\n"
        f"    size: {210 / zoom_pct}mm {297 / zoom_pct}mm;\n"
        "}"
        "body {\n"
        "   page: scaled;\n"
        "}\n"
    ))

    html = template.format(table=fn_df_to_html(df))
    pdf_bytes = wp.HTML(string=html).write_pdf(zoom=zoom_pct,
                                               stylesheets=[mycss])
    return pdf_bytes


if __name__ == "__main__":
    import numpy as np
    DF = pd.DataFrame(np.random.randint(0, 100, size=(100, 4)), columns=list('ABCD'))
    with open(r'c:\temp\x.pdf', 'wb') as f:
        f.write(write_pdf_autofit(DF, ""))


1
这个问题是关于将HTML文档渲染成PDF,与Pandas无关。 - lxop

1
WeasyPrint目前不支持此类功能。Prince的文档对其确切作用的描述相当稀少。 "内容的宽度" 如何确定?如果有适当的功能规范,我可以告诉你将其添加到WeasyPrint有多困难。顺便说一句,我通常不会在StackOverflow上关注WeasyPrint问题。写信给WeasyPrint的邮件列表或问题跟踪器会得到更多回复。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接