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 */
31 #ifdef PNG_INLINE_EXPORTS
41 unsigned char a,r,g,b;
44 static int png_read_chunk(char (*head)[4], int*destlen, unsigned char**destdata, FILE*fi)
47 unsigned char blen[4];
48 if(destlen) *destlen=0;
49 if(destdata) *destdata=0;
50 if(!fread(&blen, 4, 1, fi)) {
53 if(!fread(head, 4, 1, fi)) {
56 len = blen[0]<<24|blen[1]<<16|blen[2]<<8|blen[3];
57 if(destlen) *destlen = len;
62 *destdata = (unsigned char*)malloc(len);
63 if(!fread(*destdata, len, 1, fi)) {
65 if(destlen) *destlen=0;
69 fseek(fi, 4, SEEK_CUR);
72 fseek(fi, len+4, SEEK_CUR);
77 static unsigned int png_get_dword(FILE*fi)
82 return b[0]<<24|b[1]<<16|b[2]<<8|b[3];
93 static int png_read_header(FILE*fi, struct png_header*header)
98 unsigned char head[8] = {137,80,78,71,13,10,26,10};
99 unsigned char head2[8];
102 if(strncmp((const char*)head,(const char*)head2,4))
103 return 0; // not a png file
105 while(png_read_chunk(&id, &len, &data, fi))
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)) {
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)
116 c = data[10]; // compression mode (0)
117 f = data[11]; // filter mode (0)
118 i = data[12]; // interlace mode (0)
120 if(b!=0 && b!=4 && b!=2 && b!=3 && b!=6) {
121 fprintf(stderr, "Image mode %d not supported!\n", b);
124 if(a!=8 && (b==2 || b==6)) {
125 printf("Bpp %d in mode %d not supported!\n", a);
129 printf("Compression mode %d not supported!\n", c);
133 printf("Filter mode %d not supported!\n", f);
137 printf("Interlace mode %d not supported!\n", i);
140 //printf("%dx%d bpp:%d mode:%d comp:%d filter:%d interlace:%d\n",header->width, header->height, a,b,c,f,i);
151 typedef unsigned char byte;
152 #define ABS(a) ((a)>0?(a):(-(a)))
153 static inline byte PaethPredictor (byte a,byte b,byte c)
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
160 // return nearest of a,b,c,
161 // breaking ties in order a,b,c.
162 if (pa <= pb && pa <= pc)
169 static void applyfilter1(int mode, unsigned char*src, unsigned char*old, unsigned char*dest, int width)
172 unsigned char last=0;
173 unsigned char upperlast=0;
176 for(x=0;x<width;x++) {
183 for(x=0;x<width;x++) {
191 for(x=0;x<width;x++) {
199 for(x=0;x<width;x++) {
200 *dest = *src+(*old+last)/2;
208 for(x=0;x<width;x++) {
209 *dest = *src+PaethPredictor(last,*old,upperlast);
220 static void applyfilter2(int mode, unsigned char*src, unsigned char*old, unsigned char*dest, int width)
223 unsigned char lasta=0;
224 unsigned char lastb=0;
225 unsigned char upperlasta=0;
226 unsigned char upperlastb=0;
229 for(x=0;x<width;x++) {
237 for(x=0;x<width;x++) {
238 dest[0] = src[0]+lasta;
239 dest[1] = src[1]+lastb;
247 for(x=0;x<width;x++) {
248 dest[0] = src[0]+old[0];
249 dest[1] = src[1]+old[1];
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;
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);
282 /* also performs 24 bit conversion! */
283 static void applyfilter3(int mode, unsigned char*src, unsigned char*old, unsigned char*dest, int width)
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;
294 for(x=0;x<width;x++) {
304 for(x=0;x<width;x++) {
306 dest[1] = src[0]+lastr;
307 dest[2] = src[1]+lastg;
308 dest[3] = src[2]+lastb;
317 for(x=0;x<width;x++) {
319 dest[1] = src[0]+old[1];
320 dest[2] = src[1]+old[2];
321 dest[3] = src[2]+old[3];
328 for(x=0;x<width;x++) {
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;
342 for(x=0;x<width;x++) {
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);
360 static void inline applyfilter4(int mode, unsigned char*src, unsigned char*old, unsigned char*dest, int width)
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;
373 for(x=0;x<width;x++) {
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;
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];
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;
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);
444 EXPORT int getPNGdimensions(const char*sname, int*destwidth, int*destheight)
447 struct png_header header;
448 if ((fi = fopen(sname, "rb")) == NULL) {
449 fprintf(stderr, "Couldn't open %s\n", sname);
452 if(!png_read_header(fi, &header)) {
456 *destwidth = header.width;
457 *destheight = header.height;
461 EXPORT int getPNG(const char*sname, int*destwidth, int*destheight, unsigned char**destdata)
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;
472 unsigned char*alphapalette = 0;
473 int alphapalettelen = 0;
474 struct png_header header;
476 unsigned char*data2 = 0;
477 unsigned char alphacolor[3];
481 unsigned char *scanline;
483 if ((fi = fopen(sname, "rb")) == NULL) {
484 printf("Couldn't open %s\n", sname);
488 if(!png_read_header(fi, &header)) {
492 if(header.mode == 3 || header.mode == 0) bypp = 1;
493 else if(header.mode == 4) bypp = 2;
494 else if(header.mode == 2) bypp = 3;
495 else if(header.mode == 6) bypp = 4;
497 printf("ERROR: mode:%d\n", header.mode);
501 imagedatalen = bypp * header.width * header.height + 65536;
502 imagedata = (unsigned char*)malloc(imagedatalen);
504 fseek(fi,8,SEEK_SET);
507 if(!png_read_chunk(&tagid, &len, &data, fi))
509 if(!strncmp(tagid, "IEND", 4)) {
512 if(!strncmp(tagid, "PLTE", 4)) {
515 data = 0; //don't free data
516 //printf("%d colors in palette\n", palettelen);
518 if(!strncmp(tagid, "tRNS", 4)) {
519 if(header.mode == 3) {
521 alphapalettelen = len;
522 data = 0; //don't free data
523 //printf("found %d alpha colors\n", alphapalettelen);
524 } else if(header.mode == 0 || header.mode == 2) {
526 if(header.mode == 2) {
527 alphacolor[0] = data[1];
528 alphacolor[1] = data[3];
529 alphacolor[2] = data[5];
531 alphacolor[0] = alphacolor[1] = alphacolor[2] = data[1];
536 if(!strncmp(tagid, "IDAT", 4)) {
539 zimagedata = (unsigned char*)malloc(len);
540 memcpy(zimagedata,data,len);
542 zimagedata = (unsigned char*)realloc(zimagedata, zimagedatalen+len);
543 memcpy(&zimagedata[zimagedatalen], data, len);
544 zimagedatalen += len;
547 if(!strncmp(tagid, "tEXt", 4)) {
549 printf("Image Text: ");
551 if(data[t]>=32 && data[t]<128)
552 printf("%c", data[t]);
563 if(!zimagedata || uncompress(imagedata, &imagedatalen, zimagedata, zimagedatalen) != Z_OK) {
564 printf("Couldn't uncompress %s!\n", sname);
572 *destwidth = header.width;
573 *destheight = header.height;
575 data2 = (unsigned char*)malloc(header.width*header.height*4);
582 unsigned char* old= (unsigned char*)malloc(header.width*2);
583 memset(old, 0, header.width*2);
585 for(y=0;y<header.height;y++) {
586 int mode = imagedata[pos++]; //filter mode
590 dest = &data2[(y*header.width)*4];
592 if(header.bpp == 8) {
593 /* one byte per pixel */
594 src = &imagedata[pos];
597 /* not implemented yet */
598 fprintf(stderr, "ERROR: mode=4 bpp:%d\n", header.bpp);
603 applyfilter2(mode, src, old, dest, header.width);
604 memcpy(old, dest, header.width*2);
606 for(x=header.width-1;x>=0;x--) {
607 unsigned char gray = dest[x*2+0];
608 unsigned char alpha = dest[x*2+1];
617 } else if(header.mode == 6 || header.mode == 2) {
623 unsigned char* firstline = malloc(header.width*4);
624 memset(firstline,0,header.width*4);
625 for(y=0;y<header.height;y++) {
626 int mode = imagedata[pos++]; //filter mode
630 dest = &data2[(y*header.width)*4];
634 /* one byte per pixel */
635 src = &imagedata[pos];
636 pos+=header.width*(header.mode==6?4:3);
638 /* not implemented yet */
639 fprintf(stderr, "ERROR: bpp:%d\n", header.bpp);
647 old = &data2[(y-1)*header.width*4];
649 if(header.mode == 6) {
650 applyfilter4(mode, src, old, dest, header.width);
651 } else { // header.mode = 2
652 applyfilter3(mode, src, old, dest, header.width);
653 /* replace alpha color */
656 for(x=0;x<header.width;x++) {
657 if(dest[x*4+1] == alphacolor[0] &&
658 dest[x*4+2] == alphacolor[1] &&
659 dest[x*4+3] == alphacolor[2]) {
660 *(u32*)&dest[x*4] = 0;
668 } else if(header.mode == 0 || header.mode == 3) {
670 unsigned char*tmpline = (unsigned char*)malloc(header.width+1);
671 unsigned char*destline = (unsigned char*)malloc(header.width+1);
677 if(header.mode == 0) { // grayscale palette
678 int mult = (0x1ff>>header.bpp);
679 palettelen = 1<<header.bpp;
680 rgba = (COL*)malloc(palettelen*sizeof(COL));
681 for(i=0;i<palettelen;i++) {
687 if(rgba[i].r == alphacolor[0])
693 fprintf(stderr, "Error: No palette found!\n");
696 rgba = (COL*)malloc(palettelen*4);
697 /* 24->32 bit conversion */
698 for(i=0;i<palettelen;i++) {
699 rgba[i].r = palette[i*3+0];
700 rgba[i].g = palette[i*3+1];
701 rgba[i].b = palette[i*3+2];
702 if(alphapalette && i<alphapalettelen) {
703 rgba[i].a = alphapalette[i];
704 /*rgba[i].r = ((int)rgba[i].r*rgba[i].a)/255;
705 rgba[i].g = ((int)rgba[i].g*rgba[i].a)/255;
706 rgba[i].b = ((int)rgba[i].b*rgba[i].a)/255;*/
711 if(rgba[i].r == alphacolor[0] &&
712 rgba[i].g == alphacolor[1] &&
713 rgba[i].b == alphacolor[2])
719 for(y=0;y<header.height;y++) {
720 int mode = imagedata[pos++]; //filter mode
724 src = &imagedata[pos];
725 if(header.bpp == 8) {
730 u32 v = (1<<header.bpp)-1;
731 for(x=0;x<header.width;x++) {
732 u32 r = src[s/8]<<8 |
735 tmpline[x] = (r>>(16-header.bpp-(s&7)))&v;
739 pos+=(header.width*header.bpp+7)/8;
743 memset(destline,0,header.width);
744 old = &destline[y*header.width];
748 applyfilter1(mode, src, old, destline, header.width);
749 memcpy(tmpline,destline,header.width);
750 for(x=0;x<header.width;x++) {
751 *(COL*)&data2[y*header.width*4+x*4+0] = rgba[destline[x]];
759 printf("expected PNG mode to be 2, 3 or 6 (is:%d)\n", header.mode);
766 static char hasAlpha(unsigned char*_image, int size)
768 COL*image = (COL*)_image;
770 for(t=0;t<size;t++) {
782 int compare_colors(const void*_c1, const void*_c2) {
783 colornum_t*c1 = (colornum_t*)_c1;
784 colornum_t*c2 = (colornum_t*)_c2;
785 return c1->num - c2->num;
788 static colornum_t* getColors(COL*image, int size, int*num)
790 unsigned char*colexists = malloc((256*256*256)/8);
791 memset(colexists, 0, (256*256*256)/8);
795 /* find all different colors in the image */
796 for(t=0;t<size;t++) {
797 int index = (image[t].r)|(image[t].g)<<8|(image[t].b)<<16;
798 if(!(colexists[index/8]&(1<<(index&7)))) {
800 colexists[index/8]|=(1<<(index&7));
804 /* now store them in an array */
805 colornum_t*colors=(colornum_t*)malloc(sizeof(colornum_t)*count);
807 for(t=0;t<256*256*256;t++) {
808 if(colexists[t/8]&(1<<(t&7))) {
809 colors[pos].color = t;
815 /* next, count how often each color occurs */
816 for(t=0;t<size;t++) {
817 int col = (image[t].r)|(image[t].g)<<8|(image[t].b)<<16;
819 for(min=0, max=count, i=count/2, l=count; i != l; l=i,i=(min+max)/2) {
820 if(colors[i].color >= col) max=i;
823 assert(colors[i].color==col);
831 static COL* getOptimalPalette(COL*image, int size, int palettesize)
834 COL* ret = malloc(sizeof(COL)*palettesize);
835 memset(ret, 0, sizeof(COL)*palettesize);
836 colornum_t*colors = getColors(image, size, &num);
838 assert(palettesize<=256);
840 qsort(colors, num, sizeof(colornum_t), compare_colors);
842 if(num<=palettesize) {
843 /* if there are not more than palettesize different colors in
844 the image anyway, we are done */
847 ret[t].r = colors[t].color;
848 ret[t].g = colors[t].color>>8;
849 ret[t].b = colors[t].color>>16;
855 colornum_t*centers = malloc(sizeof(colornum_t)*palettesize);
857 for(t=0;t<palettesize;t++) {
858 centers[t].color = colors[t].color;
860 unsigned char*belongsto = (unsigned char*)malloc(num);
861 memset(belongsto, 0, num);
862 /* do a k-means clustering on the colors */
866 if(tries++ >= (palettesize+num)*2) {
867 fprintf(stderr, "Warning: didn't find optimal palette\n");
872 for(s=0;s<palettesize;s++) {
878 for(s=0;s<palettesize;s++) {
880 distance += abs((centers[s].color>>0&0xff) - (colors[t].color>>0&0xff));
881 distance += abs((centers[s].color>>8&0xff) - (colors[t].color>>8&0xff));
882 distance += abs((centers[s].color>>16&0xff) - (colors[t].color>>16&0xff));
883 distance *= colors[t].num;
889 if(bestpos!=belongsto[t])
891 belongsto[t] = bestpos;
893 for(s=0;s<palettesize;s++) {
899 if(belongsto[t]==s) {
900 r += ((colors[t].color>>0)&0xff)*colors[t].num;
901 g += ((colors[t].color>>8)&0xff)*colors[t].num;
902 b += ((colors[t].color>>16)&0xff)*colors[t].num;
903 count+=colors[t].num;
907 int random = lrand48()%num;
908 centers[s].color = colors[random].color;
915 centers[s].color = r|g<<8|b<<16;
916 centers[s].num = count;
922 for(t=0;t<palettesize;t++) {
923 ret[t].r = centers[t].color;
924 ret[t].g = centers[t].color>>8;
925 ret[t].b = centers[t].color>>16;
932 static int sqr(const int x) {return x*x;}
934 static void quantizeImage(unsigned char*_image, int size, int numcolors, unsigned char**newimage, COL**palette)
936 COL*image = (COL*)_image;
937 COL*pal= getOptimalPalette(image, size, numcolors);
939 *newimage = (unsigned char*)malloc(size);
941 for(t=0;t<size;t++) {
945 for(s=0;s<numcolors;s++) {
947 distance += sqr((pal[s].r) - (image[t].r))*5;
948 distance += sqr((pal[s].g) - (image[t].g))*6;
949 distance += sqr((pal[s].b) - (image[t].b))*4;
955 //image[t] = pal[bestcol];
956 (*newimage)[t] = bestcol;
962 static u32*crc32_table = 0;
963 static void make_crc32_table(void)
968 crc32_table = (u32*)malloc(1024);
970 for (t = 0; t < 256; t++) {
973 for (s = 0; s < 8; s++) {
974 c = (0xedb88320L*(c&1)) ^ (c >> 1);
979 static inline void png_write_byte(FILE*fi, unsigned char byte)
981 fwrite(&byte,1,1,fi);
982 mycrc32 = crc32_table[(mycrc32 ^ byte) & 0xff] ^ (mycrc32 >> 8);
984 static long png_start_chunk(FILE*fi, char*type, int len)
986 unsigned char mytype[4]={0,0,0,0};
987 unsigned char mylen[4];
993 memcpy(mytype,type,strlen(type));
995 fwrite(&mylen, 4, 1, fi);
997 png_write_byte(fi,mytype[0]);
998 png_write_byte(fi,mytype[1]);
999 png_write_byte(fi,mytype[2]);
1000 png_write_byte(fi,mytype[3]);
1003 static void png_patch_len(FILE*fi, int pos, int len)
1005 unsigned char mylen[4];
1011 fseek(fi, pos, SEEK_SET);
1012 fwrite(&mylen, 4, 1, fi);
1013 fseek(fi, 0, SEEK_END);
1015 static void png_write_bytes(FILE*fi, unsigned char*bytes, int len)
1019 png_write_byte(fi,bytes[t]);
1021 static void png_write_dword(FILE*fi, u32 dword)
1023 png_write_byte(fi,dword>>24);
1024 png_write_byte(fi,dword>>16);
1025 png_write_byte(fi,dword>>8);
1026 png_write_byte(fi,dword);
1028 static void png_end_chunk(FILE*fi)
1030 u32 tmp = mycrc32^0xffffffff;
1031 unsigned char tmp2[4];
1036 fwrite(&tmp2,4,1,fi);
1039 #define ZLIB_BUFFER_SIZE 16384
1041 static long compress_line(z_stream*zs, Bytef*line, int len, FILE*fi)
1048 int ret = deflate(zs, Z_NO_FLUSH);
1050 fprintf(stderr, "error in deflate(): %s", zs->msg?zs->msg:"unknown");
1053 if(zs->avail_out != ZLIB_BUFFER_SIZE) {
1054 int consumed = ZLIB_BUFFER_SIZE - zs->avail_out;
1056 png_write_bytes(fi, zs->next_out - consumed , consumed);
1057 zs->next_out = zs->next_out - consumed;
1058 zs->avail_out = ZLIB_BUFFER_SIZE;
1067 static int test_line(z_stream*zs_orig, Bytef*line, int linelen)
1070 int ret = deflateCopy(&zs, zs_orig);
1072 fprintf(stderr, "Couldn't copy stream\n");
1077 zs.avail_in = linelen;
1081 int mode = Z_SYNC_FLUSH;
1083 int ret = deflate(&zs, mode);
1084 if (ret != Z_OK && ret != Z_STREAM_END) {
1085 fprintf(stderr, "error in deflate(): %s (mode %s, %d bytes remaining)\n", zs.msg?zs.msg:"unknown",
1086 mode==Z_SYNC_FLUSH?"Z_SYNC_FLUSH":"Z_FINISH", zs.avail_in);
1089 if(zs.avail_out != ZLIB_BUFFER_SIZE) {
1090 int consumed = ZLIB_BUFFER_SIZE - zs.avail_out;
1092 zs.next_out = zs.next_out - consumed;
1093 zs.avail_out = ZLIB_BUFFER_SIZE;
1095 if (ret == Z_STREAM_END) {
1102 ret = deflateEnd(&zs);
1104 fprintf(stderr, "error in deflateEnd(): %s\n", zs.msg?zs.msg:"unknown");
1110 static int finishzlib(z_stream*zs, FILE*fi)
1115 ret = deflate(zs, Z_FINISH);
1117 ret != Z_STREAM_END) {
1118 fprintf(stderr, "error in deflate(finish): %s\n", zs->msg?zs->msg:"unknown");
1122 if(zs->avail_out != ZLIB_BUFFER_SIZE) {
1123 int consumed = ZLIB_BUFFER_SIZE - zs->avail_out;
1125 png_write_bytes(fi, zs->next_out - consumed , consumed);
1126 zs->next_out = zs->next_out - consumed;
1127 zs->avail_out = ZLIB_BUFFER_SIZE;
1129 if (ret == Z_STREAM_END) {
1133 ret = deflateEnd(zs);
1135 fprintf(stderr, "error in deflateEnd(): %s\n", zs->msg?zs->msg:"unknown");
1141 static void filter_line8(int filtermode, unsigned char*dest, unsigned char*src, int width)
1145 int srcwidth = width;
1147 if(filtermode == 0) {
1148 for(x=0;x<width;x++) {
1149 dest[pos2++]=src[pos++]; //alpha
1151 } else if(filtermode == 1) {
1152 /* x difference filter */
1153 dest[pos2++]=src[pos++];
1154 for(x=1;x<width;x++) {
1155 dest[pos2++]=src[pos] - src[pos-1];
1158 } else if(filtermode == 2) {
1159 /* y difference filter */
1160 for(x=0;x<width;x++) {
1161 dest[pos2++]=src[pos+0] - src[pos-srcwidth+0]; //alpha
1164 } else if(filtermode == 3) {
1165 dest[pos2++]=src[pos+0] - src[pos-srcwidth+0]/2;
1167 /* x+y difference filter */
1168 for(x=1;x<width;x++) {
1169 dest[pos2++]=src[pos+0] - (src[pos-1+0] + src[pos-srcwidth+0])/2; //alpha
1172 } else if(filtermode == 4) {
1173 dest[pos2++]=src[pos+0] - PaethPredictor(0, src[pos-srcwidth+0], 0);
1175 /* paeth difference filter */
1176 for(x=1;x<width;x++) {
1177 dest[pos2++]=src[pos+0] - PaethPredictor(src[pos-1+0], src[pos-srcwidth+0], src[pos-1-srcwidth+0]);
1183 static void filter_line32(int filtermode, unsigned char*dest, unsigned char*src, int width)
1187 int srcwidth = width*4;
1189 if(filtermode == 0) {
1190 for(x=0;x<width;x++) {
1191 dest[pos2++]=src[pos+1];
1192 dest[pos2++]=src[pos+2];
1193 dest[pos2++]=src[pos+3];
1194 dest[pos2++]=src[pos+0]; //alpha
1197 } else if(filtermode == 1) {
1198 /* x difference filter */
1199 dest[pos2++]=src[pos+1];
1200 dest[pos2++]=src[pos+2];
1201 dest[pos2++]=src[pos+3];
1202 dest[pos2++]=src[pos+0];
1204 for(x=1;x<width;x++) {
1205 dest[pos2++]=src[pos+1] - src[pos-4+1];
1206 dest[pos2++]=src[pos+2] - src[pos-4+2];
1207 dest[pos2++]=src[pos+3] - src[pos-4+3];
1208 dest[pos2++]=src[pos+0] - src[pos-4+0]; //alpha
1211 } else if(filtermode == 2) {
1212 /* y difference filter */
1213 for(x=0;x<width;x++) {
1214 dest[pos2++]=src[pos+1] - src[pos-srcwidth+1];
1215 dest[pos2++]=src[pos+2] - src[pos-srcwidth+2];
1216 dest[pos2++]=src[pos+3] - src[pos-srcwidth+3];
1217 dest[pos2++]=src[pos+0] - src[pos-srcwidth+0]; //alpha
1220 } else if(filtermode == 3) {
1221 dest[pos2++]=src[pos+1] - src[pos-srcwidth+1]/2;
1222 dest[pos2++]=src[pos+2] - src[pos-srcwidth+2]/2;
1223 dest[pos2++]=src[pos+3] - src[pos-srcwidth+3]/2;
1224 dest[pos2++]=src[pos+0] - src[pos-srcwidth+0]/2;
1226 /* x+y difference filter */
1227 for(x=1;x<width;x++) {
1228 dest[pos2++]=src[pos+1] - (src[pos-4+1] + src[pos-srcwidth+1])/2;
1229 dest[pos2++]=src[pos+2] - (src[pos-4+2] + src[pos-srcwidth+2])/2;
1230 dest[pos2++]=src[pos+3] - (src[pos-4+3] + src[pos-srcwidth+3])/2;
1231 dest[pos2++]=src[pos+0] - (src[pos-4+0] + src[pos-srcwidth+0])/2; //alpha
1234 } else if(filtermode == 4) {
1235 dest[pos2++]=src[pos+1] - PaethPredictor(0, src[pos-srcwidth+1], 0);
1236 dest[pos2++]=src[pos+2] - PaethPredictor(0, src[pos-srcwidth+2], 0);
1237 dest[pos2++]=src[pos+3] - PaethPredictor(0, src[pos-srcwidth+3], 0);
1238 dest[pos2++]=src[pos+0] - PaethPredictor(0, src[pos-srcwidth+0], 0);
1240 /* paeth difference filter */
1241 for(x=1;x<width;x++) {
1242 dest[pos2++]=src[pos+1] - PaethPredictor(src[pos-4+1], src[pos-srcwidth+1], src[pos-4-srcwidth+1]);
1243 dest[pos2++]=src[pos+2] - PaethPredictor(src[pos-4+2], src[pos-srcwidth+2], src[pos-4-srcwidth+2]);
1244 dest[pos2++]=src[pos+3] - PaethPredictor(src[pos-4+3], src[pos-srcwidth+3], src[pos-4-srcwidth+3]);
1245 dest[pos2++]=src[pos+0] - PaethPredictor(src[pos-4+0], src[pos-srcwidth+0], src[pos-4-srcwidth+0]);
1251 EXPORT void savePNG(const char*filename, unsigned char*data, int width, int height, int numcolors)
1256 unsigned char format;
1258 unsigned char* data2=0;
1261 unsigned char head[] = {137,80,78,71,13,10,26,10}; // PNG header
1282 quantizeImage(data, width*height, numcolors, &data, &palette);
1285 datalen = (width*height*bpp/8+cols*8);
1287 fi = fopen(filename, "wb");
1292 fwrite(head,sizeof(head),1,fi);
1294 png_start_chunk(fi, "IHDR", 13);
1295 png_write_dword(fi,width);
1296 png_write_dword(fi,height);
1297 png_write_byte(fi,8);
1299 png_write_byte(fi,3); //indexed
1300 else if(format == 5 && alpha==0)
1301 png_write_byte(fi,2); //rgb
1302 else if(format == 5 && alpha==1)
1303 png_write_byte(fi,6); //rgba
1306 png_write_byte(fi,0); //compression mode
1307 png_write_byte(fi,0); //filter mode
1308 png_write_byte(fi,0); //interlace mode
1312 png_start_chunk(fi, "PLTE", 768);
1313 for(t=0;t<cols;t++) {
1314 png_write_byte(fi,palette[t].r);
1315 png_write_byte(fi,palette[t].g);
1316 png_write_byte(fi,palette[t].b);
1320 long idatpos = png_start_chunk(fi, "IDAT", 0);
1322 memset(&zs,0,sizeof(z_stream));
1323 Bytef*writebuf = (Bytef*)malloc(ZLIB_BUFFER_SIZE);
1327 zs.next_out = writebuf;
1328 zs.avail_out = ZLIB_BUFFER_SIZE;
1329 ret = deflateInit(&zs, 9);
1331 fprintf(stderr, "error in deflateInit(): %s", zs.msg?zs.msg:"unknown");
1338 int srcwidth = width * (bpp/8);
1339 int linelen = 1 + ((srcwidth+3)&~3);
1340 unsigned char* line = (unsigned char*)malloc(linelen);
1341 unsigned char* bestline = (unsigned char*)malloc(linelen);
1342 memset(line, 0, linelen);
1343 for(y=0;y<height;y++)
1346 int bestsize = 0x7fffffff;
1347 for(filtermode=0;filtermode<=5;filtermode++) {
1349 if(!y && filtermode>=2)
1350 continue; // don't do y direction filters in the first row
1352 line[0]=filtermode; //filter type
1354 filter_line8(filtermode, line+1, &data[y*srcwidth], width);
1356 filter_line32(filtermode, line+1, &data[y*srcwidth], width);
1358 int size = test_line(&zs, line, linelen);
1359 if(size < bestsize) {
1360 memcpy(bestline, line, linelen);
1364 idatsize += compress_line(&zs, bestline, linelen, fi);
1366 free(line);free(bestline);
1368 idatsize += finishzlib(&zs, fi);
1369 png_patch_len(fi, idatpos, idatsize);
1372 png_start_chunk(fi, "IEND", 0);
1380 void writePNG(const char*filename, unsigned char*data, int width, int height)
1382 savePNG(filename, data, width, height, 0);
1384 void writePalettePNG(const char*filename, unsigned char*data, int width, int height)
1386 savePNG(filename, data, width, height, 256);