使用 QPrinter 和 Jinja2 生成带有图像的 pdf

Generating pdf with images using QPrinter and Jinja2

我一直在尝试生成包含图像的 PDF,但图像不显示。我已经关注了这个 guide.

指南下方有一条评论说我应该使用 app.processEvents() 来包含其他资源。

我还发现 loadFinished.connect 在我调用打印之前等待 html 加载,但我似乎无法让它工作。

这是我的代码:

class Window(QtGui.QMainWindow):
    ........
    btn1.clicked.connect(self.tohtml)
    def tohtml(self):
        # Random 2D list
        table = [[random.randint(0, 100) for j in range(10)] for i in range(10)]

        # Some Lorem Ipsum text
        paragraphs = [p[2] for p in generate_paragraphs(3)]

        self.html = render_template("test.html", table=table, paragraphs=paragraphs)
        self.topdf(self.html, "file.pdf")

    def topdf(self, html, destination):
        self.web = QWebView()
        self.web.setHtml(html)
        self.printer = QPrinter(QPrinterInfo.defaultPrinter(),QPrinter.HighResolution)
        self.printer.setPageSize(QPrinter.A4)
        self.printer.setOutputFormat(QPrinter.PdfFormat)
        self.printer.setOutputFileName(destination)  
        self.web.loadFinished.connect(self.print_pdf)

    def print_pdf (self):
        self.web.print_(self.printer)

这是我的测试html:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>

    <style>
        .centered {
            text-align: center;
        }

        .underlined {
             text-decoration: underline;
        }

        .datatable {
            width: 100%;
            border-collapse: collapse;
        }

        .datatable td {
            margin: 0px;
            border: 1px solid #000;
            text-align: right;
    }
</style>

</head>
    <body>
         <img src="IDSLOGO.jpg"/>
    </body>
</html>

任何帮助或指导将不胜感激。

首先归功于 github 的 adewes 毕竟这是他的代码

这是我的理解,至少解决了我的问题(在code_byter的帮助下)

我的模板没有任何问题,原因是缺少详细信息告诉 QWebView 我的图片在哪里添加

url = QUrl.fromLocalFile(media_path) 然后

web.setHtml(html,baseUrl = url)

现在 QWebview 为我看到图像并准备渲染它以及我来自 jinja2 的 html 字符串 最后 app.processEvents() 循环事件(渲染和获取资源)等待 QWebview 或事件完成,然后继续,因为 QWebView returns 立即不等待所有内容渲染。

代码如下:

jinja_env  = Environment(loader=FileSystemLoader("templates"))
def generate_pdf(template, filename, media_path=None, template_context=None):
    global app

    if template_context is None:
        template_context = {}                   #this is a dictionary
    template_context['media_path'] = media_path 
    #adds your os.path.abspath('your_absolute_dir_to_images') to the context dict, in the examples's case it's media

    template_path = '{0}.html'.format(template) #adds .html extension to a string ('your_template_name' + '.html')
    template = jinja_env.get_template(template_path) #gets and loads the template (your_template_name.html)
    html = template.render(**template_context)       #this executes the {{}} and {%%} inside your template
    app = QApplication.instance()
    if app is None:                                  #prevents a crash
        app = QApplication(['--platform','minimal'])
    web = QWebView()                                  #next step after setting up the jinja part is passing the generated html to WebView
    url = QUrl.fromLocalFile(media_path)              #this stores a command telling webview that this is the dir where the picture is or resources
    web.setHtml(html,baseUrl = url)                   #sets your template or html to be read and the resource location
    app.processEvents()                               #this loops through the events in QApplication and waits for webview to be finished rendering the html
    printer = QPrinter()                              #after webview renders the html this part will now execute. It's pretty straightforward
    printer.setPageSize(QPrinter.A4)
    printer.setOutputFormat(QPrinter.PdfFormat)
    printer.setOutputFileName(filename)
    web.print_(printer)                               #now prints a pdf with image yay

你可能不需要这里的一些代码来将它集成到你自己的代码中,但我会使用它,因为你基本上可以复制和粘贴它并且它会起作用(如果你有依赖项)不要如果您觉得这有用,请忘记感谢 adewes,如果我理解有误,请随时进行编辑。

编辑: 忘了说我的 html 标签看起来像这样 <img src="{{media_path}}/my_pic.png" /> 它也可能看起来像这样 <img src="file://{{media_path}}/my_pic.png" /> 但后者对我不起作用。