mirror of
https://github.com/qpdf/qpdf.git
synced 2024-11-16 01:27:07 +00:00
147 lines
2.6 KiB
C++
147 lines
2.6 KiB
C++
|
|
||
|
#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();
|
||
|
}
|