#define DEBUG 1 // #define DEBUG_HARD 42000 // #define __USE_GNU 42 // coz I love O_NOFOLLOW -> 0400000 #define MATCH_BIAS 250 // max. Manhattan Farbabstand fuer Match... > 384/2 ist wohl schlecht... #define LEERRAUM 90 // ... Streifen ... (in beide Richtungen ab 128) #define IGN_SW 1 // 0 heisst: 0..7 fuer Match testen, 1 heisst: 1..6 testen, S/W fixieren. #define TRY_LEARNING 1 // experimentelles Feature... #define CROP 33 // Rand, der nicht zum Farblernen verwendet wird #define CMY_ANNOY 1 // CMY unfair behandeln... #define ALLOW_GREY 0 // 0 oder 1: Mitte-Grau als Option lassen... #define LIFT_BLACK 1 // 0 oder 1: Nicht-so-Dunkles auch noch als Schwarz sehen #include #include #include // system... #include #include // ... #include // open #include // stat #include // waitpid #include #include // mmap msync munmap ... really usefull, also for IPC! // -------------------------------------------------------------------- void farbreduktion(unsigned char * buf, int xsize, int ysize) // Assemblervorschlaege ohne Jcc von AMD: // abs: z=wert sar 31; erg=(wert ^ z) - z // min: x -= y; sbb z,z /* wird 0 oder -1 */; z &= x; z += y { int x,y,n,nsieger,fehler,minfehler; unsigned char r,g,b,R,G,B; unsigned char * buf2; unsigned char r8[8+ALLOW_GREY]; unsigned char g8[8+ALLOW_GREY]; unsigned char b8[8+ALLOW_GREY]; #ifdef DEBUG printf("Reducing colors... %p -> %dx%d\n",buf,xsize,ysize); #endif r=g=b=255; R=G=B=0; // jetzt Grenzwerte suchen... buf2 = buf; // evtl irgendwie anders vor Ausreissern sichern? for (y=CROP;y<(ysize-CROP);y++) { for (x=CROP;x<(xsize-CROP);x++) { b=(buf2[0]B)?(B+1):B; buf2++; g=(buf2[0]G)?(G+1):G; buf2++; r=(buf2[0]R)?(R+1):R; buf2++; }; }; if ( (xsize<(3*CROP)) || (ysize<(3*CROP)) ) { r=g=b=0; R=G=B=255; // Bild war zu klein zum Suchen... }; #ifdef DEBUG printf("RGB range is r=%d..%d g=%d..%d b=%d..%d\n",r,R,g,G,b,B); #endif b8[0]=b8[1]=b8[2]=b8[3]=b; b8[4]=b8[5]=b8[6]=b8[7]=B; g8[0]=g8[1]=g8[4]=g8[5]=g; g8[2]=g8[3]=g8[6]=g8[7]=G; r8[0]=r8[2]=r8[4]=r8[6]=r; r8[1]=r8[3]=r8[5]=r8[7]=R; #ifdef CMY_ANNOY // jetzt CMY unfair behandeln... 8-) r8[3]=r8[5]=r8[6]=255; g8[3]=g8[5]=g8[6]=255; b8[3]=b8[5]=b8[6]=255; #endif if (ALLOW_GREY) { n = r+R; r8[8] = n >> 1; n = g+G; g8[8] = n >> 1; n = b+B; b8[8] = n >> 1; }; if (LIFT_BLACK) { n = r; n *= 15; n += R; r8[0] = n >> 4; n = g; n *= 15; n += G; g8[0] = n >> 4; n = b; n *= 15; n += B; b8[0] = n >> 4; }; #ifdef TRY_LEARNING srandom(42); // Farbreduktion basierend auf Manhattan distance for (y=0;y< ((ysize*xsize)>>4) ;y++) // suche 8 passende Standardfarben { buf2 = buf + (3 * (random() % (xsize * ysize)) ); // es ist wichtig, die Stichprobe zu verteilen! // eigentlich sollte auch hier CROP gelten. b=buf2[0]; buf2++; g=buf2[0]; buf2++; r=buf2[0]; buf2++; minfehler=MATCH_BIAS; // meine Wahl, Automatik waere besser. nsieger=-1; for (n=IGN_SW;n<(8-IGN_SW);n++) { fehler = abs(r-r8[n]) + abs(g-g8[n]) + abs(b-b8[n]); if ((fehler= 0) // soll Lernen von Grey erlaubt sein? { n = nsieger; #ifdef DEBUG_HARD printf("Match %d for: r=%d/%d g=%d/%d b=%d/%d (dist %d)\n", n,r,r8[n],g,g8[n],b,b8[n],minfehler); #endif if ((r>r8[n]) && (r8[n]<255) && (r8[n]!=127-LEERRAUM)) r8[n]++; if ((g>g8[n]) && (g8[n]<255) && (g8[n]!=127-LEERRAUM)) g8[n]++; if ((b>b8[n]) && (b8[n]<255) && (b8[n]!=127-LEERRAUM)) b8[n]++; if ((r0) && (r8[n]!=129+LEERRAUM)) r8[n]--; if ((g0) && (g8[n]!=129+LEERRAUM)) g8[n]--; if ((b0) && (b8[n]!=129+LEERRAUM)) b8[n]--; // andere Art von Lernfunktion waere wohl stabiler... // erste Idee: Verbot, 128 zu ueberqueren -> besser Mitte... } else { #ifdef DEBUG_HARD printf("NO match for: r=%d g=%d b=%d (maxdist %d)\n",r,g,b,minfehler); #endif }; }; #ifdef DEBUG for (n=0;n<(8+ALLOW_GREY);n++) { printf("Pal_New[%d] is r=%3d g=%3d b=%3d ",n,r8[n],g8[n],b8[n]); if (n & 1) { printf("\n"); }; }; if (ALLOW_GREY) { printf("\n"); }; #endif #endif buf2 = buf; // Farbreduktion basierend auf Manhattan distance for (y=0;y %s\n",rein,raus_mit_typ); #endif pid = fork(); if (pid == -1) return -1; if (pid == 0) { char *argv2[5]; argv2[0] = "convert"; // mit execve statt ... execvp ganzer Pfad noetig argv2[1] = opt; argv2[2] = rein; argv2[3] = raus_mit_typ; argv2[4] = NULL; execvp("convert", argv2); // execve waere kernelcall exit(127); } for (;;) { if (waitpid(pid, &status, 0) == -1) { if (errno != EINTR) return -1; } else return status; }; }; // -------------------------------------------------------------------- int main(int argc,char * argv[]) { int result,xsize,ysize; unsigned char * mapped; int * mapped_32; int fd,fsize; struct stat status; char ziel[120]; char quelle[120]; if ((argc!=2) || (!argv[0]) || (!argv[1]) || (strlen(argv[0])>=100) || (strlen(argv[1])>=100)) { printf("Erics ColoReduce:\nImage name is the only argument.\n"); return 1; }; strncpy(quelle,argv[1],100); strncat(quelle,".tga",5); // Quelle: bla.tga strncpy(ziel,"TGA:",5); strncat(ziel,quelle,110); // Ziel: fuer convert result = rufe_convert(argv[1],ziel,"+compress"); // +compress means do NOT compress if (result) { printf("convert to tga failed\n"); return 1; }; if (stat(quelle,&status)) { printf("could not stat image\n"); return 1; }; fsize = status.st_size; if (!S_ISREG(status.st_mode)) { printf("not a regular file\n"); return 1; }; #ifdef DEBUG printf("Image %s has size %d\n",quelle,fsize); #endif fd = open(quelle,O_RDWR|0400000); // 04... ist O_NOFOLLOW if (!fd) { printf("could not open image\n"); return 1; }; mapped = mmap(NULL,fsize,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0); // passt mir zwar nicht, aber MAP_PRIVATE // scheint den File nicht zu schreiben // sondern nur das RAM... also MAP_SHARED if (mapped <= 0) { printf("mmap failed\n"); return 1; }; close(fd); mapped_32 = (int *)mapped; #ifndef SPARC if (((mapped_32[0] & 0x0ffffff00) !=0x00020000) || (mapped_32[1]) || (mapped_32[2]) || (mapped_32[3] & 0x0f000f000) || ((mapped_32[4] & 0x0ffff) != 24)) { printf("this is a strange type of file, giving up\n"); return 1; }; xsize = mapped_32[3] & 0x0ffff; ysize = mapped_32[3] >> 16; #else xsize = mapped[13]; xsize <<= 8; xsize += mapped[12]; ysize = mapped[15]; ysize <<= 8; ysize += mapped[14]; // restliche Tests bei Sparc weggelassen... #endif #ifdef DEBUG printf("TGA size is %dx%d (special is %d)\n",xsize,ysize,mapped[0]); #endif farbreduktion(mapped+18+mapped[0],xsize,ysize); if (msync(mapped,fsize,MS_SYNC)) { printf("msync failed\n"); return 1; }; if (munmap(mapped,fsize)) { printf("munmap failed\n"); return 1; }; #ifdef DEBUG_HARD system("/bin/sh"); #endif result = rufe_convert(quelle,argv[1],"-verbose"); if (!result) { unlink(quelle); } else { printf("convert back failed, will keep %s\n",quelle); }; return result; };