如何让PDF输出看起来与HTML输出完全相同

时间:2018-02-17 21:02:00

标签: html django pdf

我正在尝试为我的客户创建一个PDF来开始为他们的客户开具发票。我曾经处理过创建PDF的问题,并且记住创建它们是一件巨大的痛苦。在我的Django应用程序中,我有两个视图函数,一个只是渲染我用来设计发票的模板,另一个将它转换为pdf并渲染PDF。我有两个并排打开的标签,指向每个版本模板HTML与PDF,它们看起来完全不同。是否有一种特殊的标记语言我必须使用它来创建PDF,或者它们是一个python包,它将HTML转换为PDF中该HTML的精确副本?

查看功能

from django.shortcuts import render, HttpResponse
from django.template.loader import get_template

from io import BytesIO
from xhtml2pdf import pisa


def generate_pdf(template_src, context_dict={}):
    template = get_template(template_src)
    html = template.render({})
    result = BytesIO()
    pdf = pisa.pisaDocument(BytesIO(html.encode("ISO-8859-1")), result)
    if not pdf.err:
        return HttpResponse(result.getvalue(), content_type='application/pdf')
    return None

def ronin(request):
    template = get_template('ronin.html')
    context = {}
    html = template.render(context)
    pdf = generate_pdf('ronin.html', context)
    if pdf:
        response = HttpResponse(pdf, content_type='application/pdf')
        filename = "Invoice_%s.pdf" % ("12341231")
        content = "inline; filename='%s'" % (filename)
        download = request.GET.get("download")
        if download:
            content = "attachment; filename='%s'" % (filename)
        response['Content-Disposition'] = content
        return response
    return HttpResponse("Not found")

def ronin_html(request):
    template = 'ronin.html'
    context = {}

    return render(request, template, context)

HTML

<!DOCTYPE html>
<html>

<head></head>

<body style="margin: 0;">

<style>
    #invoice-template {
        padding: 100px 100px 50px 100px
    }

    table {
        border-collapse: collapse;
    }

    table#main {
        border-bottom: 1px solid darkgray; width: 100%;
    }

    td.header.first {
        border-bottom: 1px solid darkgray;
        border-right: 1px solid darkgray;
        padding: 1% 4%;
        width: 20%;
    }

    td.header.second {
        padding: 0;
        vertical-align: top;
    }

    td.header.second .contact-details td {
        padding: 15px;
    }

    td.header.second .address td {
        padding: 15px;
    }

    td.header.second p {
        margin: 0;
    }
</style>

<div id="invoice-template">

    <table id="main" cellspacing="0">
        <tr>
            <td class="header first">
                <img src="/static/images/logo_dark.png" alt="">
            </td>
            <td class="header second">
                <table>
                    <tr class="address">
                        <td>
                            <p>ADDRESS</p>
                            <p>ADDRESS EXAMPLE St. CITY, STATE 11111</p>
                        </td>
                    </tr>
                    <tr class="contact-details">
                        <td>
                            <p>PHONE</p>
                            <p>+1 111 222 3333</p>
                        </td>
                        <td>
                            <p>WEBSITE</p>
                            <p>Website.com</p>
                        </td>
                        <td>
                            <p>FOCUS</p>
                            <p>WEBSITES / MOBILE APPS</p>
                        </td>
                    </tr>
                </table>
            </td>
        </tr>
    </table>

</div>

HTML视图 enter image description here

PDF视图 enter image description here

1 个答案:

答案 0 :(得分:1)

您可能会遇到大多数HTML到PDF库的渲染问题,特别是如果他们使用WebKit作为引擎。我推荐使用Puppeteer的组合(用于创建页面的无头chrome实例并截取屏幕截图,这将是页面的真正1:1复制品)和PDFKit来获取这些图像并将它们附加到pdf文件。

当然,这取决于您知道发票不会比完整的PDF页面大,或者如果它们是,您需要知道如何将内容分成单独的页面。

如果您真的想要PDF格式的1:1复制品,那些难题需要解决。

否则,我建议使用像wkhtmltopdf这样的东西来获得相当不错的近似值。