2
1
mirror of https://github.com/qpdf/qpdf.git synced 2024-06-06 04:10:52 +00:00

Initial implementation of other PNG decode filters

Initial implementation provided by Casey Rojas <crojas@infotechfl.com>
Some problems are fixed in a subsequent commit.
This commit is contained in:
Casey Rojas 2017-11-07 12:12:18 -05:00 committed by Jay Berkenbilt
parent d83f8f3bfa
commit 9a48720246
2 changed files with 123 additions and 37 deletions

View File

@ -2,6 +2,7 @@
#include <stdexcept>
#include <string.h>
#include <limits.h>
#include <math.h>
Pl_PNGFilter::Pl_PNGFilter(char const* identifier, Pipeline* next,
action_e action, unsigned int columns,
@ -13,6 +14,7 @@ Pl_PNGFilter::Pl_PNGFilter(char const* identifier, Pipeline* next,
prev_row(0),
buf1(0),
buf2(0),
bytes_per_pixel(bytes_per_pixel),
pos(0)
{
if ((columns == 0) || (columns > UINT_MAX - 1))
@ -82,39 +84,124 @@ Pl_PNGFilter::decodeRow()
int filter = this->cur_row[0];
if (this->prev_row)
{
switch (filter)
{
case 0: // none
break;
case 1: // sub
throw std::logic_error("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 std::logic_error("average filter not implemented");
break;
case 4: // Paeth
throw std::logic_error("Paeth filter not implemented");
break;
default:
// ignore
break;
}
switch (filter)
{
case 0:
break;
case 1:
this->decodeSub();
break;
case 2:
this->decodeUp();
break;
case 3:
this->decodeAverage();
break;
case 4:
this->decodePaeth();
break;
default:
// ignore
break;
}
}
getNext()->write(this->cur_row + 1, this->columns);
}
void
Pl_PNGFilter::decodeSub()
{
unsigned char* buffer = this->cur_row + 1;
unsigned int bpp = this->bytes_per_pixel != 0 ? this->bytes_per_pixel : 1;
for (unsigned int i = 0; i < this->columns; ++i)
{
unsigned char left = 0;
if (i >= bpp)
{
left = buffer[i - bpp];
}
buffer[i] += left;
}
}
void
Pl_PNGFilter::decodeUp()
{
unsigned char* buffer = this->cur_row + 1;
unsigned char* above_buffer = this->prev_row + 1;
for (unsigned int i = 0; i < this->columns; ++i)
{
unsigned char up = above_buffer[i];
buffer[i] += up;
}
}
void
Pl_PNGFilter::decodeAverage()
{
unsigned char* buffer = this->cur_row+1;
unsigned char* above_buffer = this->prev_row+1;
unsigned int bpp = this->bytes_per_pixel != 0 ? this->bytes_per_pixel : 1;
for (unsigned int i = 0; i < this->columns; ++i)
{
int left = 0, up = 0;
if (i >= bpp)
{
left = buffer[i - bpp];
}
up = above_buffer[i];
buffer[i] += floor((left+up) / 2);
}
}
void
Pl_PNGFilter::decodePaeth()
{
unsigned char* buffer = this->cur_row+1;
unsigned char* above_buffer = this->prev_row+1;
unsigned int bpp = this->bytes_per_pixel != 0 ? this->bytes_per_pixel : 1;
for (unsigned int i = 0; i < this->columns; ++i)
{
int left = 0,
up = above_buffer[i],
upper_left = 0;
if (i >= bpp)
{
left = buffer[i - bpp];
upper_left = above_buffer[i - bpp];
}
buffer[i] += this->PaethPredictor(left, up, upper_left);
}
}
int
Pl_PNGFilter::PaethPredictor(int a, int b, int c)
{
int p = a + b - c;
int pa = std::abs(p - a);
int pb = std::abs(p - b);
int pc = std::abs(p - c);
if (pa <= pb && pa <= pc) {
return a;
}
if (pb <= pc) {
return b;
}
return c;
}
void
Pl_PNGFilter::encodeRow()
{

View File

@ -4,15 +4,8 @@
// This pipeline applies or reverses the application of a PNG filter
// as described in the PNG specification.
// NOTE: In its initial implementation, it only encodes and decodes
// filters "none" and "up". The primary motivation of this code is to
// encode and decode PDF 1.5+ XRef streams which are often encoded
// with Flate predictor 12, which corresponds to the PNG up filter.
// At present, the bytes_per_pixel parameter is ignored, and an
// exception is thrown if any row of the file has a filter of other
// than 0 or 2. Finishing the implementation would not be difficult.
// See chapter 6 of the PNG specification for a description of the
// filter algorithms.
// NOTE: In its current implementation, this filter always encodes
// using the "up" filter, but it decodes all the filters.
#include <qpdf/Pipeline.hh>
@ -35,9 +28,14 @@ class Pl_PNGFilter: public Pipeline
virtual void finish();
private:
void decodeSub();
void decodeUp();
void decodeAverage();
void decodePaeth();
void processRow();
void encodeRow();
void decodeRow();
int PaethPredictor(int a, int b, int c);
action_e action;
unsigned int columns;
@ -45,6 +43,7 @@ class Pl_PNGFilter: public Pipeline
unsigned char* prev_row;
unsigned char* buf1;
unsigned char* buf2;
unsigned int bytes_per_pixel;
size_t pos;
size_t incoming;
};