From c1150a449b9ca33fc496eda6e3622e7d4d5394e0 Mon Sep 17 00:00:00 2001 From: m-holger Date: Sun, 14 Sep 2025 19:40:18 +0100 Subject: [PATCH] Refactor `QPDFJob`: introduce `PageNo` structure to simplify and standardize page number and index handling, update related logic accordingly. --- include/qpdf/QPDFJob.hh | 1 + libqpdf/QPDFJob.cc | 51 +++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 38 insertions(+), 14 deletions(-) diff --git a/include/qpdf/QPDFJob.hh b/include/qpdf/QPDFJob.hh index e537d97..e9941e2 100644 --- a/include/qpdf/QPDFJob.hh +++ b/include/qpdf/QPDFJob.hh @@ -425,6 +425,7 @@ class QPDFJob [[deprecated("use job_json_schema(version)")]] static std::string QPDF_DLL job_json_schema_v1(); private: + struct PageNo; struct RotationSpec; struct UnderOverlay; struct PageLabelSpec; diff --git a/libqpdf/QPDFJob.cc b/libqpdf/QPDFJob.cc index 3751a7c..2b798c0 100644 --- a/libqpdf/QPDFJob.cc +++ b/libqpdf/QPDFJob.cc @@ -243,6 +243,30 @@ ImageOptimizer::provideStreamData(QPDFObjGen const&, Pipeline* pipeline) image.pipeStreamData(p.get(), 0, decode_level, false, false); } +// Page number (1 based) and index (0 based). Defaults to page number 1 / index 0. +struct QPDFJob::PageNo +{ + PageNo() = default; + PageNo(PageNo const&) = default; + + PageNo(int no) : + idx{QIntC::to_size(no - 1)}, + no{no} + { + } + + PageNo& + operator++() + { + ++idx; + ++no; + return *this; + } + + size_t idx{0}; + int no{1}; +}; + QPDFJob::PageSpec::PageSpec( std::string const& filename, std::string const& password, std::string const& range) : filename(filename), @@ -1906,13 +1930,13 @@ QPDFJob::doUnderOverlayForPage( std::string content; int min_suffix = 1; QPDFObjectHandle resources = dest_page.getAttribute("/Resources", true); - for (int from_pageno: pagenos[pageno][uo_idx]) { + for (PageNo from_no: pagenos[pageno][uo_idx]) { doIfVerbose([&](Pipeline& v, std::string const& prefix) { - v << " " << uo.filename << " " << uo.which << " " << from_pageno << "\n"; + v << " " << uo.filename << " " << uo.which << " " << from_no.no << "\n"; }); - auto from_page = pages.at(QIntC::to_size(from_pageno - 1)); - if (!fo[from_pageno].contains(uo_idx)) { - fo[from_pageno][uo_idx] = pdf.copyForeignObject(from_page.getFormXObjectForPage()); + auto from_page = pages.at(from_no.idx); + if (!fo[from_no.no].contains(uo_idx)) { + fo[from_no.no][uo_idx] = pdf.copyForeignObject(from_page.getFormXObjectForPage()); } // If the same page is overlaid or underlaid multiple times, we'll generate multiple names @@ -1920,13 +1944,13 @@ QPDFJob::doUnderOverlayForPage( std::string name = resources.getUniqueResourceName("/Fx", min_suffix); QPDFMatrix cm; std::string new_content = dest_page.placeFormXObject( - fo[from_pageno][uo_idx], name, dest_page.getTrimBox().getArrayAsRectangle(), cm); + fo[from_no.no][uo_idx], name, dest_page.getTrimBox().getArrayAsRectangle(), cm); dest_page.copyAnnotations(from_page, cm, &dest_afdh, &from_page.qpdf()->acroform()); if (!new_content.empty()) { resources.mergeResources("<< /XObject << >> >>"_qpdf); auto xobject = resources.getKey("/XObject"); if (xobject.isDictionary()) { - xobject.replaceKey(name, fo[from_pageno][uo_idx]); + xobject.replaceKey(name, fo[from_no.no][uo_idx]); } ++min_suffix; content += new_content; @@ -1999,18 +2023,17 @@ QPDFJob::handleUnderOverlay(QPDF& pdf) QPDFPageDocumentHelper main_pdh(pdf); auto main_pages = main_pdh.getAllPages(); size_t main_npages = main_pages.size(); - for (size_t page_idx = 0; page_idx < main_npages; ++page_idx) { - auto pageno = QIntC::to_int(page_idx) + 1; + for (PageNo page; page.idx < main_npages; ++page) { doIfVerbose( - [&](Pipeline& v, std::string const& prefix) { v << " page " << pageno << "\n"; }); - if (underlay_pagenos[pageno].empty() && overlay_pagenos[pageno].empty()) { + [&](Pipeline& v, std::string const& prefix) { v << " page " << page.no << "\n"; }); + if (underlay_pagenos[page.no].empty() && overlay_pagenos[page.no].empty()) { continue; } // This code converts the original page, any underlays, and any overlays to form XObjects. // Then it concatenates display of all underlays, the original page, and all overlays. Prior // to 11.3.0, the original page contents were wrapped in q/Q, but this didn't work if the // original page had unbalanced q/Q operators. See GitHub issue #904. - auto& dest_page = main_pages.at(page_idx); + auto& dest_page = main_pages.at(page.idx); auto dest_page_oh = dest_page.getObjectHandle(); auto this_page_fo = dest_page.getFormXObjectForPage(); // The resulting form xobject lazily reads the content from the original page, which we are @@ -2027,7 +2050,7 @@ QPDFJob::handleUnderOverlay(QPDF& pdf) pdf, underlay, underlay_pagenos, - page_idx, + page.idx, uo_idx, underlay_fo, upages[uo_idx], @@ -2047,7 +2070,7 @@ QPDFJob::handleUnderOverlay(QPDF& pdf) pdf, overlay, overlay_pagenos, - page_idx, + page.idx, uo_idx, overlay_fo, opages[uo_idx], -- libgit2 0.21.4