From: kramm Date: Thu, 17 May 2007 16:07:19 +0000 (+0000) Subject: added preprocessing capabilities to png writer X-Git-Tag: buttons-working~638 X-Git-Url: http://git.asbjorn.biz/?p=swftools.git;a=commitdiff_plain;h=4513e3be4df534f961bdca64480631fe798c67fb added preprocessing capabilities to png writer --- diff --git a/lib/png.c b/lib/png.c index 9748c6a..e305872 100644 --- a/lib/png.c +++ b/lib/png.c @@ -644,7 +644,7 @@ EXPORT int getPNG(char*sname, int*destwidth, int*destheight, unsigned char**dest } else { old = &data2[(y-1)*header.width*4]; } - if(header.mode == 6) { + if(header.mode == 6) { applyfilter4(mode, src, old, dest, header.width); } else { // header.mode = 2 applyfilter3(mode, src, old, dest, header.width); @@ -784,21 +784,36 @@ 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) +static long png_start_chunk(FILE*fi, char*type, int len) { unsigned char mytype[4]={0,0,0,0}; unsigned char mylen[4]; + long filepos; mylen[0] = len>>24; mylen[1] = len>>16; mylen[2] = len>>8; mylen[3] = len; memcpy(mytype,type,strlen(type)); + filepos = ftell(fi); 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]); + return filepos; +} +static void png_patch_len(FILE*fi, int pos, int len) +{ + unsigned char mylen[4]; + long filepos; + mylen[0] = len>>24; + mylen[1] = len>>16; + mylen[2] = len>>8; + mylen[3] = len; + fseek(fi, pos, SEEK_SET); + fwrite(&mylen, 4, 1, fi); + fseek(fi, 0, SEEK_END); } static void png_write_bytes(FILE*fi, unsigned char*bytes, int len) { @@ -824,6 +839,176 @@ static void png_end_chunk(FILE*fi) fwrite(&tmp2,4,1,fi); } +#define ZLIB_BUFFER_SIZE 16384 + +static long compress_line(z_stream*zs, Bytef*line, int len, FILE*fi) +{ + long size = 0; + zs->next_in = line; + zs->avail_in = len; + + while(1) { + int ret = deflate(zs, Z_NO_FLUSH); + if (ret != Z_OK) { + fprintf(stderr, "error in deflate(): %s", zs->msg?zs->msg:"unknown"); + return 0; + } + if(zs->avail_out != ZLIB_BUFFER_SIZE) { + int consumed = ZLIB_BUFFER_SIZE - zs->avail_out; + size += consumed; + png_write_bytes(fi, zs->next_out - consumed , consumed); + zs->next_out = zs->next_out - consumed; + zs->avail_out = ZLIB_BUFFER_SIZE; + } + if(!zs->avail_in) { + break; + } + } + return size; +} + +static int test_line(z_stream*zs_orig, Bytef*line, int linelen) +{ + z_stream zs; + int ret = deflateCopy(&zs, zs_orig); + if(ret != Z_OK) { + fprintf(stderr, "Couldn't copy stream\n"); + return 0; + } + + zs.next_in = line; + zs.avail_in = linelen; + + long size = 0; + + int mode = Z_SYNC_FLUSH; + while(1) { + int ret = deflate(&zs, mode); + if (ret != Z_OK && ret != Z_STREAM_END) { + fprintf(stderr, "error in deflate(): %s (mode %s, %d bytes remaining)\n", zs.msg?zs.msg:"unknown", + mode==Z_SYNC_FLUSH?"Z_SYNC_FLUSH":"Z_FINISH", zs.avail_in); + return 0; + } + if(zs.avail_out != ZLIB_BUFFER_SIZE) { + int consumed = ZLIB_BUFFER_SIZE - zs.avail_out; + size += consumed; + zs.next_out = zs.next_out - consumed; + zs.avail_out = ZLIB_BUFFER_SIZE; + } + if (ret == Z_STREAM_END) { + break; + } + if(!zs.avail_in) { + mode = Z_FINISH; + } + } + ret = deflateEnd(&zs); + if (ret != Z_OK) { + fprintf(stderr, "error in deflateEnd(): %s\n", zs.msg?zs.msg:"unknown"); + return 0; + } + return size; +} + +static int finishzlib(z_stream*zs, FILE*fi) +{ + int size = 0; + int ret; + while(1) { + ret = deflate(zs, Z_FINISH); + if (ret != Z_OK && + ret != Z_STREAM_END) { + fprintf(stderr, "error in deflate(finish): %s\n", zs->msg?zs->msg:"unknown"); + return 0; + } + + if(zs->avail_out != ZLIB_BUFFER_SIZE) { + int consumed = ZLIB_BUFFER_SIZE - zs->avail_out; + size += consumed; + png_write_bytes(fi, zs->next_out - consumed , consumed); + zs->next_out = zs->next_out - consumed; + zs->avail_out = ZLIB_BUFFER_SIZE; + } + if (ret == Z_STREAM_END) { + break; + } + } + ret = deflateEnd(zs); + if (ret != Z_OK) { + fprintf(stderr, "error in deflateEnd(): %s\n", zs->msg?zs->msg:"unknown"); + return 0; + } + return size; +} + +static void filter_line(int filtermode, unsigned char*dest, unsigned char*src, int width) +{ + int pos2 = 0; + int pos = 0; + int srcwidth = width*4; + int x; + if(filtermode == 0) { + for(x=0;x=2) + continue; // don't do y direction filters in the first row + + line[0]=filtermode; //filter type + filter_line(filtermode, line+1, &data[y*srcwidth], width); - if((ret = compress (data2, &datalen2, data3, datalen3)) != Z_OK) { - fprintf(stderr, "zlib error in pic %d\n", ret); - return; + int size = test_line(&zs, line, linelen); + if(size < bestsize) { + memcpy(bestline, line, linelen); + bestsize = size; + } + } + idatsize += compress_line(&zs, bestline, linelen, fi); + } + free(line);free(bestline); } - png_start_chunk(fi, "IDAT", datalen2); - png_write_bytes(fi,data2,datalen2); + idatsize += finishzlib(&zs, fi); + png_patch_len(fi, idatpos, idatsize); png_end_chunk(fi); + png_start_chunk(fi, "IEND", 0); png_end_chunk(fi); + free(writebuf); free(data2); - free(data3); fclose(fi); } +