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 int png_read_chunk(char (*head)[4], int*destlen, U8**destdata, FILE*fi)
37 if(destlen) *destlen=0;
38 if(destdata) *destdata=0;
39 if(!fread(&blen, 4, 1, fi)) {
42 if(!fread(head, 4, 1, fi)) {
45 len = blen[0]<<24|blen[1]<<16|blen[2]<<8|blen[3];
46 if(destlen) *destlen = len;
51 *destdata = (U8*)malloc(len);
52 if(!fread(*destdata, len, 1, fi)) {
54 if(destlen) *destlen=0;
58 fseek(fi, 4, SEEK_CUR);
61 fseek(fi, len+4, SEEK_CUR);
66 unsigned int png_get_dword(FILE*fi)
71 return b[0]<<24|b[1]<<16|b[2]<<8|b[3];
82 int png_read_header(FILE*fi, struct png_header*header)
87 U8 head[8] = {137,80,78,71,13,10,26,10};
91 if(strncmp((const char*)head,(const char*)head2,4))
94 while(png_read_chunk(&id, &len, &data, fi))
96 //printf("Chunk: %c%c%c%c (len:%d)\n", id[0],id[1],id[2],id[3], len);
97 if(!strncasecmp(id, "IHDR", 4)) {
100 header->width = data[0]<<24|data[1]<<16|data[2]<<8|data[3];
101 header->height = data[4]<<24|data[5]<<16|data[6]<<8|data[7];
102 a = data[8]; // should be 8
103 b = data[9]; // should be 3(indexed) or 2(rgb)
105 c = data[10]; // compression mode (0)
106 f = data[11]; // filter mode (0)
107 i = data[12]; // interlace mode (0)
109 if(b!=0 && b!=4 && b!=2 && b!=3 && b!=6) {
110 fprintf(stderr, "Image mode %d not supported!\n", b);
113 if(a!=8 && (b==2 || b==6)) {
114 printf("Bpp %d in mode %d not supported!\n", a);
118 printf("Compression mode %d not supported!\n", c);
122 printf("Filter mode %d not supported!\n", f);
126 printf("Interlace mode %d not supported!\n", i);
129 //printf("%dx%d bpp:%d mode:%d comp:%d filter:%d interlace:%d\n",header->width, header->height, a,b,c,f,i);
140 typedef unsigned char byte;
141 #define ABS(a) ((a)>0?(a):(-(a)))
142 byte inline PaethPredictor (byte a,byte b,byte c)
144 // a = left, b = above, c = upper left
145 int p = a + b - c; // initial estimate
146 int pa = ABS(p - a); // distances to a, b, c
149 // return nearest of a,b,c,
150 // breaking ties in order a,b,c.
151 if (pa <= pb && pa <= pc)
158 void applyfilter1(int mode, U8*src, U8*old, U8*dest, int width)
161 unsigned char last=0;
162 unsigned char upperlast=0;
165 for(x=0;x<width;x++) {
172 for(x=0;x<width;x++) {
180 for(x=0;x<width;x++) {
188 for(x=0;x<width;x++) {
189 *dest = *src+(*old+last)/2;
196 for(x=0;x<width;x++) {
197 *dest = *src+PaethPredictor(last,*old,upperlast);
208 void applyfilter2(int mode, U8*src, U8*old, U8*dest, int width)
211 unsigned char lasta=0;
212 unsigned char lastb=0;
213 unsigned char upperlasta=0;
214 unsigned char upperlastb=0;
217 for(x=0;x<width;x++) {
225 for(x=0;x<width;x++) {
226 dest[0] = src[0]+lasta;
227 dest[1] = src[1]+lastb;
235 for(x=0;x<width;x++) {
236 dest[0] = src[0]+old[0];
237 dest[1] = src[1]+old[1];
244 for(x=0;x<width;x++) {
245 dest[0] = src[0]+(old[0]+lasta)/2;
246 dest[1] = src[1]+(old[1]+lastb)/2;
255 for(x=0;x<width;x++) {
256 dest[0] = src[0]+PaethPredictor(lasta,old[0],upperlasta);
257 dest[1] = src[1]+PaethPredictor(lastb,old[1],upperlastb);
270 /* also performs 24 bit conversion! */
271 void applyfilter3(int mode, U8*src, U8*old, U8*dest, int width)
274 unsigned char lastr=0;
275 unsigned char lastg=0;
276 unsigned char lastb=0;
277 unsigned char upperlastr=0;
278 unsigned char upperlastg=0;
279 unsigned char upperlastb=0;
282 for(x=0;x<width;x++) {
292 for(x=0;x<width;x++) {
294 dest[1] = src[0]+lastr;
295 dest[2] = src[1]+lastg;
296 dest[3] = src[2]+lastb;
305 for(x=0;x<width;x++) {
307 dest[1] = src[0]+old[1];
308 dest[2] = src[1]+old[2];
309 dest[3] = src[2]+old[3];
316 for(x=0;x<width;x++) {
318 dest[1] = src[0]+(old[1]+lastr)/2;
319 dest[2] = src[1]+(old[2]+lastg)/2;
320 dest[3] = src[2]+(old[3]+lastb)/2;
330 for(x=0;x<width;x++) {
332 dest[1] = src[0]+PaethPredictor(lastr,old[1],upperlastr);
333 dest[2] = src[1]+PaethPredictor(lastg,old[2],upperlastg);
334 dest[3] = src[2]+PaethPredictor(lastb,old[3],upperlastb);
348 void inline applyfilter4(int mode, U8*src, U8*old, U8*dest, int width)
351 unsigned char lastr=0;
352 unsigned char lastg=0;
353 unsigned char lastb=0;
354 unsigned char lasta=0;
355 unsigned char upperlastr=0;
356 unsigned char upperlastg=0;
357 unsigned char upperlastb=0;
358 unsigned char upperlasta=0;
361 for(x=0;x<width;x++) {
371 for(x=0;x<width;x++) {
372 dest[0] = src[3]+lasta;
373 dest[1] = src[0]+lastr;
374 dest[2] = src[1]+lastg;
375 dest[3] = src[2]+lastb;
385 for(x=0;x<width;x++) {
386 dest[0] = src[3]+old[0];
387 dest[1] = src[0]+old[1];
388 dest[2] = src[1]+old[2];
389 dest[3] = src[2]+old[3];
396 for(x=0;x<width;x++) {
397 dest[0] = src[3]+(old[0]+lasta)/2;
398 dest[1] = src[0]+(old[1]+lastr)/2;
399 dest[2] = src[1]+(old[2]+lastg)/2;
400 dest[3] = src[2]+(old[3]+lastb)/2;
411 for(x=0;x<width;x++) {
412 dest[0] = src[3]+PaethPredictor(lasta,old[0],upperlasta);
413 dest[1] = src[0]+PaethPredictor(lastr,old[1],upperlastr);
414 dest[2] = src[1]+PaethPredictor(lastg,old[2],upperlastg);
415 dest[3] = src[2]+PaethPredictor(lastb,old[3],upperlastb);
432 int getPNGdimensions(char*sname, int*destwidth, int*destheight)
435 struct png_header header;
436 if ((fi = fopen(sname, "rb")) == NULL) {
437 fprintf(stderr, "Couldn't open %s\n", sname);
440 if(!png_read_header(fi, &header)) {
441 fprintf(stderr, "Error reading header from file %s\n", sname);
445 *destwidth = header.width;
446 *destheight = header.height;
450 int getPNG(char*sname, int*destwidth, int*destheight, unsigned char**destdata)
457 unsigned long int imagedatalen;
458 unsigned long int zimagedatalen=0;
462 int alphapalettelen = 0;
463 struct png_header header;
470 if ((fi = fopen(sname, "rb")) == NULL) {
471 printf("Couldn't open %s\n", sname);
475 if(!png_read_header(fi, &header)) {
476 printf("Error reading header from file %s\n", sname);
480 if(header.mode == 3 || header.mode == 0) bypp = 1;
481 else if(header.mode == 4) bypp = 2;
482 else if(header.mode == 2) bypp = 3;
483 else if(header.mode == 6) bypp = 4;
485 printf("ERROR: mode:%d\n", header.mode);
489 imagedatalen = bypp * header.width * header.height + 65536;
490 imagedata = (U8*)malloc(imagedatalen);
492 fseek(fi,8,SEEK_SET);
495 if(!png_read_chunk(&tagid, &len, &data, fi))
497 if(!strncmp(tagid, "IEND", 4)) {
500 if(!strncmp(tagid, "PLTE", 4)) {
503 data = 0; //don't free data
504 //printf("%d colors in palette\n", palettelen);
506 if(!strncmp(tagid, "tRNS", 4)) {
507 if(header.mode == 3) {
509 alphapalettelen = len;
510 data = 0; //don't free data
511 //printf("found %d alpha colors\n", alphapalettelen);
514 if(!strncmp(tagid, "IDAT", 4)) {
517 zimagedata = (U8*)malloc(len);
518 memcpy(zimagedata,data,len);
520 zimagedata = (U8*)realloc(zimagedata, zimagedatalen+len);
521 memcpy(&zimagedata[zimagedatalen], data, len);
522 zimagedatalen += len;
525 if(!strncmp(tagid, "tEXt", 4)) {
527 printf("Image Text: ");
529 if(data[t]>=32 && data[t]<128)
530 printf("%c", data[t]);
540 if(!zimagedata || uncompress(imagedata, &imagedatalen, zimagedata, zimagedatalen) != Z_OK) {
541 printf("Couldn't uncompress %s!\n", sname);
549 *destwidth = header.width;
550 *destheight = header.height;
552 data2 = (U8*)malloc(header.width*header.height*4);
559 U8* old= (U8*)malloc(header.width*2);
560 memset(old, 0, header.width*2);
562 for(y=0;y<header.height;y++) {
563 int mode = imagedata[pos++]; //filter mode
567 dest = &data2[(y*header.width)*4];
569 if(header.bpp == 8) {
570 /* one byte per pixel */
571 src = &imagedata[pos];
574 /* not implemented yet */
575 fprintf(stderr, "ERROR: mode=4 bpp:%d\n", header.bpp);
580 applyfilter2(mode, src, old, dest, header.width);
581 memcpy(old, dest, header.width*2);
583 for(x=header.width-1;x>=0;x--) {
584 U8 gray = dest[x*2+0];
585 U8 alpha = dest[x*2+1];
593 } else if(header.mode == 6 || header.mode == 2) {
598 for(y=0;y<header.height;y++) {
599 int mode = imagedata[pos++]; //filter mode
603 dest = &data2[(y*header.width)*4];
607 /* one byte per pixel */
608 src = &imagedata[pos];
609 pos+=header.width*(header.mode==6?4:3);
611 /* not implemented yet */
612 fprintf(stderr, "ERROR: bpp:%d\n", header.bpp);
618 memset(data2,0,header.width*4);
619 old = &data2[y*header.width*4];
621 old = &data2[(y-1)*header.width*4];
624 applyfilter4(mode, src, old, dest, header.width);
625 else // header.mode = 2
626 applyfilter3(mode, src, old, dest, header.width);
628 } else if(header.mode == 0 || header.mode == 3) {
630 U8*tmpline = (U8*)malloc(header.width+1);
631 U8*destline = (U8*)malloc(header.width+1);
637 if(header.mode == 0) { // grayscale palette
638 int mult = (0x1ff>>header.bpp);
639 palettelen = 1<<header.bpp;
640 rgba = (COL*)malloc(palettelen*sizeof(COL));
641 for(i=0;i<palettelen;i++) {
649 fprintf(stderr, "Error: No palette found!\n");
652 rgba = (COL*)malloc(palettelen*4);
653 /* 24->32 bit conversion */
654 for(i=0;i<palettelen;i++) {
655 rgba[i].r = palette[i*3+0];
656 rgba[i].g = palette[i*3+1];
657 rgba[i].b = palette[i*3+2];
658 if(alphapalette && i<alphapalettelen) {
659 rgba[i].a = alphapalette[i];
660 /*rgba[i].r = ((int)rgba[i].r*rgba[i].a)/255;
661 rgba[i].g = ((int)rgba[i].g*rgba[i].a)/255;
662 rgba[i].b = ((int)rgba[i].b*rgba[i].a)/255;*/
669 for(y=0;y<header.height;y++) {
670 int mode = imagedata[pos++]; //filter mode
674 src = &imagedata[pos];
675 if(header.bpp == 8) {
680 U32 v = (1<<header.bpp)-1;
681 for(x=0;x<header.width;x++) {
682 U32 r = src[s/8]<<8 |
685 tmpline[x] = (r>>(16-header.bpp-(s&7)))&v;
689 pos+=(header.width*header.bpp+7)/8;
693 memset(destline,0,header.width);
694 old = &destline[y*header.width];
698 applyfilter1(mode, src, old, destline, header.width);
699 memcpy(tmpline,destline,header.width);
700 for(x=0;x<header.width;x++) {
701 *(COL*)&data2[y*header.width*4+x*4+0] = rgba[destline[x]];
708 printf("expected PNG mode to be 2, 3 or 6 (is:%d)\n", header.mode);
717 static U32*crc32_table = 0;
718 static void make_crc32_table(void)
723 crc32_table = (U32*)malloc(1024);
725 for (t = 0; t < 256; t++) {
728 for (s = 0; s < 8; s++) {
729 c = (0xedb88320L*(c&1)) ^ (c >> 1);
734 static inline void png_write_byte(FILE*fi, U8 byte)
736 fwrite(&byte,1,1,fi);
737 mycrc32 = crc32_table[(mycrc32 ^ byte) & 0xff] ^ (mycrc32 >> 8);
739 static void png_start_chunk(FILE*fi, char*type, int len)
741 U8 mytype[4]={0,0,0,0};
747 memcpy(mytype,type,strlen(type));
748 fwrite(&mylen, 4, 1, fi);
750 png_write_byte(fi,mytype[0]);
751 png_write_byte(fi,mytype[1]);
752 png_write_byte(fi,mytype[2]);
753 png_write_byte(fi,mytype[3]);
755 static void png_write_bytes(FILE*fi, U8*bytes, int len)
759 png_write_byte(fi,bytes[t]);
761 static void png_write_dword(FILE*fi, U32 dword)
763 png_write_byte(fi,dword>>24);
764 png_write_byte(fi,dword>>16);
765 png_write_byte(fi,dword>>8);
766 png_write_byte(fi,dword);
768 static void png_end_chunk(FILE*fi)
770 U32 tmp = mycrc32^0xffffffff;
776 fwrite(&tmp2,4,1,fi);
779 void writePNG(char*filename, unsigned char*data, int width, int height)
791 U8 head[] = {137,80,78,71,13,10,26,10}; // PNG header
806 datalen = (width*height*bpp/8+cols*8);
808 fi = fopen(filename, "wb");
813 fwrite(head,sizeof(head),1,fi);
815 png_start_chunk(fi, "IHDR", 13);
816 png_write_dword(fi,width);
817 png_write_dword(fi,height);
818 png_write_byte(fi,8);
820 png_write_byte(fi,3); //indexed
821 else if(format == 5 && alpha==0)
822 png_write_byte(fi,2); //rgb
823 else if(format == 5 && alpha==1)
824 png_write_byte(fi,6); //rgba
827 png_write_byte(fi,0); //compression mode
828 png_write_byte(fi,0); //filter mode
829 png_write_byte(fi,0); //interlace mode
833 png_start_chunk(fi, "PLTE", 768);
836 png_write_byte(fi,palette[t].r);
837 png_write_byte(fi,palette[t].g);
838 png_write_byte(fi,palette[t].b);
845 int srcwidth = width * (bpp/8);
846 datalen3 = (width*4+5)*height;
847 data3 = (U8*)malloc(datalen3);
848 for(y=0;y<height;y++)
850 data3[pos2++]=0; //filter type
851 for(x=0;x<width;x++) {
852 data3[pos2++]=data[pos+1];
853 data3[pos2++]=data[pos+2];
854 data3[pos2++]=data[pos+3];
855 data3[pos2++]=data[pos+0]; //alpha
858 pos+=((srcwidth+3)&~3)-srcwidth; //align
864 data2 = malloc(datalen2);
866 if((ret = compress (data2, &datalen2, data3, datalen3)) != Z_OK) {
867 fprintf(stderr, "zlib error in pic %d\n", ret);
870 png_start_chunk(fi, "IDAT", datalen2);
871 png_write_bytes(fi,data2,datalen2);
873 png_start_chunk(fi, "IEND", 0);