+static inline u32 color_hash(COL*col)
+{
+ u32 col32 = *(u32*)col;
+ u32 hash = (col32 >> 17) ^ col32;
+ hash ^= ((hash>>8) + 1) ^ hash;
+ return hash;
+}
+
+static int png_get_number_of_palette_entries(COL*img, int width, int height, COL*palette, char*has_alpha)
+{
+ int len = width*height;
+ int t;
+ int palsize = 0;
+ int size[256];
+ int palette_overflow = 0;
+ u32 lastcol32 = 0;
+
+ memset(size, 0, sizeof(size));
+
+ u32*pal = (u32*)malloc(65536*sizeof(u32));
+ int*count = (int*)malloc(65536*sizeof(int));
+
+ assert(sizeof(COL)==sizeof(u32));
+ assert(width && height);
+
+ lastcol32 = (*(u32*)&img[0])^0xffffffff; // don't match
+
+ for(t=0;t<len;t++) {
+ u32 col32 = *(u32*)&img[t];
+ if(col32 == lastcol32)
+ continue;
+
+ if(img[t].a!=255)
+ *has_alpha=1;
+ int i;
+
+ u32 hash = color_hash(&img[t])&255;
+
+ int csize = size[hash];
+ u32*cpal = &pal[hash*256];
+ int*ccount = &count[hash*256];
+ for(i=0;i<csize;i++) {
+ if(col32 == cpal[i]) {
+ ccount[i]++;
+ break;
+ }
+ }
+ if(i==csize) {
+ if(palsize==256) {
+ palette_overflow = 1;
+ break;
+ }
+ count[size[hash]] = 1;
+ cpal[size[hash]++] = col32;
+ palsize++;
+ }
+ lastcol32 = col32;
+ }
+ if(palette_overflow) {
+ free(pal);
+ *has_alpha=1;
+ return width*height;
+ }
+ if(palette) {
+ int i = 0;
+ int occurences[256];
+ for(t=0;t<256;t++) {
+ int s;
+ int csize = size[t];
+ u32* cpal = &pal[t*256];
+ int* ccount = &count[t*256];
+ for(s=0;s<csize;s++) {
+ occurences[i] = ccount[s];
+ palette[i++] = *(COL*)(&cpal[s]);
+ }
+ }
+ assert(i==palsize);
+ int j;
+ for(i=0;i<palsize-1;i++) {
+ for(j=i+1;j<palsize;j++) {
+ if(occurences[j] < occurences[i]) {
+ int o = occurences[i];
+ COL c = palette[i];
+ occurences[i] = occurences[j];
+ palette[i] = palette[j];
+ occurences[j] = o;
+ palette[j] = c;
+ }
+ }
+ }
+ }
+ free(pal);
+ free(count);
+ return palsize;
+}
+
+static void png_map_to_palette(COL*src, unsigned char*dest, int size, COL*palette, int palette_size)
+{
+ int t;
+ int palette_hash[1024];
+ memset(palette_hash, 0, sizeof(int)*1024);
+
+ for(t=0;t<palette_size;t++) {
+ u32 hash = color_hash(&palette[t])&1023;
+ while(palette_hash[hash])
+ hash = (hash+1)&1023;
+ palette_hash[hash] = t;
+ }
+
+ for(t=0;t<size;t++) {
+ u32 hash = color_hash(&src[t]);
+ int index = 0;
+ while(1) {
+ hash&=1023;
+ index = palette_hash[hash];
+ if(!memcmp(&palette[index], &src[t], sizeof(COL)))
+ break;
+ hash++;
+ }
+ dest[t] = palette_hash[hash];
+ }
+}
+
+static int png_apply_specific_filter_8(int filtermode, unsigned char*dest, unsigned char*src, int width)