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 */
27 typedef unsigned char U8;
28 typedef unsigned long U32;
33 #define REVERSESWAP16(s) ((((s)>>8)&0x00ff)|(((s)<<8)&0xff00))
34 #define REVERSESWAP32(s) (REVERSESWAP16(((s)>>16)&0x0000ffff)|((REVERSESWAP16(s)<<16)&0xffff0000))
36 int png_read_chunk(char (*head)[4], int*destlen, U8**destdata, FILE*fi)
39 if(destlen) *destlen=0;
40 if(destdata) *destdata=0;
41 if(!fread(&len, 4, 1, fi)) {
44 if(!fread(head, 4, 1, fi)) {
47 len = REVERSESWAP32(len);
48 if(destlen) *destlen = len;
53 *destdata = (U8*)malloc(len);
54 if(!fread(*destdata, len, 1, fi)) {
56 if(destlen) *destlen=0;
60 fseek(fi, 4, SEEK_CUR);
63 fseek(fi, len+4, SEEK_CUR);
68 unsigned int png_get_dword(FILE*fi)
72 return REVERSESWAP32(a);
83 int png_read_header(FILE*fi, struct png_header*header)
88 U8 head[8] = {137,80,78,71,13,10,26,10};
92 if(strncmp((const char*)head,(const char*)head2,4))
95 while(png_read_chunk(&id, &len, &data, fi))
97 //printf("Chunk: %c%c%c%c (len:%d)\n", id[0],id[1],id[2],id[3], len);
98 if(!strncasecmp(id, "IHDR", 4)) {
101 header->width = REVERSESWAP32(*(U32*)&data[0]);
102 header->height = REVERSESWAP32(*(U32*)&data[4]);
103 a = data[8]; // should be 8
104 b = data[9]; // should be 3(indexed) or 2(rgb)
106 c = data[10]; // compression mode (0)
107 f = data[11]; // filter mode (0)
108 i = data[12]; // interlace mode (0)
110 if(b!=0 && b!=2 && b!=3 && b!=6) {
111 fprintf(stderr, "Image mode %d not supported!\n", b);
113 fprintf(stderr, "(This is a grayscale image with alpha channel-\n");
114 fprintf(stderr, " try converting it into an RGB image with alpha channel)\n");
118 if(a!=8 && (b==2 || b==6)) {
119 printf("Bpp %d in mode %d not supported!\n", a);
123 printf("Compression mode %d not supported!\n", c);
127 printf("Filter mode %d not supported!\n", f);
131 printf("Interlace mode %d not supported!\n", i);
134 //printf("%dx%d bpp:%d mode:%d comp:%d filter:%d interlace:%d\n",header->width, header->height, a,b,c,f,i);
145 typedef unsigned char byte;
146 #define ABS(a) ((a)>0?(a):(-(a)))
147 byte inline PaethPredictor (byte a,byte b,byte c)
149 // a = left, b = above, c = upper left
150 int p = a + b - c; // initial estimate
151 int pa = ABS(p - a); // distances to a, b, c
154 // return nearest of a,b,c,
155 // breaking ties in order a,b,c.
156 if (pa <= pb && pa <= pc)
163 void applyfilter1(int mode, U8*src, U8*old, U8*dest, int width)
166 unsigned char last=0;
167 unsigned char upperlast=0;
170 for(x=0;x<width;x++) {
177 for(x=0;x<width;x++) {
185 for(x=0;x<width;x++) {
193 for(x=0;x<width;x++) {
194 *dest = *src+(*old+last)/2;
201 for(x=0;x<width;x++) {
202 *dest = *src+PaethPredictor(last,*old,upperlast);
213 void applyfilter2(int mode, U8*src, U8*old, U8*dest, int width)
216 unsigned char lasta=0;
217 unsigned char lastb=0;
218 unsigned char upperlasta=0;
219 unsigned char upperlastb=0;
222 for(x=0;x<width;x++) {
230 for(x=0;x<width;x++) {
231 dest[0] = src[0]+lasta;
232 dest[1] = src[1]+lastb;
240 for(x=0;x<width;x++) {
241 dest[0] = src[0]+old[0];
242 dest[1] = src[1]+old[1];
249 for(x=0;x<width;x++) {
250 dest[0] = src[0]+(old[0]+lasta)/2;
251 dest[1] = src[1]+(old[1]+lastb)/2;
260 for(x=0;x<width;x++) {
261 dest[0] = src[0]+PaethPredictor(lasta,old[0],upperlasta);
262 dest[1] = src[1]+PaethPredictor(lastb,old[1],upperlastb);
275 /* also performs 24 bit conversion! */
276 void applyfilter3(int mode, U8*src, U8*old, U8*dest, int width)
279 unsigned char lastr=0;
280 unsigned char lastg=0;
281 unsigned char lastb=0;
282 unsigned char upperlastr=0;
283 unsigned char upperlastg=0;
284 unsigned char upperlastb=0;
287 for(x=0;x<width;x++) {
297 for(x=0;x<width;x++) {
299 dest[1] = src[0]+lastr;
300 dest[2] = src[1]+lastg;
301 dest[3] = src[2]+lastb;
310 for(x=0;x<width;x++) {
312 dest[1] = src[0]+old[1];
313 dest[2] = src[1]+old[2];
314 dest[3] = src[2]+old[3];
321 for(x=0;x<width;x++) {
323 dest[1] = src[0]+(old[1]+lastr)/2;
324 dest[2] = src[1]+(old[2]+lastg)/2;
325 dest[3] = src[2]+(old[3]+lastb)/2;
335 for(x=0;x<width;x++) {
337 dest[1] = src[0]+PaethPredictor(lastr,old[1],upperlastr);
338 dest[2] = src[1]+PaethPredictor(lastg,old[2],upperlastg);
339 dest[3] = src[2]+PaethPredictor(lastb,old[3],upperlastb);
353 void inline applyfilter4(int mode, U8*src, U8*old, U8*dest, int width)
356 unsigned char lastr=0;
357 unsigned char lastg=0;
358 unsigned char lastb=0;
359 unsigned char lasta=0;
360 unsigned char upperlastr=0;
361 unsigned char upperlastg=0;
362 unsigned char upperlastb=0;
363 unsigned char upperlasta=0;
366 for(x=0;x<width;x++) {
376 for(x=0;x<width;x++) {
377 dest[0] = src[3]+lasta;
378 dest[1] = src[0]+lastr;
379 dest[2] = src[1]+lastg;
380 dest[3] = src[2]+lastb;
390 for(x=0;x<width;x++) {
391 dest[0] = src[3]+old[0];
392 dest[1] = src[0]+old[1];
393 dest[2] = src[1]+old[2];
394 dest[3] = src[2]+old[3];
401 for(x=0;x<width;x++) {
402 dest[0] = src[3]+(old[0]+lasta)/2;
403 dest[1] = src[0]+(old[1]+lastr)/2;
404 dest[2] = src[1]+(old[2]+lastg)/2;
405 dest[3] = src[2]+(old[3]+lastb)/2;
416 for(x=0;x<width;x++) {
417 dest[0] = src[3]+PaethPredictor(lasta,old[0],upperlasta);
418 dest[1] = src[0]+PaethPredictor(lastr,old[1],upperlastr);
419 dest[2] = src[1]+PaethPredictor(lastg,old[2],upperlastg);
420 dest[3] = src[2]+PaethPredictor(lastb,old[3],upperlastb);
437 int getPNGdimensions(char*sname, int*destwidth, int*destheight)
440 struct png_header header;
441 if ((fi = fopen(sname, "rb")) == NULL) {
442 fprintf(stderr, "Couldn't open %s\n", sname);
445 if(!png_read_header(fi, &header)) {
446 fprintf(stderr, "Error reading header from file %s\n", sname);
450 *destwidth = header.width;
451 *destheight = header.height;
455 int getPNG(char*sname, int*destwidth, int*destheight, unsigned char**destdata)
462 unsigned long int imagedatalen;
463 unsigned long int zimagedatalen=0;
467 int alphapalettelen = 0;
468 struct png_header header;
474 if ((fi = fopen(sname, "rb")) == NULL) {
475 printf("Couldn't open %s\n", sname);
479 if(!png_read_header(fi, &header)) {
480 printf("Error reading header from file %s\n", sname);
484 if(header.mode == 3 || header.mode == 0) bypp = 1;
486 if(header.mode == 2) bypp = 3;
488 if(header.mode == 6) bypp = 4;
490 printf("ERROR: mode:%d\n", header.mode);
494 imagedatalen = bypp * header.width * header.height + 65536;
495 imagedata = (U8*)malloc(imagedatalen);
497 fseek(fi,8,SEEK_SET);
500 if(!png_read_chunk(&tagid, &len, &data, fi))
502 if(!strncmp(tagid, "IEND", 4)) {
505 if(!strncmp(tagid, "PLTE", 4)) {
508 data = 0; //don't free data
509 //printf("%d colors in palette\n", palettelen);
511 if(!strncmp(tagid, "tRNS", 4)) {
512 if(header.mode == 3) {
514 alphapalettelen = len;
515 data = 0; //don't free data
516 //printf("found %d alpha colors\n", alphapalettelen);
519 if(!strncmp(tagid, "IDAT", 4)) {
522 zimagedata = (U8*)malloc(len);
523 memcpy(zimagedata,data,len);
525 zimagedata = (U8*)realloc(zimagedata, zimagedatalen+len);
526 memcpy(&zimagedata[zimagedatalen], data, len);
527 zimagedatalen += len;
530 if(!strncmp(tagid, "tEXt", 4)) {
532 printf("Image Text: ");
534 if(data[t]>=32 && data[t]<128)
535 printf("%c", data[t]);
545 if(!zimagedata || uncompress(imagedata, &imagedatalen, zimagedata, zimagedatalen) != Z_OK) {
546 printf("Couldn't uncompress %s!\n", sname);
554 *destwidth = header.width;
555 *destheight = header.height;
557 if(header.mode == 6 || header.mode == 2)
559 U8*data2 = (U8*)malloc(header.width*header.height*4);
564 for(y=0;y<header.height;y++) {
565 int mode = imagedata[pos++]; //filter mode
569 dest = &data2[(y*header.width)*4];
573 /* one byte per pixel */
574 src = &imagedata[pos];
575 pos+=header.width*(header.mode==6?4:3);
577 /* not implemented yet */
578 printf("ERROR: bpp:%d\n", header.bpp);
584 memset(data2,0,header.width*4);
585 old = &data2[y*header.width*4];
587 old = &data2[(y-1)*header.width*4];
590 applyfilter4(mode, src, old, dest, header.width);
591 else // header.mode = 2
592 applyfilter3(mode, src, old, dest, header.width);
594 } else if(header.mode == 0 || header.mode == 3) {
596 U8*data2 = (U8*)malloc(header.width*header.height*4);
597 U8*tmpline = (U8*)malloc(header.width+1);
598 U8*destline = (U8*)malloc(header.width+1);
604 if(header.mode == 0) { // grayscale palette
605 int mult = (0x1ff>>header.bpp);
606 palettelen = 1<<header.bpp;
607 rgba = (COL*)malloc(palettelen*sizeof(COL));
608 for(i=0;i<palettelen;i++) {
616 fprintf(stderr, "Error: No palette found!\n");
619 rgba = (COL*)malloc(palettelen*4);
620 /* 24->32 bit conversion */
621 for(i=0;i<palettelen;i++) {
622 rgba[i].r = palette[i*3+0];
623 rgba[i].g = palette[i*3+1];
624 rgba[i].b = palette[i*3+2];
625 if(alphapalette && i<alphapalettelen) {
626 rgba[i].a = alphapalette[i];
627 /*rgba[i].r = ((int)rgba[i].r*rgba[i].a)/255;
628 rgba[i].g = ((int)rgba[i].g*rgba[i].a)/255;
629 rgba[i].b = ((int)rgba[i].b*rgba[i].a)/255;*/
636 for(y=0;y<header.height;y++) {
637 int mode = imagedata[pos++]; //filter mode
641 src = &imagedata[pos];
642 if(header.bpp == 8) {
647 U32 v = (1<<header.bpp)-1;
648 for(x=0;x<header.width;x++) {
649 U32 r = src[s/8]<<8 |
652 tmpline[x] = (r>>(16-header.bpp-(s&7)))&v;
656 pos+=(header.width*header.bpp+7)/8;
660 memset(destline,0,header.width);
661 old = &destline[y*header.width];
665 applyfilter1(mode, src, old, destline, header.width);
666 memcpy(tmpline,destline,header.width);
667 for(x=0;x<header.width;x++) {
668 *(COL*)&data2[y*header.width*4+x*4+0] = rgba[destline[x]];
675 printf("expected PNG mode to be 2, 3 or 6 (is:%d)\n", header.mode);
684 static U32*crc32_table = 0;
685 static void make_crc32_table(void)
690 crc32_table = (U32*)malloc(1024);
692 for (t = 0; t < 256; t++) {
695 for (s = 0; s < 8; s++) {
696 c = (0xedb88320L*(c&1)) ^ (c >> 1);
701 static inline void png_write_byte(FILE*fi, U8 byte)
703 fwrite(&byte,1,1,fi);
704 mycrc32 = crc32_table[(mycrc32 ^ byte) & 0xff] ^ (mycrc32 >> 8);
706 static void png_start_chunk(FILE*fi, char*type, int len)
708 U8 mytype[4]={0,0,0,0};
709 U32 mylen = REVERSESWAP32(len);
710 memcpy(mytype,type,strlen(type));
711 fwrite(&mylen, 4, 1, fi);
713 png_write_byte(fi,mytype[0]);
714 png_write_byte(fi,mytype[1]);
715 png_write_byte(fi,mytype[2]);
716 png_write_byte(fi,mytype[3]);
718 static void png_write_bytes(FILE*fi, U8*bytes, int len)
722 png_write_byte(fi,bytes[t]);
724 static void png_write_dword(FILE*fi, U32 dword)
726 png_write_byte(fi,dword>>24);
727 png_write_byte(fi,dword>>16);
728 png_write_byte(fi,dword>>8);
729 png_write_byte(fi,dword);
731 static void png_end_chunk(FILE*fi)
733 U32 tmp = REVERSESWAP32((mycrc32^0xffffffff));
737 void writePNG(char*filename, unsigned char*data, int width, int height)
749 U8 head[] = {137,80,78,71,13,10,26,10}; // PNG header
764 datalen = (width*height*bpp/8+cols*8);
766 fi = fopen(filename, "wb");
771 fwrite(head,sizeof(head),1,fi);
773 png_start_chunk(fi, "IHDR", 13);
774 png_write_dword(fi,width);
775 png_write_dword(fi,height);
776 png_write_byte(fi,8);
778 png_write_byte(fi,3); //indexed
779 else if(format == 5 && alpha==0)
780 png_write_byte(fi,2); //rgb
781 else if(format == 5 && alpha==1)
782 png_write_byte(fi,6); //rgba
785 png_write_byte(fi,0); //compression mode
786 png_write_byte(fi,0); //filter mode
787 png_write_byte(fi,0); //interlace mode
791 png_start_chunk(fi, "PLTE", 768);
794 png_write_byte(fi,palette[t].r);
795 png_write_byte(fi,palette[t].g);
796 png_write_byte(fi,palette[t].b);
803 int srcwidth = width * (bpp/8);
804 datalen3 = (width*4+5)*height;
805 data3 = (U8*)malloc(datalen3);
806 for(y=0;y<height;y++)
808 data3[pos2++]=0; //filter type
809 for(x=0;x<width;x++) {
810 data3[pos2++]=data[pos+1];
811 data3[pos2++]=data[pos+2];
812 data3[pos2++]=data[pos+3];
813 data3[pos2++]=data[pos+0]; //alpha
816 pos+=((srcwidth+3)&~3)-srcwidth; //align
822 data2 = malloc(datalen2);
824 if((ret = compress (data2, &datalen2, data3, datalen3)) != Z_OK) {
825 fprintf(stderr, "zlib error in pic %d\n", ret);
828 png_start_chunk(fi, "IDAT", datalen2);
829 png_write_bytes(fi,data2,datalen2);
831 png_start_chunk(fi, "IEND", 0);