aboutsummaryrefslogtreecommitdiffstats
path: root/libqpdf/Pl_PNGFilter.cc
diff options
context:
space:
mode:
Diffstat (limited to 'libqpdf/Pl_PNGFilter.cc')
-rw-r--r--libqpdf/Pl_PNGFilter.cc146
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();
+}