1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
|
#include <qpdf/QPDFPageLabelDocumentHelper.hh>
#include <qpdf/QTC.hh>
QPDFPageLabelDocumentHelper::Members::~Members()
{
}
QPDFPageLabelDocumentHelper::Members::Members()
{
}
QPDFPageLabelDocumentHelper::QPDFPageLabelDocumentHelper(QPDF& qpdf) :
QPDFDocumentHelper(qpdf),
m(new Members())
{
QPDFObjectHandle root = qpdf.getRoot();
if (root.hasKey("/PageLabels"))
{
this->m->labels = new QPDFNumberTreeObjectHelper(
root.getKey("/PageLabels"));
}
}
bool
QPDFPageLabelDocumentHelper::hasPageLabels()
{
return 0 != this->m->labels.getPointer();
}
QPDFObjectHandle
QPDFPageLabelDocumentHelper::getLabelForPage(long long page_idx)
{
QPDFObjectHandle result(QPDFObjectHandle::newNull());
if (! hasPageLabels())
{
return result;
}
QPDFNumberTreeObjectHelper::numtree_number offset = 0;
QPDFObjectHandle label;
if (! this->m->labels->findObjectAtOrBelow(page_idx, label, offset))
{
return result;
}
if (! label.isDictionary())
{
return result;
}
QPDFObjectHandle S = label.getKey("/S"); // type (D, R, r, A, a)
QPDFObjectHandle P = label.getKey("/P"); // prefix
QPDFObjectHandle St = label.getKey("/St"); // starting number
long long start = 1;
if (St.isInteger())
{
start = St.getIntValue();
}
start += offset;
result = QPDFObjectHandle::newDictionary();
result.replaceOrRemoveKey("/S", S);
result.replaceOrRemoveKey("/P", P);
result.replaceOrRemoveKey("/St", QPDFObjectHandle::newInteger(start));
return result;
}
void
QPDFPageLabelDocumentHelper::getLabelsForPageRange(
long long start_idx, long long end_idx, long long new_start_idx,
std::vector<QPDFObjectHandle>& new_labels)
{
// Start off with a suitable label for the first page. For every
// remaining page, if that page has an explicit entry, copy it.
// Otherwise, let the subsequent page just sequence from the prior
// entry. If there is no entry for the first page, fabricate one
// that would match how the page would look in a new file in which
// it also didn't have an explicit label.
QPDFObjectHandle label = getLabelForPage(start_idx);
if (label.isNull())
{
label = QPDFObjectHandle::newDictionary();
label.replaceKey(
"/St", QPDFObjectHandle::newInteger(1 + new_start_idx));
}
// See if the new label is redundant based on the previous entry
// in the vector. If so, don't add it.
size_t size = new_labels.size();
bool skip_first = false;
if (size >= 2)
{
QPDFObjectHandle last = new_labels.at(size - 1);
QPDFObjectHandle last_idx = new_labels.at(size - 2);
if (last_idx.isInteger() && last.isDictionary() &&
(label.getKey("/S").unparse() == last.getKey("/S").unparse()) &&
(label.getKey("/P").unparse() == last.getKey("/P").unparse()) &&
label.getKey("/St").isInteger() &&
last.getKey("/St").isInteger())
{
long long int st_delta =
label.getKey("/St").getIntValue() -
last.getKey("/St").getIntValue();
long long int idx_delta =
new_start_idx - last_idx.getIntValue();
if (st_delta == idx_delta)
{
QTC::TC("qpdf", "QPDFPageLabelDocumentHelper skip first");
skip_first = true;
}
}
}
if (! skip_first)
{
new_labels.push_back(QPDFObjectHandle::newInteger(new_start_idx));
new_labels.push_back(label);
}
long long int idx_offset = new_start_idx - start_idx;
for (long long i = start_idx + 1; i <= end_idx; ++i)
{
if (this->m->labels->hasIndex(i) &&
(label = getLabelForPage(i)).isDictionary())
{
new_labels.push_back(QPDFObjectHandle::newInteger(i + idx_offset));
new_labels.push_back(label);
}
}
}
|