Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions staplelib/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,8 @@ def pdf_page_enumeration(pdf):
if len(pagelabels_nums_list) > 0 and i >= pagelabels_nums_list[0]:
pagelabels_nums_list.pop(0) # discard index
pnle = pagelabels_nums_list.pop(0)
style = pnle.get('/S', '/D')
# An omitted /S means the label consists only of its prefix.
style = pnle.get('/S')
prefix = pnle.get('/P', '')
next_pageno = pnle.get('/St', 1)
pageno_str = ''
Expand All @@ -310,7 +311,7 @@ def pdf_page_enumeration(pdf):
pageno_str = int_to_roman(next_pageno)
elif style == '/r':
pageno_str = int_to_roman(next_pageno).lower()
else:
elif style is not None:
raise CommandError("Malformded PDF: unkown page numbering style " + style)
labels.append(prefix + pageno_str)
next_pageno += 1
Expand Down
81 changes: 81 additions & 0 deletions tests/test_oss_regression_62.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
"""Regression coverage for prefix-only PDF page labels (issue #62)."""

import pytest
from PyPDF2 import PdfFileWriter
from PyPDF2.generic import (
ArrayObject,
DictionaryObject,
NameObject,
NumberObject,
createStringObject,
)

from staplelib import main


@pytest.mark.parametrize(
"ranges, expected",
[
(
[(0, {"/P": "1"}), (1, {"/P": "2"}), (2, {"/P": "3"})],
["1", "2", "3"],
),
(
[(0, {"/P": "i"}), (1, {"/P": "ii"}),
(2, {"/P": "1"}), (3, {"/P": "2"})],
["i", "ii", "1", "2"],
),
([(0, {"/P": "Cover", "/St": 12})], ["Cover", "Cover", "Cover"]),
([(0, {})], ["", ""]),
([(0, {"/S": "/D", "/P": "A-", "/St": 9})], ["A-9", "A-10"]),
(
[(0, {"/S": "/D", "/St": 7}),
(1, {"/S": "/A", "/St": 27}),
(2, {"/S": "/a", "/St": 2}),
(3, {"/S": "/R", "/St": 4}),
(4, {"/S": "/r", "/St": 6})],
["7", "AA", "b", "IV", "vi"],
),
(None, ["1", "2", "3"]),
],
ids=[
"numeric-prefixes",
"roman-and-numeric-prefixes",
"prefix-only-range",
"empty-prefix",
"decimal-prefix-and-start",
"explicit-numbering-styles",
"no-page-labels",
],
)
def test_list_logical_page_labels(tmp_path, capsys, ranges, expected):
writer = PdfFileWriter()
for _ in expected:
writer.addBlankPage(72, 72)

if ranges is not None:
nums = ArrayObject()
for index, values in ranges:
label = DictionaryObject()
for key, value in values.items():
if key == "/S":
label[NameObject(key)] = NameObject(value)
elif key == "/St":
label[NameObject(key)] = NumberObject(value)
else:
label[NameObject(key)] = createStringObject(value)
nums.extend([NumberObject(index), label])
writer._root_object[NameObject("/PageLabels")] = DictionaryObject(
{NameObject("/Nums"): nums}
)

path = tmp_path / "labels.pdf"
with path.open("wb") as stream:
writer.write(stream)

main(["list-logical", str(path)])

assert capsys.readouterr().out == "".join(
"{}\t{}\n".format(label, index)
for index, label in enumerate(expected, 1)
)