3 Copyright (c) 2003/2004/2005 Matthias Kramm <kramm@quiss.org>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
30 #ifdef PNG_INLINE_EXPORTS
40 unsigned char a,r,g,b;
43 static int png_read_chunk(char (*head)[4], int*destlen, unsigned char**destdata, FILE*fi)
46 unsigned char blen[4];
47 if(destlen) *destlen=0;
48 if(destdata) *destdata=0;
49 if(!fread(&blen, 4, 1, fi)) {
52 if(!fread(head, 4, 1, fi)) {
55 len = blen[0]<<24|blen[1]<<16|blen[2]<<8|blen[3];
56 if(destlen) *destlen = len;
61 *destdata = (unsigned char*)malloc(len);
62 if(!fread(*destdata, len, 1, fi)) {
64 if(destlen) *destlen=0;
68 fseek(fi, 4, SEEK_CUR);
71 fseek(fi, len+4, SEEK_CUR);
76 static unsigned int png_get_dword(FILE*fi)
81 return b[0]<<24|b[1]<<16|b[2]<<8|b[3];
92 static int png_read_header(FILE*fi, struct png_header*header)
97 unsigned char head[8] = {137,80,78,71,13,10,26,10};
98 unsigned char head2[8];
101 if(strncmp((const char*)head,(const char*)head2,4))
102 return 0; // not a png file
104 while(png_read_chunk(&id, &len, &data, fi))
106 //printf("Chunk: %c%c%c%c (len:%d)\n", id[0],id[1],id[2],id[3], len);
107 if(!strncmp(id, "IHDR", 4)) {
110 header->width = data[0]<<24|data[1]<<16|data[2]<<8|data[3];
111 header->height = data[4]<<24|data[5]<<16|data[6]<<8|data[7];
112 a = data[8]; // should be 8
113 b = data[9]; // should be 3(indexed) or 2(rgb)
115 c = data[10]; // compression mode (0)
116 f = data[11]; // filter mode (0)
117 i = data[12]; // interlace mode (0)
119 if(b!=0 && b!=4 && b!=2 && b!=3 && b!=6) {
120 fprintf(stderr, "Image mode %d not supported!\n", b);
123 if(a!=8 && (b==2 || b==6)) {
124 printf("Bpp %d in mode %d not supported!\n", a);
128 printf("Compression mode %d not supported!\n", c);
132 printf("Filter mode %d not supported!\n", f);
136 printf("Interlace mode %d not supported!\n", i);
139 //printf("%dx%d bpp:%d mode:%d comp:%d filter:%d interlace:%d\n",header->width, header->height, a,b,c,f,i);
150 typedef unsigned char byte;
151 #define ABS(a) ((a)>0?(a):(-(a)))
152 static inline byte PaethPredictor (byte a,byte b,byte c)
154 // a = left, b = above, c = upper left
155 int p = a + b - c; // initial estimate
156 int pa = ABS(p - a); // distances to a, b, c
159 // return nearest of a,b,c,
160 // breaking ties in order a,b,c.
161 if (pa <= pb && pa <= pc)
168 static void applyfilter1(int mode, unsigned char*src, unsigned char*old, unsigned char*dest, int width)
171 unsigned char last=0;
172 unsigned char upperlast=0;
175 for(x=0;x<width;x++) {
182 for(x=0;x<width;x++) {
190 for(x=0;x<width;x++) {
198 for(x=0;x<width;x++) {
199 *dest = *src+(*old+last)/2;
207 for(x=0;x<width;x++) {
208 *dest = *src+PaethPredictor(last,*old,upperlast);
219 static void applyfilter2(int mode, unsigned char*src, unsigned char*old, unsigned char*dest, int width)
222 unsigned char lasta=0;
223 unsigned char lastb=0;
224 unsigned char upperlasta=0;
225 unsigned char upperlastb=0;
228 for(x=0;x<width;x++) {
236 for(x=0;x<width;x++) {
237 dest[0] = src[0]+lasta;
238 dest[1] = src[1]+lastb;
246 for(x=0;x<width;x++) {
247 dest[0] = src[0]+old[0];
248 dest[1] = src[1]+old[1];
255 for(x=0;x<width;x++) {
256 dest[0] = src[0]+(old[0]+lasta)/2;
257 dest[1] = src[1]+(old[1]+lastb)/2;
266 for(x=0;x<width;x++) {
267 dest[0] = src[0]+PaethPredictor(lasta,old[0],upperlasta);
268 dest[1] = src[1]+PaethPredictor(lastb,old[1],upperlastb);
281 /* also performs 24 bit conversion! */
282 static void applyfilter3(int mode, unsigned char*src, unsigned char*old, unsigned char*dest, int width)
285 unsigned char lastr=0;
286 unsigned char lastg=0;
287 unsigned char lastb=0;
288 unsigned char upperlastr=0;
289 unsigned char upperlastg=0;
290 unsigned char upperlastb=0;
293 for(x=0;x<width;x++) {
303 for(x=0;x<width;x++) {
305 dest[1] = src[0]+lastr;
306 dest[2] = src[1]+lastg;
307 dest[3] = src[2]+lastb;
316 for(x=0;x<width;x++) {
318 dest[1] = src[0]+old[1];
319 dest[2] = src[1]+old[2];
320 dest[3] = src[2]+old[3];
327 for(x=0;x<width;x++) {
329 dest[1] = src[0]+(old[1]+lastr)/2;
330 dest[2] = src[1]+(old[2]+lastg)/2;
331 dest[3] = src[2]+(old[3]+lastb)/2;
341 for(x=0;x<width;x++) {
343 dest[1] = src[0]+PaethPredictor(lastr,old[1],upperlastr);
344 dest[2] = src[1]+PaethPredictor(lastg,old[2],upperlastg);
345 dest[3] = src[2]+PaethPredictor(lastb,old[3],upperlastb);
359 static void inline applyfilter4(int mode, unsigned char*src, unsigned char*old, unsigned char*dest, int width)
362 unsigned char lastr=0;
363 unsigned char lastg=0;
364 unsigned char lastb=0;
365 unsigned char lasta=0;
366 unsigned char upperlastr=0;
367 unsigned char upperlastg=0;
368 unsigned char upperlastb=0;
369 unsigned char upperlasta=0;
372 for(x=0;x<width;x++) {
382 for(x=0;x<width;x++) {
383 dest[0] = src[3]+lasta;
384 dest[1] = src[0]+lastr;
385 dest[2] = src[1]+lastg;
386 dest[3] = src[2]+lastb;
396 for(x=0;x<width;x++) {
397 dest[0] = src[3]+old[0];
398 dest[1] = src[0]+old[1];
399 dest[2] = src[1]+old[2];
400 dest[3] = src[2]+old[3];
407 for(x=0;x<width;x++) {
408 dest[0] = src[3]+(old[0]+lasta)/2;
409 dest[1] = src[0]+(old[1]+lastr)/2;
410 dest[2] = src[1]+(old[2]+lastg)/2;
411 dest[3] = src[2]+(old[3]+lastb)/2;
422 for(x=0;x<width;x++) {
423 dest[0] = src[3]+PaethPredictor(lasta,old[0],upperlasta);
424 dest[1] = src[0]+PaethPredictor(lastr,old[1],upperlastr);
425 dest[2] = src[1]+PaethPredictor(lastg,old[2],upperlastg);
426 dest[3] = src[2]+PaethPredictor(lastb,old[3],upperlastb);
443 EXPORT int getPNGdimensions(const char*sname, int*destwidth, int*destheight)
446 struct png_header header;
447 if ((fi = fopen(sname, "rb")) == NULL) {
448 fprintf(stderr, "Couldn't open %s\n", sname);
451 if(!png_read_header(fi, &header)) {
455 *destwidth = header.width;
456 *destheight = header.height;
460 EXPORT int getPNG(const char*sname, int*destwidth, int*destheight, unsigned char**destdata)
465 unsigned char*imagedata;
466 unsigned char*zimagedata=0;
467 unsigned long int imagedatalen;
468 unsigned long int zimagedatalen=0;
469 unsigned char*palette = 0;
471 unsigned char*alphapalette = 0;
472 int alphapalettelen = 0;
473 struct png_header header;
475 unsigned char*data2 = 0;
476 unsigned char alphacolor[3];
480 unsigned char *scanline;
482 if ((fi = fopen(sname, "rb")) == NULL) {
483 printf("Couldn't open %s\n", sname);
487 if(!png_read_header(fi, &header)) {
491 if(header.mode == 3 || header.mode == 0) bypp = 1;
492 else if(header.mode == 4) bypp = 2;
493 else if(header.mode == 2) bypp = 3;
494 else if(header.mode == 6) bypp = 4;
496 printf("ERROR: mode:%d\n", header.mode);
500 imagedatalen = bypp * header.width * header.height + 65536;
501 imagedata = (unsigned char*)malloc(imagedatalen);
503 fseek(fi,8,SEEK_SET);
506 if(!png_read_chunk(&tagid, &len, &data, fi))
508 if(!strncmp(tagid, "IEND", 4)) {
511 if(!strncmp(tagid, "PLTE", 4)) {
514 data = 0; //don't free data
515 //printf("%d colors in palette\n", palettelen);
517 if(!strncmp(tagid, "tRNS", 4)) {
518 if(header.mode == 3) {
520 alphapalettelen = len;
521 data = 0; //don't free data
522 //printf("found %d alpha colors\n", alphapalettelen);
523 } else if(header.mode == 0 || header.mode == 2) {
525 if(header.mode == 2) {
526 alphacolor[0] = data[1];
527 alphacolor[1] = data[3];
528 alphacolor[2] = data[5];
530 alphacolor[0] = alphacolor[1] = alphacolor[2] = data[1];
535 if(!strncmp(tagid, "IDAT", 4)) {
538 zimagedata = (unsigned char*)malloc(len);
539 memcpy(zimagedata,data,len);
541 zimagedata = (unsigned char*)realloc(zimagedata, zimagedatalen+len);
542 memcpy(&zimagedata[zimagedatalen], data, len);
543 zimagedatalen += len;
546 if(!strncmp(tagid, "tEXt", 4)) {
548 printf("Image Text: ");
550 if(data[t]>=32 && data[t]<128)
551 printf("%c", data[t]);
562 if(!zimagedata || uncompress(imagedata, &imagedatalen, zimagedata, zimagedatalen) != Z_OK) {
563 printf("Couldn't uncompress %s!\n", sname);
571 *destwidth = header.width;
572 *destheight = header.height;
574 data2 = (unsigned char*)malloc(header.width*header.height*4);
581 unsigned char* old= (unsigned char*)malloc(header.width*2);
582 memset(old, 0, header.width*2);
584 for(y=0;y<header.height;y++) {
585 int mode = imagedata[pos++]; //filter mode
589 dest = &data2[(y*header.width)*4];
591 if(header.bpp == 8) {
592 /* one byte per pixel */
593 src = &imagedata[pos];
596 /* not implemented yet */
597 fprintf(stderr, "ERROR: mode=4 bpp:%d\n", header.bpp);
602 applyfilter2(mode, src, old, dest, header.width);
603 memcpy(old, dest, header.width*2);
605 for(x=header.width-1;x>=0;x--) {
606 unsigned char gray = dest[x*2+0];
607 unsigned char alpha = dest[x*2+1];
616 } else if(header.mode == 6 || header.mode == 2) {
622 unsigned char* firstline = malloc(header.width*4);
623 memset(firstline,0,header.width*4);
624 for(y=0;y<header.height;y++) {
625 int mode = imagedata[pos++]; //filter mode
629 dest = &data2[(y*header.width)*4];
633 /* one byte per pixel */
634 src = &imagedata[pos];
635 pos+=header.width*(header.mode==6?4:3);
637 /* not implemented yet */
638 fprintf(stderr, "ERROR: bpp:%d\n", header.bpp);
646 old = &data2[(y-1)*header.width*4];
648 if(header.mode == 6) {
649 applyfilter4(mode, src, old, dest, header.width);
650 } else { // header.mode = 2
651 applyfilter3(mode, src, old, dest, header.width);
652 /* replace alpha color */
655 for(x=0;x<header.width;x++) {
656 if(dest[x*4+1] == alphacolor[0] &&
657 dest[x*4+2] == alphacolor[1] &&
658 dest[x*4+3] == alphacolor[2]) {
659 *(u32*)&dest[x*4] = 0;
667 } else if(header.mode == 0 || header.mode == 3) {
669 unsigned char*tmpline = (unsigned char*)malloc(header.width+1);
670 unsigned char*destline = (unsigned char*)malloc(header.width+1);
676 if(header.mode == 0) { // grayscale palette
677 int mult = (0x1ff>>header.bpp);
678 palettelen = 1<<header.bpp;
679 rgba = (COL*)malloc(palettelen*sizeof(COL));
680 for(i=0;i<palettelen;i++) {
686 if(rgba[i].r == alphacolor[0])
692 fprintf(stderr, "Error: No palette found!\n");
695 rgba = (COL*)malloc(palettelen*4);
696 /* 24->32 bit conversion */
697 for(i=0;i<palettelen;i++) {
698 rgba[i].r = palette[i*3+0];
699 rgba[i].g = palette[i*3+1];
700 rgba[i].b = palette[i*3+2];
701 if(alphapalette && i<alphapalettelen) {
702 rgba[i].a = alphapalette[i];
703 /*rgba[i].r = ((int)rgba[i].r*rgba[i].a)/255;
704 rgba[i].g = ((int)rgba[i].g*rgba[i].a)/255;
705 rgba[i].b = ((int)rgba[i].b*rgba[i].a)/255;*/
710 if(rgba[i].r == alphacolor[0] &&
711 rgba[i].g == alphacolor[1] &&
712 rgba[i].b == alphacolor[2])
718 for(y=0;y<header.height;y++) {
719 int mode = imagedata[pos++]; //filter mode
723 src = &imagedata[pos];
724 if(header.bpp == 8) {
729 u32 v = (1<<header.bpp)-1;
730 for(x=0;x<header.width;x++) {
731 u32 r = src[s/8]<<8 |
734 tmpline[x] = (r>>(16-header.bpp-(s&7)))&v;
738 pos+=(header.width*header.bpp+7)/8;
742 memset(destline,0,header.width);
743 old = &destline[y*header.width];
747 applyfilter1(mode, src, old, destline, header.width);
748 memcpy(tmpline,destline,header.width);
749 for(x=0;x<header.width;x++) {
750 *(COL*)&data2[y*header.width*4+x*4+0] = rgba[destline[x]];
758 printf("expected PNG mode to be 2, 3 or 6 (is:%d)\n", header.mode);
767 static u32*crc32_table = 0;
768 static void make_crc32_table(void)
773 crc32_table = (u32*)malloc(1024);
775 for (t = 0; t < 256; t++) {
778 for (s = 0; s < 8; s++) {
779 c = (0xedb88320L*(c&1)) ^ (c >> 1);
784 static inline void png_write_byte(FILE*fi, unsigned char byte)
786 fwrite(&byte,1,1,fi);
787 mycrc32 = crc32_table[(mycrc32 ^ byte) & 0xff] ^ (mycrc32 >> 8);
789 static long png_start_chunk(FILE*fi, char*type, int len)
791 unsigned char mytype[4]={0,0,0,0};
792 unsigned char mylen[4];
798 memcpy(mytype,type,strlen(type));
800 fwrite(&mylen, 4, 1, fi);
802 png_write_byte(fi,mytype[0]);
803 png_write_byte(fi,mytype[1]);
804 png_write_byte(fi,mytype[2]);
805 png_write_byte(fi,mytype[3]);
808 static void png_patch_len(FILE*fi, int pos, int len)
810 unsigned char mylen[4];
816 fseek(fi, pos, SEEK_SET);
817 fwrite(&mylen, 4, 1, fi);
818 fseek(fi, 0, SEEK_END);
820 static void png_write_bytes(FILE*fi, unsigned char*bytes, int len)
824 png_write_byte(fi,bytes[t]);
826 static void png_write_dword(FILE*fi, u32 dword)
828 png_write_byte(fi,dword>>24);
829 png_write_byte(fi,dword>>16);
830 png_write_byte(fi,dword>>8);
831 png_write_byte(fi,dword);
833 static void png_end_chunk(FILE*fi)
835 u32 tmp = mycrc32^0xffffffff;
836 unsigned char tmp2[4];
841 fwrite(&tmp2,4,1,fi);
844 #define ZLIB_BUFFER_SIZE 16384
846 static long compress_line(z_stream*zs, Bytef*line, int len, FILE*fi)
853 int ret = deflate(zs, Z_NO_FLUSH);
855 fprintf(stderr, "error in deflate(): %s", zs->msg?zs->msg:"unknown");
858 if(zs->avail_out != ZLIB_BUFFER_SIZE) {
859 int consumed = ZLIB_BUFFER_SIZE - zs->avail_out;
861 png_write_bytes(fi, zs->next_out - consumed , consumed);
862 zs->next_out = zs->next_out - consumed;
863 zs->avail_out = ZLIB_BUFFER_SIZE;
872 static int test_line(z_stream*zs_orig, Bytef*line, int linelen)
875 int ret = deflateCopy(&zs, zs_orig);
877 fprintf(stderr, "Couldn't copy stream\n");
882 zs.avail_in = linelen;
886 int mode = Z_SYNC_FLUSH;
888 int ret = deflate(&zs, mode);
889 if (ret != Z_OK && ret != Z_STREAM_END) {
890 fprintf(stderr, "error in deflate(): %s (mode %s, %d bytes remaining)\n", zs.msg?zs.msg:"unknown",
891 mode==Z_SYNC_FLUSH?"Z_SYNC_FLUSH":"Z_FINISH", zs.avail_in);
894 if(zs.avail_out != ZLIB_BUFFER_SIZE) {
895 int consumed = ZLIB_BUFFER_SIZE - zs.avail_out;
897 zs.next_out = zs.next_out - consumed;
898 zs.avail_out = ZLIB_BUFFER_SIZE;
900 if (ret == Z_STREAM_END) {
907 ret = deflateEnd(&zs);
909 fprintf(stderr, "error in deflateEnd(): %s\n", zs.msg?zs.msg:"unknown");
915 static int finishzlib(z_stream*zs, FILE*fi)
920 ret = deflate(zs, Z_FINISH);
922 ret != Z_STREAM_END) {
923 fprintf(stderr, "error in deflate(finish): %s\n", zs->msg?zs->msg:"unknown");
927 if(zs->avail_out != ZLIB_BUFFER_SIZE) {
928 int consumed = ZLIB_BUFFER_SIZE - zs->avail_out;
930 png_write_bytes(fi, zs->next_out - consumed , consumed);
931 zs->next_out = zs->next_out - consumed;
932 zs->avail_out = ZLIB_BUFFER_SIZE;
934 if (ret == Z_STREAM_END) {
938 ret = deflateEnd(zs);
940 fprintf(stderr, "error in deflateEnd(): %s\n", zs->msg?zs->msg:"unknown");
946 static void filter_line(int filtermode, unsigned char*dest, unsigned char*src, int width)
950 int srcwidth = width*4;
952 if(filtermode == 0) {
953 for(x=0;x<width;x++) {
954 dest[pos2++]=src[pos+1];
955 dest[pos2++]=src[pos+2];
956 dest[pos2++]=src[pos+3];
957 dest[pos2++]=src[pos+0]; //alpha
960 } else if(filtermode == 1) {
961 /* x difference filter */
962 dest[pos2++]=src[pos+1];
963 dest[pos2++]=src[pos+2];
964 dest[pos2++]=src[pos+3];
965 dest[pos2++]=src[pos+0];
967 for(x=1;x<width;x++) {
968 dest[pos2++]=src[pos+1] - src[pos-4+1];
969 dest[pos2++]=src[pos+2] - src[pos-4+2];
970 dest[pos2++]=src[pos+3] - src[pos-4+3];
971 dest[pos2++]=src[pos+0] - src[pos-4+0]; //alpha
974 } else if(filtermode == 2) {
975 /* y difference filter */
976 for(x=0;x<width;x++) {
977 dest[pos2++]=src[pos+1] - src[pos-srcwidth+1];
978 dest[pos2++]=src[pos+2] - src[pos-srcwidth+2];
979 dest[pos2++]=src[pos+3] - src[pos-srcwidth+3];
980 dest[pos2++]=src[pos+0] - src[pos-srcwidth+0]; //alpha
983 } else if(filtermode == 3) {
984 dest[pos2++]=src[pos+1] - src[pos-srcwidth+1]/2;
985 dest[pos2++]=src[pos+2] - src[pos-srcwidth+2]/2;
986 dest[pos2++]=src[pos+3] - src[pos-srcwidth+3]/2;
987 dest[pos2++]=src[pos+0] - src[pos-srcwidth+0]/2;
989 /* x+y difference filter */
990 for(x=1;x<width;x++) {
991 dest[pos2++]=src[pos+1] - (src[pos-4+1] + src[pos-srcwidth+1])/2;
992 dest[pos2++]=src[pos+2] - (src[pos-4+2] + src[pos-srcwidth+2])/2;
993 dest[pos2++]=src[pos+3] - (src[pos-4+3] + src[pos-srcwidth+3])/2;
994 dest[pos2++]=src[pos+0] - (src[pos-4+0] + src[pos-srcwidth+0])/2; //alpha
997 } else if(filtermode == 4) {
998 dest[pos2++]=src[pos+1] - PaethPredictor(0, src[pos-srcwidth+1], 0);
999 dest[pos2++]=src[pos+2] - PaethPredictor(0, src[pos-srcwidth+2], 0);
1000 dest[pos2++]=src[pos+3] - PaethPredictor(0, src[pos-srcwidth+3], 0);
1001 dest[pos2++]=src[pos+0] - PaethPredictor(0, src[pos-srcwidth+0], 0);
1003 /* paeth difference filter */
1004 for(x=1;x<width;x++) {
1005 dest[pos2++]=src[pos+1] - PaethPredictor(src[pos-4+1], src[pos-srcwidth+1], src[pos-4-srcwidth+1]);
1006 dest[pos2++]=src[pos+2] - PaethPredictor(src[pos-4+2], src[pos-srcwidth+2], src[pos-4-srcwidth+2]);
1007 dest[pos2++]=src[pos+3] - PaethPredictor(src[pos-4+3], src[pos-srcwidth+3], src[pos-4-srcwidth+3]);
1008 dest[pos2++]=src[pos+0] - PaethPredictor(src[pos-4+0], src[pos-srcwidth+0], src[pos-4-srcwidth+0]);
1014 EXPORT void writePNG(const char*filename, unsigned char*data, int width, int height)
1019 unsigned char format;
1021 unsigned char* data2=0;
1024 unsigned char head[] = {137,80,78,71,13,10,26,10}; // PNG header
1040 datalen = (width*height*bpp/8+cols*8);
1042 fi = fopen(filename, "wb");
1047 fwrite(head,sizeof(head),1,fi);
1049 png_start_chunk(fi, "IHDR", 13);
1050 png_write_dword(fi,width);
1051 png_write_dword(fi,height);
1052 png_write_byte(fi,8);
1054 png_write_byte(fi,3); //indexed
1055 else if(format == 5 && alpha==0)
1056 png_write_byte(fi,2); //rgb
1057 else if(format == 5 && alpha==1)
1058 png_write_byte(fi,6); //rgba
1061 png_write_byte(fi,0); //compression mode
1062 png_write_byte(fi,0); //filter mode
1063 png_write_byte(fi,0); //interlace mode
1066 /* if(format == 3) {
1067 png_start_chunk(fi, "PLTE", 768);
1069 for(t=0;t<256;t++) {
1070 png_write_byte(fi,palette[t].r);
1071 png_write_byte(fi,palette[t].g);
1072 png_write_byte(fi,palette[t].b);
1076 long idatpos = png_start_chunk(fi, "IDAT", 0);
1078 memset(&zs,0,sizeof(z_stream));
1079 Bytef*writebuf = (Bytef*)malloc(ZLIB_BUFFER_SIZE);
1083 zs.next_out = writebuf;
1084 zs.avail_out = ZLIB_BUFFER_SIZE;
1085 ret = deflateInit(&zs, 9);
1087 fprintf(stderr, "error in deflateInit(): %s", zs.msg?zs.msg:"unknown");
1094 int srcwidth = width * (bpp/8);
1095 int linelen = 1 + ((srcwidth+3)&~3);
1096 unsigned char* line = (unsigned char*)malloc(linelen);
1097 unsigned char* bestline = (unsigned char*)malloc(linelen);
1098 memset(line, 0, linelen);
1099 for(y=0;y<height;y++)
1102 int bestsize = 0x7fffffff;
1103 for(filtermode=0;filtermode<5;filtermode++) {
1105 if(!y && filtermode>=2)
1106 continue; // don't do y direction filters in the first row
1108 line[0]=filtermode; //filter type
1109 filter_line(filtermode, line+1, &data[y*srcwidth], width);
1111 int size = test_line(&zs, line, linelen);
1112 if(size < bestsize) {
1113 memcpy(bestline, line, linelen);
1117 idatsize += compress_line(&zs, bestline, linelen, fi);
1119 free(line);free(bestline);
1121 idatsize += finishzlib(&zs, fi);
1122 png_patch_len(fi, idatpos, idatsize);
1125 png_start_chunk(fi, "IEND", 0);