Commit c1150a449b9ca33fc496eda6e3622e7d4d5394e0

Authored by m-holger
1 parent 2d36aedf

Refactor `QPDFJob`: introduce `PageNo` structure to simplify and standardize pag…

…e number and index handling, update related logic accordingly.
include/qpdf/QPDFJob.hh
@@ -425,6 +425,7 @@ class QPDFJob @@ -425,6 +425,7 @@ class QPDFJob
425 [[deprecated("use job_json_schema(version)")]] static std::string QPDF_DLL job_json_schema_v1(); 425 [[deprecated("use job_json_schema(version)")]] static std::string QPDF_DLL job_json_schema_v1();
426 426
427 private: 427 private:
  428 + struct PageNo;
428 struct RotationSpec; 429 struct RotationSpec;
429 struct UnderOverlay; 430 struct UnderOverlay;
430 struct PageLabelSpec; 431 struct PageLabelSpec;
libqpdf/QPDFJob.cc
@@ -243,6 +243,30 @@ ImageOptimizer::provideStreamData(QPDFObjGen const&, Pipeline* pipeline) @@ -243,6 +243,30 @@ ImageOptimizer::provideStreamData(QPDFObjGen const&, Pipeline* pipeline)
243 image.pipeStreamData(p.get(), 0, decode_level, false, false); 243 image.pipeStreamData(p.get(), 0, decode_level, false, false);
244 } 244 }
245 245
  246 +// Page number (1 based) and index (0 based). Defaults to page number 1 / index 0.
  247 +struct QPDFJob::PageNo
  248 +{
  249 + PageNo() = default;
  250 + PageNo(PageNo const&) = default;
  251 +
  252 + PageNo(int no) :
  253 + idx{QIntC::to_size(no - 1)},
  254 + no{no}
  255 + {
  256 + }
  257 +
  258 + PageNo&
  259 + operator++()
  260 + {
  261 + ++idx;
  262 + ++no;
  263 + return *this;
  264 + }
  265 +
  266 + size_t idx{0};
  267 + int no{1};
  268 +};
  269 +
