使用 ReportLab 显示页数

发布于 2024-07-15 02:52:15 字数 305 浏览 5 评论 0原文

我正在尝试将一个简单的“第 x 页,共 y 页”添加到使用 ReportLab 制作的报告中。我发现 这篇关于它的旧文章,但也许六年后出现了更直接的东西? ^^;
我也找到了这个食谱,但是当我使用它时,生成的PDF缺少图像。 。

I'm trying to add a simple "page x of y" to a report made with ReportLab.. I found this old post about it, but maybe six years later something more straightforward has emerged? ^^;
I found this recipe too, but when I use it, the resulting PDF is missing the images..

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

下雨或天晴 2024-07-22 02:52:15

我能够从 ActiveState 实现 NumberedCanvas 方法。 这很容易做到,并且没有改变我现有的代码。 我所要做的就是添加 NumberedCanvas 类并在构建文档时添加 canvasmaker 属性。 我还更改了“x of y”显示位置的测量值:

self.doc.build(pdf)

成为

self.doc.build(pdf, canvasmaker=NumberedCanvas) 

doc 是 BaseDocTemplate,pdf 是我的可流动元素列表。

I was able to implement the NumberedCanvas approach from ActiveState. It was very easy to do and did not change much of my existing code. All I had to do was add that NumberedCanvas class and add the canvasmaker attribute when building my doc. I also changed the measurements of where the "x of y" was displayed:

self.doc.build(pdf)

became

self.doc.build(pdf, canvasmaker=NumberedCanvas) 

doc is a BaseDocTemplate and pdf is my list of flowable elements.

无所的.畏惧 2024-07-22 02:52:15

使用 doc.multiBuild

并在页面标题方法中(由“onLaterPages=”定义):

global TOTALPAGES
if doc.page > TOTALPAGES:
    TOTALPAGES = doc.page
else:
    canvas.drawString(270 * mm, 5 * mm, "Seite %d/%d" % (doc.page,TOTALPAGES))

use doc.multiBuild

and in the page header method (defined by "onLaterPages="):

global TOTALPAGES
if doc.page > TOTALPAGES:
    TOTALPAGES = doc.page
else:
    canvas.drawString(270 * mm, 5 * mm, "Seite %d/%d" % (doc.page,TOTALPAGES))
离鸿 2024-07-22 02:52:15

只是为您挖掘一些代码,我们使用以下代码:

SimpleDocTemplate(...).build(self.story,
                             onFirstPage=self._on_page,
                             onLaterPages=self._on_page)

现在 self._on_page 是为每个页面调用的方法,如下所示:

def _on_page(self, canvas, doc):
    # ... do any additional page formatting here for each page
    print doc.page

Just digging up some code for you, we use this:

SimpleDocTemplate(...).build(self.story,
                             onFirstPage=self._on_page,
                             onLaterPages=self._on_page)

Now self._on_page is a method that gets called for each page like:

def _on_page(self, canvas, doc):
    # ... do any additional page formatting here for each page
    print doc.page
萌面超妹 2024-07-22 02:52:15

我想出了一个针对鸭嘴兽的解决方案,它更容易理解(至少我认为是)。 您可以手动执行两次构建。 在第一个版本中,您可以存储总页数。 在第二个构建中,您已经提前知道了。 我认为它更容易使用和理解,因为它适用于鸭嘴兽级别的事件处理程序,而不是画布级别的事件。

import copy
import io

from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.lib.units import inch

styles = getSampleStyleSheet()

Title = "Hello world"
pageinfo = "platypus example"

total_pages = 0


def on_page(canvas, doc: SimpleDocTemplate):
    global total_pages
    total_pages = max(total_pages, doc.page)
    canvas.saveState()
    canvas.setFont('Times-Roman', 9)
    canvas.drawString(inch, 0.75 * inch, "Page %d %s" % (doc.page, total_pages))
    canvas.restoreState()


