From 53971d50be39448c980d842a1fe1f525b4cee597 Mon Sep 17 00:00:00 2001 From: Jay Berkenbilt Date: Sat, 13 Jan 2018 14:15:20 -0500 Subject: Add Pl_TIFFPredictor --- libqpdf/Pl_TIFFPredictor.cc | 123 +++++++++++++++++++++++++++++++++++++++ libqpdf/build.mk | 1 + libqpdf/qpdf/Pl_TIFFPredictor.hh | 39 +++++++++++++ 3 files changed, 163 insertions(+) create mode 100644 libqpdf/Pl_TIFFPredictor.cc create mode 100644 libqpdf/qpdf/Pl_TIFFPredictor.hh (limited to 'libqpdf') 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 +#include +#include +#include +#include +#include +#include +#include + +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 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(); +} diff --git a/libqpdf/build.mk b/libqpdf/build.mk index 75d0054e..c75c3dd9 100644 --- a/libqpdf/build.mk +++ b/libqpdf/build.mk @@ -32,6 +32,7 @@ SRCS_libqpdf = \ libqpdf/Pl_RunLength.cc \ libqpdf/Pl_SHA2.cc \ libqpdf/Pl_StdioFile.cc \ + libqpdf/Pl_TIFFPredictor.cc \ libqpdf/QPDF.cc \ libqpdf/QPDFExc.cc \ libqpdf/QPDFObjGen.cc \ diff --git a/libqpdf/qpdf/Pl_TIFFPredictor.hh b/libqpdf/qpdf/Pl_TIFFPredictor.hh new file mode 100644 index 00000000..235068ee --- /dev/null +++ b/libqpdf/qpdf/Pl_TIFFPredictor.hh @@ -0,0 +1,39 @@ +#ifndef __PL_TIFFPREDICTOR_HH__ +#define __PL_TIFFPREDICTOR_HH__ + +// This pipeline reverses the application of a TIFF predictor as +// described in the TIFF specification. + +#include + +class Pl_TIFFPredictor: public Pipeline +{ + public: + enum action_e { a_encode, a_decode }; + + QPDF_DLL + Pl_TIFFPredictor(char const* identifier, Pipeline* next, + action_e action, unsigned int columns, + unsigned int samples_per_pixel = 1, + unsigned int bits_per_sample = 8); + QPDF_DLL + virtual ~Pl_TIFFPredictor(); + + QPDF_DLL + virtual void write(unsigned char* data, size_t len); + QPDF_DLL + virtual void finish(); + + private: + void processRow(); + + action_e action; + unsigned int columns; + unsigned int bytes_per_row; + unsigned int samples_per_pixel; + unsigned int bits_per_sample; + unsigned char* cur_row; + size_t pos; +}; + +#endif // __PL_TIFFPREDICTOR_HH__ -- cgit v1.2.3-54-g00ecf