246 QPDFJob::PageSpec::PageSpec( 270 QPDFJob::PageSpec::PageSpec(
247 std::string const& filename, std::string const& password, std::string const& range) : 271 std::string const& filename, std::string const& password, std::string const& range) :
248 filename(filename), 272 filename(filename),
@@ -1906,13 +1930,13 @@ QPDFJob::doUnderOverlayForPage( @@ -1906,13 +1930,13 @@ QPDFJob::doUnderOverlayForPage(
1906 std::string content; 1930 std::string content;
1907 int min_suffix = 1; 1931 int min_suffix = 1;
1908 QPDFObjectHandle resources = dest_page.getAttribute("/Resources", true); 1932 QPDFObjectHandle resources = dest_page.getAttribute("/Resources", true);
1909 - for (int from_pageno: pagenos[pageno][uo_idx]) { 1933 + for (PageNo from_no: pagenos[pageno][uo_idx]) {
1910 doIfVerbose([&](Pipeline& v, std::string const& prefix) { 1934 doIfVerbose([&](Pipeline& v, std::string const& prefix) {
1911 - v << " " << uo.filename << " " << uo.which << " " << from_pageno << "\n"; 1935 + v << " " << uo.filename << " " << uo.which << " " << from_no.no << "\n";
1912 }); 1936 });
1913 - auto from_page = pages.at(QIntC::to_size(from_pageno - 1));  
1914 - if (!fo[from_pageno].contains(uo_idx)) {  
1915 - fo[from_pageno][uo_idx] = pdf.copyForeignObject(from_page.getFormXObjectForPage()); 1937 + auto from_page = pages.at(from_no.idx);
  1938 + if (!fo[from_no.no].contains(uo_idx)) {
  1939 + fo[from_no.no][uo_idx] = pdf.copyForeignObject(from_page.getFormXObjectForPage());
1916 } 1940 }
1917 1941
1918 // If the same page is overlaid or underlaid multiple times, we'll generate multiple names 1942 // If the same page is overlaid or underlaid multiple times, we'll generate multiple names
@@ -1920,13 +1944,13 @@ QPDFJob::doUnderOverlayForPage( @@ -1920,13 +1944,13 @@ QPDFJob::doUnderOverlayForPage(
1920 std::string name = resources.getUniqueResourceName("/Fx", min_suffix); 1944 std::string name = resources.getUniqueResourceName("/Fx", min_suffix);
1921 QPDFMatrix cm; 1945 QPDFMatrix cm;
1922 std::string new_content = dest_page.placeFormXObject( 1946 std::string new_content = dest_page.placeFormXObject(
1923 - fo[from_pageno][uo_idx], name, dest_page.getTrimBox().getArrayAsRectangle(), cm); 1947 + fo[from_no.no][uo_idx], name, dest_page.getTrimBox().getArrayAsRectangle(), cm);
1924 dest_page.copyAnnotations(from_page, cm, &dest_afdh, &from_page.qpdf()->acroform()); 1948 dest_page.copyAnnotations(from_page, cm, &dest_afdh, &from_page.qpdf()->acroform());
1925 if (!new_content.empty()) { 1949 if (!new_content.empty()) {
1926 resources.mergeResources("<< /XObject << >> >>"_qpdf); 1950 resources.mergeResources("<< /XObject << >> >>"_qpdf);
1927 auto xobject = resources.getKey("/XObject"); 1951 auto xobject = resources.getKey("/XObject");
1928 if (xobject.isDictionary()) { 1952 if (xobject.isDictionary()) {
1929 - xobject.replaceKey(name, fo[from_pageno][uo_idx]); 1953 + xobject.replaceKey(name, fo[from_no.no][uo_idx]);
1930 } 1954 }
1931 ++min_suffix; 1955 ++min_suffix;
1932 content += new_content; 1956 content += new_content;
@@ -1999,18 +2023,17 @@ QPDFJob::handleUnderOverlay(QPDF&amp; pdf) @@ -1999,18 +2023,17 @@ QPDFJob::handleUnderOverlay(QPDF&amp; pdf)
1999 QPDFPageDocumentHelper main_pdh(pdf); 2023 QPDFPageDocumentHelper main_pdh(pdf);
2000 auto main_pages = main_pdh.getAllPages(); 2024 auto main_pages = main_pdh.getAllPages();
2001 size_t main_npages = main_pages.size(); 2025 size_t main_npages = main_pages.size();
2002 - for (size_t page_idx = 0; page_idx < main_npages; ++page_idx) {  
2003 - auto pageno = QIntC::to_int(page_idx) + 1; 2026 + for (PageNo page; page.idx < main_npages; ++page) {
2004 doIfVerbose( 2027 doIfVerbose(
2005 - [&](Pipeline& v, std::string const& prefix) { v << " page " << pageno << "\n"; });  
2006 - if (underlay_pagenos[pageno].empty() && overlay_pagenos[pageno].empty()) { 2028 + [&](Pipeline& v, std::string const& prefix) { v << " page " << page.no << "\n"; });
  2029 + if (underlay_pagenos[page.no].empty() && overlay_pagenos[page.no].empty()) {
2007 continue; 2030 continue;
2008 } 2031 }
2009 // This code converts the original page, any underlays, and any overlays to form XObjects. 2032 // This code converts the original page, any underlays, and any overlays to form XObjects.
2010 // Then it concatenates display of all underlays, the original page, and all overlays. Prior 2033 // Then it concatenates display of all underlays, the original page, and all overlays. Prior
2011 // to 11.3.0, the original page contents were wrapped in q/Q, but this didn't work if the 2034 // to 11.3.0, the original page contents were wrapped in q/Q, but this didn't work if the
2012 // original page had unbalanced q/Q operators. See GitHub issue #904. 2035 // original page had unbalanced q/Q operators. See GitHub issue #904.
2013 - auto& dest_page = main_pages.at(page_idx); 2036 + auto& dest_page = main_pages.at(page.idx);
2014 auto dest_page_oh = dest_page.getObjectHandle(); 2037 auto dest_page_oh = dest_page.getObjectHandle();
2015 auto this_page_fo = dest_page.getFormXObjectForPage(); 2038 auto this_page_fo = dest_page.getFormXObjectForPage();
2016 // The resulting form xobject lazily reads the content from the original page, which we are 2039 // The resulting form xobject lazily reads the content from the original page, which we are
@@ -2027,7 +2050,7 @@ QPDFJob::handleUnderOverlay(QPDF&amp; pdf) @@ -2027,7 +2050,7 @@ QPDFJob::handleUnderOverlay(QPDF&amp; pdf)
2027 pdf, 2050 pdf,
2028 underlay, 2051 underlay,
2029 underlay_pagenos, 2052 underlay_pagenos,
2030 - page_idx, 2053 + page.idx,
2031 uo_idx, 2054 uo_idx,
2032 underlay_fo, 2055 underlay_fo,
2033 upages[uo_idx], 2056 upages[uo_idx],
@@ -2047,7 +2070,7 @@ QPDFJob::handleUnderOverlay(QPDF&amp; pdf) @@ -2047,7 +2070,7 @@ QPDFJob::handleUnderOverlay(QPDF&amp; pdf)
2047 pdf, 2070 pdf,
2048 overlay, 2071 overlay,
2049 overlay_pagenos, 2072 overlay_pagenos,
2050 - page_idx, 2073 + page.idx,
2051 uo_idx, 2074 uo_idx,
2052 overlay_fo, 2075 overlay_fo,
2053 opages[uo_idx], 2076 opages[uo_idx],