Story = [Spacer(1, 2 * inch)]
style = styles["Normal"]
for i in range(100):
    bogustext = ("This is Paragraph number %s. " % i) * 20
    p = Paragraph(bogustext, style)
    Story.append(p)
    Story.append(Spacer(1, 0.2 * inch))

# You MUST use a deep copy of the story!
# https://mail.python.org/pipermail/python-list/2022-March/905728.html

# First pass
with io.BytesIO() as out:
    doc = SimpleDocTemplate(out)
    doc.build(copy.deepcopy(Story), onFirstPage=on_page, onLaterPages=on_page)
# Second pass
with open("test.pdf", "wb+") as out:
    doc = SimpleDocTemplate(out)
    doc.build(copy.deepcopy(Story), onFirstPage=on_page, onLaterPages=on_page)

您只需要确保始终渲染原始故事的深层副本即可。 否则就行不通。 (您将得到一个空页面作为输出,或者一个渲染错误,告诉您 Flowable 不适合框架。)

I came up with a solution for platypus, that is easier to understand (at least I think it is). You can manually do two builds. In the first build, you can store the total number of pages. In the second build, you already know it in advance. I think it is easier to use and understand, because it works with platypus level event handlers, instead of canvas level events.

import copy
import io

from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.lib.units import inch

styles = getSampleStyleSheet()

Title = "Hello world"
pageinfo = "platypus example"

total_pages = 0


def on_page(canvas, doc: SimpleDocTemplate):
    global total_pages
    total_pages = max(total_pages, doc.page)
    canvas.saveState()
    canvas.setFont('Times-Roman', 9)
    canvas.drawString(inch, 0.75 * inch, "Page %d %s" % (doc.page, total_pages))
    canvas.restoreState()


Story = [Spacer(1, 2 * inch)]
style = styles["Normal"]
for i in range(100):
    bogustext = ("This is Paragraph number %s. " % i) * 20
    p = Paragraph(bogustext, style)
    Story.append(p)
    Story.append(Spacer(1, 0.2 * inch))

# You MUST use a deep copy of the story!
# https://mail.python.org/pipermail/python-list/2022-March/905728.html

# First pass
with io.BytesIO() as out:
    doc = SimpleDocTemplate(out)
    doc.build(copy.deepcopy(Story), onFirstPage=on_page, onLaterPages=on_page)
# Second pass
with open("test.pdf", "wb+") as out:
    doc = SimpleDocTemplate(out)
    doc.build(copy.deepcopy(Story), onFirstPage=on_page, onLaterPages=on_page)

You just need to make sure that you always render a deep copy of your original story. Otherwise it won't work. (You will either get an empty page as the output, or a render error telling that a Flowable doesn't fit in the frame.)

晨敛清荷 2024-07-22 02:52:15

我对结构进行了深度复制,因此在第一次构建后它仍然可用。 然后我获取文档中的总页数并将其保存在参数 pdf.final_pages 中。 在第二个版本中,我使用此参数在文档标题中打印正确的页码:

import copy
    
    
class CustomDocTemplate(SimpleDocTemplate):
    def __init__(self, filename, version, **kwargs):
            super().__init__(filename, **kwargs)
            self.pagesize = A4
            self.width, self.height = A4
            self.leftMargin = kwargs.get('leftMargin', 2 * cm)
            self.rightMargin = kwargs.get('rightMargin', 2 * cm)
            self.topMargin = kwargs.get('topMargin', 2.5 * cm)
            self.bottomMargin = kwargs.get('bottomMargin', 1.5 * cm)        
            self.final_pages = 0
            self.total_pages = 0

    frame = Frame(self.leftMargin,
                      self.bottomMargin,
                      self.width - self.leftMargin - self.rightMargin,
                      self.height - self.topMargin - self.bottomMargin - self.HEADER_HEIGHT,
                      id='normal')
    template = PageTemplate(id='header_footer', frames=frame, onPage=self.draw_header_footer)
        self.addPageTemplates([template])

    def draw_header_footer(self, canvas, doc):
            canvas.saveState()`enter code here`
            self.draw_header(canvas, doc)
            canvas.restoreState()

    def draw_header(self, canvas, doc):
            header = Drawing(550, self.HEADER_HEIGHT)
        
            page_number_text = f'Page {doc.page} of {self.final_pages}'
            header.add(String(157, 6, page_number_text, fontSize=9, fontName="DejaVuSans"))

            renderPDF.draw(header, canvas, doc.leftMargin, doc.height + doc.topMargin - self.HEADER_HEIGHT)
    
    
    def afterPage(self):
            self.total_pages += 1  # Increment page count after each page is built
            super().afterPage()  # Call the superclass method
    
        
