diff options
author | Jay Berkenbilt <ejb@ql.org> | 2018-01-13 20:15:20 +0100 |
---|---|---|
committer | Jay Berkenbilt <ejb@ql.org> | 2018-01-14 01:49:42 +0100 |
commit | 53971d50be39448c980d842a1fe1f525b4cee597 (patch) | |
tree | 4a8ddcfcecd26d7cc1713e74ecf06d842ef163f6 /libqpdf/Pl_TIFFPredictor.cc | |
parent | d9c90497089ae5cf00891d6febfa7f486f021833 (diff) | |
download | qpdf-53971d50be39448c980d842a1fe1f525b4cee597.tar.zst |
Add Pl_TIFFPredictor
Diffstat (limited to 'libqpdf/Pl_TIFFPredictor.cc')
-rw-r--r-- | libqpdf/Pl_TIFFPredictor.cc | 123 |
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(); +} |