replaced libart with new polygon code
[swftools.git] / lib / png.c
1 /*  png.c
2    
3    Copyright (c) 2003/2004/2005 Matthias Kramm <kramm@quiss.org>
4
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.
9
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.
14
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 */
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <assert.h>
23 #include <math.h>
24 #include <fcntl.h>
25 #include <zlib.h>
26
27 #ifdef EXPORT
28 #undef EXPORT
29 #endif
30
31 #ifdef PNG_INLINE_EXPORTS
32 #define EXPORT static
33 #else
34 #define EXPORT
35 #include "png.h"
36 #endif
37
38 typedef unsigned u32;
39
40 typedef struct _COL {
41     unsigned char a,r,g,b;
42 } COL;
43
44 static int png_read_chunk(char (*head)[4], int*destlen, unsigned char**destdata, FILE*fi)
45 {
46     unsigned int len;
47     unsigned char blen[4];
48     if(destlen) *destlen=0;
49     if(destdata) *destdata=0;
50     if(!fread(&blen, 4, 1, fi)) {
51         return 0;
52     }
53     if(!fread(head, 4, 1, fi)) {
54         return 0;
55     }
56     len = blen[0]<<24|blen[1]<<16|blen[2]<<8|blen[3];
57     if(destlen) *destlen = len;
58     if(destdata) {
59         if(!len) {
60             *destdata = 0;
61         } else {
62             *destdata = (unsigned char*)malloc(len);
63             if(!fread(*destdata, len, 1, fi)) {
64                 *destdata = 0;
65                 if(destlen) *destlen=0;
66                 return 0;
67             }
68         }
69         fseek(fi, 4, SEEK_CUR);
70
71     } else {
72         fseek(fi, len+4, SEEK_CUR);
73     }
74     return 1;
75 }
76
77 static unsigned int png_get_dword(FILE*fi)
78 {
79     unsigned int a;
80     unsigned char b[4];
81     fread(&b,4,1,fi);
82     return b[0]<<24|b[1]<<16|b[2]<<8|b[3];
83 }
84
85 struct png_header
86 {
87     int width;
88     int height;
89     int bpp;
90     int mode;
91 };
92
93 static int png_read_header(FILE*fi, struct png_header*header)
94 {
95     char id[4];
96     int len;
97     int ok=0;
98     unsigned char head[8] = {137,80,78,71,13,10,26,10};
99     unsigned char head2[8];
100     unsigned char*data;
101     fread(head2,8,1,fi);
102     if(strncmp((const char*)head,(const char*)head2,4))
103         return 0; // not a png file
104     
105     while(png_read_chunk(&id, &len, &data, fi))
106     {
107         //printf("Chunk: %c%c%c%c (len:%d)\n", id[0],id[1],id[2],id[3], len);
108         if(!strncmp(id, "IHDR", 4)) {
109             char a,b,c,f,i;
110             if(len < 8) exit(1);
111             header->width = data[0]<<24|data[1]<<16|data[2]<<8|data[3];
112             header->height = data[4]<<24|data[5]<<16|data[6]<<8|data[7];
113             a = data[8];      // should be 8
114             b = data[9];      // should be 3(indexed) or 2(rgb)
115
116             c = data[10];     // compression mode (0)
117             f = data[11];     // filter mode (0)
118             i = data[12];     // interlace mode (0)
119
120             if(b!=0 && b!=4 && b!=2 && b!=3 && b!=6) {
121                 fprintf(stderr, "Image mode %d not supported!\n", b);
122                 return 0;
123             }
124             if(a!=8 && (b==2 || b==6)) {
125                 printf("Bpp %d in mode %d not supported!\n", a);
126                 return 0;
127             }
128             if(c!=0) {
129                 printf("Compression mode %d not supported!\n", c);
130                 return 0;
131             }
132             if(f!=0) {
133                 printf("Filter mode %d not supported!\n", f);
134                 return 0;
135             }
136             if(i!=0) {
137                 printf("Interlace mode %d not supported!\n", i);
138                 return 0;
139             }
140             //printf("%dx%d bpp:%d mode:%d comp:%d filter:%d interlace:%d\n",header->width, header->height, a,b,c,f,i);
141             header->bpp = a;
142             header->mode = b;
143             ok = 1;
144         } 
145         
146         free(data);
147     }
148     return ok;
149 }
150
151 typedef unsigned char byte;
152 #define ABS(a) ((a)>0?(a):(-(a)))
153 static inline byte PaethPredictor (byte a,byte b,byte c)
154 {
155         // a = left, b = above, c = upper left
156         int p = a + b - c;        // initial estimate
157         int pa = ABS(p - a);      // distances to a, b, c
158         int pb = ABS(p - b);
159         int pc = ABS(p - c);
160         // return nearest of a,b,c,
161         // breaking ties in order a,b,c.
162         if (pa <= pb && pa <= pc) 
163                 return a;
164         else if (pb <= pc) 
165                 return b;
166         else return c;
167 }
168
169 static void applyfilter1(int mode, unsigned char*src, unsigned char*old, unsigned char*dest, int width)
170 {
171     int x;
172     unsigned char last=0;
173     unsigned char upperlast=0;
174
175     if(mode==0) {
176         for(x=0;x<width;x++) {
177             *dest = *src;
178             dest++;
179             src++;
180         }
181     }
182     else if(mode==1) {
183         for(x=0;x<width;x++) {
184             *dest = *src+last;
185             last = *dest;
186             dest++;
187             src++;
188         }
189     }
190     else if(mode==2) {
191         for(x=0;x<width;x++) {
192             *dest = *src+*old;
193             dest++;
194             old++;
195             src++;
196         }
197     }
198     else if(mode==3) {
199         for(x=0;x<width;x++) {
200             *dest = *src+(*old+last)/2;
201             last = *dest;
202             dest++;
203             old++;
204             src++;
205         }
206     }
207     else if(mode==4) {
208         for(x=0;x<width;x++) {
209             *dest = *src+PaethPredictor(last,*old,upperlast);
210             last = *dest;
211             upperlast = *old;
212             dest++;
213             old++;
214             src++;
215         }
216     }    
217
218 }
219
220 static void applyfilter2(int mode, unsigned char*src, unsigned char*old, unsigned char*dest, int width)
221 {
222     int x;
223     unsigned char lasta=0;
224     unsigned char lastb=0;
225     unsigned char upperlasta=0;
226     unsigned char upperlastb=0;
227
228     if(mode==0) {
229         for(x=0;x<width;x++) {
230             dest[0] = src[0];
231             dest[1] = src[1];
232             dest+=2;
233             src+=2;
234         }
235     }
236     else if(mode==1) {
237         for(x=0;x<width;x++) {
238             dest[0] = src[0]+lasta;
239             dest[1] = src[1]+lastb;
240             lasta = dest[0];
241             lastb = dest[1];
242             dest+=2;
243             src+=2;
244         }
245     }
246     else if(mode==2) {
247         for(x=0;x<width;x++) {
248             dest[0] = src[0]+old[0];
249             dest[1] = src[1]+old[1];
250             dest+=2;
251             old+=2;
252             src+=2;
253         }
254     }
255     else if(mode==3) {
256         for(x=0;x<width;x++) {
257             dest[0] = src[0]+(old[0]+lasta)/2;
258             dest[1] = src[1]+(old[1]+lastb)/2;
259             lasta = dest[0];
260             lastb = dest[1];
261             dest+=2;
262             old+=2;
263             src+=2;
264         }
265     }
266     else if(mode==4) {
267         for(x=0;x<width;x++) {
268             dest[0] = src[0]+PaethPredictor(lasta,old[0],upperlasta);
269             dest[1] = src[1]+PaethPredictor(lastb,old[1],upperlastb);
270             lasta = dest[0];
271             lastb = dest[1];
272             upperlasta = old[0];
273             upperlastb = old[1];
274             dest+=2;
275             old+=2;
276             src+=2;
277         }
278     }    
279 }
280
281
282 /* also performs 24 bit conversion! */
283 static void applyfilter3(int mode, unsigned char*src, unsigned char*old, unsigned char*dest, int width)
284 {
285     int x;
286     unsigned char lastr=0;
287     unsigned char lastg=0;
288     unsigned char lastb=0;
289     unsigned char upperlastr=0;
290     unsigned char upperlastg=0;
291     unsigned char upperlastb=0;
292
293     if(mode==0) {
294         for(x=0;x<width;x++) {
295             dest[0] = 255;
296             dest[1] = src[0];
297             dest[2] = src[1];
298             dest[3] = src[2];
299             dest+=4;
300             src+=3;
301         }
302     }
303     else if(mode==1) {
304         for(x=0;x<width;x++) {
305             dest[0] = 255;
306             dest[1] = src[0]+lastr;
307             dest[2] = src[1]+lastg;
308             dest[3] = src[2]+lastb;
309             lastr = dest[1];
310             lastg = dest[2];
311             lastb = dest[3];
312             dest+=4;
313             src+=3;
314         }
315     }
316     else if(mode==2) {
317         for(x=0;x<width;x++) {
318             dest[0] = 255;
319             dest[1] = src[0]+old[1];
320             dest[2] = src[1]+old[2];
321             dest[3] = src[2]+old[3];
322             dest+=4;
323             old+=4;
324             src+=3;
325         }
326     }
327     else if(mode==3) {
328         for(x=0;x<width;x++) {
329             dest[0] = 255;
330             dest[1] = src[0]+(old[1]+lastr)/2;
331             dest[2] = src[1]+(old[2]+lastg)/2;
332             dest[3] = src[2]+(old[3]+lastb)/2;
333             lastr = dest[1];
334             lastg = dest[2];
335             lastb = dest[3];
336             dest+=4;
337             old+=4;
338             src+=3;
339         }
340     }
341     else if(mode==4) {
342         for(x=0;x<width;x++) {
343             dest[0] = 255;
344             dest[1] = src[0]+PaethPredictor(lastr,old[1],upperlastr);
345             dest[2] = src[1]+PaethPredictor(lastg,old[2],upperlastg);
346             dest[3] = src[2]+PaethPredictor(lastb,old[3],upperlastb);
347             lastr = dest[1];
348             lastg = dest[2];
349             lastb = dest[3];
350             upperlastr = old[1];
351             upperlastg = old[2];
352             upperlastb = old[3];
353             dest+=4;
354             old+=4;
355             src+=3;
356         }
357     }    
358 }
359
360 static void inline applyfilter4(int mode, unsigned char*src, unsigned char*old, unsigned char*dest, int width)
361 {
362     int x;
363     unsigned char lastr=0;
364     unsigned char lastg=0;
365     unsigned char lastb=0;
366     unsigned char lasta=0;
367     unsigned char upperlastr=0;
368     unsigned char upperlastg=0;
369     unsigned char upperlastb=0;
370     unsigned char upperlasta=0;
371
372     if(mode==0) {
373         for(x=0;x<width;x++) {
374             dest[0] = src[3];
375             dest[1] = src[0];
376             dest[2] = src[1];
377             dest[3] = src[2];
378             dest+=4;
379             src+=4;
380         }
381     }
382     else if(mode==1) {
383         for(x=0;x<width;x++) {
384             dest[0] = src[3]+lasta;
385             dest[1] = src[0]+lastr;
386             dest[2] = src[1]+lastg;
387             dest[3] = src[2]+lastb;
388             lasta = dest[0];
389             lastr = dest[1];
390             lastg = dest[2];
391             lastb = dest[3];
392             dest+=4;
393             src+=4;
394         }
395     }
396     else if(mode==2) {
397         for(x=0;x<width;x++) {
398             dest[0] = src[3]+old[0];
399             dest[1] = src[0]+old[1];
400             dest[2] = src[1]+old[2];
401             dest[3] = src[2]+old[3];
402             dest+=4;
403             old+=4;
404             src+=4;
405         }
406     }
407     else if(mode==3) {
408         for(x=0;x<width;x++) {
409             dest[0] = src[3]+(old[0]+lasta)/2;
410             dest[1] = src[0]+(old[1]+lastr)/2;
411             dest[2] = src[1]+(old[2]+lastg)/2;
412             dest[3] = src[2]+(old[3]+lastb)/2;
413             lasta = dest[0];
414             lastr = dest[1];
415             lastg = dest[2];
416             lastb = dest[3];
417             dest+=4;
418             old+=4;
419             src+=4;
420         }
421     }
422     else if(mode==4) {
423         for(x=0;x<width;x++) {
424             dest[0] = src[3]+PaethPredictor(lasta,old[0],upperlasta);
425             dest[1] = src[0]+PaethPredictor(lastr,old[1],upperlastr);
426             dest[2] = src[1]+PaethPredictor(lastg,old[2],upperlastg);
427             dest[3] = src[2]+PaethPredictor(lastb,old[3],upperlastb);
428             lasta = dest[0];
429             lastr = dest[1];
430             lastg = dest[2];
431             lastb = dest[3];
432             upperlasta = old[0];
433             upperlastr = old[1];
434             upperlastg = old[2];
435             upperlastb = old[3];
436             dest+=4;
437             old+=4;
438             src+=4;
439         }
440     }    
441 }
442
443
444 EXPORT int getPNGdimensions(const char*sname, int*destwidth, int*destheight)
445 {
446     FILE*fi;
447     struct png_header header;
448     if ((fi = fopen(sname, "rb")) == NULL) {
449         fprintf(stderr, "Couldn't open %s\n", sname);
450         return 0;
451     }
452     if(!png_read_header(fi, &header)) {
453         return 0;
454     }
455
456     *destwidth = header.width;
457     *destheight = header.height;
458     return 1;
459 }
460
461 EXPORT int getPNG(const char*sname, int*destwidth, int*destheight, unsigned char**destdata)
462 {
463     char tagid[4];
464     int len;
465     unsigned char*data;
466     unsigned char*imagedata;
467     unsigned char*zimagedata=0;
468     unsigned long int imagedatalen;
469     unsigned long int zimagedatalen=0;
470     unsigned char*palette = 0;
471     int palettelen = 0;
472     unsigned char*alphapalette = 0;
473     int alphapalettelen = 0;
474     struct png_header header;
475     int bypp;
476     unsigned char*data2 = 0;
477     unsigned char alphacolor[3];
478     int hasalphacolor=0;
479
480     FILE *fi;
481     unsigned char *scanline;
482
483     if ((fi = fopen(sname, "rb")) == NULL) {
484         printf("Couldn't open %s\n", sname);
485         return 0;
486     }
487
488     if(!png_read_header(fi, &header)) {
489         fclose(fi);
490         return 0;
491     }
492
493     if(header.mode == 3 || header.mode == 0) bypp = 1;
494     else if(header.mode == 4) bypp = 2;
495     else if(header.mode == 2) bypp = 3;
496     else if(header.mode == 6) bypp = 4;
497     else {
498         printf("ERROR: mode:%d\n", header.mode);
499         return 0;
500     }
501
502     imagedatalen = bypp * header.width * header.height + 65536;
503     imagedata = (unsigned char*)malloc(imagedatalen);
504
505     fseek(fi,8,SEEK_SET);
506     while(!feof(fi))
507     {
508         if(!png_read_chunk(&tagid, &len, &data, fi))
509             break;
510         if(!strncmp(tagid, "IEND", 4)) {
511             break;
512         }
513         if(!strncmp(tagid, "PLTE", 4)) {
514             palette = data;
515             palettelen = len/3;
516             data = 0; //don't free data
517             //printf("%d colors in palette\n", palettelen);
518         }
519         if(!strncmp(tagid, "tRNS", 4)) {
520             if(header.mode == 3) {
521                 alphapalette = data;
522                 alphapalettelen = len;
523                 data = 0; //don't free data
524                 //printf("found %d alpha colors\n", alphapalettelen);
525             } else if(header.mode == 0 || header.mode == 2) {
526                 int t;
527                 if(header.mode == 2) {
528                     alphacolor[0] = data[1];
529                     alphacolor[1] = data[3];
530                     alphacolor[2] = data[5];
531                 } else {
532                     alphacolor[0] = alphacolor[1] = alphacolor[2] = data[1];
533                 }
534                 hasalphacolor = 1;
535             }
536         }
537         if(!strncmp(tagid, "IDAT", 4)) {
538             if(!zimagedata) {
539                 zimagedatalen = len;
540                 zimagedata = (unsigned char*)malloc(len);
541                 memcpy(zimagedata,data,len);
542             } else {
543                 zimagedata = (unsigned char*)realloc(zimagedata, zimagedatalen+len);
544                 memcpy(&zimagedata[zimagedatalen], data, len);
545                 zimagedatalen += len;
546             }
547         }
548         if(!strncmp(tagid, "tEXt", 4)) {
549             /*int t;
550             printf("Image Text: ");
551             for(t=0;t<len;t++) {
552                 if(data[t]>=32 && data[t]<128)
553                     printf("%c", data[t]);
554                 else
555                     printf("?");
556             }
557             printf("\n");*/
558         }
559         if(data) {
560             free(data); data=0;
561         }
562     }
563     
564     if(!zimagedata || uncompress(imagedata, &imagedatalen, zimagedata, zimagedatalen) != Z_OK) {
565         printf("Couldn't uncompress %s!\n", sname);
566         if(zimagedata)
567             free(zimagedata);
568         return 0;
569     }
570     free(zimagedata);
571     fclose(fi);
572
573     *destwidth = header.width;
574     *destheight = header.height;
575         
576     data2 = (unsigned char*)malloc(header.width*header.height*4);
577
578     if(header.mode == 4)
579     {
580         int i,s=0;
581         int x,y;
582         int pos=0;
583         unsigned char* old= (unsigned char*)malloc(header.width*2);
584         memset(old, 0, header.width*2);
585         *destdata = data2;
586         for(y=0;y<header.height;y++) {
587             int mode = imagedata[pos++]; //filter mode
588             unsigned char*src;
589             unsigned char*dest;
590             int x;
591             dest = &data2[(y*header.width)*4];
592
593             if(header.bpp == 8) {
594                 /* one byte per pixel */
595                 src = &imagedata[pos];
596                 pos+=header.width*2;
597             } else {
598                 /* not implemented yet */
599                 fprintf(stderr, "ERROR: mode=4 bpp:%d\n", header.bpp);
600                 free(data2);
601                 return 0;
602             }
603
604             applyfilter2(mode, src, old, dest, header.width);
605             memcpy(old, dest, header.width*2);
606
607             for(x=header.width-1;x>=0;x--) {
608                 unsigned char gray = dest[x*2+0];
609                 unsigned char alpha = dest[x*2+1];
610                 dest[x*4+0] = alpha;
611                 dest[x*4+1] = gray;
612                 dest[x*4+2] = gray;
613                 dest[x*4+3] = gray;
614             }
615         }
616         free(old);
617         free(imagedata);
618     } else if(header.mode == 6 || header.mode == 2) {
619         int i,s=0;
620         int x,y;
621         int pos=0;
622         *destdata = data2;
623         
624         unsigned char* firstline = malloc(header.width*4);
625         memset(firstline,0,header.width*4);
626         for(y=0;y<header.height;y++) {
627             int mode = imagedata[pos++]; //filter mode
628             unsigned char*src;
629             unsigned char*dest;
630             unsigned char*old;
631             dest = &data2[(y*header.width)*4];
632
633             if(header.bpp == 8)
634             {
635                 /* one byte per pixel */
636                 src = &imagedata[pos];
637                 pos+=header.width*(header.mode==6?4:3);
638             } else {
639                 /* not implemented yet */
640                 fprintf(stderr, "ERROR: bpp:%d\n", header.bpp);
641                 free(data2);
642                 return 0;
643             }
644
645             if(!y) {
646                 old = firstline;
647             } else {
648                 old = &data2[(y-1)*header.width*4];
649             }
650             if(header.mode == 6) { 
651                 applyfilter4(mode, src, old, dest, header.width);
652             } else { // header.mode = 2
653                 applyfilter3(mode, src, old, dest, header.width);
654                 /* replace alpha color */
655                 if(hasalphacolor) {
656                     int x;
657                     for(x=0;x<header.width;x++) {
658                         if(dest[x*4+1] == alphacolor[0] &&
659                            dest[x*4+2] == alphacolor[1] &&
660                            dest[x*4+3] == alphacolor[2]) {
661                             *(u32*)&dest[x*4] = 0;
662                         }
663                     }
664                 }
665             }
666         }
667         free(firstline);
668         free(imagedata);
669     } else if(header.mode == 0 || header.mode == 3) {
670         COL*rgba = 0;
671         unsigned char*tmpline = (unsigned char*)malloc(header.width+1);
672         unsigned char*destline = (unsigned char*)malloc(header.width+1);
673         int i,x,y;
674         int pos=0;
675         
676         *destdata = data2;
677         
678         if(header.mode == 0) { // grayscale palette
679             int mult = (0x1ff>>header.bpp);
680             palettelen = 1<<header.bpp;
681             rgba = (COL*)malloc(palettelen*sizeof(COL));
682             for(i=0;i<palettelen;i++) {
683                 rgba[i].a = 255;
684                 rgba[i].r = i*mult;
685                 rgba[i].g = i*mult;
686                 rgba[i].b = i*mult;
687                 if(hasalphacolor) {
688                     if(rgba[i].r == alphacolor[0])
689                         rgba[i].a = 0;
690                 }
691             }
692         } else {
693             if(!palette) {
694                 fprintf(stderr, "Error: No palette found!\n");
695                 exit(1);
696             }
697             rgba = (COL*)malloc(palettelen*4);
698             /* 24->32 bit conversion */
699             for(i=0;i<palettelen;i++) {
700                 rgba[i].r = palette[i*3+0];
701                 rgba[i].g = palette[i*3+1];
702                 rgba[i].b = palette[i*3+2];
703                 if(alphapalette && i<alphapalettelen) {
704                     rgba[i].a = alphapalette[i];
705                     /*rgba[i].r = ((int)rgba[i].r*rgba[i].a)/255;
706                     rgba[i].g = ((int)rgba[i].g*rgba[i].a)/255;
707                     rgba[i].b = ((int)rgba[i].b*rgba[i].a)/255;*/
708                 } else {
709                     rgba[i].a = 255;
710                 }
711                 if(hasalphacolor) {
712                     if(rgba[i].r == alphacolor[0] &&
713                        rgba[i].g == alphacolor[1] &&
714                        rgba[i].b == alphacolor[2])
715                         rgba[i].a = 0;
716                 }
717             }
718         }
719
720         for(y=0;y<header.height;y++) {
721             int mode = imagedata[pos++]; //filter mode
722             int x;
723             unsigned char*old;
724             unsigned char*src;
725             src = &imagedata[pos];
726             if(header.bpp == 8) {
727                 pos+=header.width;
728             } else {
729                 int x,s=0;
730                 int bitpos = 0;
731                 u32 v = (1<<header.bpp)-1;
732                 for(x=0;x<header.width;x++) {
733                     u32 r = src[s/8]<<8 | 
734                             src[s/8+1];
735                     int t;
736                     tmpline[x] = (r>>(16-header.bpp-(s&7)))&v;
737                     s+=header.bpp;
738                 }
739                 src = tmpline;
740                 pos+=(header.width*header.bpp+7)/8;
741             }
742
743             if(!y) {
744                 memset(destline,0,header.width);
745                 old = &destline[y*header.width];
746             } else {
747                 old = tmpline;
748             }
749             applyfilter1(mode, src, old, destline, header.width);
750             memcpy(tmpline,destline,header.width);
751             for(x=0;x<header.width;x++) {
752                 *(COL*)&data2[y*header.width*4+x*4+0] = rgba[destline[x]];
753             }
754         }
755         free(tmpline);
756         free(destline);
757         free(rgba);
758         free(imagedata);
759     } else {
760         printf("expected PNG mode to be 2, 3 or 6 (is:%d)\n", header.mode);
761         return 0;
762     }
763
764     return 1;
765 }
766
767 static char hasAlpha(unsigned char*_image, int size)
768 {
769     COL*image = (COL*)_image;
770     int t;
771     for(t=0;t<size;t++) {
772         if(image[t].a!=255)
773             return 1;
774     }
775     return 0;
776 }
777
778 typedef struct {
779     u32 num;
780     u32 color;
781 } colornum_t;
782
783 static int compare_colors(const void*_c1, const void*_c2) {
784     colornum_t*c1 = (colornum_t*)_c1;
785     colornum_t*c2 = (colornum_t*)_c2;
786     return c2->num - c1->num;
787 }
788
789 static colornum_t* getColors(COL*image, int size, int*num)
790 {
791     unsigned char*colexists = malloc((256*256*256)/8);
792     memset(colexists, 0, (256*256*256)/8);
793     int t;
794     int count=0;
795
796     /* find all different colors in the image */
797     for(t=0;t<size;t++) {
798         int index = (image[t].r)|(image[t].g)<<8|(image[t].b)<<16;
799         if(!(colexists[index/8]&(1<<(index&7)))) {
800             count++;
801             colexists[index/8]|=(1<<(index&7));
802         }
803     }
804     
805     /* now store them in an array */
806     colornum_t*colors=(colornum_t*)malloc(sizeof(colornum_t)*count);
807     int pos=0;
808     for(t=0;t<256*256*256;t++) {
809         if(colexists[t/8]&(1<<(t&7))) {
810             colors[pos].color = t;
811             colors[pos].num = 0;
812             pos++;
813         }
814     }
815
816     /* next, count how often each color occurs */
817     for(t=0;t<size;t++) {
818         int col = (image[t].r)|(image[t].g)<<8|(image[t].b)<<16;
819         int min,max,i,l;
820         for(min=0, max=count, i=count/2, l=count; i != l; l=i,i=(min+max)/2) {
821             // binary search
822             if(colors[i].color >= col) max=i;
823             else min=i+1;
824         }
825         assert(colors[i].color==col);
826         colors[i].num++;
827     }
828     free(colexists);
829     *num = count;
830     return colors;
831 }
832
833 static COL* getOptimalPalette(COL*image, int size, int palettesize)
834 {
835     int num;
836     COL* ret = malloc(sizeof(COL)*palettesize);
837     memset(ret, 0, sizeof(COL)*palettesize);
838     colornum_t*colors = getColors(image, size, &num);
839
840     assert(palettesize<=256);
841
842     qsort(colors, num, sizeof(colornum_t), compare_colors);
843
844     if(num<=palettesize) {
845         /* if there are not more than palettesize different colors in 
846            the image anyway, we are done */
847         int t;
848         for(t=0;t<num;t++) {
849             ret[t].r = colors[t].color;
850             ret[t].g = colors[t].color>>8;
851             ret[t].b = colors[t].color>>16;
852             ret[t].a = 255;
853         }
854         return ret;
855     }
856
857     if(num>2048) {
858         /* if there are too many different colors, pick the ones that
859            occur most often */
860         num = 2048;
861     }
862
863     colornum_t*centers = malloc(sizeof(colornum_t)*palettesize);
864     int t;
865     for(t=0;t<palettesize;t++) {
866         centers[t].color = colors[t].color;
867     }
868     unsigned char*belongsto = (unsigned char*)malloc(num);
869     memset(belongsto, 0, num);
870     /* do a k-means clustering on the colors */
871     char change = 1;
872     int tries = 0;
873     while(change) {
874         if(tries++ >= (palettesize+num)*2) {
875             fprintf(stderr, "Warning: didn't find optimal palette\n");
876             break;
877         }
878         change = 0;
879         int s,t;
880         for(s=0;s<palettesize;s++) {
881             centers[s].num = 0;
882         }
883         for(t=0;t<num;t++) {
884             int best=0x7fffffff;
885             int bestpos=0;
886             for(s=0;s<palettesize;s++) {
887                 int distance = 0;
888                 distance += abs((centers[s].color>>0&0xff) - (colors[t].color>>0&0xff));
889                 distance += abs((centers[s].color>>8&0xff) - (colors[t].color>>8&0xff));
890                 distance += abs((centers[s].color>>16&0xff) - (colors[t].color>>16&0xff));
891                 distance *= colors[t].num;
892                 if(distance<best) {
893                     best = distance;
894                     bestpos = s;
895                 }
896             }
897             if(bestpos!=belongsto[t])
898                 change = 1;
899             belongsto[t] = bestpos;
900         }
901         for(s=0;s<palettesize;s++) {
902             int r=0;
903             int g=0;
904             int b=0;
905             int count=0;
906             for(t=0;t<num;t++) {
907                 if(belongsto[t]==s) {
908                     r += ((colors[t].color>>0)&0xff)*colors[t].num;
909                     g += ((colors[t].color>>8)&0xff)*colors[t].num;
910                     b += ((colors[t].color>>16)&0xff)*colors[t].num;
911                     count+=colors[t].num;
912                 }
913             }
914             if(!count) {
915                 int random = rand()%num;
916                 centers[s].color = colors[random].color;
917                 centers[s].num = 0;
918                 change = 1;
919             } else {
920                 r /= count;
921                 g /= count;
922                 b /= count;
923                 centers[s].color = r|g<<8|b<<16;
924                 centers[s].num = count;
925             }
926         }
927     }
928     free(belongsto);
929     free(colors);
930     for(t=0;t<palettesize;t++) {
931         ret[t].r = centers[t].color;
932         ret[t].g = centers[t].color>>8;
933         ret[t].b = centers[t].color>>16;
934         ret[t].a = 255;
935     }
936     free(centers);
937     return ret;
938 }
939
940 static int sqr(const int x) {return x*x;}
941
942 static void quantizeImage(unsigned char*_image, int size, int numcolors, unsigned char**newimage, COL**palette) 
943 {
944     COL*image = (COL*)_image;
945     COL*pal= getOptimalPalette(image, size, numcolors);
946     *palette = pal;
947     *newimage = (unsigned char*)malloc(size);
948     int t;
949     for(t=0;t<size;t++) {
950         int best=0x7fffffff;
951         int bestcol = 0;
952         int s;
953         for(s=0;s<numcolors;s++) {
954             int distance = 0;
955             distance += sqr((pal[s].r) - (image[t].r))*5;
956             distance += sqr((pal[s].g) - (image[t].g))*6;
957             distance += sqr((pal[s].b) - (image[t].b))*4;
958             if(distance<best) {
959                 best = distance;
960                 bestcol = s;
961             }
962         }
963         //image[t] = pal[bestcol];
964         (*newimage)[t] = bestcol;
965     }
966 }
967
968 static u32 mycrc32;
969
970 static u32*crc32_table = 0;
971 static void make_crc32_table(void)
972 {
973   int t;
974   if(crc32_table) 
975       return;
976   crc32_table = (u32*)malloc(1024);
977
978   for (t = 0; t < 256; t++) {
979     u32 c = t;
980     int s;
981     for (s = 0; s < 8; s++) {
982       c = (0xedb88320L*(c&1)) ^ (c >> 1);
983     }
984     crc32_table[t] = c;
985   }
986 }
987 static inline void png_write_byte(FILE*fi, unsigned char byte)
988 {
989     fwrite(&byte,1,1,fi);
990     mycrc32 = crc32_table[(mycrc32 ^ byte) & 0xff] ^ (mycrc32 >> 8);
991 }
992 static long png_start_chunk(FILE*fi, char*type, int len)
993 {
994     unsigned char mytype[4]={0,0,0,0};
995     unsigned char mylen[4];
996     long filepos;
997     mylen[0] = len>>24;
998     mylen[1] = len>>16;
999     mylen[2] = len>>8;
1000     mylen[3] = len;
1001     memcpy(mytype,type,strlen(type));
1002     filepos = ftell(fi);
1003     fwrite(&mylen, 4, 1, fi);
1004     mycrc32=0xffffffff;
1005     png_write_byte(fi,mytype[0]);
1006     png_write_byte(fi,mytype[1]);
1007     png_write_byte(fi,mytype[2]);
1008     png_write_byte(fi,mytype[3]);
1009     return filepos;
1010 }
1011 static void png_patch_len(FILE*fi, int pos, int len)
1012 {
1013     unsigned char mylen[4];
1014     long filepos;
1015     mylen[0] = len>>24;
1016     mylen[1] = len>>16;
1017     mylen[2] = len>>8;
1018     mylen[3] = len;
1019     fseek(fi, pos, SEEK_SET);
1020     fwrite(&mylen, 4, 1, fi);
1021     fseek(fi, 0, SEEK_END);
1022 }
1023 static void png_write_bytes(FILE*fi, unsigned char*bytes, int len)
1024 {
1025     int t;
1026     for(t=0;t<len;t++)
1027         png_write_byte(fi,bytes[t]);
1028 }
1029 static void png_write_dword(FILE*fi, u32 dword)
1030 {
1031     png_write_byte(fi,dword>>24);
1032     png_write_byte(fi,dword>>16);
1033     png_write_byte(fi,dword>>8);
1034     png_write_byte(fi,dword);
1035 }
1036 static void png_end_chunk(FILE*fi)
1037 {
1038     u32 tmp = mycrc32^0xffffffff;
1039     unsigned char tmp2[4];
1040     tmp2[0] = tmp>>24;
1041     tmp2[1] = tmp>>16;
1042     tmp2[2] = tmp>>8;
1043     tmp2[3] = tmp;
1044     fwrite(&tmp2,4,1,fi);
1045 }
1046
1047 #define ZLIB_BUFFER_SIZE 16384
1048
1049 static long compress_line(z_stream*zs, Bytef*line, int len, FILE*fi)
1050 {
1051     long size = 0;
1052     zs->next_in = line;
1053     zs->avail_in = len;
1054
1055     while(1) {
1056         int ret = deflate(zs, Z_NO_FLUSH);
1057         if (ret != Z_OK) {
1058             fprintf(stderr, "error in deflate(): %s", zs->msg?zs->msg:"unknown");
1059             return 0;
1060         }
1061         if(zs->avail_out != ZLIB_BUFFER_SIZE) {
1062             int consumed = ZLIB_BUFFER_SIZE - zs->avail_out;
1063             size += consumed;
1064             png_write_bytes(fi, zs->next_out - consumed , consumed);
1065             zs->next_out = zs->next_out - consumed;
1066             zs->avail_out = ZLIB_BUFFER_SIZE;
1067         }
1068         if(!zs->avail_in) {
1069             break;
1070         }
1071     }
1072     return size;
1073 }
1074
1075 static int test_line(z_stream*zs_orig, Bytef*line, int linelen)
1076 {
1077     z_stream zs;
1078     int ret = deflateCopy(&zs, zs_orig);
1079     if(ret != Z_OK) {
1080         fprintf(stderr, "Couldn't copy stream\n");
1081         return 0;
1082     }
1083
1084     zs.next_in = line;
1085     zs.avail_in = linelen;
1086
1087     long size = 0;
1088
1089     int mode = Z_SYNC_FLUSH;
1090     while(1) {
1091         int ret = deflate(&zs, mode);
1092         if (ret != Z_OK && ret != Z_STREAM_END) {
1093             fprintf(stderr, "error in deflate(): %s (mode %s, %d bytes remaining)\n", zs.msg?zs.msg:"unknown", 
1094                     mode==Z_SYNC_FLUSH?"Z_SYNC_FLUSH":"Z_FINISH", zs.avail_in);
1095             return 0;
1096         }
1097         if(zs.avail_out != ZLIB_BUFFER_SIZE) {
1098             int consumed = ZLIB_BUFFER_SIZE - zs.avail_out;
1099             size += consumed;
1100             zs.next_out = zs.next_out - consumed;
1101             zs.avail_out = ZLIB_BUFFER_SIZE;
1102         }
1103         if (ret == Z_STREAM_END) {
1104             break;
1105         }
1106         if(!zs.avail_in) {
1107             mode = Z_FINISH;
1108         }
1109     }
1110     ret = deflateEnd(&zs);
1111     if (ret != Z_OK) {
1112         fprintf(stderr, "error in deflateEnd(): %s\n", zs.msg?zs.msg:"unknown");
1113         return 0;
1114     }
1115     return size;
1116 }
1117
1118 static int finishzlib(z_stream*zs, FILE*fi)
1119 {
1120     int size = 0;
1121     int ret;
1122     while(1) {
1123         ret = deflate(zs, Z_FINISH);
1124         if (ret != Z_OK &&
1125             ret != Z_STREAM_END) {
1126             fprintf(stderr, "error in deflate(finish): %s\n", zs->msg?zs->msg:"unknown");
1127             return 0;
1128         }
1129
1130         if(zs->avail_out != ZLIB_BUFFER_SIZE) {
1131             int consumed = ZLIB_BUFFER_SIZE - zs->avail_out;
1132             size += consumed;
1133             png_write_bytes(fi, zs->next_out - consumed , consumed);
1134             zs->next_out = zs->next_out - consumed;
1135             zs->avail_out = ZLIB_BUFFER_SIZE;
1136         }
1137         if (ret == Z_STREAM_END) {
1138             break;
1139         }
1140     }
1141     ret = deflateEnd(zs);
1142     if (ret != Z_OK) {
1143         fprintf(stderr, "error in deflateEnd(): %s\n", zs->msg?zs->msg:"unknown");
1144         return 0;
1145     }
1146     return size;
1147 }
1148
1149 static void filter_line8(int filtermode, unsigned char*dest, unsigned char*src, int width)
1150 {
1151     int pos2 = 0;
1152     int pos = 0;
1153     int srcwidth = width;
1154     int x;
1155     if(filtermode == 0) {
1156         for(x=0;x<width;x++) {
1157             dest[pos2++]=src[pos++]; //alpha
1158         }
1159     } else if(filtermode == 1) {
1160         /* x difference filter */
1161         dest[pos2++]=src[pos++];
1162         for(x=1;x<width;x++) {
1163             dest[pos2++]=src[pos] - src[pos-1];
1164             pos++;
1165         }
1166     } else if(filtermode == 2) {
1167         /* y difference filter */
1168         for(x=0;x<width;x++) {
1169             dest[pos2++]=src[pos+0] - src[pos-srcwidth+0]; //alpha
1170             pos++;
1171         }
1172     } else if(filtermode == 3) {
1173         dest[pos2++]=src[pos+0] - src[pos-srcwidth+0]/2;
1174         pos++;
1175         /* x+y difference filter */
1176         for(x=1;x<width;x++) {
1177             dest[pos2++]=src[pos+0] - (src[pos-1+0] + src[pos-srcwidth+0])/2; //alpha
1178             pos++;
1179         }
1180     } else if(filtermode == 4) {
1181         dest[pos2++]=src[pos+0] - PaethPredictor(0, src[pos-srcwidth+0], 0);
1182         pos++;
1183         /* paeth difference filter */
1184         for(x=1;x<width;x++) {
1185             dest[pos2++]=src[pos+0] - PaethPredictor(src[pos-1+0], src[pos-srcwidth+0], src[pos-1-srcwidth+0]);
1186             pos++;
1187         }
1188     }
1189 }
1190
1191 static void filter_line32(int filtermode, unsigned char*dest, unsigned char*src, int width)
1192 {
1193     int pos2 = 0;
1194     int pos = 0;
1195     int srcwidth = width*4;
1196     int x;
1197     if(filtermode == 0) {
1198         for(x=0;x<width;x++) {
1199             dest[pos2++]=src[pos+1];
1200             dest[pos2++]=src[pos+2];
1201             dest[pos2++]=src[pos+3];
1202             dest[pos2++]=src[pos+0]; //alpha
1203             pos+=4;
1204         }
1205     } else if(filtermode == 1) {
1206         /* x difference filter */
1207         dest[pos2++]=src[pos+1];
1208         dest[pos2++]=src[pos+2];
1209         dest[pos2++]=src[pos+3];
1210         dest[pos2++]=src[pos+0];
1211         pos+=4;
1212         for(x=1;x<width;x++) {
1213             dest[pos2++]=src[pos+1] - src[pos-4+1];
1214             dest[pos2++]=src[pos+2] - src[pos-4+2];
1215             dest[pos2++]=src[pos+3] - src[pos-4+3];
1216             dest[pos2++]=src[pos+0] - src[pos-4+0]; //alpha
1217             pos+=4;
1218         }
1219     } else if(filtermode == 2) {
1220         /* y difference filter */
1221         for(x=0;x<width;x++) {
1222             dest[pos2++]=src[pos+1] - src[pos-srcwidth+1];
1223             dest[pos2++]=src[pos+2] - src[pos-srcwidth+2];
1224             dest[pos2++]=src[pos+3] - src[pos-srcwidth+3];
1225             dest[pos2++]=src[pos+0] - src[pos-srcwidth+0]; //alpha
1226             pos+=4;
1227         }
1228     } else if(filtermode == 3) {
1229         dest[pos2++]=src[pos+1] - src[pos-srcwidth+1]/2;
1230         dest[pos2++]=src[pos+2] - src[pos-srcwidth+2]/2;
1231         dest[pos2++]=src[pos+3] - src[pos-srcwidth+3]/2;
1232         dest[pos2++]=src[pos+0] - src[pos-srcwidth+0]/2;
1233         pos+=4;
1234         /* x+y difference filter */
1235         for(x=1;x<width;x++) {
1236             dest[pos2++]=src[pos+1] - (src[pos-4+1] + src[pos-srcwidth+1])/2;
1237             dest[pos2++]=src[pos+2] - (src[pos-4+2] + src[pos-srcwidth+2])/2;
1238             dest[pos2++]=src[pos+3] - (src[pos-4+3] + src[pos-srcwidth+3])/2;
1239             dest[pos2++]=src[pos+0] - (src[pos-4+0] + src[pos-srcwidth+0])/2; //alpha
1240             pos+=4;
1241         }
1242     } else if(filtermode == 4) {
1243         dest[pos2++]=src[pos+1] - PaethPredictor(0, src[pos-srcwidth+1], 0);
1244         dest[pos2++]=src[pos+2] - PaethPredictor(0, src[pos-srcwidth+2], 0);
1245         dest[pos2++]=src[pos+3] - PaethPredictor(0, src[pos-srcwidth+3], 0);
1246         dest[pos2++]=src[pos+0] - PaethPredictor(0, src[pos-srcwidth+0], 0);
1247         pos+=4;
1248         /* paeth difference filter */
1249         for(x=1;x<width;x++) {
1250             dest[pos2++]=src[pos+1] - PaethPredictor(src[pos-4+1], src[pos-srcwidth+1], src[pos-4-srcwidth+1]);
1251             dest[pos2++]=src[pos+2] - PaethPredictor(src[pos-4+2], src[pos-srcwidth+2], src[pos-4-srcwidth+2]);
1252             dest[pos2++]=src[pos+3] - PaethPredictor(src[pos-4+3], src[pos-srcwidth+3], src[pos-4-srcwidth+3]);
1253             dest[pos2++]=src[pos+0] - PaethPredictor(src[pos-4+0], src[pos-srcwidth+0], src[pos-4-srcwidth+0]);
1254             pos+=4;
1255         }
1256     }
1257 }
1258
1259 EXPORT void savePNG(const char*filename, unsigned char*data, int width, int height, int numcolors)
1260 {
1261     FILE*fi;
1262     int crc;
1263     int t;
1264     unsigned char format;
1265     unsigned char tmp;
1266     unsigned char* data2=0;
1267     u32 datalen;
1268     u32 datalen2;
1269     unsigned char head[] = {137,80,78,71,13,10,26,10}; // PNG header
1270     int cols;
1271     char alpha = 1;
1272     int pos = 0;
1273     int error;
1274     u32 tmp32;
1275     int bpp;
1276     int ret;
1277     z_stream zs;
1278     COL*palette=0;
1279
1280     make_crc32_table();
1281
1282     if(!numcolors) {
1283         bpp = 32;
1284         cols = 0;
1285         format = 5;
1286     } else {
1287         bpp = 8;
1288         cols = numcolors;
1289         format = 3;
1290         quantizeImage(data, width*height, numcolors, &data, &palette);
1291     }
1292
1293     datalen = (width*height*bpp/8+cols*8);
1294     
1295     fi = fopen(filename, "wb");
1296     if(!fi) {
1297         perror("open");
1298         return;
1299     }
1300     fwrite(head,sizeof(head),1,fi);     
1301
1302     png_start_chunk(fi, "IHDR", 13);
1303      png_write_dword(fi,width);
1304      png_write_dword(fi,height);
1305      png_write_byte(fi,8);
1306      if(format == 3)
1307      png_write_byte(fi,3); //indexed
1308      else if(format == 5 && alpha==0)
1309      png_write_byte(fi,2); //rgb
1310      else if(format == 5 && alpha==1)
1311      png_write_byte(fi,6); //rgba
1312      else return;
1313
1314      png_write_byte(fi,0); //compression mode
1315      png_write_byte(fi,0); //filter mode
1316      png_write_byte(fi,0); //interlace mode
1317     png_end_chunk(fi);
1318
1319     if(format == 3) {
1320         png_start_chunk(fi, "PLTE", 768);
1321          for(t=0;t<cols;t++) {
1322              png_write_byte(fi,palette[t].r);
1323              png_write_byte(fi,palette[t].g);
1324              png_write_byte(fi,palette[t].b);
1325          }
1326         png_end_chunk(fi);
1327     }
1328     long idatpos = png_start_chunk(fi, "IDAT", 0);
1329     
1330     memset(&zs,0,sizeof(z_stream));
1331     Bytef*writebuf = (Bytef*)malloc(ZLIB_BUFFER_SIZE);
1332     zs.zalloc = Z_NULL;
1333     zs.zfree  = Z_NULL;
1334     zs.opaque = Z_NULL;
1335     zs.next_out = writebuf;
1336     zs.avail_out = ZLIB_BUFFER_SIZE;
1337     ret = deflateInit(&zs, 9);
1338     if (ret != Z_OK) {
1339         fprintf(stderr, "error in deflateInit(): %s", zs.msg?zs.msg:"unknown");
1340         return;
1341     }
1342
1343     long idatsize = 0;
1344     {
1345         int x,y;
1346         int bypp = bpp/8;
1347         int srcwidth = width * bypp;
1348         int linelen = 1 + srcwidth;
1349         if(bypp==2) 
1350             linelen = 1 + ((srcwidth+1)&~1);
1351         else if(bypp==3) 
1352             linelen = 1 + ((srcwidth+2)/3)*3;
1353         else if(bypp==4) 
1354             linelen = 1 + ((srcwidth+3)&~3);
1355         unsigned char* line = (unsigned char*)malloc(linelen);
1356         unsigned char* bestline = (unsigned char*)malloc(linelen);
1357         memset(line, 0, linelen);
1358         for(y=0;y<height;y++)
1359         {
1360             int filtermode;
1361             int bestsize = 0x7fffffff;
1362             for(filtermode=0;filtermode<=0;filtermode++) {
1363                 if(!y && filtermode>=2)
1364                     continue; // don't do y direction filters in the first row
1365                 
1366                 line[0]=filtermode; //filter type
1367                 if(bpp==8)
1368                     filter_line8(filtermode, line+1, &data[y*srcwidth], width);
1369                 else
1370                     filter_line32(filtermode, line+1, &data[y*srcwidth], width);
1371
1372                 int size = test_line(&zs, line, linelen);
1373                 if(size < bestsize) {
1374                     memcpy(bestline, line, linelen);
1375                     bestsize = size;
1376                 }
1377             }
1378             idatsize += compress_line(&zs, bestline, linelen, fi);
1379         }
1380         free(line);free(bestline);
1381     }
1382     idatsize += finishzlib(&zs, fi);
1383     png_patch_len(fi, idatpos, idatsize);
1384     png_end_chunk(fi);
1385
1386     png_start_chunk(fi, "IEND", 0);
1387     png_end_chunk(fi);
1388
1389     free(writebuf);
1390     free(data2);
1391     fclose(fi);
1392 }
1393
1394 EXPORT void writePNG(const char*filename, unsigned char*data, int width, int height)
1395 {
1396     savePNG(filename, data, width, height, 0);
1397 }
1398 EXPORT void writePalettePNG(const char*filename, unsigned char*data, int width, int height)
1399 {
1400     savePNG(filename, data, width, height, 256);
1401 }