Add method QPDF::Writer::getCompressibleObjSet

Create set without creation of an intermediate vector.
This commit is contained in:
m-holger 2024-02-25 22:40:09 +00:00
parent ae00ee6119
commit 0df0d00c58
3 changed files with 47 additions and 20 deletions

View File

@ -756,7 +756,13 @@ class QPDF
static std::vector<QPDFObjGen>
getCompressibleObjGens(QPDF& qpdf)
{
return qpdf.getCompressibleObjGens();
return qpdf.getCompressibleObjVector();
}
static std::vector<bool>
getCompressibleObjSet(QPDF& qpdf)
{
return qpdf.getCompressibleObjSet();
}
static std::map<QPDFObjGen, QPDFXRefEntry> const&
@ -1110,7 +1116,10 @@ class QPDF
bool compressed);
// Get a list of objects that would be permitted in an object stream.
std::vector<QPDFObjGen> getCompressibleObjGens();
template <typename T>
std::vector<T> getCompressibleObjGens();
std::vector<QPDFObjGen> getCompressibleObjVector();
std::vector<bool> getCompressibleObjSet();
// methods to support page handling

View File

@ -2397,6 +2397,19 @@ QPDF::tableSize()
}
std::vector<QPDFObjGen>
QPDF::getCompressibleObjVector()
{
return getCompressibleObjGens<QPDFObjGen>();
}
std::vector<bool>
QPDF::getCompressibleObjSet()
{
return getCompressibleObjGens<bool>();
}
template <typename T>
std::vector<T>
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<QPDFObjectHandle> queue;
queue.reserve(512);
queue.push_back(m->trailer);
std::vector<QPDFObjGen> result;
std::vector<T> result;
if constexpr (std::is_same_v<T, QPDFObjGen>) {
result.reserve(m->obj_cache.size());
} else if constexpr (std::is_same_v<T, bool>) {
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<T, QPDFObjGen>) {
result.push_back(og);
} else if constexpr (std::is_same_v<T, bool>) {
result[id + 1U] = true;
}
}
}
if (obj.isStream()) {

View File

@ -1964,13 +1964,11 @@ QPDFWriter::preserveObjectStreams()
}
}
} else {
std::set<QPDFObjGen> eligible;
std::vector<QPDFObjGen> eligible_v = QPDF::Writer::getCompressibleObjGens(m->pdf);
eligible = std::set<QPDFObjGen>(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<size_t>(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;
}
}