Commit 9a487202463c2bf05fc8fce8ae6a1005348a69a0

Authored by Casey Rojas
Committed by Jay Berkenbilt
1 parent d83f8f3b

Initial implementation of other PNG decode filters

Initial implementation provided by Casey Rojas <crojas@infotechfl.com>
Some problems are fixed in a subsequent commit.
libqpdf/Pl_PNGFilter.cc
@@ -2,6 +2,7 @@ @@ -2,6 +2,7 @@
2 #include <stdexcept> 2 #include <stdexcept>
3 #include <string.h> 3 #include <string.h>
4 #include <limits.h> 4 #include <limits.h>
  5 +#include <math.h>
5 6
6 Pl_PNGFilter::Pl_PNGFilter(char const* identifier, Pipeline* next, 7 Pl_PNGFilter::Pl_PNGFilter(char const* identifier, Pipeline* next,
7 action_e action, unsigned int columns, 8 action_e action, unsigned int columns,
@@ -13,6 +14,7 @@ Pl_PNGFilter::Pl_PNGFilter(char const* identifier, Pipeline* next, @@ -13,6 +14,7 @@ Pl_PNGFilter::Pl_PNGFilter(char const* identifier, Pipeline* next,
13 prev_row(0), 14 prev_row(0),
14 buf1(0), 15 buf1(0),
15 buf2(0), 16 buf2(0),
  17 + bytes_per_pixel(bytes_per_pixel),
16 pos(0) 18 pos(0)
17 { 19 {
18 if ((columns == 0) || (columns > UINT_MAX - 1)) 20 if ((columns == 0) || (columns > UINT_MAX - 1))
@@ -82,40 +84,125 @@ Pl_PNGFilter::decodeRow() @@ -82,40 +84,125 @@ Pl_PNGFilter::decodeRow()
82 int filter = this->cur_row[0]; 84 int filter = this->cur_row[0];
83 if (this->prev_row) 85 if (this->prev_row)
84 { 86 {
85 - switch (filter)  
86 - {  
87 - case 0: // none  
88 - break;  
89 -  
90 - case 1: // sub  
91 - throw std::logic_error("sub filter not implemented");  
92 - break;  
93 -  
94 - case 2: // up  
95 - for (unsigned int i = 1; i <= this->columns; ++i)  
96 - {  
97 - this->cur_row[i] += this->prev_row[i];  
98 - }  
99 - break;  
100 -  
101 - case 3: // average  
102 - throw std::logic_error("average filter not implemented");  
103 - break;  
104 -  
105 - case 4: // Paeth  
106 - throw std::logic_error("Paeth filter not implemented");  
107 - break;  
108 -  
109 - default:  
110 - // ignore  
111 - break;  
112 - } 87 + switch (filter)
  88 + {
  89 + case 0:
  90 + break;
  91 + case 1:
  92 + this->decodeSub();
  93 + break;
  94 + case 2:
  95 + this->decodeUp();
  96 + break;
  97 + case 3:
  98 + this->decodeAverage();
  99 + break;
  100 + case 4:
  101 + this->decodePaeth();
  102 + break;
  103 + default:
  104 + // ignore
  105 + break;
  106 + }
113 } 107 }
114 108
115 getNext()->write(this->cur_row + 1, this->columns); 109 getNext()->write(this->cur_row + 1, this->columns);
116 } 110 }
117 111
118 void 112 void
  113 +Pl_PNGFilter::decodeSub()
  114 +{
  115 + unsigned char* buffer = this->cur_row + 1;
  116 + unsigned int bpp = this->bytes_per_pixel != 0 ? this->bytes_per_pixel : 1;
  117 +
  118 + for (unsigned int i = 0; i < this->columns; ++i)
  119 + {
  120 + unsigned char left = 0;
  121 +
  122 + if (i >= bpp)
  123 + {
  124 + left = buffer[i - bpp];
  125 + }
  126 +
  127 + buffer[i] += left;
  128 + }
  129 +}
  130 +
  131 +void
  132 +Pl_PNGFilter::decodeUp()
  133 +{
  134 + unsigned char* buffer = this->cur_row + 1;
  135 + unsigned char* above_buffer = this->prev_row + 1;
  136 +
  137 + for (unsigned int i = 0; i < this->columns; ++i)
  138 + {
  139 + unsigned char up = above_buffer[i];
  140 + buffer[i] += up;
  141 + }
  142 +}
  143 +
  144 +void
  145 +Pl_PNGFilter::decodeAverage()
  146 +{
  147 + unsigned char* buffer = this->cur_row+1;
  148 + unsigned char* above_buffer = this->prev_row+1;
  149 + unsigned int bpp = this->bytes_per_pixel != 0 ? this->bytes_per_pixel : 1;
  150 +
  151 + for (unsigned int i = 0; i < this->columns; ++i)
  152 + {
  153 + int left = 0, up = 0;
  154 +
  155 + if (i >= bpp)
  156 + {
  157 + left = buffer[i - bpp];
  158 + }
  159 +
  160 + up = above_buffer[i];
  161 + buffer[i] += floor((left+up) / 2);
  162 + }
  163 +}
  164 +
  165 +void
  166 +Pl_PNGFilter::decodePaeth()
  167 +{
  168 + unsigned char* buffer = this->cur_row+1;
  169 + unsigned char* above_buffer = this->prev_row+1;
  170 + unsigned int bpp = this->bytes_per_pixel != 0 ? this->bytes_per_pixel : 1;
  171 +
  172 + for (unsigned int i = 0; i < this->columns; ++i)
  173 + {
  174 + int left = 0,
  175 + up = above_buffer[i],
  176 + upper_left = 0;
  177 +
  178 + if (i >= bpp)
  179 + {
  180 + left = buffer[i - bpp];
  181 + upper_left = above_buffer[i - bpp];
  182 + }
  183 +
  184 + buffer[i] += this->PaethPredictor(left, up, upper_left);
  185 + }
  186 +}
  187 +
  188 +int
  189 +Pl_PNGFilter::PaethPredictor(int a, int b, int c)
  190 +{
  191 + int p = a + b - c;
  192 + int pa = std::abs(p - a);
  193 + int pb = std::abs(p - b);
  194 + int pc = std::abs(p - c);
  195 +
  196 + if (pa <= pb && pa <= pc) {
  197 + return a;
  198 + }
  199 + if (pb <= pc) {
  200 + return b;
  201 + }
  202 + return c;
  203 +}
  204 +
  205 +void
119 Pl_PNGFilter::encodeRow() 206 Pl_PNGFilter::encodeRow()
120 { 207 {
121 // For now, hard-code to using UP filter. 208 // For now, hard-code to using UP filter.
libqpdf/qpdf/Pl_PNGFilter.hh
@@ -4,15 +4,8 @@ @@ -4,15 +4,8 @@
4 // This pipeline applies or reverses the application of a PNG filter 4 // This pipeline applies or reverses the application of a PNG filter
5 // as described in the PNG specification. 5 // as described in the PNG specification.
6 6
7 -// NOTE: In its initial implementation, it only encodes and decodes  
8 -// filters "none" and "up". The primary motivation of this code is to  
9 -// encode and decode PDF 1.5+ XRef streams which are often encoded  
10 -// with Flate predictor 12, which corresponds to the PNG up filter.  
11 -// At present, the bytes_per_pixel parameter is ignored, and an  
12 -// exception is thrown if any row of the file has a filter of other  
13 -// than 0 or 2. Finishing the implementation would not be difficult.  
14 -// See chapter 6 of the PNG specification for a description of the  
15 -// filter algorithms. 7 +// NOTE: In its current implementation, this filter always encodes
  8 +// using the "up" filter, but it decodes all the filters.
16 9
17 #include <qpdf/Pipeline.hh> 10 #include <qpdf/Pipeline.hh>
18 11
@@ -35,9 +28,14 @@ class Pl_PNGFilter: public Pipeline @@ -35,9 +28,14 @@ class Pl_PNGFilter: public Pipeline
35 virtual void finish(); 28 virtual void finish();
36 29
37 private: 30 private:
  31 + void decodeSub();
  32 + void decodeUp();
  33 + void decodeAverage();
  34 + void decodePaeth();
38 void processRow(); 35 void processRow();
39 void encodeRow(); 36 void encodeRow();
40 void decodeRow(); 37 void decodeRow();
  38 + int PaethPredictor(int a, int b, int c);
41 39
42 action_e action; 40 action_e action;
43 unsigned int columns; 41 unsigned int columns;
@@ -45,6 +43,7 @@ class Pl_PNGFilter: public Pipeline @@ -45,6 +43,7 @@ class Pl_PNGFilter: public Pipeline
45 unsigned char* prev_row; 43 unsigned char* prev_row;
46 unsigned char* buf1; 44 unsigned char* buf1;
47 unsigned char* buf2; 45 unsigned char* buf2;
  46 + unsigned int bytes_per_pixel;
48 size_t pos; 47 size_t pos;
49 size_t incoming; 48 size_t incoming;
50 }; 49 };