Logo Search packages:      
Sourcecode: qpdf version File versions  Download package

Pl_PNGFilter.cc

#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();
}

Generated by  Doxygen 1.6.0   Back to index