pdf = CustomDocTemplate('sample.pdf',
            pagesize=A4,
            leftMargin=2 * cm,
            rightMargin=2 * cm,
            bottomMargin=2 * cm,
            topMargin=3 * cm,
                        )
        
structure = []
            
structure.append(Spacer(1, 0.5 * cm))
text1 = Paragraph(f'№ 2/15.07.2024')
structure.append(text1)

# First phase       
pdf.build(copy.deepcopy(structure), onFirstPage=pdf.draw_header_footer, onLaterPages=pdf.draw_header_footer)

pdf.final_pages = pdf.total_pages
# Second phase 
pdf.build(copy.deepcopy(structure), onFirstPage=pdf.draw_header_footer, onLaterPages=pdf.draw_header_footer)

I make a deep copy of the structure, so it is still available after the first build. Then I get the total number of the pages in the document and save it in parameter pdf.final_pages. In second build I use this parameter to print the correct pages number in the header of the document:

import copy
    
    
class CustomDocTemplate(SimpleDocTemplate):
    def __init__(self, filename, version, **kwargs):
            super().__init__(filename, **kwargs)
            self.pagesize = A4
            self.width, self.height = A4
            self.leftMargin = kwargs.get('leftMargin', 2 * cm)
            self.rightMargin = kwargs.get('rightMargin', 2 * cm)
            self.topMargin = kwargs.get('topMargin', 2.5 * cm)
            self.bottomMargin = kwargs.get('bottomMargin', 1.5 * cm)        
            self.final_pages = 0
            self.total_pages = 0

    frame = Frame(self.leftMargin,
                      self.bottomMargin,
                      self.width - self.leftMargin - self.rightMargin,
                      self.height - self.topMargin - self.bottomMargin - self.HEADER_HEIGHT,
                      id='normal')
    template = PageTemplate(id='header_footer', frames=frame, onPage=self.draw_header_footer)
        self.addPageTemplates([template])

    def draw_header_footer(self, canvas, doc):
            canvas.saveState()`enter code here`
            self.draw_header(canvas, doc)
            canvas.restoreState()

    def draw_header(self, canvas, doc):
            header = Drawing(550, self.HEADER_HEIGHT)
        
            page_number_text = f'Page {doc.page} of {self.final_pages}'
            header.add(String(157, 6, page_number_text, fontSize=9, fontName="DejaVuSans"))

            renderPDF.draw(header, canvas, doc.leftMargin, doc.height + doc.topMargin - self.HEADER_HEIGHT)
    
    
    def afterPage(self):
            self.total_pages += 1  # Increment page count after each page is built
            super().afterPage()  # Call the superclass method
    
        
pdf = CustomDocTemplate('sample.pdf',
            pagesize=A4,
            leftMargin=2 * cm,
            rightMargin=2 * cm,
            bottomMargin=2 * cm,
            topMargin=3 * cm,
                        )
        
structure = []
            
structure.append(Spacer(1, 0.5 * cm))
text1 = Paragraph(f'№ 2/15.07.2024')
structure.append(text1)

# First phase       
pdf.build(copy.deepcopy(structure), onFirstPage=pdf.draw_header_footer, onLaterPages=pdf.draw_header_footer)

pdf.final_pages = pdf.total_pages
# Second phase 
pdf.build(copy.deepcopy(structure), onFirstPage=pdf.draw_header_footer, onLaterPages=pdf.draw_header_footer)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文