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:
parent
d83f8f3bfa
commit
9a48720246
|
@ -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()
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue
Block a user