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