From 0df0d00c588f3ca5f71524f96817a84c4b98bc2c Mon Sep 17 00:00:00 2001 From: m-holger Date: Sun, 25 Feb 2024 22:40:09 +0000 Subject: [PATCH] Add method QPDF::Writer::getCompressibleObjSet Create set without creation of an intermediate vector. --- include/qpdf/QPDF.hh | 13 +++++++++++-- libqpdf/QPDF.cc | 28 ++++++++++++++++++++++++++-- libqpdf/QPDFWriter.cc | 26 ++++++++++---------------- 3 files changed, 47 insertions(+), 20 deletions(-) diff --git a/include/qpdf/QPDF.hh b/include/qpdf/QPDF.hh index 10fa404a..b366b17b 100644 --- a/include/qpdf/QPDF.hh +++ b/include/qpdf/QPDF.hh @@ -756,7 +756,13 @@ class QPDF static std::vector getCompressibleObjGens(QPDF& qpdf) { - return qpdf.getCompressibleObjGens(); + return qpdf.getCompressibleObjVector(); + } + + static std::vector + getCompressibleObjSet(QPDF& qpdf) + { + return qpdf.getCompressibleObjSet(); } static std::map const& @@ -1110,7 +1116,10 @@ class QPDF bool compressed); // Get a list of objects that would be permitted in an object stream. - std::vector getCompressibleObjGens(); + template + std::vector getCompressibleObjGens(); + std::vector getCompressibleObjVector(); + std::vector getCompressibleObjSet(); // methods to support page handling diff --git a/libqpdf/QPDF.cc b/libqpdf/QPDF.cc index 5417c9ba..3f776852 100644 --- a/libqpdf/QPDF.cc +++ b/libqpdf/QPDF.cc @@ -2397,6 +2397,19 @@ QPDF::tableSize() } std::vector +QPDF::getCompressibleObjVector() +{ + return getCompressibleObjGens(); +} + +std::vector +QPDF::getCompressibleObjSet() +{ + return getCompressibleObjGens(); +} + +template +std::vector QPDF::getCompressibleObjGens() { // Return a list of objects that are allowed to be in object streams. Walk through the objects @@ -2414,7 +2427,14 @@ QPDF::getCompressibleObjGens() std::vector queue; queue.reserve(512); queue.push_back(m->trailer); - std::vector result; + std::vector result; + if constexpr (std::is_same_v) { + result.reserve(m->obj_cache.size()); + } else if constexpr (std::is_same_v) { + result.resize(max_obj + 1U, false); + } else { + throw std::logic_error("Unsupported type in QPDF::getCompressibleObjGens"); + } while (!queue.empty()) { auto obj = queue.back(); queue.pop_back(); @@ -2446,7 +2466,11 @@ QPDF::getCompressibleObjGens() } else if (!(obj.isStream() || (obj.isDictionaryOfType("/Sig") && obj.hasKey("/ByteRange") && obj.hasKey("/Contents")))) { - result.push_back(og); + if constexpr (std::is_same_v) { + result.push_back(og); + } else if constexpr (std::is_same_v) { + result[id + 1U] = true; + } } } if (obj.isStream()) { diff --git a/libqpdf/QPDFWriter.cc b/libqpdf/QPDFWriter.cc index aaf954e2..2ad4d786 100644 --- a/libqpdf/QPDFWriter.cc +++ b/libqpdf/QPDFWriter.cc @@ -1964,13 +1964,11 @@ QPDFWriter::preserveObjectStreams() } } } else { - std::set eligible; - std::vector eligible_v = QPDF::Writer::getCompressibleObjGens(m->pdf); - eligible = std::set(eligible_v.begin(), eligible_v.end()); + auto eligible = QPDF::Writer::getCompressibleObjSet(m->pdf); for (; iter != end; ++iter) { if (iter->second.getType() == 2) { - QPDFObjGen og(iter->first.getObj(), 0); - if (eligible.count(og)) { + auto id = static_cast(iter->first.getObj()); + if (id < eligible.size() && eligible[id]) { m->obj[iter->first].object_stream = iter->second.getObjStreamNumber(); } else { QTC::TC("qpdf", "QPDFWriter exclude from object stream"); @@ -2009,22 +2007,18 @@ QPDFWriter::generateObjectStreams() ++n_per; } unsigned int n = 0; - int cur_ostream = 0; - for (auto const& iter: eligible) { - if ((n % n_per) == 0) { - if (n > 0) { - QTC::TC("qpdf", "QPDFWriter generate >1 ostream"); - } + int cur_ostream = m->pdf.newIndirectNull().getObjectID(); + for (auto const& item: eligible) { + if (n == n_per) { + QTC::TC("qpdf", "QPDFWriter generate >1 ostream"); n = 0; - } - if (n == 0) { // Construct a new null object as the "original" object stream. The rest of the code // knows that this means we're creating the object stream from scratch. - cur_ostream = m->pdf.makeIndirectObject(QPDFObjectHandle::newNull()).getObjectID(); + cur_ostream = m->pdf.newIndirectNull().getObjectID(); } - auto& obj = m->obj[iter]; + auto& obj = m->obj[item]; obj.object_stream = cur_ostream; - obj.gen = iter.getGen(); + obj.gen = item.getGen(); ++n; } }