Commit 9a487202463c2bf05fc8fce8ae6a1005348a69a0
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.
Showing
2 changed files
with
123 additions
and
37 deletions
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 | }; |