1 /* pnglite.c - pnglite library
2 For conditions of distribution and use, see copyright notice in pnglite.h
3 */
4 #define DO_CRC_CHECKS 1
5 #define USE_ZLIB 1
6
7 #if USE_ZLIB
8 #include <zlib.h>
9 #else
10 #include "zlite.h"
11 #endif
12
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include "pnglite.h"
17
18
19
20 static png_alloc_t png_alloc;
21 static png_free_t png_free;
22
file_read(png_t * png,void * out,size_t size,size_t numel)23 static size_t file_read(png_t* png, void* out, size_t size, size_t numel)
24 {
25 size_t result;
26 if(png->read_fun)
27 {
28 result = png->read_fun(out, size, numel, png->user_pointer);
29 }
30 else
31 {
32 if(!out)
33 {
34 result = fseek(png->user_pointer, (long)(size*numel), SEEK_CUR);
35 }
36 else
37 {
38 result = fread(out, size, numel, png->user_pointer);
39 }
40 }
41
42 return result;
43 }
44
file_write(png_t * png,void * p,size_t size,size_t numel)45 static size_t file_write(png_t* png, void* p, size_t size, size_t numel)
46 {
47 size_t result;
48
49 if(png->write_fun)
50 {
51 result = png->write_fun(p, size, numel, png->user_pointer);
52 }
53 else
54 {
55 result = fwrite(p, size, numel, png->user_pointer);
56 }
57
58 return result;
59 }
60
file_read_ul(png_t * png,unsigned * out)61 static int file_read_ul(png_t* png, unsigned *out)
62 {
63 unsigned char buf[4];
64
65 if(file_read(png, buf, 1, 4) != 4)
66 return PNG_FILE_ERROR;
67
68 *out = (buf[0]<<24) | (buf[1]<<16) | (buf[2]<<8) | buf[3];
69
70 return PNG_NO_ERROR;
71 }
72
file_write_ul(png_t * png,unsigned in)73 static int file_write_ul(png_t* png, unsigned in)
74 {
75 unsigned char buf[4];
76
77 buf[0] = (in>>24) & 0xff;
78 buf[1] = (in>>16) & 0xff;
79 buf[2] = (in>>8) & 0xff;
80 buf[3] = (in) & 0xff;
81
82 if(file_write(png, buf, 1, 4) != 4)
83 return PNG_FILE_ERROR;
84
85 return PNG_NO_ERROR;
86 }
87
88
get_ul(unsigned char * buf)89 static unsigned get_ul(unsigned char* buf)
90 {
91 unsigned result;
92 unsigned char foo[4];
93
94 memcpy(foo, buf, 4);
95
96 result = (foo[0]<<24) | (foo[1]<<16) | (foo[2]<<8) | foo[3];
97
98 return result;
99 }
100
set_ul(unsigned char * buf,unsigned in)101 static unsigned set_ul(unsigned char* buf, unsigned in)
102 {
103 buf[0] = (in>>24) & 0xff;
104 buf[1] = (in>>16) & 0xff;
105 buf[2] = (in>>8) & 0xff;
106 buf[3] = (in) & 0xff;
107
108 return PNG_NO_ERROR;
109 }
110
png_init(png_alloc_t pngalloc,png_free_t pngfree)111 int png_init(png_alloc_t pngalloc, png_free_t pngfree)
112 {
113 if(pngalloc)
114 png_alloc = pngalloc;
115 else
116 png_alloc = &malloc;
117
118 if(pngfree)
119 png_free = pngfree;
120 else
121 png_free = &free;
122
123 return PNG_NO_ERROR;
124 }
125
png_get_bpp(png_t * png)126 static int png_get_bpp(png_t* png)
127 {
128 int bpp;
129
130 switch(png->color_type)
131 {
132 case PNG_GREYSCALE:
133 bpp = 1; break;
134 case PNG_TRUECOLOR:
135 bpp = 3; break;
136 case PNG_INDEXED:
137 bpp = 1; break;
138 case PNG_GREYSCALE_ALPHA:
139 bpp = 2; break;
140 case PNG_TRUECOLOR_ALPHA:
141 bpp = 4; break;
142 default:
143 return PNG_FILE_ERROR;
144 }
145
146 bpp *= png->depth/8;
147
148 return bpp;
149 }
150
png_read_ihdr(png_t * png)151 static int png_read_ihdr(png_t* png)
152 {
153 unsigned length;
154 #if DO_CRC_CHECKS
155 unsigned orig_crc;
156 unsigned calc_crc;
157 #endif
158 unsigned char ihdr[13+4]; /* length should be 13, make room for type (IHDR) */
159
160 file_read_ul(png, &length);
161
162 if(length != 13)
163 {
164 printf("%d\n", length);
165 return PNG_CRC_ERROR;
166 }
167
168 if(file_read(png, ihdr, 1, 13+4) != 13+4)
169 return PNG_EOF_ERROR;
170 #if DO_CRC_CHECKS
171 file_read_ul(png, &orig_crc);
172
173 calc_crc = crc32(0L, 0, 0);
174 calc_crc = crc32(calc_crc, ihdr, 13+4);
175
176 if(orig_crc != calc_crc)
177 return PNG_CRC_ERROR;
178 #else
179 file_read_ul(png);
180 #endif
181
182 png->width = get_ul(ihdr+4);
183 png->height = get_ul(ihdr+8);
184 png->depth = ihdr[12];
185 png->color_type = ihdr[13];
186 png->compression_method = ihdr[14];
187 png->filter_method = ihdr[15];
188 png->interlace_method = ihdr[16];
189
190 if(png->color_type == PNG_INDEXED)
191 return PNG_NOT_SUPPORTED;
192
193 if(png->depth != 8 && png->depth != 16)
194 return PNG_NOT_SUPPORTED;
195
196 if(png->interlace_method)
197 return PNG_NOT_SUPPORTED;
198
199 return PNG_NO_ERROR;
200 }
201
png_write_ihdr(png_t * png)202 static int png_write_ihdr(png_t* png)
203 {
204 unsigned char ihdr[13+4];
205 unsigned char *p = ihdr;
206 unsigned crc;
207
208 file_write(png, "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A", 1, 8);
209
210 file_write_ul(png, 13);
211
212 *p = 'I'; p++;
213 *p = 'H'; p++;
214 *p = 'D'; p++;
215 *p = 'R'; p++;
216 set_ul(p, png->width); p+=4;
217 set_ul(p, png->height); p+=4;
218 *p = png->depth; p++;
219 *p = png->color_type; p++;
220 *p = 0; p++;
221 *p = 0; p++;
222 *p = 0; p++;
223
224 file_write(png, ihdr, 1, 13+4);
225
226 crc = crc32(0L, 0, 0);
227 crc = crc32(crc, ihdr, 13+4);
228
229 file_write_ul(png, crc);
230
231 return PNG_NO_ERROR;
232 }
233
png_print_info(png_t * png)234 void png_print_info(png_t* png)
235 {
236 printf("PNG INFO:\n");
237 printf("\twidth:\t\t%d\n", png->width);
238 printf("\theight:\t\t%d\n", png->height);
239 printf("\tdepth:\t\t%d\n", png->depth);
240 printf("\tcolor:\t\t");
241
242 switch(png->color_type)
243 {
244 case PNG_GREYSCALE: printf("greyscale\n"); break;
245 case PNG_TRUECOLOR: printf("truecolor\n"); break;
246 case PNG_INDEXED: printf("palette\n"); break;
247 case PNG_GREYSCALE_ALPHA: printf("greyscale with alpha\n"); break;
248 case PNG_TRUECOLOR_ALPHA: printf("truecolor with alpha\n"); break;
249 default: printf("unknown, this is not good\n"); break;
250 }
251
252 printf("\tcompression:\t%s\n", png->compression_method?"unknown, this is not good":"inflate/deflate");
253 printf("\tfilter:\t\t%s\n", png->filter_method?"unknown, this is not good":"adaptive");
254 printf("\tinterlace:\t%s\n", png->interlace_method?"interlace":"no interlace");
255 }
256
png_open_read(png_t * png,png_read_callback_t read_fun,void * user_pointer)257 int png_open_read(png_t* png, png_read_callback_t read_fun, void* user_pointer)
258 {
259 char header[8];
260 int result;
261
262 png->read_fun = read_fun;
263 png->write_fun = 0;
264 png->user_pointer = user_pointer;
265
266 if(!read_fun && !user_pointer)
267 return PNG_WRONG_ARGUMENTS;
268
269 if(file_read(png, header, 1, 8) != 8)
270 return PNG_EOF_ERROR;
271
272 if(memcmp(header, "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A", 8) != 0)
273 return PNG_HEADER_ERROR;
274
275 result = png_read_ihdr(png);
276
277 png->bpp = (unsigned char)png_get_bpp(png);
278
279 return result;
280 }
281
png_open_write(png_t * png,png_write_callback_t write_fun,void * user_pointer)282 int png_open_write(png_t* png, png_write_callback_t write_fun, void* user_pointer)
283 {
284 png->write_fun = write_fun;
285 png->read_fun = 0;
286 png->user_pointer = user_pointer;
287
288 if(!write_fun && !user_pointer)
289 return PNG_WRONG_ARGUMENTS;
290
291 return PNG_NO_ERROR;
292 }
293
png_open(png_t * png,png_read_callback_t read_fun,void * user_pointer)294 int png_open(png_t* png, png_read_callback_t read_fun, void* user_pointer)
295 {
296 return png_open_read(png, read_fun, user_pointer);
297 }
298
png_open_file_read(png_t * png,const char * filename)299 int png_open_file_read(png_t *png, const char* filename)
300 {
301 FILE* fp = fopen(filename, "rb");
302
303 if(!fp)
304 return PNG_FILE_ERROR;
305
306 return png_open_read(png, 0, fp);
307 }
308
png_open_file_write(png_t * png,const char * filename)309 int png_open_file_write(png_t *png, const char* filename)
310 {
311 FILE* fp = fopen(filename, "wb");
312
313 if(!fp)
314 return PNG_FILE_ERROR;
315
316 return png_open_write(png, 0, fp);
317 }
318
png_open_file(png_t * png,const char * filename)319 int png_open_file(png_t *png, const char* filename)
320 {
321 return png_open_file_read(png, filename);
322 }
323
png_close_file(png_t * png)324 int png_close_file(png_t* png)
325 {
326 fclose(png->user_pointer);
327
328 return PNG_NO_ERROR;
329 }
330
png_init_deflate(png_t * png,unsigned char * data,int datalen)331 static int png_init_deflate(png_t* png, unsigned char* data, int datalen)
332 {
333 z_stream *stream;
334 png->zs = png_alloc(sizeof(z_stream));
335
336 stream = png->zs;
337
338 if(!stream)
339 return PNG_MEMORY_ERROR;
340
341 memset(stream, 0, sizeof(z_stream));
342
343 if(deflateInit(stream, Z_DEFAULT_COMPRESSION) != Z_OK)
344 return PNG_ZLIB_ERROR;
345
346 stream->next_in = data;
347 stream->avail_in = datalen;
348
349 return PNG_NO_ERROR;
350 }
351
png_init_inflate(png_t * png)352 static int png_init_inflate(png_t* png)
353 {
354 #if USE_ZLIB
355 z_stream *stream;
356 png->zs = png_alloc(sizeof(z_stream));
357 #else
358 zl_stream *stream;
359 png->zs = png_alloc(sizeof(zl_stream));
360 #endif
361
362 stream = png->zs;
363
364 if(!stream)
365 return PNG_MEMORY_ERROR;
366
367
368
369 #if USE_ZLIB
370 memset(stream, 0, sizeof(z_stream));
371 if(inflateInit(stream) != Z_OK)
372 return PNG_ZLIB_ERROR;
373 #else
374 memset(stream, 0, sizeof(zl_stream));
375 if(z_inflateInit(stream) != Z_OK)
376 return PNG_ZLIB_ERROR;
377 #endif
378
379 stream->next_out = png->png_data;
380 stream->avail_out = png->png_datalen;
381
382 return PNG_NO_ERROR;
383 }
384
png_end_deflate(png_t * png)385 static int png_end_deflate(png_t* png)
386 {
387 z_stream *stream = png->zs;
388
389 if(!stream)
390 return PNG_MEMORY_ERROR;
391
392 deflateEnd(stream);
393
394 png_free(png->zs);
395
396 return PNG_NO_ERROR;
397 }
398
png_end_inflate(png_t * png)399 static int png_end_inflate(png_t* png)
400 {
401 #if USE_ZLIB
402 z_stream *stream = png->zs;
403 #else
404 zl_stream *stream = png->zs;
405 #endif
406
407 if(!stream)
408 return PNG_MEMORY_ERROR;
409
410 #if USE_ZLIB
411 if(inflateEnd(stream) != Z_OK)
412 #else
413 if(z_inflateEnd(stream) != Z_OK)
414 #endif
415 {
416 printf("ZLIB says: %s\n", stream->msg);
417 return PNG_ZLIB_ERROR;
418 }
419
420 png_free(png->zs);
421
422 return PNG_NO_ERROR;
423 }
424
png_inflate(png_t * png,char * data,int len)425 static int png_inflate(png_t* png, char* data, int len)
426 {
427 int result;
428 #if USE_ZLIB
429 z_stream *stream = png->zs;
430 #else
431 zl_stream *stream = png->zs;
432 #endif
433
434 if(!stream)
435 return PNG_MEMORY_ERROR;
436
437 stream->next_in = (unsigned char*)data;
438 stream->avail_in = len;
439
440 #if USE_ZLIB
441 result = inflate(stream, Z_SYNC_FLUSH);
442 #else
443 result = z_inflate(stream);
444 #endif
445
446 if(result != Z_STREAM_END && result != Z_OK)
447 {
448 printf("%s\n", stream->msg);
449 return PNG_ZLIB_ERROR;
450 }
451
452 if(stream->avail_in != 0)
453 return PNG_ZLIB_ERROR;
454
455 return PNG_NO_ERROR;
456 }
457
png_deflate(png_t * png,char * outdata,int outlen,int * outwritten)458 static int png_deflate(png_t* png, char* outdata, int outlen, int *outwritten)
459 {
460 int result;
461
462 z_stream *stream = png->zs;
463
464
465 if(!stream)
466 return PNG_MEMORY_ERROR;
467
468 stream->next_out = (unsigned char*)outdata;
469 stream->avail_out = outlen;
470
471 result = deflate(stream, Z_SYNC_FLUSH);
472
473 *outwritten = outlen - stream->avail_out;
474
475 if(result != Z_STREAM_END && result != Z_OK)
476 {
477 printf("%s\n", stream->msg);
478 return PNG_ZLIB_ERROR;
479 }
480
481 return result;
482 }
483
png_write_idats(png_t * png,unsigned char * data)484 static int png_write_idats(png_t* png, unsigned char* data)
485 {
486 unsigned char *chunk;
487 unsigned long written;
488 unsigned long crc;
489 unsigned size = png->width * png->height * png->bpp + png->height;
490
491 (void)png_init_deflate;
492 (void)png_end_deflate;
493 (void)png_deflate;
494
495 chunk = png_alloc(size + 8);
496 memcpy(chunk, "IDAT", 4);
497
498 written = size;
499 compress(chunk+4, &written, data, size);
500
501 crc = crc32(0L, Z_NULL, 0);
502 crc = crc32(crc, chunk, written+4);
503 set_ul(chunk+written+4, crc);
504 file_write_ul(png, written);
505 file_write(png, chunk, 1, written+8);
506 png_free(chunk);
507
508 file_write_ul(png, 0);
509 file_write(png, "IEND", 1, 4);
510 crc = crc32(0L, (const unsigned char *)"IEND", 4);
511 file_write_ul(png, crc);
512
513 return PNG_NO_ERROR;
514 }
515
png_read_idat(png_t * png,unsigned firstlen)516 static int png_read_idat(png_t* png, unsigned firstlen)
517 {
518 unsigned type = 0;
519 char *chunk;
520 int result;
521 unsigned length = firstlen;
522 unsigned old_len = length;
523
524 #if DO_CRC_CHECKS
525 unsigned orig_crc;
526 unsigned calc_crc;
527 #endif
528
529 chunk = png_alloc(firstlen);
530
531 result = png_init_inflate(png);
532
533 if(result != PNG_NO_ERROR)
534 {
535 png_end_inflate(png);
536 png_free(chunk);
537 return result;
538 }
539
540 do
541 {
542 if(file_read(png, chunk, 1, length) != length)
543 {
544 png_end_inflate(png);
545 png_free(chunk);
546 return PNG_FILE_ERROR;
547 }
548
549 #if DO_CRC_CHECKS
550 calc_crc = crc32(0L, Z_NULL, 0);
551 calc_crc = crc32(calc_crc, (unsigned char*)"IDAT", 4);
552 calc_crc = crc32(calc_crc, (unsigned char*)chunk, length);
553
554 file_read_ul(png, &orig_crc);
555
556 if(orig_crc != calc_crc)
557 {
558 result = PNG_CRC_ERROR;
559 break;
560 }
561 #else
562 file_read_ul(png);
563 #endif
564
565 result = png_inflate(png, chunk, length);
566
567 if(result != PNG_NO_ERROR) break;
568
569 file_read_ul(png, &length);
570
571 if(length > old_len)
572 {
573 png_free(chunk);
574 chunk = png_alloc(length);
575 old_len = length;
576 }
577
578 if(file_read(png, &type, 1, 4) != 4)
579 {
580 result = PNG_FILE_ERROR;
581 break;
582 }
583
584 }while(type == *(unsigned int*)"IDAT");
585
586 if(type == *(unsigned int*)"IEND")
587 result = PNG_DONE;
588
589 png_free(chunk);
590 png_end_inflate(png);
591
592 return result;
593 }
594
png_process_chunk(png_t * png)595 static int png_process_chunk(png_t* png)
596 {
597 int result = PNG_NO_ERROR;
598 unsigned type;
599 unsigned length;
600
601 file_read_ul(png, &length);
602
603 if(file_read(png, &type, 1, 4) != 4)
604 return PNG_FILE_ERROR;
605
606 if(type == *(unsigned int*)"IDAT") /* if we found an idat, all other idats should be followed with no other chunks in between */
607 {
608 png->png_datalen = png->width * png->height * png->bpp + png->height;
609 png->png_data = png_alloc(png->png_datalen);
610
611 if(!png->png_data)
612 return PNG_MEMORY_ERROR;
613
614 return png_read_idat(png, length);
615 }
616 else if(type == *(unsigned int*)"IEND")
617 {
618 return PNG_DONE;
619 }
620 else
621 {
622 file_read(png, 0, 1, length + 4); /* unknown chunk */
623 }
624
625 return result;
626 }
627
png_filter_sub(int stride,unsigned char * in,unsigned char * out,int len)628 static void png_filter_sub(int stride, unsigned char* in, unsigned char* out, int len)
629 {
630 int i;
631 unsigned char a = 0;
632
633 for(i = 0; i < len; i++)
634 {
635 if(i >= stride)
636 a = out[i - stride];
637
638 out[i] = in[i] + a;
639 }
640 }
641
png_filter_up(int stride,unsigned char * in,unsigned char * out,unsigned char * prev_line,int len)642 static void png_filter_up(int stride, unsigned char* in, unsigned char* out, unsigned char* prev_line, int len)
643 {
644 int i;
645
646 if(prev_line)
647 {
648 for(i = 0; i < len; i++)
649 out[i] = in[i] + prev_line[i];
650 }
651 else
652 memcpy(out, in, len);
653 }
654
png_filter_average(int stride,unsigned char * in,unsigned char * out,unsigned char * prev_line,int len)655 static void png_filter_average(int stride, unsigned char* in, unsigned char* out, unsigned char* prev_line, int len)
656 {
657 int i;
658 unsigned char a = 0;
659 unsigned char b = 0;
660 unsigned int sum = 0;
661
662 for(i = 0; i < len; i++)
663 {
664 if(prev_line)
665 b = prev_line[i];
666
667 if(i >= stride)
668 a = out[i - stride];
669
670 sum = a;
671 sum += b;
672
673 out[i] = (char)(in[i] + sum/2);
674 }
675 }
676
png_paeth(unsigned char a,unsigned char b,unsigned char c)677 static unsigned char png_paeth(unsigned char a, unsigned char b, unsigned char c)
678 {
679 int p = (int)a + b - c;
680 int pa = abs(p - a);
681 int pb = abs(p - b);
682 int pc = abs(p - c);
683
684 int pr;
685
686 if(pa <= pb && pa <= pc)
687 pr = a;
688 else if(pb <= pc)
689 pr = b;
690 else
691 pr = c;
692
693 return (char)pr;
694 }
695
png_filter_paeth(int stride,unsigned char * in,unsigned char * out,unsigned char * prev_line,int len)696 static void png_filter_paeth(int stride, unsigned char* in, unsigned char* out, unsigned char* prev_line, int len)
697 {
698 int i;
699 unsigned char a;
700 unsigned char b;
701 unsigned char c;
702
703 for(i = 0; i < len; i++)
704 {
705 if(prev_line && i >= stride)
706 {
707 a = out[i - stride];
708 b = prev_line[i];
709 c = prev_line[i - stride];
710 }
711 else
712 {
713 if(prev_line)
714 b = prev_line[i];
715 else
716 b = 0;
717
718 if(i >= stride)
719 a = out[i - stride];
720 else
721 a = 0;
722
723 c = 0;
724 }
725
726 out[i] = in[i] + png_paeth(a, b, c);
727 }
728 }
729
png_filter(png_t * png,unsigned char * data)730 static int png_filter(png_t* png, unsigned char* data)
731 {
732
733
734 return PNG_NO_ERROR;
735 }
736
png_unfilter(png_t * png,unsigned char * data)737 static int png_unfilter(png_t* png, unsigned char* data)
738 {
739 unsigned i;
740 unsigned pos = 0;
741 unsigned outpos = 0;
742 unsigned char *filtered = png->png_data;
743
744 int stride = png->bpp;
745
746 while(pos < png->png_datalen)
747 {
748 unsigned char filter = filtered[pos];
749
750 pos++;
751
752 if(png->depth == 16)
753 {
754 for(i = 0; i < png->width * stride; i+=2)
755 {
756 *(short*)(filtered+pos+i) = (filtered[pos+i] << 8) | filtered[pos+i+1];
757 }
758 }
759
760 switch(filter)
761 {
762 case 0: /* none */
763 memcpy(data+outpos, filtered+pos, png->width * stride);
764 break;
765 case 1: /* sub */
766 png_filter_sub(stride, filtered+pos, data+outpos, png->width * stride);
767 break;
768 case 2: /* up */
769 if(outpos)
770 png_filter_up(stride, filtered+pos, data+outpos, data + outpos - (png->width*stride), png->width*stride);
771 else
772 png_filter_up(stride, filtered+pos, data+outpos, 0, png->width*stride);
773 break;
774 case 3: /* average */
775 if(outpos)
776 png_filter_average(stride, filtered+pos, data+outpos, data + outpos - (png->width*stride), png->width*stride);
777 else
778 png_filter_average(stride, filtered+pos, data+outpos, 0, png->width*stride);
779 break;
780 case 4: /* paeth */
781 if(outpos)
782 png_filter_paeth(stride, filtered+pos, data+outpos, data + outpos - (png->width*stride), png->width*stride);
783 else
784 png_filter_paeth(stride, filtered+pos, data+outpos, 0, png->width*stride);
785 break;
786 default:
787 return PNG_UNKNOWN_FILTER;
788 }
789
790 outpos += png->width * stride;
791 pos += png->width * stride;
792 }
793
794 return PNG_NO_ERROR;
795 }
796
png_get_data(png_t * png,unsigned char * data)797 int png_get_data(png_t* png, unsigned char* data)
798 {
799 int result = PNG_NO_ERROR;
800
801 while(result == PNG_NO_ERROR)
802 {
803 result = png_process_chunk(png);
804 }
805
806 if(result != PNG_DONE)
807 {
808 png_free(png->png_data);
809 return result;
810 }
811
812 result = png_unfilter(png, data);
813
814 png_free(png->png_data);
815
816 return result;
817 }
818
png_set_data(png_t * png,unsigned width,unsigned height,char depth,int color,unsigned char * data)819 int png_set_data(png_t* png, unsigned width, unsigned height, char depth, int color, unsigned char* data)
820 {
821 int i;
822 unsigned char *filtered;
823 png->width = width;
824 png->height = height;
825 png->depth = depth;
826 png->color_type = color;
827 png->bpp = png_get_bpp(png);
828
829 filtered = png_alloc(width * height * png->bpp + height);
830
831 for(i = 0; i < png->height; i++)
832 {
833 filtered[i*png->width*png->bpp+i] = 0;
834 memcpy(&filtered[i*png->width*png->bpp+i+1], data + i * png->width*png->bpp, png->width*png->bpp);
835 }
836
837 png_filter(png, filtered);
838 png_write_ihdr(png);
839 png_write_idats(png, filtered);
840
841 png_free(filtered);
842 return PNG_NO_ERROR;
843 }
844
845
png_error_string(int error)846 char* png_error_string(int error)
847 {
848 switch(error)
849 {
850 case PNG_NO_ERROR:
851 return "No error";
852 case PNG_FILE_ERROR:
853 return "Unknown file error.";
854 case PNG_HEADER_ERROR:
855 return "No PNG header found. Are you sure this is a PNG?";
856 case PNG_IO_ERROR:
857 return "Failure while reading file.";
858 case PNG_EOF_ERROR:
859 return "Reached end of file.";
860 case PNG_CRC_ERROR:
861 return "CRC or chunk length error.";
862 case PNG_MEMORY_ERROR:
863 return "Could not allocate memory.";
864 case PNG_ZLIB_ERROR:
865 return "zlib reported an error.";
866 case PNG_UNKNOWN_FILTER:
867 return "Unknown filter method used in scanline.";
868 case PNG_DONE:
869 return "PNG done";
870 case PNG_NOT_SUPPORTED:
871 return "The PNG is unsupported by pnglite, too bad for you!";
872 case PNG_WRONG_ARGUMENTS:
873 return "Wrong combination of arguments passed to png_open. You must use either a read_function or supply a file pointer to use.";
874 default:
875 return "Unknown error.";
876 };
877 }
878