/*********************************************/ /* FixPal 2.9 */ /* Copyright (c) Marian Dvorsky */ /* See FixPal.Txt for details */ /* */ /* FixPal module */ /*********************************************/ #include "fixpal.h" #include <stdarg.h> #include <dos.h> void unscale_palette(PALETTE *pal); void scale_palette(PALETTE *pal); /* Common pallete */ RGB common[65535]; unsigned int distances[65535]; /* New transparent color rgb */ RGB newtrans; int newtranb; RGB oldtrans; int count; /* Methods used */ unsigned char method; unsigned char findmethod; /* Total colors in common palette */ unsigned int limit; unsigned int colors; unsigned int maxcolors; unsigned int omaxcolors; unsigned int transc; signed int tolerance; int remap; int transb; int bitmapno; char bitmaps[255][255]; char palfile[255]; char logfile[255]; char inputpal[255]; char s[255]; FILE *filelog; // Returns largest of three numbers inline int max(int a, int b, int c) { return(c>=(a>=b?a:b)?c:(a>=b?a:b)); } /* Returns distance of 2 colors */ int distance(RGB c1,RGB c2) { return ( (c1.r-c2.r)*(c1.r-c2.r) + (c1.g-c2.g)*(c1.g-c2.g) + (c1.b-c2.b)*(c1.b-c2.b)); } void save_to_log(char *format, ...) { char buf[256]; if (strcmp(logfile,"") != 0) { va_list ap; va_start(ap, format); vsprintf(buf, format, ap); va_end(ap); fprintf(filelog,"%s\n",buf); fflush(filelog); } } /* Find color in common palette. Returns color */ int findcolor(int r,int g,int b) { unsigned int x,a; int col = 0; int qual; RGB color; color.r = r; color.g = g; color.b = b; qual = 200000; for (x=0;x<=colors;x++){ a = distance(color,common[x]); if (a < qual) { qual = a; col = x; } } save_to_log(" - finding color (%d,%d,%d). Found this one: (%d,%d,%d)",r,g,b,common[col].r,common[col].g,common[col].b); /* for (x=0;x<=colors;x++){ if (max(abs(color.r-common[x].r),abs(color.g-common[x].g),abs(color.b-common[x].b)) < qual) { qual = max(abs(color.r-common[x].r),abs(color.g-common[x].g),abs(color.b-common[x].b)); col = x; } }*/ return(col); } /* Add color to common palette (do checking for same colors) */ void addcolor(int r,int g,int b) { if (colors < limit){ unsigned int x; int exists; exists = 0; for (x=0;x<=colors;x++){ if ((r >= common[x].r-tolerance) && (r <= common[x].r+tolerance) && (g >= common[x].g-tolerance) && (g <= common[x].g+tolerance) && (b >= common[x].b-tolerance) && (b <= common[x].b+tolerance)) { exists = 1; break; } } if (!exists){ common[colors].r = r; common[colors].g = g; common[colors].b = b; save_to_log(" - new color found (r:%d,g:%d,b:%d)",r,g,b); colors++; } } } /* Reads palette from file and adds colors to common palette */ void readpal(char *name,int attrib, int param) { PALETTE pal; BITMAP *bmp; unsigned short int newcolors[256]; unsigned int x,y; unsigned int col; int cd; // color depth; bmp = load_bitmap(name,pal); save_to_log("Reading file %s.",name); cd = bitmap_color_depth(bmp); save_to_log(" - bitmap info: (%dx%dx%d)",bmp->w,bmp->h,cd); if (cd == 8) { for (x=0;x<=255;x++) newcolors[x] = -1; select_palette(pal); } for (y=0;y<bmp->h;y++) { for (x=0;x<bmp->w;x++) { col = getpixel(bmp,x,y); if ((!transb || transc!=col) && (cd!=8 || newcolors[col]!=0)) { if (cd==8) newcolors[col] = 0; addcolor(getr_depth(cd,col),getg_depth(cd,col),getb_depth(cd,col)); } } } destroy_bitmap(bmp); count++; printf("\r %d files loaded (colors used: %d)",count,colors); fflush(stdout); } /* Modifies bitmap file */ void modifybmp(char *name,int attrib,int param) { int newcolors[256]; PALETTE inpal; PALETTE *outpal; BITMAP *bmp; int x,y,cd; unsigned int col,newcol; save_to_log("Modifying file %s.",name); bmp = load_bitmap(name,inpal); cd = bitmap_color_depth(bmp); save_to_log(" - color depth: %d",cd); if (cd==8) { for (x=0;x<=255;x++) newcolors[x] = -1; select_palette(inpal); } if (strcmp(palfile,"") == 0) outpal = (PALETTE*)&common; else outpal = (PALETTE*)&inpal; for (y=0;y<bmp->h;y++) for (x=0;x<bmp->w;x++) { col = getpixel(bmp,x,y); if ((transb) && (transc == col)) newcol = 0; else { if (cd==8 && newcolors[col] != -1) newcol = newcolors[col]; else { if (getr_depth(cd,col)==oldtrans.r && getg_depth(cd,col)==oldtrans.g && getb_depth(cd,col)==oldtrans.b) { newcol = 0; } else if (findmethod == 'a') newcol = findcolor(getr_depth(cd,col)>>2,getg_depth(cd,col)>>2,getb_depth(cd,col)>>2); else newcol = bestfit_color(common,inpal[col].r,inpal[col].g,inpal[col].b); if (cd==8) newcolors[col] = newcol; } } putpixel(bmp,x,y,newcol); } remove(name); bmp->vtable->color_depth = 8; save_bitmap(name,bmp,*outpal); destroy_bitmap(bmp); count++; printf("\r %d files modified",count); fflush(stdout); /* Create backup files */ /* char *fil; fil = (char*)malloc(255); strcpy(fil,name); fil[strlen(name)-1] = '~'; rename(name,fil); free((void*)fil);*/ } /* Writes syntax on the screen */ void write_syntax_fix(void) { printf(" Syntax: fixpal.exe [method] infile [infile [infile]...] [options]\n"); printf(" method - method you want to use (s,g,c)\n"); printf(" infile - graphic file(s) in format tga,pcx,bmp (use wildcard\n"); printf(" or filelist (add '@' before filelist name))\n\n"); printf(" Options:\n"); printf(" -pfilename : save palette ONLY to specified file\n"); printf(" -mcol : set max number of colors in palette\n"); printf(" -fx : finding best color method (x = a,b)\n"); printf(" -tr,g,b : set rgb structure of transparent color\n"); printf(" -ntr,g,b : set rgb structure of new transparent color\n"); printf(" -llogfile : creates logfile\n"); printf(" -r : reduce hi/truecolor files to 8 bit before processing\n"); printf(" for method s\n"); printf(" -Tc : set original transparent color (can't combine with -t)\n"); printf(" -sc : set color tolerance (0-255)\n"); printf(" for method c\n"); printf(" -ifilename : re-map bitmaps' color to palette in this file\n"); } void for_each_file_in_filelist(char *name,void (*callback)()) { FILE *f; char fil[255]; f = fopen(name,"r"); if (f) { while (!feof(f)) { fscanf(f,"%s\n",fil); if (exists(fil)) (*callback)(fil,0,0); } fclose(f); } } /* Reads palettes of all files specified */ void read_palettes(void) { int x; printf(" - reading palettes...\n"); count=0; for (x=0; x<bitmapno;x++) if (bitmaps[x][0] == '@') for_each_file_in_filelist(bitmaps[x],readpal); else for_each_file(bitmaps[x],FA_ARCH,readpal,0); printf("\n"); if (count == 0) { printf(" no files found !\n"); exit(255); } // printf(" Total colors: %d\n",colors); } /* Modifies structure of bitmap (replace old colors with new) */ void modify_bitmaps(void) { int x; count=0; printf(" - modifying bitmaps...\n"); for (x=0; x<bitmapno;x++) { if (bitmaps[x][0] == '@') for_each_file_in_filelist(bitmaps[x],modifybmp); else for_each_file(bitmaps[x],FA_ARCH,modifybmp,0); } printf("\n"); } /* Writes palette to file */ void write_palette(void) { BITMAP *bmp; printf(" - writing palette...\n"); bmp = create_bitmap(1,1); save_bitmap(palfile,bmp,common); destroy_bitmap(bmp); } /* Set default options */ void default_options_fix() { maxcolors = 256; /* Color 0 is ALWAYS RGB 0,0,0 ! */ common[0].r = 0; common[0].g = 0; common[0].b = 0; colors = 1; remap=1; strcpy(palfile,""); set_color_conversion(COLORCONV_NONE); strcpy(logfile,""); strcpy(inputpal,""); newtranb = 0; method = 'g'; tolerance = 0; findmethod = 'a'; transb = 0; bitmapno = 0; } /* Read FixPal options */ void read_options_fix(int argc, char *argv[]) { int x,setted=0; char s[255]; sscanf(argv[1],"%s",&s); if ((s[0] != 's') && (s[0] != 'c') && (s[0] != 'g') && (strlen(s)==1)) { printf("Invalid method specified: %c.\n",s[0]); exit(255); } if (strlen(s)==1) method = s[0]; for (x=1;x<=argc-1;x++) { if ((argv[x][0] != '-') && (strlen(argv[x])>1)) { if (bitmapno == 254) { printf("Too many wildcards/files/filelists ! (Max 255) \n"); exit(0); } strcpy(bitmaps[bitmapno],argv[x]); bitmapno++; } if ((argv[x][0] == '-') && (argv[x][1] == 'p')) { sscanf(argv[x]+2,"%s",palfile); remap=0; } if ((argv[x][0] == '-') && (argv[x][1] == 'l')) { sscanf(argv[x]+2,"%s",logfile); } if ((argv[x][0] == '-') && (argv[x][1] == 'i')) { if (method != 'c') { printf("-i parameter only allowed in c method!\n"); exit(255); } sscanf(argv[x]+2,"%s",inputpal); } if ((argv[x][0] == '-') && (argv[x][1] == 'm')) { sscanf(argv[x]+2,"%d",&maxcolors); if ((maxcolors > 256) || (maxcolors <= 0)) { printf("Invalid number of colors: %d.\n",maxcolors); exit(1); } } if ((argv[x][0] == '-') && (argv[x][1] == 'r')) { set_color_conversion(COLORCONV_REDUCE_TO_256); } if ((argv[x][0] == '-') && (argv[x][1] == 's')) { if (method != 's') { printf("-s parameter only allowed in s method!\n"); exit(255); } sscanf(argv[x]+2,"%d",&tolerance); if ((tolerance > 255) || (tolerance <= 0)) { printf("Invalid tolerance: %d.\n",tolerance); exit(1); } } if ((argv[x][0] == '-') && (argv[x][1] == 't')) { if (method != 's' && method != 'g') { printf("-t parameter only allowed in s and g method!\n"); exit(255); } if (setted) { printf("You can't combine parameter -t with -T\n"); exit(0); } sscanf(argv[x]+2,"%d,%d,%d",&common[0].r,&common[0].g,&common[0].b); setted = 1; } if ((argv[x][0] == '-') && (argv[x][1] == 'f')) { sscanf(argv[x]+2,"%c",&findmethod); if (findmethod != 'a' && findmethod != 'b') { printf("Invalid finding method: %c\n",findmethod); exit(255); } } if ((argv[x][0] == '-') && (argv[x][1] == 'T')) { if (method != 's') { printf("-T parameter only allowed in s method!\n"); exit(255); } if (setted) { printf("You can't combine parameter -T with -t\n"); exit(0); } sscanf(argv[x]+2,"%d",&transc); setted = 1; transb = 1; } if ((argv[x][0] == '-') && (argv[x][1] == 'n') && (argv[x][2] == 't')) { if (method != 's' && method != 'g') { printf("-nt parameter only allowed in s and g method!\n"); exit(255); } sscanf(argv[x]+3,"%d,%d,%d",&newtrans.r,&newtrans.g,&newtrans.b); newtranb=1; } } if (!remap && (strcmp(palfile,"") == 0)) { printf("You have to specify output palette file (-p parameter).\n"); exit(255); } } /* Load custom common palette from bitmap file */ void load_palette(void) { BITMAP *bmp; bmp = load_bitmap(inputpal,common); if (bmp) { destroy_bitmap(bmp); colors = maxcolors; } else { printf("Palette file '%s' doesn't exists !\n",inputpal); exit(255); } scale_palette(&common); } /* Guess method. Reduces colors -> maxcolors */ void reduce_colors() { unsigned int x,z,f,n,a,p; PALETTE newpal; unsigned int unique_colors=colors; if (colors <= maxcolors) return; colors=1; newpal[0]=common[0]; for (z=1;z<maxcolors;z++) { // Find furthest color of it's nearest neighbor f = 0; p = 0; for (x=0;x<unique_colors;x++) { n = 200000; if (z==1) { distances[x] = distance(newpal[0],common[x]); n = distances[x]; } else { a = distance(newpal[z-1],common[x]); if (a < distances[x]) { n = a; distances[x] = a; } n=distances[x]; } if (f < n) { f = n; p = x; } } newpal[z] = common[p]; } colors = maxcolors; memcpy(common,newpal,colors*sizeof(RGB)); } /* Begin of FixPal module */ void fixpal(int argc, char *argv[]) { struct date d; struct time t; default_options_fix(); read_options_fix(argc,argv); if (strcmp(logfile,"") != 0) { filelog = fopen(logfile,"wt"); getdate(&d); gettime(&t); save_to_log("Log file started %d/%d/%d %d:%d:%d",d.da_day,d.da_mon,d.da_year,t.ti_hour,t.ti_min,t.ti_sec); } /* Set colors limit */ switch (method){ case 's': limit = maxcolors; break; case 'g': limit = 65535; break; } /* Create common palette */ oldtrans=common[0]; switch (method){ case 's': case 'g': read_palettes(); break; case 'c': load_palette(); break; } if (method=='g') reduce_colors(); if (newtranb) { common[0].r = newtrans.r; common[0].g = newtrans.g; common[0].b = newtrans.b; } unscale_palette(&common); /* Final remap */ if (remap) modify_bitmaps(); /* Save palette if needed */ if (strcmp(palfile,"") != 0) write_palette(); if (strcmp(logfile,"") != 0) fclose(filelog); }