struct png_header
{
- int width;
- int height;
+ unsigned width;
+ unsigned height;
int bpp;
int mode;
};
else return c;
}
-static void applyfilter1(int mode, unsigned char*src, unsigned char*old, unsigned char*dest, int width)
+static void applyfilter1(int mode, unsigned char*src, unsigned char*old, unsigned char*dest, unsigned width)
{
int x;
unsigned char last=0;
}
-static void applyfilter2(int mode, unsigned char*src, unsigned char*old, unsigned char*dest, int width)
+static void applyfilter2(int mode, unsigned char*src, unsigned char*old, unsigned char*dest, unsigned width)
{
int x;
unsigned char lasta=0;
/* also performs 24 bit conversion! */
-static void applyfilter3(int mode, unsigned char*src, unsigned char*old, unsigned char*dest, int width)
+static void applyfilter3(int mode, unsigned char*src, unsigned char*old, unsigned char*dest, unsigned width)
{
int x;
unsigned char lastr=0;
}
}
-static void inline applyfilter4(int mode, unsigned char*src, unsigned char*old, unsigned char*dest, int width)
+void png_inverse_filter_32(int mode, unsigned char*src, unsigned char*old, unsigned char*dest, unsigned width)
{
int x;
unsigned char lastr=0;
}
}
-
-EXPORT int getPNGdimensions(const char*sname, int*destwidth, int*destheight)
+EXPORT int png_getdimensions(const char*sname, unsigned*destwidth, unsigned*destheight)
{
FILE*fi;
struct png_header header;
*destwidth = header.width;
*destheight = header.height;
+ fclose(fi);
return 1;
}
-EXPORT int getPNG(const char*sname, int*destwidth, int*destheight, unsigned char**destdata)
+EXPORT int png_load(const char*sname, unsigned*destwidth, unsigned*destheight, unsigned char**destdata)
{
char tagid[4];
int len;
unsigned char*data;
unsigned char*imagedata;
unsigned char*zimagedata=0;
- unsigned long int imagedatalen;
unsigned long int zimagedatalen=0;
unsigned char*palette = 0;
int palettelen = 0;
return 0;
}
- imagedatalen = bypp * header.width * header.height + 65536;
+ unsigned long long imagedatalen_64 = ((unsigned long long)header.width + 1) * header.height * bypp;
+ if(imagedatalen_64 > 0xffffffff)
+ return 0;
+ unsigned long imagedatalen = (unsigned long)imagedatalen_64;
imagedata = (unsigned char*)malloc(imagedatalen);
fseek(fi,8,SEEK_SET);
}
}
+ fclose(fi);
if(!zimagedata || uncompress(imagedata, &imagedatalen, zimagedata, zimagedatalen) != Z_OK) {
printf("Couldn't uncompress %s!\n", sname);
if(zimagedata)
return 0;
}
free(zimagedata);
- fclose(fi);
*destwidth = header.width;
*destheight = header.height;
old = &data2[(y-1)*header.width*4];
}
if(header.mode == 6) {
- applyfilter4(mode, src, old, dest, header.width);
+ png_inverse_filter_32(mode, src, old, dest, header.width);
} else { // header.mode = 2
applyfilter3(mode, src, old, dest, header.width);
/* replace alpha color */
return hash;
}
-static int png_get_number_of_palette_entries(COL*img, int width, int height, COL*palette, char*has_alpha)
+static int png_get_number_of_palette_entries(COL*img, unsigned width, unsigned height, COL*palette, char*has_alpha)
{
int len = width*height;
int t;
}
}
-static int png_apply_specific_filter_8(int filtermode, unsigned char*dest, unsigned char*src, int width)
+static int png_apply_specific_filter_8(int filtermode, unsigned char*dest, unsigned char*src, unsigned width)
{
int pos2 = 0;
int pos = 0;
- int srcwidth = width;
+ unsigned srcwidth = width;
int x;
if(filtermode == 0) {
for(x=0;x<width;x++) {
return filtermode;
}
-static int png_apply_specific_filter_32(int filtermode, unsigned char*dest, unsigned char*src, int width)
+static int png_apply_specific_filter_32(int filtermode, unsigned char*dest, unsigned char*src, unsigned width)
{
int pos2 = 0;
int pos = 0;
- int srcwidth = width*4;
+ unsigned srcwidth = width*4;
int x;
if(filtermode == 0) {
for(x=0;x<width;x++) {
}
return filtermode;
}
-
+
static int*num_bits_table = 0;
static void make_num_bits_table()
}
}
-static int png_apply_filter(unsigned char*dest, unsigned char*src, int width, int y, int bpp)
+static int png_find_best_filter(unsigned char*src, unsigned width, int bpp, int y)
{
make_num_bits_table();
-
+
int num_filters = y>0?5:2; //don't apply y-direction filter in first line
+
+ int bytes_per_pixel = bpp>>3;
+ int w = width*bytes_per_pixel;
+ int back_x = bytes_per_pixel;
+ int back_y = y?width*bytes_per_pixel:0;
+
+ unsigned char*pairs[5];
+ pairs[0] = calloc(1, 8192);
+ pairs[1] = calloc(1, 8192);
+ pairs[2] = calloc(1, 8192);
+ pairs[3] = calloc(1, 8192);
+ pairs[4] = calloc(1, 8192);
+
+ unsigned char old[5];
+ int l = bytes_per_pixel - 1;
+ old[0] = src[l];
+ old[1] = src[l];
+ old[2] = src[l] - src[l-back_y];
+ old[3] = src[l] - src[l-back_y];
+ old[4] = src[l] - PaethPredictor(0, src[l-back_y], 0);
+
+ int different_pairs[5] = {0,0,0,0,0};
+
+ int x;
+ for(x=bytes_per_pixel;x<w;x++) {
+ unsigned char dest[5];
+ dest[0] = src[x];
+ dest[1] = src[x] - src[x-back_x];
+ dest[2] = src[x] - src[x-back_y];
+ dest[3] = src[x] - (src[x-back_x] + src[x-back_y])/2;
+ dest[4] = src[x] - PaethPredictor(src[x-back_x], src[x-back_y], src[x-back_x-back_y]);
+
+ int i;
+ for(i=0;i<5;i++) {
+ int v = dest[i]<<8|old[i];
+ int p = v>>3;
+ int b = 1<<(v&7);
+ if(!pairs[i][p]&b) {
+ pairs[i][p]|=b;
+ different_pairs[i]++;
+ }
+ }
+ memcpy(old, dest, sizeof(old));
+ }
int f;
int best_nr = 0;
int best_energy = INT_MAX;
+ for(f=0;f<num_filters;f++) {
+ int energy = different_pairs[f];
+ if(energy<best_energy) {
+ best_nr = f;
+ best_energy = energy;
+ }
+ }
+ free(pairs[0]);
+ free(pairs[1]);
+ free(pairs[2]);
+ free(pairs[3]);
+ free(pairs[4]);
+ return best_nr;
+}
+
+
+static int png_apply_filter(unsigned char*dest, unsigned char*src, unsigned width, int y, int bpp)
+{
+ int best_nr = 0;
+#if 0
+ make_num_bits_table();
+ int num_filters = y>0?5:2; //don't apply y-direction filter in first line
+ int f;
+ int best_energy = INT_MAX;
int w = width*(bpp/8);
unsigned char* pairs = malloc(8192);
assert(bpp==8 || bpp==32);
best_energy = energy;
}
}
+ free(pairs);
+#else
+ best_nr = png_find_best_filter(src, width, bpp, y);
+#endif
if(bpp==8)
png_apply_specific_filter_8(best_nr, dest, src, width);
else
png_apply_specific_filter_32(best_nr, dest, src, width);
- free(pairs);
return best_nr;
}
-int png_apply_filter_8(unsigned char*dest, unsigned char*src, int width, int y)
+int png_apply_filter_8(unsigned char*dest, unsigned char*src, unsigned width, int y)
{
- png_apply_filter(dest, src, width, y, 8);
+ return png_apply_filter(dest, src, width, y, 8);
}
-int png_apply_filter_32(unsigned char*dest, unsigned char*src, int width, int y)
+int png_apply_filter_32(unsigned char*dest, unsigned char*src, unsigned width, int y)
{
- png_apply_filter(dest, src, width, y, 32);
+ return png_apply_filter(dest, src, width, y, 32);
}
-EXPORT void savePNG(const char*filename, unsigned char*data, int width, int height, int numcolors)
+EXPORT void png_write_palette_based(const char*filename, unsigned char*data, unsigned width, unsigned height, int numcolors)
{
FILE*fi;
int crc;
unsigned char format;
unsigned char tmp;
unsigned char* data2=0;
- u32 datalen;
- u32 datalen2;
unsigned char head[] = {137,80,78,71,13,10,26,10}; // PNG header
int cols;
char alpha = 1;
png_quantize_image(data, width*height, numcolors, &data, palette);
}
- datalen = (width*height*bpp/8+cols*8);
-
fi = fopen(filename, "wb");
if(!fi) {
perror("open");
{
int x,y;
int bypp = bpp/8;
- int srcwidth = width * bypp;
- int linelen = 1 + srcwidth;
+ unsigned srcwidth = width * bypp;
+ unsigned linelen = 1 + srcwidth;
if(bypp==2)
linelen = 1 + ((srcwidth+1)&~1);
else if(bypp==3)
fclose(fi);
}
-EXPORT void writePNG(const char*filename, unsigned char*data, int width, int height)
+EXPORT void png_write(const char*filename, unsigned char*data, unsigned width, unsigned height)
{
- savePNG(filename, data, width, height, 0);
+ png_write_palette_based(filename, data, width, height, 0);
}
-EXPORT void writePalettePNG(const char*filename, unsigned char*data, int width, int height)
+EXPORT void png_write_palette_based_2(const char*filename, unsigned char*data, unsigned width, unsigned height)
{
- savePNG(filename, data, width, height, 256);
+ png_write_palette_based(filename, data, width, height, 256);
}