When processing PDF documents in batches, you often need to add consistent page numbering to existing files. With Spire.PDF for Python, you can draw dynamic page numbers directly on the canvas of an existing PDF, without creating a separate PDF and merging it afterward.
This article demonstrates how to center page numbers in a PDF footer, with a focus on customizing the page number format —such as Page X or X / Y—and using coordinates to position them anywhere on the page, including the left, center, or right of the footer, or any location in the header.
Coordinate units: PDF coordinates are measured in points, where 1 point = 1/72 inch. The page coordinate system starts at the upper-left corner, with X increasing to the right and Y increasing downward.
Prerequisites
Install the required library:
pip install spire.pdf
Understanding the Two Dynamic Fields
Page numbering relies on two dynamic fields:
- PdfPageNumberField : Represents the current page number and resolves to the actual number when rendered.
- PdfPageCountField : Represents the total number of pages and resolves to the page count when rendered.
These fields are dynamic rather than hardcoded strings, allowing page numbering to reflect the document’s page count when rendered.
Control the Format with PdfCompositeField
PdfCompositeField combines a static text template with dynamic fields to produce a complete line of text. The template string determines the page number format , so changing the format only requires updating this string.
Basic syntax:
compositeField = PdfCompositeField(font, brush, "Template text", [field1, field2, ...])
Here, {0} refers to the first field in the list, {1} refers to the second field, and so on.
Complete Code: Centered Footer with “Page X of Y”
The following example uses the Page {0} of {1} format, centers the page numbers in the footer, and adds a separator line:
from spire.pdf.common import *
from spire.pdf import *
# Create a PdfDocument object
doc = PdfDocument()
# Load a local PDF file
doc.LoadFromFile("input.pdf")
# Define the font, brush, and pen
font = PdfTrueTypeFont("Arial", 14.0, PdfFontStyle.Regular, True)
brush = PdfBrushes.get_Black()
pen = PdfPen(brush, 1.0)
# Set margins
leftMargin = 54.0
rightMargin = 54.0
bottomMargin = 72.0
# Create fields for the current page number and total page count
pageNumberField = PdfPageNumberField()
pageCountField = PdfPageCountField()
# Combine the fields using an English page number template
compositeField = PdfCompositeField(
font, brush, "Page {0} of {1}", [pageNumberField, pageCountField]
)
# Iterate through all pages
for i in range(doc.Pages.Count):
page = doc.Pages.get_Item(i)
pageSize = page.Size
# Draw a separator line in the footer
page.Canvas.DrawLine(
pen,
leftMargin,
pageSize.Height - bottomMargin + 15.0,
pageSize.Width - rightMargin,
pageSize.Height - bottomMargin + 15.0
)
# Measure the page number text to calculate its centered position
text = "Page {} of {}".format(i + 1, doc.Pages.Count)
pageNumberSize = font.MeasureString(text)
# Set the page number position: horizontally centered
compositeField.Location = PointF(
(pageSize.Width - pageNumberSize.Width) / 2,
pageSize.Height - bottomMargin + 18.0
)
# Draw the page number
compositeField.Draw(page.Canvas, 0.0, 0.0)
# Save the new file
doc.SaveToFile("Output/CenterAlignedPageNumbers.pdf")
# Release resources
doc.Dispose()
Customize the Page Number Format
The page number format depends on the template string and the dynamic fields supplied. Below are several common formats. Replace the third argument of PdfCompositeField and adjust the field list as needed.
Format 1: Current Page Only — Page X
This format requires only the page number field:
compositeField = PdfCompositeField(
font, brush, "Page {0}", [pageNumberField])
Format 2: Compact Numeric Format — X / Y
compositeField = PdfCompositeField(
font, brush, "{0} / {1}", [pageNumberField, pageCountField])
Format 3: Current Page and Total Pages — Page X / Total Y Pages
compositeField = PdfCompositeField(
font, brush, "Page {0} / Total {1} Pages", [pageNumberField, pageCountField])
Format 4: Total Page Count Only — Total Y Pages
compositeField = PdfCompositeField(
font, brush, "Total {1} Pages", [pageNumberField, pageCountField])
Note: A field can be included in the list without appearing in the template; it simply will not be displayed. You can combine field placeholders in any order and customize surrounding text or separators, such as “Page,” “of,” “Total,” or “/,” to suit your layout.
Customize the Position with Coordinates
The page number position is controlled by compositeField.Location = PointF(x, y):
- Center:
x = (page width - text width) / 2 - Left:
x = leftMargin - Right:
x = pageSize.Width - pageNumberSize.Width - rightMargin - Vertical position: Adjust Y to move the text up or down. Smaller Y values move it toward the top of the page, allowing placement in the header.
The following example combines a custom format and position: a right-aligned footer using X / Y.
compositeField = PdfCompositeField(
font, brush, "{0} / {1}", [pageNumberField, pageCountField]
)
for i in range(doc.Pages.Count):
page = doc.Pages.get_Item(i)
pageSize = page.Size
text = "{} / {}".format(i + 1, doc.Pages.Count)
pageNumberSize = font.MeasureString(text)
# Right alignment: X = page width - text width - right margin
compositeField.Location = PointF(
pageSize.Width - pageNumberSize.Width - rightMargin,
pageSize.Height - bottomMargin + 18.0
)
compositeField.Draw(page.Canvas, 0.0, 0.0)
Things to Keep in Mind
- The example uses Arial. If it is unavailable in your environment, replace it with another installed font. For Chinese or other multilingual text, choose a font that supports the required characters.
- If page numbers overlap existing content, adjust their coordinates to place them in an unused area. The margin variables in these examples control drawing positions; they do not create additional blank space or reflow existing content.
Conclusion
This approach lets you customize the page number format and its position independently. Change the template string to switch between formats such as Page X, X / Y, and Page X of Y, then adjust the Location coordinates to place the text anywhere in the footer or header. This flexibility makes it useful for applying consistent page numbering when processing PDFs in batches.

Top comments (0)