aboutsummaryrefslogtreecommitdiffstats
path: root/libqpdf/Pl_TIFFPredictor.cc
diff options
context:
space:
mode:
authorJay Berkenbilt <ejb@ql.org>2018-01-13 20:15:20 +0100
committerJay Berkenbilt <ejb@ql.org>2018-01-14 01:49:42 +0100
commit53971d50be39448c980d842a1fe1f525b4cee597 (patch)
tree4a8ddcfcecd26d7cc1713e74ecf06d842ef163f6 /libqpdf/Pl_TIFFPredictor.cc
parentd9c90497089ae5cf00891d6febfa7f486f021833 (diff)
downloadqpdf-53971d50be39448c980d842a1fe1f525b4cee597.tar.zst
Add Pl_TIFFPredictor
Diffstat (limited to 'libqpdf/Pl_TIFFPredictor.cc')
-rw-r--r--libqpdf/Pl_TIFFPredictor.cc123
1 files changed, 123 insertions, 0 deletions
diff --git a/libqpdf/Pl_TIFFPredictor.cc b/libqpdf/Pl_TIFFPredictor.cc
new file mode 100644
index 00000000..42cfbb1a
--- /dev/null
+++ b/libqpdf/Pl_TIFFPredictor.cc
@@ -0,0 +1,123 @@
+#include <qpdf/Pl_TIFFPredictor.hh>
+#include <qpdf/QTC.hh>
+#include <qpdf/BitStream.hh>
+#include <qpdf/BitWriter.hh>
+#include <stdexcept>
+#include <vector>
+#include <string.h>
+#include <limits.h>
+
+Pl_TIFFPredictor::Pl_TIFFPredictor(char const* identifier, Pipeline* next,
+ action_e action, unsigned int columns,
+ unsigned int samples_per_pixel,
+ unsigned int bits_per_sample) :
+ Pipeline(identifier, next),
+ action(action),
+ columns(columns),
+ samples_per_pixel(samples_per_pixel),
+ bits_per_sample(bits_per_sample),
+ cur_row(0),
+ pos(0)
+{
+ if (samples_per_pixel < 1)
+ {
+ throw std::runtime_error(
+ "TIFFPredictor created with invalid samples_per_pixel");
+ }
+ if ((bits_per_sample < 1) ||
+ (bits_per_sample > (8 * (sizeof(unsigned long long)))))
+ {
+ throw std::runtime_error(
+ "TIFFPredictor created with invalid bits_per_sample");
+ }
+ unsigned long long bpr =
+ ((columns * bits_per_sample * samples_per_pixel) + 7) / 8;
+ if ((bpr == 0) || (bpr > (UINT_MAX - 1)))
+ {
+ throw std::runtime_error(
+ "TIFFPredictor created with invalid columns value");
+ }
+ this->bytes_per_row = bpr & UINT_MAX;
+ this->cur_row = new unsigned char[this->bytes_per_row];
+ memset(this->cur_row, 0, this->bytes_per_row);
+}
+
+Pl_TIFFPredictor::~Pl_TIFFPredictor()
+{
+ delete [] cur_row;
+}
+
+void
+Pl_TIFFPredictor::write(unsigned char* data, size_t len)
+{
+ size_t left = this->bytes_per_row - this->pos;
+ size_t offset = 0;
+ while (len >= left)
+ {
+ // finish off current row
+ memcpy(this->cur_row + this->pos, data + offset, left);
+ offset += left;
+ len -= left;
+
+ processRow();
+
+ // Prepare for next row
+ memset(this->cur_row, 0, this->bytes_per_row);
+ left = this->bytes_per_row;
+ this->pos = 0;
+ }
+ if (len)
+ {
+ memcpy(this->cur_row + this->pos, data + offset, len);
+ }
+ this->pos += len;
+}
+
+void
+Pl_TIFFPredictor::processRow()
+{
+ QTC::TC("libtests", "Pl_TIFFPredictor processRow",
+ (action == a_decode ? 0 : 1));
+ BitWriter bw(this->getNext());
+ BitStream in(this->cur_row, this->bytes_per_row);
+ std::vector<long long> prev;
+ 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);
+ }
+ for (unsigned int col = 1; col < this->columns; ++col)
+ {
+ for (unsigned int i = 0; i < this->samples_per_pixel; ++i)
+ {
+ 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;
+ }
+ else
+ {
+ new_sample += prev[i];
+ prev[i] = new_sample;
+ }
+ bw.writeBitsSigned(new_sample, this->bits_per_sample);
+ }
+ }
+ bw.flush();
+}
+
+void
+Pl_TIFFPredictor::finish()
+{
+ if (this->pos)
+ {
+ // write partial row
+ processRow();
+ }
+ this->pos = 0;
+ memset(this->cur_row, 0, this->bytes_per_row);
+ getNext()->finish();
+}