After exploring the PDF standard and a bit of hacking, I found that the following function will add a single PageLabels entry that creates page lables starting from offset (i.e. the first page will be labelled the offset, the second page, offset+1, etc.).
# output_pdf is an instance of PdfFileWriter().
# offset is the desired page offset.
def add_pagelabels(output_pdf, offset):
number_type = PDF.DictionaryObject()
number_type.update({PDF.NameObject("/S"):PDF.NameObject("/D")})
number_type.update({PDF.NameObject("/St"):PDF.NumberObject(offset)})
nums_array = PDF.ArrayObject()
nums_array.append(PDF.NumberObject(0)) # physical page index
nums_array.append(number_type)
page_numbers = PDF.DictionaryObject()
page_numbers.update({PDF.NameObject("/Nums"):nums_array})
page_labels = PDF.DictionaryObject()
page_labels.update({PDF.NameObject("/PageLabels"): page_numbers})
root_obj = output_pdf._root_object
root_obj.update(page_labels)
Additional page label entries can be created (i.e. with different offsets or different numbering styles).
Note that the first PDF page has an index of 0.
# Use PyPDF to manipulate pages
from PyPDF4 import PdfFileWriter, PdfFileReader
# To manipulate the PDF dictionary
import PyPDF4.pdf as PDF
def pdf_pagelabels_roman():
number_type = PDF.DictionaryObject()
number_type.update({PDF.NameObject("/S"):PDF.NameObject("/r")})
return number_type
def pdf_pagelabels_decimal():
number_type = PDF.DictionaryObject()
number_type.update({PDF.NameObject("/S"):PDF.NameObject("/D")})
return number_type
def pdf_pagelabels_decimal_with_offset(offset):
number_type = pdf_pagelabels_decimal()
number_type.update({PDF.NameObject("/St"):PDF.NumberObject(offset)})
return number_type
...
nums_array = PDF.ArrayObject()
# Each entry consists of an index followed by a page label...
nums_array.append(PDF.NumberObject(0)) # Page 0:
nums_array.append(pdf_pagelabels_roman()) # Roman numerals
# Each entry consists of an index followed by a page label...
nums_array.append(PDF.NumberObject(1)) # Page 1 -- 10:
nums_array.append(pdf_pagelabels_decimal_with_offset(first_offset)) # Decimal numbers, with Offset
# Each entry consists of an index followed by a page label...
nums_array.append(PDF.NumberObject(10)) # Page 11 --> :
nums_array.append(pdf_pagelabels_decimal_with_offset(second_offset))
page_numbers = PDF.DictionaryObject()
page_numbers.update({PDF.NameObject("/Nums"):nums_array})
page_labels = PDF.DictionaryObject()
page_labels.update({PDF.NameObject("/PageLabels"): page_numbers})
root_obj = output._root_object
root_obj.update(page_labels)
Answer from KevinM on Stack Overflowpdf generation - Python/PyPDF4: How do I specify the /PageLabels in the created PDF? - Stack Overflow
Installing PyPDF4 on Python3.9 on a MacBo… - Apple Community
Newest 'pypdf4' Questions - Stack Overflow
PyPDF2 and PyPDF4 fails to extract text from the PDF - Python - The freeCodeCamp Forum
Initially I just googled for a way to get the number of pages in a pdf file. First result was PyPDF2 so I just used that.
After a while I got an error from a file, so I started looking around and realized that there are 4 different forks of this library!
What is going on here? Why are there so many forks?
In other news, later on I will be scraping some text from some pdf files. Which library would you recommend? I won't be needing OCR, the text is already in the files.
Thanks!
» pip install pypdf