Here is my answer which uses Matplotlib PDF backend to generate a PDF w/ just page numbers and PyPDF2 to merge the "footer" PDF w/ the desired PDF:
def add_header_footer(source_path, save_path, footer_pdf_path=None, start_page=0, header_text=None):
''' Adds header & footer info to existing PDFs '''
footer_pdf_path = os.path.join(os.path.dirname(source_path), 'footer.pdf')
reader = PdfReader(source_path)
writer = PdfWriter()
n_pages = len(reader.pages)
# Step 1: generate header/footer PDF to be merged into source PDF
pp = PdfPages(footer_pdf_path)
for p in range(n_pages):
fig = plt.figure(num=613, figsize=(8.5, 11), constrained_layout=1, facecolor='white')
fig.patch.set_alpha(0)
fig.text(0.48, 0.04, f'{p + 1} | <FOOTER TEXT>',
horizontalalignment='center', weight='bold',
verticalalignment='bottom', fontsize=6, color='grey')
if header_text is not None:
fig.text(0.1, 0.95, header_text,
horizontalalignment='left', weight='bold',
verticalalignment='center', fontsize=6, color='grey')
pp.savefig(fig)
plt.close()
pp.close()
footer_reader = PdfReader(footer_pdf_path)
# Step 2: merge source PDF & header/footer PDF
for index in list(range(start_page, n_pages)):
content_page = reader.pages[index]
footer_page = footer_reader.pages[index]
mediabox = content_page.mediabox
content_page.merge_page(footer_page)
content_page.mediabox = mediabox
writer.add_page(content_page)
# Step 3: save merged PDF
with open(save_path, "wb") as fp:
writer.write(fp)
return None