From d890a03706282500c2129ae8ab7b399069038192 Mon Sep 17 00:00:00 2001 From: kramm Date: Thu, 7 Apr 2005 09:00:38 +0000 Subject: [PATCH] initial revision --- lib/png.c | 837 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/png.h | 35 +++ 2 files changed, 872 insertions(+) create mode 100644 lib/png.c create mode 100644 lib/png.h diff --git a/lib/png.c b/lib/png.c new file mode 100644 index 0000000..8dd105b --- /dev/null +++ b/lib/png.c @@ -0,0 +1,837 @@ +/* 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 +#include "png.h" + +typedef unsigned char U8; +typedef unsigned long U32; +typedef struct _COL { + U8 a,r,g,b; +} COL; + +#define REVERSESWAP16(s) ((((s)>>8)&0x00ff)|(((s)<<8)&0xff00)) +#define REVERSESWAP32(s) (REVERSESWAP16(((s)>>16)&0x0000ffff)|((REVERSESWAP16(s)<<16)&0xffff0000)) + +int png_read_chunk(char (*head)[4], int*destlen, U8**destdata, FILE*fi) +{ + unsigned int len; + if(destlen) *destlen=0; + if(destdata) *destdata=0; + if(!fread(&len, 4, 1, fi)) { + return 0; + } + if(!fread(head, 4, 1, fi)) { + return 0; + } + len = REVERSESWAP32(len); + if(destlen) *destlen = len; + if(destdata) { + if(!len) { + *destdata = 0; + } else { + *destdata = (U8*)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; +} + +unsigned int png_get_dword(FILE*fi) +{ + unsigned int a; + fread(&a,4,1,fi); + return REVERSESWAP32(a); +} + +struct png_header +{ + int width; + int height; + int bpp; + int mode; +}; + +int png_read_header(FILE*fi, struct png_header*header) +{ + char id[4]; + int len; + int ok=0; + U8 head[8] = {137,80,78,71,13,10,26,10}; + U8 head2[8]; + U8*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 = REVERSESWAP32(*(U32*)&data[0]); + header->height = REVERSESWAP32(*(U32*)&data[4]); + 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!=2 && b!=3 && b!=6) { + fprintf(stderr, "Image mode %d not supported!\n", b); + if(b == 4) { + fprintf(stderr, "(This is a grayscale image with alpha channel-\n"); + fprintf(stderr, " try converting it into an RGB image with alpha channel)\n"); + } + 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))) +byte inline 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; +} + +void applyfilter1(int mode, U8*src, U8*old, U8*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); + } + + 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; + + if(header.mode == 6 || header.mode == 2) + { + U8*data2 = (U8*)malloc(header.width*header.height*4); + 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, U8 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) +{ + U8 mytype[4]={0,0,0,0}; + U32 mylen = REVERSESWAP32(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, U8*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 = REVERSESWAP32((mycrc32^0xffffffff)); + fwrite(&tmp,4,1,fi); +} + +void writePNG(char*filename, unsigned char*data, int width, int height) +{ + FILE*fi; + int crc; + int t; + U8 format; + U8 tmp; + U8* data2=0; + U8* data3=0; + U32 datalen; + U32 datalen2; + U32 datalen3; + U8 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 = (U8*)malloc(datalen3); + for(y=0;y + + 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 */ + +#ifndef __png_h__ +#define __png_h__ + +#ifdef __cplusplus +extern "C" { +#endif + +int getPNG(char*sname, int*destwidth, int*destheight, unsigned char**destdata); +int getPNGdimensions(char*sname, int*destwidth, int*destheight); +void writePNG(char*filename, unsigned char*data, int width, int height); + +#ifdef __cplusplus +} +#endif + +#endif + -- 1.7.10.4