forked from openkylin/qpdf
126 lines
3.9 KiB
C++
126 lines
3.9 KiB
C++
#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);
|
|
}
|
|
}
|
|
}
|
|
|