/* png.c Copyright (c) 2003/2004/2005 Matthias Kramm This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #ifdef EXPORT #undef EXPORT #endif #ifdef PNG_INLINE_EXPORTS #define EXPORT static #else #define EXPORT #include "png.h" #endif typedef unsigned u32; typedef struct _COL { unsigned char a,r,g,b; } COL; static int png_read_chunk(char (*head)[4], int*destlen, unsigned char**destdata, FILE*fi) { unsigned int len; unsigned char blen[4]; if(destlen) *destlen=0; if(destdata) *destdata=0; if(!fread(&blen, 4, 1, fi)) { return 0; } if(!fread(head, 4, 1, fi)) { return 0; } len = blen[0]<<24|blen[1]<<16|blen[2]<<8|blen[3]; if(destlen) *destlen = len; if(destdata) { if(!len) { *destdata = 0; } else { *destdata = (unsigned char*)malloc(len); if(!fread(*destdata, len, 1, fi)) { *destdata = 0; if(destlen) *destlen=0; return 0; } } fseek(fi, 4, SEEK_CUR); } else { fseek(fi, len+4, SEEK_CUR); } return 1; } static unsigned int png_get_dword(FILE*fi) { unsigned int a; unsigned char b[4]; fread(&b,4,1,fi); return b[0]<<24|b[1]<<16|b[2]<<8|b[3]; } struct png_header { int width; int height; int bpp; int mode; }; static int png_read_header(FILE*fi, struct png_header*header) { char id[4]; int len; int ok=0; unsigned char head[8] = {137,80,78,71,13,10,26,10}; unsigned char head2[8]; unsigned char*data; fread(head2,8,1,fi); if(strncmp((const char*)head,(const char*)head2,4)) return 0; while(png_read_chunk(&id, &len, &data, fi)) { //printf("Chunk: %c%c%c%c (len:%d)\n", id[0],id[1],id[2],id[3], len); if(!strncasecmp(id, "IHDR", 4)) { char a,b,c,f,i; if(len < 8) exit(1); header->width = data[0]<<24|data[1]<<16|data[2]<<8|data[3]; header->height = data[4]<<24|data[5]<<16|data[6]<<8|data[7]; a = data[8]; // should be 8 b = data[9]; // should be 3(indexed) or 2(rgb) c = data[10]; // compression mode (0) f = data[11]; // filter mode (0) i = data[12]; // interlace mode (0) if(b!=0 && b!=4 && b!=2 && b!=3 && b!=6) { fprintf(stderr, "Image mode %d not supported!\n", b); return 0; } if(a!=8 && (b==2 || b==6)) { printf("Bpp %d in mode %d not supported!\n", a); return 0; } if(c!=0) { printf("Compression mode %d not supported!\n", c); return 0; } if(f!=0) { printf("Filter mode %d not supported!\n", f); return 0; } if(i!=0) { printf("Interlace mode %d not supported!\n", i); return 0; } //printf("%dx%d bpp:%d mode:%d comp:%d filter:%d interlace:%d\n",header->width, header->height, a,b,c,f,i); header->bpp = a; header->mode = b; ok = 1; } free(data); } return ok; } typedef unsigned char byte; #define ABS(a) ((a)>0?(a):(-(a))) static inline byte PaethPredictor (byte a,byte b,byte c) { // a = left, b = above, c = upper left int p = a + b - c; // initial estimate int pa = ABS(p - a); // distances to a, b, c int pb = ABS(p - b); int pc = ABS(p - c); // return nearest of a,b,c, // breaking ties in order a,b,c. if (pa <= pb && pa <= pc) return a; else if (pb <= pc) return b; else return c; } static void applyfilter1(int mode, unsigned char*src, unsigned char*old, unsigned char*dest, int width) { int x; unsigned char last=0; unsigned char upperlast=0; if(mode==0) { for(x=0;x=32 && data[t]<128) printf("%c", data[t]); else printf("?"); } printf("\n");*/ } if(data) { free(data); data=0; } } if(!zimagedata || uncompress(imagedata, &imagedatalen, zimagedata, zimagedatalen) != Z_OK) { printf("Couldn't uncompress %s!\n", sname); if(zimagedata) free(zimagedata); return 0; } free(zimagedata); fclose(fi); *destwidth = header.width; *destheight = header.height; data2 = (unsigned char*)malloc(header.width*header.height*4); if(header.mode == 4) { int i,s=0; int x,y; int pos=0; unsigned char* old= (unsigned char*)malloc(header.width*2); memset(old, 0, header.width*2); *destdata = data2; for(y=0;y=0;x--) { unsigned char gray = dest[x*2+0]; unsigned char alpha = dest[x*2+1]; dest[x*4+0] = alpha; dest[x*4+1] = gray; dest[x*4+2] = gray; dest[x*4+3] = gray; } } free(old); free(imagedata); } else if(header.mode == 6 || header.mode == 2) { int i,s=0; int x,y; int pos=0; *destdata = data2; for(y=0;y>header.bpp); palettelen = 1<32 bit conversion */ for(i=0;i>(16-header.bpp-(s&7)))&v; s+=header.bpp; } src = tmpline; pos+=(header.width*header.bpp+7)/8; } if(!y) { memset(destline,0,header.width); old = &destline[y*header.width]; } else { old = tmpline; } applyfilter1(mode, src, old, destline, header.width); memcpy(tmpline,destline,header.width); for(x=0;x> 1); } crc32_table[t] = c; } } static inline void png_write_byte(FILE*fi, unsigned char byte) { fwrite(&byte,1,1,fi); mycrc32 = crc32_table[(mycrc32 ^ byte) & 0xff] ^ (mycrc32 >> 8); } static void png_start_chunk(FILE*fi, char*type, int len) { unsigned char mytype[4]={0,0,0,0}; unsigned char mylen[4]; mylen[0] = len>>24; mylen[1] = len>>16; mylen[2] = len>>8; mylen[3] = len; memcpy(mytype,type,strlen(type)); fwrite(&mylen, 4, 1, fi); mycrc32=0xffffffff; png_write_byte(fi,mytype[0]); png_write_byte(fi,mytype[1]); png_write_byte(fi,mytype[2]); png_write_byte(fi,mytype[3]); } static void png_write_bytes(FILE*fi, unsigned char*bytes, int len) { int t; for(t=0;t>24); png_write_byte(fi,dword>>16); png_write_byte(fi,dword>>8); png_write_byte(fi,dword); } static void png_end_chunk(FILE*fi) { u32 tmp = mycrc32^0xffffffff; unsigned char tmp2[4]; tmp2[0] = tmp>>24; tmp2[1] = tmp>>16; tmp2[2] = tmp>>8; tmp2[3] = tmp; fwrite(&tmp2,4,1,fi); } EXPORT void writePNG(char*filename, unsigned char*data, int width, int height) { FILE*fi; int crc; int t; unsigned char format; unsigned char tmp; unsigned char* data2=0; unsigned char* data3=0; u32 datalen; u32 datalen2; u32 datalen3; unsigned char head[] = {137,80,78,71,13,10,26,10}; // PNG header int cols; char alpha = 1; int pos = 0; int error; u32 tmp32; int bpp; int ret; make_crc32_table(); bpp = 32; cols = 0; format = 5; datalen = (width*height*bpp/8+cols*8); fi = fopen(filename, "wb"); if(!fi) { perror("open"); return; } fwrite(head,sizeof(head),1,fi); png_start_chunk(fi, "IHDR", 13); png_write_dword(fi,width); png_write_dword(fi,height); png_write_byte(fi,8); if(format == 3) png_write_byte(fi,3); //indexed else if(format == 5 && alpha==0) png_write_byte(fi,2); //rgb else if(format == 5 && alpha==1) png_write_byte(fi,6); //rgba else return; png_write_byte(fi,0); //compression mode png_write_byte(fi,0); //filter mode png_write_byte(fi,0); //interlace mode png_end_chunk(fi); /* if(format == 3) { png_start_chunk(fi, "PLTE", 768); for(t=0;t<256;t++) { png_write_byte(fi,palette[t].r); png_write_byte(fi,palette[t].g); png_write_byte(fi,palette[t].b); } png_end_chunk(fi); }*/ { int pos2 = 0; int x,y; int srcwidth = width * (bpp/8); datalen3 = (width*4+5)*height; data3 = (unsigned char*)malloc(datalen3); for(y=0;y