diff options
Diffstat (limited to 'libqpdf/QPDFPageLabelDocumentHelper.cc')
-rw-r--r-- | libqpdf/QPDFPageLabelDocumentHelper.cc | 125 |
1 files changed, 125 insertions, 0 deletions
diff --git a/libqpdf/QPDFPageLabelDocumentHelper.cc b/libqpdf/QPDFPageLabelDocumentHelper.cc new file mode 100644 index 00000000..63be5809 --- /dev/null +++ b/libqpdf/QPDFPageLabelDocumentHelper.cc @@ -0,0 +1,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[size - 1]; + QPDFObjectHandle last_idx = new_labels[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); + } + } +} + |