#define DEBUG 1 // #define DEBUG_HARD 42000 #define CROP 25 // Rand, der nicht zum Farblernen verwendet wird (Prozent rundum) #define CMY_ANNOY 1 // CMY unfair behandeln... #define WHITE 192 // ab dort wirds als W betrachtet (64..255 sinnvoll) #define BLACK 96 // bis dort S (0..100 oder so) #define Q 5 // soviele LSB werden ignoriert (0..7 sinnvoll) #define REVIDENCE 1.4 #define GEVIDENCE 1.3 #define BEVIDENCE 1.2 // Schwelle fuer z.B. r / avg(g,b), um Rot zu erkennen etc. #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 { #define QQ (256>>Q) int x,y,n,count; int xcrop,ycrop,anzpixel,linebytes; unsigned /* char */ int r,g,b,R,G,B; float rguess,gguess,bguess; unsigned char * buf2; int rhist[QQ],ghist[QQ],bhist[QQ]; #ifdef DEBUG printf("Reducing colors... %p -> %dx%d\n",buf,xsize,ysize); #endif xcrop = (CROP * xsize) / 100; ycrop = (CROP * ysize) / 100; xcrop = ((xcrop*3) > xsize) ? 0 : xcrop; ycrop = ((ycrop*3) > ysize) ? 0 : ycrop; anzpixel = xsize * ysize; linebytes = xsize * 3; r=g=b=255; R=G=B=0; for (n=0;nBLACK) || (g>BLACK) || (b>BLACK))) // ignoriere S/W! { rhist[r >> Q]++; ghist[g >> Q]++; bhist[b >> Q]++; }; }; }; count=0; for (n=0;n rhist[n]) ? count : rhist[n]; count = (count > ghist[n]) ? count : ghist[n]; count = (count > bhist[n]) ? count : bhist[n]; }; count >>= 8; count = (count) ? count : 1; for (n=0;n255) ? 255 : rhist[n]; ghist[n]= ghist[n]/count; ghist[n]= (ghist[n]>255) ? 255 : ghist[n]; bhist[n]= bhist[n]/count; bhist[n]= (bhist[n]>255) ? 255 : bhist[n]; }; #ifdef DEBUG buf2 = buf; // Histogramm einblenden if ((xsize>148) && (ysize>20)) { buf2 = buf + (linebytes * 10) + 30; for (x=0;x>Q)) ? buf2[y] : 255; }; buf2 += 6; }; buf2 = buf + (linebytes * 13) + 30; for (x=0;x>Q)) ? buf2[y] : 255; }; buf2 += 6; }; buf2 = buf + (linebytes * 16) + 30; for (x=0;x>Q)) ? buf2[y] : 255; }; buf2 += 6; }; }; #endif r=g=b=0; R=G=B=255; #ifdef DEBUG printf("R: "); for (n=0;nBLACK) || (g>BLACK) || (b>BLACK))) // ignoriere S/W! { n=0; rguess = 1.0 * r / (0.5 * (g+b)); gguess = 1.0 * g / (0.5 * (r+b)); bguess = 1.0 * b / (0.5 * (r+g)); if (rguess>REVIDENCE) n=1; if (gguess>GEVIDENCE) n=2; if (bguess>BEVIDENCE) n=3; if ( ((rguess>REVIDENCE) && (gguess>GEVIDENCE)) || ((gguess>GEVIDENCE) && (bguess>BEVIDENCE)) || ((rguess>REVIDENCE) && (bguess>BEVIDENCE)) ) /* then */ n=0; r=g=b=0; if (n==1) r=255; if (n==2) g=255; if (n==3) b=255; if ((r | b | g) != 255) r=g=b=64; buf2[0]=b; buf2[1]=g; buf2[2]=r; // 2:3-Mehrheits-Trick } else { buf2[0]=buf2[1]=buf2[2]= (r>WHITE) ? 255 : 0; }; buf2 += 3; }; }; return; }; // -------------------------------------------------------------------- int rufe_convert(char * rein, char * raus_mit_typ,char * opt) { int pid,status; #ifdef DEBUG printf("Converting %s -> %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 if ( (xsize*ysize*3)>(fsize-(18+mapped[0])) ) { printf("wrong header in tga, giving up\n"); return 1; }; #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"); #ifndef DEBUG if (!result) { unlink(quelle); } else { printf("convert back failed, will keep %s\n",quelle); }; #endif return result; };