Commit 0df0d00c588f3ca5f71524f96817a84c4b98bc2c
1 parent
ae00ee61
Add method QPDF::Writer::getCompressibleObjSet
Create set without creation of an intermediate vector.
Showing
3 changed files
with
47 additions
and
20 deletions
include/qpdf/QPDF.hh
| ... | ... | @@ -756,7 +756,13 @@ class QPDF |
| 756 | 756 | static std::vector<QPDFObjGen> |
| 757 | 757 | getCompressibleObjGens(QPDF& qpdf) |
| 758 | 758 | { |
| 759 | - return qpdf.getCompressibleObjGens(); | |
| 759 | + return qpdf.getCompressibleObjVector(); | |
| 760 | + } | |
| 761 | + | |
| 762 | + static std::vector<bool> | |
| 763 | + getCompressibleObjSet(QPDF& qpdf) | |
| 764 | + { | |
| 765 | + return qpdf.getCompressibleObjSet(); | |
| 760 | 766 | } |
| 761 | 767 | |
| 762 | 768 | static std::map<QPDFObjGen, QPDFXRefEntry> const& |
| ... | ... | @@ -1110,7 +1116,10 @@ class QPDF |
| 1110 | 1116 | bool compressed); |
| 1111 | 1117 | |
| 1112 | 1118 | // Get a list of objects that would be permitted in an object stream. |
| 1113 | - std::vector<QPDFObjGen> getCompressibleObjGens(); | |
| 1119 | + template <typename T> | |
| 1120 | + std::vector<T> getCompressibleObjGens(); | |
| 1121 | + std::vector<QPDFObjGen> getCompressibleObjVector(); | |
| 1122 | + std::vector<bool> getCompressibleObjSet(); | |
| 1114 | 1123 | |
| 1115 | 1124 | // methods to support page handling |
| 1116 | 1125 | ... | ... |
libqpdf/QPDF.cc
| ... | ... | @@ -2397,6 +2397,19 @@ QPDF::tableSize() |
| 2397 | 2397 | } |
| 2398 | 2398 | |
| 2399 | 2399 | std::vector<QPDFObjGen> |
| 2400 | +QPDF::getCompressibleObjVector() | |
| 2401 | +{ | |
| 2402 | + return getCompressibleObjGens<QPDFObjGen>(); | |
| 2403 | +} | |
| 2404 | + | |
| 2405 | +std::vector<bool> | |
| 2406 | +QPDF::getCompressibleObjSet() | |
| 2407 | +{ | |
| 2408 | + return getCompressibleObjGens<bool>(); | |
| 2409 | +} | |
| 2410 | + | |
| 2411 | +template <typename T> | |
| 2412 | +std::vector<T> | |
| 2400 | 2413 | QPDF::getCompressibleObjGens() |
| 2401 | 2414 | { |
| 2402 | 2415 | // Return a list of objects that are allowed to be in object streams. Walk through the objects |
| ... | ... | @@ -2414,7 +2427,14 @@ QPDF::getCompressibleObjGens() |
| 2414 | 2427 | std::vector<QPDFObjectHandle> queue; |
| 2415 | 2428 | queue.reserve(512); |
| 2416 | 2429 | queue.push_back(m->trailer); |
| 2417 | - std::vector<QPDFObjGen> result; | |
| 2430 | + std::vector<T> result; | |
| 2431 | + if constexpr (std::is_same_v<T, QPDFObjGen>) { | |
| 2432 | + result.reserve(m->obj_cache.size()); | |
| 2433 | + } else if constexpr (std::is_same_v<T, bool>) { | |
| 2434 | + result.resize(max_obj + 1U, false); | |
| 2435 | + } else { | |
| 2436 | + throw std::logic_error("Unsupported type in QPDF::getCompressibleObjGens"); | |
| 2437 | + } | |
| 2418 | 2438 | while (!queue.empty()) { |
| 2419 | 2439 | auto obj = queue.back(); |
| 2420 | 2440 | queue.pop_back(); |
| ... | ... | @@ -2446,7 +2466,11 @@ QPDF::getCompressibleObjGens() |
| 2446 | 2466 | } else if (!(obj.isStream() || |
| 2447 | 2467 | (obj.isDictionaryOfType("/Sig") && obj.hasKey("/ByteRange") && |
| 2448 | 2468 | obj.hasKey("/Contents")))) { |
| 2449 | - result.push_back(og); | |
| 2469 | + if constexpr (std::is_same_v<T, QPDFObjGen>) { | |
| 2470 | + result.push_back(og); | |
| 2471 | + } else if constexpr (std::is_same_v<T, bool>) { | |
| 2472 | + result[id + 1U] = true; | |
| 2473 | + } | |
| 2450 | 2474 | } |
| 2451 | 2475 | } |
| 2452 | 2476 | if (obj.isStream()) { | ... | ... |
libqpdf/QPDFWriter.cc
| ... | ... | @@ -1964,13 +1964,11 @@ QPDFWriter::preserveObjectStreams() |
| 1964 | 1964 | } |
| 1965 | 1965 | } |
| 1966 | 1966 | } else { |
| 1967 | - std::set<QPDFObjGen> eligible; | |
| 1968 | - std::vector<QPDFObjGen> eligible_v = QPDF::Writer::getCompressibleObjGens(m->pdf); | |
| 1969 | - eligible = std::set<QPDFObjGen>(eligible_v.begin(), eligible_v.end()); | |
| 1967 | + auto eligible = QPDF::Writer::getCompressibleObjSet(m->pdf); | |
| 1970 | 1968 | for (; iter != end; ++iter) { |
| 1971 | 1969 | if (iter->second.getType() == 2) { |
| 1972 | - QPDFObjGen og(iter->first.getObj(), 0); | |
| 1973 | - if (eligible.count(og)) { | |
| 1970 | + auto id = static_cast<size_t>(iter->first.getObj()); | |
| 1971 | + if (id < eligible.size() && eligible[id]) { | |
| 1974 | 1972 | m->obj[iter->first].object_stream = iter->second.getObjStreamNumber(); |
| 1975 | 1973 | } else { |
| 1976 | 1974 | QTC::TC("qpdf", "QPDFWriter exclude from object stream"); |
| ... | ... | @@ -2009,22 +2007,18 @@ QPDFWriter::generateObjectStreams() |
| 2009 | 2007 | ++n_per; |
| 2010 | 2008 | } |
| 2011 | 2009 | unsigned int n = 0; |
| 2012 | - int cur_ostream = 0; | |
| 2013 | - for (auto const& iter: eligible) { | |
| 2014 | - if ((n % n_per) == 0) { | |
| 2015 | - if (n > 0) { | |
| 2016 | - QTC::TC("qpdf", "QPDFWriter generate >1 ostream"); | |
| 2017 | - } | |
| 2010 | + int cur_ostream = m->pdf.newIndirectNull().getObjectID(); | |
| 2011 | + for (auto const& item: eligible) { | |
| 2012 | + if (n == n_per) { | |
| 2013 | + QTC::TC("qpdf", "QPDFWriter generate >1 ostream"); | |
| 2018 | 2014 | n = 0; |
| 2019 | - } | |
| 2020 | - if (n == 0) { | |
| 2021 | 2015 | // Construct a new null object as the "original" object stream. The rest of the code |
| 2022 | 2016 | // knows that this means we're creating the object stream from scratch. |
| 2023 | - cur_ostream = m->pdf.makeIndirectObject(QPDFObjectHandle::newNull()).getObjectID(); | |
| 2017 | + cur_ostream = m->pdf.newIndirectNull().getObjectID(); | |
| 2024 | 2018 | } |
| 2025 | - auto& obj = m->obj[iter]; | |
| 2019 | + auto& obj = m->obj[item]; | |
| 2026 | 2020 | obj.object_stream = cur_ostream; |
| 2027 | - obj.gen = iter.getGen(); | |
| 2021 | + obj.gen = item.getGen(); | |
| 2028 | 2022 | ++n; |
| 2029 | 2023 | } |
| 2030 | 2024 | } | ... | ... |