Commit a3a55be9cdebd517f4dce9ff66aeda78b136b003

Authored by Jay Berkenbilt
1 parent 9a487202

Correct errors in PNG filters and make use from library

libqpdf/Pl_PNGFilter.cc
@@ -2,32 +2,54 @@ @@ -2,32 +2,54 @@
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>  
6 5
7 Pl_PNGFilter::Pl_PNGFilter(char const* identifier, Pipeline* next, 6 Pl_PNGFilter::Pl_PNGFilter(char const* identifier, Pipeline* next,
8 action_e action, unsigned int columns, 7 action_e action, unsigned int columns,
9 - unsigned int bytes_per_pixel) : 8 + unsigned int samples_per_pixel,
  9 + unsigned int bits_per_sample) :
10 Pipeline(identifier, next), 10 Pipeline(identifier, next),
11 action(action), 11 action(action),
12 - columns(columns),  
13 cur_row(0), 12 cur_row(0),
14 prev_row(0), 13 prev_row(0),
15 buf1(0), 14 buf1(0),
16 buf2(0), 15 buf2(0),
17 - bytes_per_pixel(bytes_per_pixel),  
18 pos(0) 16 pos(0)
19 { 17 {
20 - if ((columns == 0) || (columns > UINT_MAX - 1)) 18 + if ((samples_per_pixel < 1) || (samples_per_pixel > 4))
  19 + {
  20 + throw std::runtime_error(
  21 + "PNGFilter created with invalid samples_per_pixel not from 1 to 4");
  22 + }
  23 + if (! ((bits_per_sample == 1) ||
  24 + (bits_per_sample == 2) ||
  25 + (bits_per_sample == 4) ||
  26 + (bits_per_sample == 8) ||
  27 + (bits_per_sample == 16)))
  28 + {
  29 + throw std::runtime_error(
  30 + "PNGFilter created with invalid bits_per_sample not"
  31 + " 1, 2, 4, 8, or 16");
  32 + }
  33 + this->bytes_per_pixel = ((bits_per_sample * samples_per_pixel) + 7) / 8;
  34 + unsigned long long bpr =
  35 + ((columns * bits_per_sample * samples_per_pixel) + 7) / 8;
  36 + if ((bpr == 0) || (bpr > (UINT_MAX - 1)))
21 { 37 {
22 throw std::runtime_error( 38 throw std::runtime_error(
23 "PNGFilter created with invalid columns value"); 39 "PNGFilter created with invalid columns value");
24 } 40 }
25 - this->buf1 = new unsigned char[columns + 1];  
26 - this->buf2 = new unsigned char[columns + 1];  
27 - this->cur_row = buf1; 41 + this->bytes_per_row = bpr & UINT_MAX;
  42 + this->buf1 = new unsigned char[this->bytes_per_row + 1];
  43 + this->buf2 = new unsigned char[this->bytes_per_row + 1];
  44 + memset(this->buf1, 0, this->bytes_per_row + 1);
  45 + memset(this->buf2, 0, this->bytes_per_row + 1);
  46 + this->cur_row = this->buf1;
  47 + this->prev_row = this->buf2;
28 48
29 // number of bytes per incoming row 49 // number of bytes per incoming row
30 - this->incoming = (action == a_encode ? columns : columns + 1); 50 + this->incoming = (action == a_encode ?
  51 + this->bytes_per_row :
  52 + this->bytes_per_row + 1);
31 } 53 }
32 54
33 Pl_PNGFilter::~Pl_PNGFilter() 55 Pl_PNGFilter::~Pl_PNGFilter()
@@ -54,7 +76,7 @@ Pl_PNGFilter::write(unsigned char* data, size_t len) @@ -54,7 +76,7 @@ Pl_PNGFilter::write(unsigned char* data, size_t len)
54 unsigned char* t = this->prev_row; 76 unsigned char* t = this->prev_row;
55 this->prev_row = this->cur_row; 77 this->prev_row = this->cur_row;
56 this->cur_row = t ? t : this->buf2; 78 this->cur_row = t ? t : this->buf2;
57 - memset(this->cur_row, 0, this->columns + 1); 79 + memset(this->cur_row, 0, this->bytes_per_row + 1);
58 left = this->incoming; 80 left = this->incoming;
59 this->pos = 0; 81 this->pos = 0;
60 } 82 }
@@ -106,16 +128,16 @@ Pl_PNGFilter::decodeRow() @@ -106,16 +128,16 @@ Pl_PNGFilter::decodeRow()
106 } 128 }
107 } 129 }
108 130
109 - getNext()->write(this->cur_row + 1, this->columns); 131 + getNext()->write(this->cur_row + 1, this->bytes_per_row);
110 } 132 }
111 133
112 void 134 void
113 Pl_PNGFilter::decodeSub() 135 Pl_PNGFilter::decodeSub()
114 { 136 {
115 unsigned char* buffer = this->cur_row + 1; 137 unsigned char* buffer = this->cur_row + 1;
116 - unsigned int bpp = this->bytes_per_pixel != 0 ? this->bytes_per_pixel : 1; 138 + unsigned int bpp = this->bytes_per_pixel;
117 139
118 - for (unsigned int i = 0; i < this->columns; ++i) 140 + for (unsigned int i = 0; i < this->bytes_per_row; ++i)
119 { 141 {
120 unsigned char left = 0; 142 unsigned char left = 0;
121 143
@@ -134,7 +156,7 @@ Pl_PNGFilter::decodeUp() @@ -134,7 +156,7 @@ Pl_PNGFilter::decodeUp()
134 unsigned char* buffer = this->cur_row + 1; 156 unsigned char* buffer = this->cur_row + 1;
135 unsigned char* above_buffer = this->prev_row + 1; 157 unsigned char* above_buffer = this->prev_row + 1;
136 158
137 - for (unsigned int i = 0; i < this->columns; ++i) 159 + for (unsigned int i = 0; i < this->bytes_per_row; ++i)
138 { 160 {
139 unsigned char up = above_buffer[i]; 161 unsigned char up = above_buffer[i];
140 buffer[i] += up; 162 buffer[i] += up;
@@ -144,13 +166,14 @@ Pl_PNGFilter::decodeUp() @@ -144,13 +166,14 @@ Pl_PNGFilter::decodeUp()
144 void 166 void
145 Pl_PNGFilter::decodeAverage() 167 Pl_PNGFilter::decodeAverage()
146 { 168 {
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; 169 + unsigned char* buffer = this->cur_row + 1;
  170 + unsigned char* above_buffer = this->prev_row + 1;
  171 + unsigned int bpp = this->bytes_per_pixel;
150 172
151 - for (unsigned int i = 0; i < this->columns; ++i) 173 + for (unsigned int i = 0; i < this->bytes_per_row; ++i)
152 { 174 {
153 - int left = 0, up = 0; 175 + int left = 0;
  176 + int up = 0;
154 177
155 if (i >= bpp) 178 if (i >= bpp)
156 { 179 {
@@ -158,22 +181,22 @@ Pl_PNGFilter::decodeAverage() @@ -158,22 +181,22 @@ Pl_PNGFilter::decodeAverage()
158 } 181 }
159 182
160 up = above_buffer[i]; 183 up = above_buffer[i];
161 - buffer[i] += floor((left+up) / 2); 184 + buffer[i] += (left+up) / 2;
162 } 185 }
163 } 186 }
164 187
165 void 188 void
166 Pl_PNGFilter::decodePaeth() 189 Pl_PNGFilter::decodePaeth()
167 { 190 {
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; 191 + unsigned char* buffer = this->cur_row + 1;
  192 + unsigned char* above_buffer = this->prev_row + 1;
  193 + unsigned int bpp = this->bytes_per_pixel;
171 194
172 - for (unsigned int i = 0; i < this->columns; ++i) 195 + for (unsigned int i = 0; i < this->bytes_per_row; ++i)
173 { 196 {
174 - int left = 0,  
175 - up = above_buffer[i],  
176 - upper_left = 0; 197 + int left = 0;
  198 + int up = above_buffer[i];
  199 + int upper_left = 0;
177 200
178 if (i >= bpp) 201 if (i >= bpp)
179 { 202 {
@@ -193,10 +216,12 @@ Pl_PNGFilter::PaethPredictor(int a, int b, int c) @@ -193,10 +216,12 @@ Pl_PNGFilter::PaethPredictor(int a, int b, int c)
193 int pb = std::abs(p - b); 216 int pb = std::abs(p - b);
194 int pc = std::abs(p - c); 217 int pc = std::abs(p - c);
195 218
196 - if (pa <= pb && pa <= pc) { 219 + if (pa <= pb && pa <= pc)
  220 + {
197 return a; 221 return a;
198 } 222 }
199 - if (pb <= pc) { 223 + if (pb <= pc)
  224 + {
200 return b; 225 return b;
201 } 226 }
202 return c; 227 return c;
@@ -210,7 +235,7 @@ Pl_PNGFilter::encodeRow() @@ -210,7 +235,7 @@ Pl_PNGFilter::encodeRow()
210 getNext()->write(&ch, 1); 235 getNext()->write(&ch, 1);
211 if (this->prev_row) 236 if (this->prev_row)
212 { 237 {
213 - for (unsigned int i = 0; i < this->columns; ++i) 238 + for (unsigned int i = 0; i < this->bytes_per_row; ++i)
214 { 239 {
215 ch = this->cur_row[i] - this->prev_row[i]; 240 ch = this->cur_row[i] - this->prev_row[i];
216 getNext()->write(&ch, 1); 241 getNext()->write(&ch, 1);
@@ -218,7 +243,7 @@ Pl_PNGFilter::encodeRow() @@ -218,7 +243,7 @@ Pl_PNGFilter::encodeRow()
218 } 243 }
219 else 244 else
220 { 245 {
221 - getNext()->write(this->cur_row, this->columns); 246 + getNext()->write(this->cur_row, this->bytes_per_row);
222 } 247 }
223 } 248 }
224 249
@@ -233,7 +258,7 @@ Pl_PNGFilter::finish() @@ -233,7 +258,7 @@ Pl_PNGFilter::finish()
233 this->prev_row = 0; 258 this->prev_row = 0;
234 this->cur_row = buf1; 259 this->cur_row = buf1;
235 this->pos = 0; 260 this->pos = 0;
236 - memset(this->cur_row, 0, this->columns + 1); 261 + memset(this->cur_row, 0, this->bytes_per_row + 1);
237 262
238 getNext()->finish(); 263 getNext()->finish();
239 } 264 }
libqpdf/QPDF.cc
@@ -1006,7 +1006,7 @@ QPDF::processXRefStream(qpdf_offset_t xref_offset, QPDFObjectHandle&amp; xref_obj) @@ -1006,7 +1006,7 @@ QPDF::processXRefStream(qpdf_offset_t xref_offset, QPDFObjectHandle&amp; xref_obj)
1006 // that this multiplication does not cause an overflow. 1006 // that this multiplication does not cause an overflow.
1007 size_t expected_size = entry_size * num_entries; 1007 size_t expected_size = entry_size * num_entries;
1008 1008
1009 - PointerHolder<Buffer> bp = xref_obj.getStreamData(); 1009 + PointerHolder<Buffer> bp = xref_obj.getStreamData(qpdf_dl_specialized);
1010 size_t actual_size = bp->getSize(); 1010 size_t actual_size = bp->getSize();
1011 1011
1012 if (expected_size != actual_size) 1012 if (expected_size != actual_size)
@@ -1837,7 +1837,7 @@ QPDF::resolveObjectsInStream(int obj_stream_number) @@ -1837,7 +1837,7 @@ QPDF::resolveObjectsInStream(int obj_stream_number)
1837 1837
1838 std::map<int, int> offsets; 1838 std::map<int, int> offsets;
1839 1839
1840 - PointerHolder<Buffer> bp = obj_stream.getStreamData(); 1840 + PointerHolder<Buffer> bp = obj_stream.getStreamData(qpdf_dl_specialized);
1841 PointerHolder<InputSource> input = new BufferInputSource( 1841 PointerHolder<InputSource> input = new BufferInputSource(
1842 "object stream " + QUtil::int_to_string(obj_stream_number), 1842 "object stream " + QUtil::int_to_string(obj_stream_number),
1843 bp.getPointer()); 1843 bp.getPointer());
libqpdf/QPDFWriter.cc
@@ -2684,7 +2684,7 @@ QPDFWriter::writeXRefStream(int xref_id, int max_id, qpdf_offset_t max_offset, @@ -2684,7 +2684,7 @@ QPDFWriter::writeXRefStream(int xref_id, int max_id, qpdf_offset_t max_offset,
2684 } 2684 }
2685 p = pushPipeline( 2685 p = pushPipeline(
2686 new Pl_PNGFilter( 2686 new Pl_PNGFilter(
2687 - "pngify xref", p, Pl_PNGFilter::a_encode, esize, 0)); 2687 + "pngify xref", p, Pl_PNGFilter::a_encode, esize));
2688 } 2688 }
2689 activatePipelineStack(); 2689 activatePipelineStack();
2690 for (int i = first; i <= last; ++i) 2690 for (int i = first; i <= last; ++i)
libqpdf/QPDF_Stream.cc
@@ -114,7 +114,9 @@ QPDF_Stream::getRawStreamData() @@ -114,7 +114,9 @@ QPDF_Stream::getRawStreamData()
114 bool 114 bool
115 QPDF_Stream::understandDecodeParams( 115 QPDF_Stream::understandDecodeParams(
116 std::string const& filter, QPDFObjectHandle decode_obj, 116 std::string const& filter, QPDFObjectHandle decode_obj,
117 - int& predictor, int& columns, bool& early_code_change) 117 + int& predictor, int& columns,
  118 + int& colors, int& bits_per_component,
  119 + bool& early_code_change)
118 { 120 {
119 bool filterable = true; 121 bool filterable = true;
120 std::set<std::string> keys = decode_obj.getKeys(); 122 std::set<std::string> keys = decode_obj.getKeys();
@@ -122,13 +124,15 @@ QPDF_Stream::understandDecodeParams( @@ -122,13 +124,15 @@ QPDF_Stream::understandDecodeParams(
122 iter != keys.end(); ++iter) 124 iter != keys.end(); ++iter)
123 { 125 {
124 std::string const& key = *iter; 126 std::string const& key = *iter;
125 - if ((filter == "/FlateDecode") && (key == "/Predictor")) 127 + if (((filter == "/FlateDecode") || (filter == "/LZWDecode")) &&
  128 + (key == "/Predictor"))
126 { 129 {
127 QPDFObjectHandle predictor_obj = decode_obj.getKey(key); 130 QPDFObjectHandle predictor_obj = decode_obj.getKey(key);
128 if (predictor_obj.isInteger()) 131 if (predictor_obj.isInteger())
129 { 132 {
130 predictor = predictor_obj.getIntValue(); 133 predictor = predictor_obj.getIntValue();
131 - if (! ((predictor == 1) || (predictor == 12))) 134 + if (! ((predictor == 1) ||
  135 + ((predictor >= 10) && (predictor <= 15))))
132 { 136 {
133 filterable = false; 137 filterable = false;
134 } 138 }
@@ -155,12 +159,26 @@ QPDF_Stream::understandDecodeParams( @@ -155,12 +159,26 @@ QPDF_Stream::understandDecodeParams(
155 filterable = false; 159 filterable = false;
156 } 160 }
157 } 161 }
158 - else if (key == "/Columns") 162 + else if ((key == "/Columns") ||
  163 + (key == "/Colors") ||
  164 + (key == "/BitsPerComponent"))
159 { 165 {
160 - QPDFObjectHandle columns_obj = decode_obj.getKey(key);  
161 - if (columns_obj.isInteger()) 166 + QPDFObjectHandle param_obj = decode_obj.getKey(key);
  167 + if (param_obj.isInteger())
162 { 168 {
163 - columns = columns_obj.getIntValue(); 169 + int val = param_obj.getIntValue();
  170 + if (key == "/Columns")
  171 + {
  172 + columns = val;
  173 + }
  174 + else if (key == "/Colors")
  175 + {
  176 + colors = val;
  177 + }
  178 + else if (key == "/BitsPerComponent")
  179 + {
  180 + bits_per_component = val;
  181 + }
164 } 182 }
165 else 183 else
166 { 184 {
@@ -190,6 +208,7 @@ QPDF_Stream::filterable(std::vector&lt;std::string&gt;&amp; filters, @@ -190,6 +208,7 @@ QPDF_Stream::filterable(std::vector&lt;std::string&gt;&amp; filters,
190 bool& specialized_compression, 208 bool& specialized_compression,
191 bool& lossy_compression, 209 bool& lossy_compression,
192 int& predictor, int& columns, 210 int& predictor, int& columns,
  211 + int& colors, int& bits_per_component,
193 bool& early_code_change) 212 bool& early_code_change)
194 { 213 {
195 if (filter_abbreviations.empty()) 214 if (filter_abbreviations.empty())
@@ -295,6 +314,8 @@ QPDF_Stream::filterable(std::vector&lt;std::string&gt;&amp; filters, @@ -295,6 +314,8 @@ QPDF_Stream::filterable(std::vector&lt;std::string&gt;&amp; filters,
295 // Initialize values to their defaults as per the PDF spec 314 // Initialize values to their defaults as per the PDF spec
296 predictor = 1; 315 predictor = 1;
297 columns = 0; 316 columns = 0;
  317 + colors = 1;
  318 + bits_per_component = 8;
298 early_code_change = true; 319 early_code_change = true;
299 320
300 // See if we can support any decode parameters that are specified. 321 // See if we can support any decode parameters that are specified.
@@ -344,7 +365,8 @@ QPDF_Stream::filterable(std::vector&lt;std::string&gt;&amp; filters, @@ -344,7 +365,8 @@ QPDF_Stream::filterable(std::vector&lt;std::string&gt;&amp; filters,
344 { 365 {
345 if (! understandDecodeParams( 366 if (! understandDecodeParams(
346 filters.at(i), decode_item, 367 filters.at(i), decode_item,
347 - predictor, columns, early_code_change)) 368 + predictor, columns, colors, bits_per_component,
  369 + early_code_change))
348 { 370 {
349 filterable = false; 371 filterable = false;
350 } 372 }
@@ -378,6 +400,8 @@ QPDF_Stream::pipeStreamData(Pipeline* pipeline, @@ -378,6 +400,8 @@ QPDF_Stream::pipeStreamData(Pipeline* pipeline,
378 std::vector<std::string> filters; 400 std::vector<std::string> filters;
379 int predictor = 1; 401 int predictor = 1;
380 int columns = 0; 402 int columns = 0;
  403 + int colors = 1;
  404 + int bits_per_component = 8;
381 bool early_code_change = true; 405 bool early_code_change = true;
382 bool specialized_compression = false; 406 bool specialized_compression = false;
383 bool lossy_compression = false; 407 bool lossy_compression = false;
@@ -385,7 +409,9 @@ QPDF_Stream::pipeStreamData(Pipeline* pipeline, @@ -385,7 +409,9 @@ QPDF_Stream::pipeStreamData(Pipeline* pipeline,
385 if (filter) 409 if (filter)
386 { 410 {
387 filter = filterable(filters, specialized_compression, lossy_compression, 411 filter = filterable(filters, specialized_compression, lossy_compression,
388 - predictor, columns, early_code_change); 412 + predictor, columns,
  413 + colors, bits_per_component,
  414 + early_code_change);
389 if ((decode_level < qpdf_dl_all) && lossy_compression) 415 if ((decode_level < qpdf_dl_all) && lossy_compression)
390 { 416 {
391 filter = false; 417 filter = false;
@@ -430,21 +456,23 @@ QPDF_Stream::pipeStreamData(Pipeline* pipeline, @@ -430,21 +456,23 @@ QPDF_Stream::pipeStreamData(Pipeline* pipeline,
430 iter != filters.rend(); ++iter) 456 iter != filters.rend(); ++iter)
431 { 457 {
432 std::string const& filter = *iter; 458 std::string const& filter = *iter;
  459 +
  460 + if (((filter == "/FlateDecode") || (filter == "/LZWDecode")) &&
  461 + ((predictor >= 10) && (predictor <= 15)))
  462 + {
  463 + QTC::TC("qpdf", "QPDF_Stream PNG filter");
  464 + pipeline = new Pl_PNGFilter(
  465 + "png decode", pipeline, Pl_PNGFilter::a_decode,
  466 + columns, colors, bits_per_component);
  467 + to_delete.push_back(pipeline);
  468 + }
  469 +
433 if (filter == "/Crypt") 470 if (filter == "/Crypt")
434 { 471 {
435 // Ignore -- handled by pipeStreamData 472 // Ignore -- handled by pipeStreamData
436 } 473 }
437 else if (filter == "/FlateDecode") 474 else if (filter == "/FlateDecode")
438 { 475 {
439 - if (predictor == 12)  
440 - {  
441 - QTC::TC("qpdf", "QPDF_Stream PNG filter");  
442 - pipeline = new Pl_PNGFilter(  
443 - "png decode", pipeline, Pl_PNGFilter::a_decode,  
444 - columns, 0 /* not used */);  
445 - to_delete.push_back(pipeline);  
446 - }  
447 -  
448 pipeline = new Pl_Flate("stream inflate", 476 pipeline = new Pl_Flate("stream inflate",
449 pipeline, Pl_Flate::a_inflate); 477 pipeline, Pl_Flate::a_inflate);
450 to_delete.push_back(pipeline); 478 to_delete.push_back(pipeline);
libqpdf/qpdf/Pl_PNGFilter.hh
@@ -18,7 +18,8 @@ class Pl_PNGFilter: public Pipeline @@ -18,7 +18,8 @@ class Pl_PNGFilter: public Pipeline
18 QPDF_DLL 18 QPDF_DLL
19 Pl_PNGFilter(char const* identifier, Pipeline* next, 19 Pl_PNGFilter(char const* identifier, Pipeline* next,
20 action_e action, unsigned int columns, 20 action_e action, unsigned int columns,
21 - unsigned int bytes_per_pixel); 21 + unsigned int samples_per_pixel = 1,
  22 + unsigned int bits_per_sample = 8);
22 QPDF_DLL 23 QPDF_DLL
23 virtual ~Pl_PNGFilter(); 24 virtual ~Pl_PNGFilter();
24 25
@@ -38,12 +39,12 @@ class Pl_PNGFilter: public Pipeline @@ -38,12 +39,12 @@ class Pl_PNGFilter: public Pipeline
38 int PaethPredictor(int a, int b, int c); 39 int PaethPredictor(int a, int b, int c);
39 40
40 action_e action; 41 action_e action;
41 - unsigned int columns; 42 + unsigned int bytes_per_row;
  43 + unsigned int bytes_per_pixel;
42 unsigned char* cur_row; 44 unsigned char* cur_row;
43 unsigned char* prev_row; 45 unsigned char* prev_row;
44 unsigned char* buf1; 46 unsigned char* buf1;
45 unsigned char* buf2; 47 unsigned char* buf2;
46 - unsigned int bytes_per_pixel;  
47 size_t pos; 48 size_t pos;
48 size_t incoming; 49 size_t incoming;
49 }; 50 };
libqpdf/qpdf/QPDF_Stream.hh
@@ -54,10 +54,14 @@ class QPDF_Stream: public QPDFObject @@ -54,10 +54,14 @@ class QPDF_Stream: public QPDFObject
54 size_t length); 54 size_t length);
55 bool understandDecodeParams( 55 bool understandDecodeParams(
56 std::string const& filter, QPDFObjectHandle decode_params, 56 std::string const& filter, QPDFObjectHandle decode_params,
57 - int& predictor, int& columns, bool& early_code_change); 57 + int& predictor, int& columns,
  58 + int& colors, int& bits_per_component,
  59 + bool& early_code_change);
58 bool filterable(std::vector<std::string>& filters, 60 bool filterable(std::vector<std::string>& filters,
59 bool& specialized_compression, bool& lossy_compression, 61 bool& specialized_compression, bool& lossy_compression,
60 - int& predictor, int& columns, bool& early_code_change); 62 + int& predictor, int& columns,
  63 + int& colors, int& bits_per_component,
  64 + bool& early_code_change);
61 void warn(QPDFExc const& e); 65 void warn(QPDFExc const& e);
62 66
63 QPDF* qpdf; 67 QPDF* qpdf;
libtests/png_filter.cc
@@ -17,7 +17,7 @@ void run(char const* filename, bool encode, unsigned int columns) @@ -17,7 +17,7 @@ void run(char const* filename, bool encode, unsigned int columns)
17 Pipeline* pl = new Pl_PNGFilter( 17 Pipeline* pl = new Pl_PNGFilter(
18 "png", out, 18 "png", out,
19 encode ? Pl_PNGFilter::a_encode : Pl_PNGFilter::a_decode, 19 encode ? Pl_PNGFilter::a_encode : Pl_PNGFilter::a_decode,
20 - columns, 0 /* not used */); 20 + columns);
21 assert((2 * (columns + 1)) < 1024); 21 assert((2 * (columns + 1)) < 1024);
22 unsigned char buf[1024]; 22 unsigned char buf[1024];
23 size_t len; 23 size_t len;