diff options
author | Jay Berkenbilt <ejb@ql.org> | 2008-04-29 14:55:25 +0200 |
---|---|---|
committer | Jay Berkenbilt <ejb@ql.org> | 2008-04-29 14:55:25 +0200 |
commit | 9a0b88bf7777c153dc46ace22db74ef24d51583a (patch) | |
tree | f567ac1cf2bf5071a611eb49323a935b6ac938ff /libqpdf/Pl_PNGFilter.cc | |
download | qpdf-9a0b88bf7777c153dc46ace22db74ef24d51583a.tar.zst |
update release date to actual daterelease-qpdf-2.0
git-svn-id: svn+q:///qpdf/trunk@599 71b93d88-0707-0410-a8cf-f5a4172ac649
Diffstat (limited to 'libqpdf/Pl_PNGFilter.cc')
-rw-r--r-- | libqpdf/Pl_PNGFilter.cc | 146 |
1 files changed, 146 insertions, 0 deletions
diff --git a/libqpdf/Pl_PNGFilter.cc b/libqpdf/Pl_PNGFilter.cc new file mode 100644 index 00000000..28b87c5e --- /dev/null +++ b/libqpdf/Pl_PNGFilter.cc @@ -0,0 +1,146 @@ + +#include <qpdf/Pl_PNGFilter.hh> +#include <string.h> + +Pl_PNGFilter::Pl_PNGFilter(char const* identifier, Pipeline* next, + action_e action, unsigned int columns, + unsigned int bytes_per_pixel) : + Pipeline(identifier, next), + action(action), + columns(columns), + cur_row(0), + prev_row(0), + buf1(0), + buf2(0), + pos(0) +{ + this->buf1 = new unsigned char[columns + 1]; + this->buf2 = new unsigned char[columns + 1]; + this->cur_row = buf1; + + // number of bytes per incoming row + this->incoming = (action == a_encode ? columns : columns + 1); +} + +Pl_PNGFilter::~Pl_PNGFilter() +{ + delete [] buf1; + delete [] buf2; +} + +void +Pl_PNGFilter::write(unsigned char* data, int len) +{ + int left = this->incoming - this->pos; + unsigned int offset = 0; + while (len >= left) + { + // finish off current row + memcpy(this->cur_row + this->pos, data + offset, left); + offset += left; + len -= left; + + processRow(); + + // Swap rows + unsigned char* t = this->prev_row; + this->prev_row = this->cur_row; + this->cur_row = t ? t : this->buf2; + memset(this->cur_row, 0, this->columns + 1); + left = this->incoming; + this->pos = 0; + } + if (len) + { + memcpy(this->cur_row + this->pos, data + offset, len); + } + this->pos += len; +} + +void +Pl_PNGFilter::processRow() +{ + if (this->action == a_encode) + { + encodeRow(); + } + else + { + decodeRow(); + } +} + +void +Pl_PNGFilter::decodeRow() +{ + int filter = (int) this->cur_row[0]; + if (this->prev_row) + { + switch (filter) + { + case 0: // none + break; + + case 1: // sub + throw Exception("sub filter not implemented"); + break; + + case 2: // up + for (unsigned int i = 1; i <= this->columns; ++i) + { + this->cur_row[i] += this->prev_row[i]; + } + break; + + case 3: // average + throw Exception("average filter not implemented"); + break; + + case 4: // Paeth + throw Exception("Paeth filter not implemented"); + break; + + default: + // ignore + break; + } + } + + getNext()->write(this->cur_row + 1, this->columns); +} + +void +Pl_PNGFilter::encodeRow() +{ + // For now, hard-code to using UP filter. + unsigned char ch = 2; + getNext()->write(&ch, 1); + if (this->prev_row) + { + for (unsigned int i = 0; i < this->columns; ++i) + { + ch = this->cur_row[i] - this->prev_row[i]; + getNext()->write(&ch, 1); + } + } + else + { + getNext()->write(this->cur_row, this->columns); + } +} + +void +Pl_PNGFilter::finish() +{ + if (this->pos) + { + // write partial row + processRow(); + } + this->prev_row = 0; + this->cur_row = buf1; + this->pos = 0; + memset(this->cur_row, 0, this->columns + 1); + + getNext()->finish(); +} |