From 902fd6df71e89127fdf82a1a309c9c24927276c7 Mon Sep 17 00:00:00 2001 From: m-holger Date: Sun, 21 Jan 2024 17:19:40 +0000 Subject: [PATCH 1/8] Change Pl_TIFFPredictor::cur_row to std::vector --- libqpdf/Pl_TIFFPredictor.cc | 13 ++++++------- libqpdf/qpdf/Pl_TIFFPredictor.hh | 4 +++- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/libqpdf/Pl_TIFFPredictor.cc b/libqpdf/Pl_TIFFPredictor.cc index 51594d11..c8e0b5ba 100644 --- a/libqpdf/Pl_TIFFPredictor.cc +++ b/libqpdf/Pl_TIFFPredictor.cc @@ -35,8 +35,7 @@ Pl_TIFFPredictor::Pl_TIFFPredictor( throw std::runtime_error("TIFFPredictor created with invalid columns value"); } this->bytes_per_row = bpr & UINT_MAX; - this->cur_row = QUtil::make_shared_array(this->bytes_per_row); - memset(this->cur_row.get(), 0, this->bytes_per_row); + this->cur_row.assign(this->bytes_per_row, 0); } void @@ -46,19 +45,19 @@ Pl_TIFFPredictor::write(unsigned char const* data, size_t len) size_t offset = 0; while (len >= left) { // finish off current row - memcpy(this->cur_row.get() + this->pos, data + offset, left); + memcpy(this->cur_row.data() + this->pos, data + offset, left); offset += left; len -= left; processRow(); // Prepare for next row - memset(this->cur_row.get(), 0, this->bytes_per_row); + this->cur_row.assign(this->bytes_per_row, 0); left = this->bytes_per_row; this->pos = 0; } if (len) { - memcpy(this->cur_row.get() + this->pos, data + offset, len); + memcpy(this->cur_row.data() + this->pos, data + offset, len); } this->pos += len; } @@ -68,7 +67,7 @@ Pl_TIFFPredictor::processRow() { QTC::TC("libtests", "Pl_TIFFPredictor processRow", (action == a_decode ? 0 : 1)); BitWriter bw(this->getNext()); - BitStream in(this->cur_row.get(), this->bytes_per_row); + BitStream in(this->cur_row.data(), this->bytes_per_row); std::vector prev; for (unsigned int i = 0; i < this->samples_per_pixel; ++i) { long long sample = in.getBitsSigned(this->bits_per_sample); @@ -100,6 +99,6 @@ Pl_TIFFPredictor::finish() processRow(); } this->pos = 0; - memset(this->cur_row.get(), 0, this->bytes_per_row); + this->cur_row.assign(this->bytes_per_row, 0); getNext()->finish(); } diff --git a/libqpdf/qpdf/Pl_TIFFPredictor.hh b/libqpdf/qpdf/Pl_TIFFPredictor.hh index 21757593..7e35350d 100644 --- a/libqpdf/qpdf/Pl_TIFFPredictor.hh +++ b/libqpdf/qpdf/Pl_TIFFPredictor.hh @@ -6,6 +6,8 @@ #include +#include + class Pl_TIFFPredictor: public Pipeline { public: @@ -31,7 +33,7 @@ class Pl_TIFFPredictor: public Pipeline unsigned int bytes_per_row; unsigned int samples_per_pixel; unsigned int bits_per_sample; - std::shared_ptr cur_row; + std::vector cur_row; size_t pos; }; From 5b7a44e1cc97035226b001e10993a3ad394389dc Mon Sep 17 00:00:00 2001 From: m-holger Date: Sun, 21 Jan 2024 17:57:10 +0000 Subject: [PATCH 2/8] In Pl_TIFFPredictor remove calls to memcpy Instead of overwriting cur_row.data() use clear and insert. --- libqpdf/Pl_TIFFPredictor.cc | 22 ++++++++-------------- libqpdf/qpdf/Pl_TIFFPredictor.hh | 1 - 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/libqpdf/Pl_TIFFPredictor.cc b/libqpdf/Pl_TIFFPredictor.cc index c8e0b5ba..462d364b 100644 --- a/libqpdf/Pl_TIFFPredictor.cc +++ b/libqpdf/Pl_TIFFPredictor.cc @@ -3,10 +3,8 @@ #include #include #include -#include #include -#include #include #include @@ -21,8 +19,7 @@ Pl_TIFFPredictor::Pl_TIFFPredictor( action(action), columns(columns), samples_per_pixel(samples_per_pixel), - bits_per_sample(bits_per_sample), - pos(0) + bits_per_sample(bits_per_sample) { if (samples_per_pixel < 1) { throw std::runtime_error("TIFFPredictor created with invalid samples_per_pixel"); @@ -35,31 +32,28 @@ Pl_TIFFPredictor::Pl_TIFFPredictor( throw std::runtime_error("TIFFPredictor created with invalid columns value"); } this->bytes_per_row = bpr & UINT_MAX; - this->cur_row.assign(this->bytes_per_row, 0); } void Pl_TIFFPredictor::write(unsigned char const* data, size_t len) { - size_t left = this->bytes_per_row - this->pos; + size_t left = this->bytes_per_row - cur_row.size(); size_t offset = 0; while (len >= left) { // finish off current row - memcpy(this->cur_row.data() + this->pos, data + offset, left); + cur_row.insert(cur_row.end(), data + offset, data + offset + left); offset += left; len -= left; processRow(); // Prepare for next row - this->cur_row.assign(this->bytes_per_row, 0); + this->cur_row.clear(); left = this->bytes_per_row; - this->pos = 0; } if (len) { - memcpy(this->cur_row.data() + this->pos, data + offset, len); + cur_row.insert(cur_row.end(), data + offset, data + offset + len); } - this->pos += len; } void @@ -94,11 +88,11 @@ Pl_TIFFPredictor::processRow() void Pl_TIFFPredictor::finish() { - if (this->pos) { + if (!cur_row.empty()) { // write partial row + cur_row.insert(cur_row.end(), bytes_per_row - cur_row.size(), 0); processRow(); } - this->pos = 0; - this->cur_row.assign(this->bytes_per_row, 0); + cur_row.clear(); getNext()->finish(); } diff --git a/libqpdf/qpdf/Pl_TIFFPredictor.hh b/libqpdf/qpdf/Pl_TIFFPredictor.hh index 7e35350d..ba429734 100644 --- a/libqpdf/qpdf/Pl_TIFFPredictor.hh +++ b/libqpdf/qpdf/Pl_TIFFPredictor.hh @@ -34,7 +34,6 @@ class Pl_TIFFPredictor: public Pipeline unsigned int samples_per_pixel; unsigned int bits_per_sample; std::vector cur_row; - size_t pos; }; #endif // PL_TIFFPREDICTOR_HH From 73dec35209cfcdb83a3cb08c6c47734a9291ec1f Mon Sep 17 00:00:00 2001 From: m-holger Date: Sun, 21 Jan 2024 18:21:01 +0000 Subject: [PATCH 3/8] Simplify address arithmetic in Pl_TIFFPredictor --- libqpdf/Pl_TIFFPredictor.cc | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/libqpdf/Pl_TIFFPredictor.cc b/libqpdf/Pl_TIFFPredictor.cc index 462d364b..7535d38f 100644 --- a/libqpdf/Pl_TIFFPredictor.cc +++ b/libqpdf/Pl_TIFFPredictor.cc @@ -37,23 +37,21 @@ Pl_TIFFPredictor::Pl_TIFFPredictor( void Pl_TIFFPredictor::write(unsigned char const* data, size_t len) { - size_t left = this->bytes_per_row - cur_row.size(); - size_t offset = 0; - while (len >= left) { + auto end = data + len; + auto row_end = data + (bytes_per_row - cur_row.size()); + while (row_end <= end) { // finish off current row - cur_row.insert(cur_row.end(), data + offset, data + offset + left); - offset += left; - len -= left; + cur_row.insert(cur_row.end(), data, row_end); + data = row_end; + row_end += bytes_per_row; processRow(); // Prepare for next row - this->cur_row.clear(); - left = this->bytes_per_row; - } - if (len) { - cur_row.insert(cur_row.end(), data + offset, data + offset + len); + cur_row.clear(); } + + cur_row.insert(cur_row.end(), data, end); } void From 2e8b5f290c03bd4cd67f9240cb1fff3122e0b12c Mon Sep 17 00:00:00 2001 From: m-holger Date: Mon, 22 Jan 2024 00:32:15 +0000 Subject: [PATCH 4/8] In Pl_TIFFPredictor avoid repeated calls to getNext --- libqpdf/Pl_TIFFPredictor.cc | 7 ++++--- libqpdf/qpdf/Pl_TIFFPredictor.hh | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/libqpdf/Pl_TIFFPredictor.cc b/libqpdf/Pl_TIFFPredictor.cc index 7535d38f..5454cfe6 100644 --- a/libqpdf/Pl_TIFFPredictor.cc +++ b/libqpdf/Pl_TIFFPredictor.cc @@ -19,7 +19,8 @@ Pl_TIFFPredictor::Pl_TIFFPredictor( action(action), columns(columns), samples_per_pixel(samples_per_pixel), - bits_per_sample(bits_per_sample) + bits_per_sample(bits_per_sample), + p_next(getNext()) { if (samples_per_pixel < 1) { throw std::runtime_error("TIFFPredictor created with invalid samples_per_pixel"); @@ -58,7 +59,7 @@ void Pl_TIFFPredictor::processRow() { QTC::TC("libtests", "Pl_TIFFPredictor processRow", (action == a_decode ? 0 : 1)); - BitWriter bw(this->getNext()); + BitWriter bw(p_next); BitStream in(this->cur_row.data(), this->bytes_per_row); std::vector prev; for (unsigned int i = 0; i < this->samples_per_pixel; ++i) { @@ -92,5 +93,5 @@ Pl_TIFFPredictor::finish() processRow(); } cur_row.clear(); - getNext()->finish(); + p_next->finish(); } diff --git a/libqpdf/qpdf/Pl_TIFFPredictor.hh b/libqpdf/qpdf/Pl_TIFFPredictor.hh index ba429734..6557e15c 100644 --- a/libqpdf/qpdf/Pl_TIFFPredictor.hh +++ b/libqpdf/qpdf/Pl_TIFFPredictor.hh @@ -34,6 +34,7 @@ class Pl_TIFFPredictor: public Pipeline unsigned int samples_per_pixel; unsigned int bits_per_sample; std::vector cur_row; + Pipeline* p_next; }; #endif // PL_TIFFPREDICTOR_HH From c01fc3c2ae3a6487d310f807bc25499d5d517c61 Mon Sep 17 00:00:00 2001 From: m-holger Date: Fri, 26 Jan 2024 19:13:34 +0000 Subject: [PATCH 5/8] In Pl_TIFFPredictor::processRow avoid repeated vector allocation Also, modernize for loop. --- libqpdf/Pl_TIFFPredictor.cc | 17 +++++++++-------- libqpdf/qpdf/Pl_TIFFPredictor.hh | 1 + 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/libqpdf/Pl_TIFFPredictor.cc b/libqpdf/Pl_TIFFPredictor.cc index 5454cfe6..8820f4bc 100644 --- a/libqpdf/Pl_TIFFPredictor.cc +++ b/libqpdf/Pl_TIFFPredictor.cc @@ -7,6 +7,7 @@ #include #include #include +#include Pl_TIFFPredictor::Pl_TIFFPredictor( char const* identifier, @@ -60,23 +61,23 @@ Pl_TIFFPredictor::processRow() { QTC::TC("libtests", "Pl_TIFFPredictor processRow", (action == a_decode ? 0 : 1)); BitWriter bw(p_next); - BitStream in(this->cur_row.data(), this->bytes_per_row); - std::vector prev; + BitStream in(cur_row.data(), cur_row.size()); + previous.clear(); for (unsigned int i = 0; i < this->samples_per_pixel; ++i) { long long sample = in.getBitsSigned(this->bits_per_sample); bw.writeBitsSigned(sample, this->bits_per_sample); - prev.push_back(sample); + previous.push_back(sample); } for (unsigned int col = 1; col < this->columns; ++col) { - for (unsigned int i = 0; i < this->samples_per_pixel; ++i) { + for (auto& prev : previous) { long long sample = in.getBitsSigned(this->bits_per_sample); long long new_sample = sample; if (action == a_encode) { - new_sample -= prev[i]; - prev[i] = sample; + new_sample -= prev; + prev = sample; } else { - new_sample += prev[i]; - prev[i] = new_sample; + new_sample += prev; + prev = new_sample; } bw.writeBitsSigned(new_sample, this->bits_per_sample); } diff --git a/libqpdf/qpdf/Pl_TIFFPredictor.hh b/libqpdf/qpdf/Pl_TIFFPredictor.hh index 6557e15c..4579ba1f 100644 --- a/libqpdf/qpdf/Pl_TIFFPredictor.hh +++ b/libqpdf/qpdf/Pl_TIFFPredictor.hh @@ -34,6 +34,7 @@ class Pl_TIFFPredictor: public Pipeline unsigned int samples_per_pixel; unsigned int bits_per_sample; std::vector cur_row; + std::vector previous; Pipeline* p_next; }; From b7abb12f55ec2bd45eb8b20c2c058395c289111b Mon Sep 17 00:00:00 2001 From: m-holger Date: Fri, 26 Jan 2024 20:56:21 +0000 Subject: [PATCH 6/8] In Pl_TIFFPredictor::processRow remove special case for first column --- libqpdf/Pl_TIFFPredictor.cc | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/libqpdf/Pl_TIFFPredictor.cc b/libqpdf/Pl_TIFFPredictor.cc index 8820f4bc..5454d13a 100644 --- a/libqpdf/Pl_TIFFPredictor.cc +++ b/libqpdf/Pl_TIFFPredictor.cc @@ -6,8 +6,6 @@ #include #include -#include -#include Pl_TIFFPredictor::Pl_TIFFPredictor( char const* identifier, @@ -62,14 +60,9 @@ Pl_TIFFPredictor::processRow() QTC::TC("libtests", "Pl_TIFFPredictor processRow", (action == a_decode ? 0 : 1)); BitWriter bw(p_next); BitStream in(cur_row.data(), cur_row.size()); - previous.clear(); - for (unsigned int i = 0; i < this->samples_per_pixel; ++i) { - long long sample = in.getBitsSigned(this->bits_per_sample); - bw.writeBitsSigned(sample, this->bits_per_sample); - previous.push_back(sample); - } - for (unsigned int col = 1; col < this->columns; ++col) { - for (auto& prev : previous) { + previous.assign(samples_per_pixel, 0); + for (unsigned int col = 0; col < this->columns; ++col) { + for (auto& prev: previous) { long long sample = in.getBitsSigned(this->bits_per_sample); long long new_sample = sample; if (action == a_encode) { From 20ca1e8644339ebb3df84c645b2244b5f786a6b3 Mon Sep 17 00:00:00 2001 From: m-holger Date: Fri, 26 Jan 2024 20:17:56 +0000 Subject: [PATCH 7/8] In Pl_TIFFPredictor::processRow optimize 8 bits_per_sample case --- libqpdf/Pl_TIFFPredictor.cc | 50 ++++++++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 14 deletions(-) diff --git a/libqpdf/Pl_TIFFPredictor.cc b/libqpdf/Pl_TIFFPredictor.cc index 5454d13a..a4addaae 100644 --- a/libqpdf/Pl_TIFFPredictor.cc +++ b/libqpdf/Pl_TIFFPredictor.cc @@ -58,24 +58,46 @@ void Pl_TIFFPredictor::processRow() { QTC::TC("libtests", "Pl_TIFFPredictor processRow", (action == a_decode ? 0 : 1)); - BitWriter bw(p_next); - BitStream in(cur_row.data(), cur_row.size()); previous.assign(samples_per_pixel, 0); - for (unsigned int col = 0; col < this->columns; ++col) { - for (auto& prev: previous) { - long long sample = in.getBitsSigned(this->bits_per_sample); - long long new_sample = sample; - if (action == a_encode) { - new_sample -= prev; - prev = sample; - } else { - new_sample += prev; - prev = new_sample; + if (bits_per_sample != 8) { + BitWriter bw(p_next); + BitStream in(cur_row.data(), cur_row.size()); + for (unsigned int col = 0; col < this->columns; ++col) { + for (auto& prev: previous) { + long long sample = in.getBitsSigned(this->bits_per_sample); + long long new_sample = sample; + if (action == a_encode) { + new_sample -= prev; + prev = sample; + } else { + new_sample += prev; + prev = new_sample; + } + bw.writeBitsSigned(new_sample, this->bits_per_sample); + } + } + bw.flush(); + } else { + auto next = cur_row.begin(); + auto cr_end = cur_row.end(); + auto pr_end = previous.end(); + + while (next != cr_end) { + for (auto prev = previous.begin(); prev != pr_end && next != cr_end; ++prev, ++next) { + long long sample = *next; + long long new_sample = sample; + if (action == a_encode) { + new_sample -= *prev; + *prev = sample; + } else { + new_sample += *prev; + *prev = new_sample; + } + auto out = static_cast(255U & new_sample); + p_next->write(&out, 1); } - bw.writeBitsSigned(new_sample, this->bits_per_sample); } } - bw.flush(); } void From d946ad6c3076073b9950df2ee25304c2d2a999ad Mon Sep 17 00:00:00 2001 From: m-holger Date: Sat, 27 Jan 2024 17:03:32 +0000 Subject: [PATCH 8/8] In Pl_TIFFPredictor::processRow buffer output --- libqpdf/Pl_TIFFPredictor.cc | 5 +++-- libqpdf/qpdf/Pl_TIFFPredictor.hh | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/libqpdf/Pl_TIFFPredictor.cc b/libqpdf/Pl_TIFFPredictor.cc index a4addaae..ec477049 100644 --- a/libqpdf/Pl_TIFFPredictor.cc +++ b/libqpdf/Pl_TIFFPredictor.cc @@ -78,6 +78,7 @@ Pl_TIFFPredictor::processRow() } bw.flush(); } else { + out.clear(); auto next = cur_row.begin(); auto cr_end = cur_row.end(); auto pr_end = previous.end(); @@ -93,10 +94,10 @@ Pl_TIFFPredictor::processRow() new_sample += *prev; *prev = new_sample; } - auto out = static_cast(255U & new_sample); - p_next->write(&out, 1); + out.push_back(static_cast(255U & new_sample)); } } + p_next->write(out.data(), out.size()); } } diff --git a/libqpdf/qpdf/Pl_TIFFPredictor.hh b/libqpdf/qpdf/Pl_TIFFPredictor.hh index 4579ba1f..276ed54d 100644 --- a/libqpdf/qpdf/Pl_TIFFPredictor.hh +++ b/libqpdf/qpdf/Pl_TIFFPredictor.hh @@ -35,6 +35,7 @@ class Pl_TIFFPredictor: public Pipeline unsigned int bits_per_sample; std::vector cur_row; std::vector previous; + std::vector out; Pipeline* p_next; };