/* PCX2PBM v0.0 - Copyright (c) 1996 by Dave Humphrey - aj589@freenet.carleton.ca * Converts PCX to Planer bitmaps and vice-versa */ //Some conversion routines I got from a BMP conversion source code #define HexToLong(Start) (unsigned long)(*(Start) & 0xff) + \ (unsigned long)((*(Start + 1) << 8) & 0xffff) + \ (unsigned long)(((unsigned long)*(Start+3) << 24) & 0xffffffffl) + \ (unsigned long)(((unsigned long)*(Start+2) << 16) & 0xffffffl) #define HexToInt(Start) (unsigned int)(*(Start) & 0xff) + \ (unsigned int)((*(Start + 1) << 8) & 0xffff) //General include files #include #include #include #include #include #include #include #include //Include files for the graphics routines, can remove if your using/creating //your own #include "c:\tc\xlib612\include\xlib.h" #include "c:\tc\xlib612\include\xpal.h" #include "c:\tc\xlib612\include\xpoint.h" #include "c:\tc\xlib612\include\xrect.h" #include "c:\tc\xlib612\include\xtext.h" #include "c:\tc\xlib612\include\xbmtools.h" #include "c:\tc\xlib612\include\xpbitmap.h" #define VERSION 0.10 #define CR 0x0A //Standard boolean type typedef enum {TRUE = 1, FALSE = 0} boolean; //STRUCTURES typedef struct RBG_color_typ { unsigned char red, green, blue; } RGB_color, *RGB_color_ptr; typedef struct pcx_header_typ { char manufacturer; char version; char encoding; char bits_per_pixel; int x,y; int width,height; int horz_res; int vert_res; char ega_palette[48]; char reserved; char num_color_planes; int bytes_per_line; int palette_type; char padding[58]; } pcx_header, *pcx_header_ptr; typedef struct pcx_picture_typ { pcx_header header; RGB_color palette[256]; char far *buffer; } pcx_picture, *pcx_picture_ptr; typedef struct pbm_picture_typ { unsigned int width, height; unsigned int image_size; char far *data; } pbm_picture, *pbm_picture_ptr; //Procedure/function prototypes void bug (char *string, char *filename); void chrcat (char *buf, const char ch); void display_help (void); unsigned get_filesize (const char *filename); int find_color (char *pal); boolean if_exist (const char *filename); void int_to_hex (unsigned int i, char *buf); boolean load_config (char *filename); boolean load_pcx (char *filename, pcx_picture_ptr image, char *pal); boolean load_pal (char *pal, char *file); boolean load_pbm (pbm_picture_ptr picture_ptr, char *file_ptr); boolean load_font (char *userfont); void long_to_hex (unsigned long i, char *buf); void put_pcx (int x, int y, unsigned int width, unsigned int height, char far *pic); boolean save_pal (char *pal, const char *filename); boolean save_pbm (char *filename, pbm_picture_ptr pic); boolean save_pcx (pcx_picture_ptr pic, char *pal, char *filename); char pal_path[80] = ".\\"; char pbm_path[80] = ".\\"; char pcx_path[80] = ".\\"; char bak_path[80] = ".\\"; int c; //========= Notifies User of a bug/error ==================================== void bug(char *string, char *filename) { /* General error message routine notifying user of an error */ x_text_mode(); //Switch to text mode clrscr(); printf ("DAGPIC.C v%3.2f, 27 November 1996, Dave Humphrey\n", VERSION); printf ("BUG: %s\n", string); if (filename != NULL) printf ("Filename = %s\n", filename); printf ("\n\n"); _exit(1); //Exit program } //========= End of procedure bug() ========================================== //========= Appends a character to end of string ============================ void chrcat(char *buf, const char ch) { int i = strlen(buf); *(buf + i + 1) = '\0'; *(buf + i) = ch; } //========= End of procedure chrcat() ======================================= //========= Displays a simple help screen =================================== void display_help(void) { printf ("\n"); printf ("PCX2PBM v%3.2f Copyright (c) 1996 - Dave Humphrey\n", VERSION); printf ("Converts PCX to PBM and vice-versa.\n\n"); printf (" PCX2PBM filename [options]\n\n"); printf (" Options...\n"); printf (" filename - The PBM file you wish to convert\n"); printf (" /B:PCX file - The PCX file you wish to convert\n"); printf (" /2[pcx, pbm] - Convert PBM-PCX or PCX-PBM\n"); printf (" [/P:palette] - Saves the palette from PCX's\n"); printf (" [/D] - Display image, otherwise no output to screen\n"); printf ("Bugs/comments etc... can be E-Mailed to: aj589@freenet.carleton.ca\n\n"); } //========= End of procedure display_help() ================================= //========= Finds the 'whitest' in palette Color for Box+Text =============== int find_color(char *pal) { /* Looks for the color with the highest average in the current palette. * This color is returned and used for printing text etc...*/ int y, r, b, g, avg; int best_c = 255, max_avg = 0; for (y = 0; y < 255; y++) { //Look through all colours in paleete //Read the 3 color values, red, green, and blue r = (int) *pal; pal++; g = (int) *pal; pal++; b = (int) *pal; pal++; avg = (r + g + b) / 3; //Compute the average if (avg > max_avg) { //Compare with maximum average max_avg = avg; best_c = y; } } return(best_c); } //========= End of function find_color() ==================================== //========= Returns the size of the file ==================================== unsigned int get_filesize(const char *filename) { FILE *f; struct stat file_stat; if (!if_exist(filename)) return(0); f = fopen(filename, "r"); fstat(fileno(f), &file_stat); fclose(f); return((unsigned int)file_stat.st_size); } //========= End of function get_filesize() ================================== //========= Returns TRUE if file exists ===================================== boolean if_exist(const char *filename) { FILE *f; //Attempt to open file if ((f = fopen(filename, "r")) == NULL) return(FALSE); fclose(f); //File was opened and therefore exists, close it return(TRUE); } //========= End of function if_exist() ====================================== //========== Converts a Int to Hexadecimal String =========================== void int_to_hex (unsigned int i, char *buf) { unsigned int rem, div; rem = i/256; div = i - rem * 256; *(buf + 1) = (unsigned char) rem; *(buf) = (unsigned char) div; *(buf + 2) = '\0'; } //========== End of procedure int_to_hex() ================================== //========== Attempts to Load and Parse a Config file ======================= boolean load_config(char *filename) { FILE *f; char ch, buffer[101], *temp_ptr, buffer1[101], *temp_ptr1; char command[21], arg[81]; boolean done = FALSE; if ((f = fopen(filename, "rt")) == NULL) return(FALSE); do { buffer[0] = '\0'; do { ch = fgetc(f); chrcat(&buffer[0], ch); } while (ch != CR && strlen(buffer) < 100 && ch != EOF); if (ch == EOF) { done = TRUE; buffer[strlen(buffer) - 1] = CR; } else if (ch == CR) buffer[strlen(buffer) - 1] = 0; temp_ptr = &buffer[0]; if (*temp_ptr != '#') { while (*temp_ptr == 32 && *temp_ptr != CR) //Remove leading spaces temp_ptr++; if (*temp_ptr != CR) { strcpy(buffer1, temp_ptr); temp_ptr1 = &buffer[0]; while (*temp_ptr1 != 32 && *temp_ptr1 != CR) temp_ptr1++; if (*temp_ptr1 != CR) { *temp_ptr1 = 0; strcpy(command, buffer); temp_ptr1++; while (*temp_ptr1 == 32 && *temp_ptr1 != CR) //Remove mid spaces temp_ptr1++; if (*temp_ptr1 != CR) { strcpy(buffer, temp_ptr1); while (*temp_ptr1 != 32 && *temp_ptr1 != CR) temp_ptr1++; *temp_ptr1 = 0; strcpy(arg, buffer); if (strcmp(arg, ".") == 0) arg[0] = 0; if (strcmpi(command, "pal") == 0) strcpy(pal_path, arg); else if (strcmpi(command, "pbm") == 0) strcpy(pbm_path, arg); else if (strcmpi(command, "pcx") == 0) strcpy(pcx_path, arg); else if (strcmpi(command, "bak") == 0) strcpy(bak_path, arg); else if (strcmpi(command, "end") == 0) done = TRUE; } } } } //End of if != '#' } while (!done); fclose(f); return(TRUE); } //========== End of function load_config ==================================== //========= Loads the game pallette into memory ============================= boolean load_pal (char *pal, char *file) { int count; FILE *f; if ((f = fopen (file, "rb")) == NULL) bug("Could not open palette file!", file); for (count = 1; count < 256*3; count++) { *pal = fgetc(f); pal = pal + 1; } fclose(f); return (TRUE); } //========= End of procedure load_pal() ===================================== //========= Loads a picture named *file_ptr into picture_ptr ================ boolean load_pbm(pbm_picture_ptr picture_ptr, char *file_ptr) { int count; unsigned image_size; char *data_ptr; FILE *f; if ((f = fopen (file_ptr, "rb")) == NULL) return (FALSE); picture_ptr->width = 4*fgetc(f); picture_ptr->height = fgetc(f); image_size = picture_ptr->height*picture_ptr->width; if ((picture_ptr->data = (char *) farmalloc(image_size + 3)) == NULL) return (FALSE); data_ptr = picture_ptr->data; *data_ptr = picture_ptr->width/4; data_ptr++; *data_ptr = picture_ptr->height; data_ptr++; for (count = 1; count <= image_size; count++) { *data_ptr = fgetc(f); data_ptr++; } fclose(f); return (TRUE); } //========== End of load_pbm() ============================================== //========== Loads a user defined font into memory ========================== boolean load_font (char *userfont) { FILE *f; char font_file[16] = "smalthin.fnt", ch; if ((f = fopen (font_file, "rb")) == NULL) return (FALSE); do { ch = fgetc (f); *userfont = ch; userfont++; } while (ch != EOF); fclose (f); return (TRUE); } //========== End of procedure load_font() =================================== //========= Loads a PCX into memory and converts it to IMG structure ======== boolean load_pcx(char *filename, pcx_picture_ptr image, char *pal) { // this function loads a pcx file into a picture structure, the actual image // data for the pcx file is decompressed and expanded into a secondary buffer // within the picture structure, the separate images can be grabbed from this // buffer later. also the header and palette are loaded FILE *fp; int num_bytes, i, row_diff, row, bytes; unsigned int count, image_size; unsigned char data; char far *temp_buffer; //open the file if ((fp = fopen(filename, "rb")) == NULL) bug("Could not open PCX file!", filename); //load the header temp_buffer = (char far *)image; for (i = 0; i < 128; i++) { temp_buffer[i] = (char)getc(fp); } // end for index image->header.width++; image->header.height++; // load the data and decompress into buffer count = 0; i = 0; if ((image->buffer = (char far *) farmalloc(image->header.width * image->header.height + 3)) == NULL) bug("Could not allocate PCX buffer!", NULL); image->buffer[0] = (unsigned char) image->header.width; image->buffer[1] = (unsigned char) image->header.height; row_diff = image->header.bytes_per_line - image->header.width; image_size = image->header.width * image->header.height; row = 0; bytes = 0; while(count <= image_size) { // is this a rle? if (row_diff > 0 && i >= image->header.width) { //Remove row padding if (i == image->header.bytes_per_line) { i = 0; row++; count--; } else if (i >= image->header.width) { i = 0; row++; while (i != row_diff) { data = (unsigned char) getc(fp); bytes++; if (data >= 192) { data = (unsigned char)getc(fp); bytes++; } i++; } i = 0; } } else { // get the first piece of data data = (unsigned char) getc(fp); bytes++; if (data >= 192) { // how many bytes in run? num_bytes = data - 192; // get the actual data for the run data = (unsigned char)getc(fp); bytes++; // replicate data in buffer num_bytes times while(num_bytes-- > 0) { *(image->buffer + count + 2) = data; count++; i++; } // end while } // end if rle else { // actual data, just copy it into buffer at next location *(image->buffer + count + 2) = data; count++; i++; } // end else not rle }//End of else not row padding } // end while fseek(fp,-768L,SEEK_END); //load the pallete into the palette for (i = 0; i < 256; i++) { //get the red component image->palette[i].red = (unsigned char)(getc(fp) >> 2); *pal = image->palette[i].red; pal++; //get the green component image->palette[i].green = (unsigned char)(getc(fp) >> 2); *pal = image->palette[i].green; pal++; //get the blue component image->palette[i].blue = (unsigned char)(getc(fp) >> 2); *pal = image->palette[i].blue; pal++; } //end for i return(TRUE); } //========== End of function load_pcx() ===================================== //========== Converts a Long Int to Hexadecimal String ====================== void long_to_hex (unsigned long i, char *buf) { unsigned long rem, div; rem = i/256/256/256; div = i - rem * 256 * 256 * 256; *(buf + 3) = (unsigned char) rem; rem = div/256/256; div = div - rem * 256 * 256; *(buf + 2) = (unsigned char) rem; rem = div/256; div = div - rem * 256; *(buf + 1) = (unsigned char) rem; *(buf) = (unsigned char) div; *(buf + 4) = '\0'; } //========== End of procedure long_to_hex() ================================= //========== Puts a PCX Image onto the Screen =============================== void put_pcx (int x, int y, unsigned int width, unsigned int height, char far *pic) { int x1, y1, i = 0; pic += 2; //Skip height+width info... //Print out the image for (y1 = y; y1 < y + height; y1++) for (x1 = x; x1 < x + width; x1++, i++, pic++) x_put_pix(x1, y1, VisiblePageOffs, *pic); //Replace with put_pixel routine if not using XLIB library } //========== End of procedure put_pcx() ===================================== //========= Saves the game pallette to disk ================================= boolean save_pal (char *pal, const char *filename) { int count; char ch; FILE *f; if (if_exist(filename)) { printf ("\nFile %s already exists. Overwrite? [y/n]?", filename); do { ch = toupper(getch()); } while (ch != 'Y' && ch != 'N' && ch != 27); printf("\n"); if (ch != 'Y') return(FALSE); } //End of if file exists if ((f = fopen (filename, "wb")) == NULL) return(FALSE); for (count = 0; count < 256*3; count++) { fputc(*pal, f); pal = pal + 1; } fclose(f); return (TRUE); } //========= End of procedure load_pal() ===================================== //========== Saves a PBM - planer bitmap ==================================== boolean save_pbm(char *filename, pbm_picture_ptr pic) { FILE *f; unsigned int i; char *data_ptr, ch; if (if_exist(filename)) { //Does file already exist? printf ("\nFile %s already exists. Overwrite [y/n]?", filename); do { ch = toupper(getch()); } while (ch != 'Y' && ch != 'N' && ch != 27); printf("\n"); if (ch != 'Y') return(FALSE); } //Overwrite file for writing new data if ((f = fopen(filename, "wb")) == NULL) return(FALSE); data_ptr = pic->data; for (i = 0; i < pic->image_size + 2; i++) { fputc(*data_ptr, f); data_ptr++; } fclose(f); return(TRUE); } //========== End of function save_pbm() ===================================== //========== Saves pcx to disk ============================================== boolean save_pcx (pcx_picture_ptr pic, char *pal, char *filename) { /* I got some of this from some pcx source code file but alot from * actually looking at a pcx file. There are a few numbers near the * beginning which I don't know what they are, and a few other things * which I don't understand, but for the most part it works... */ int x, y = 1, num; unsigned int image_size; char buffer[80], pre, *temp_ptr, ch; FILE *f; //Attempt to open file for writing to if (if_exist(filename)) { printf ("\nFile %s already exists. Overwrite? [y/n]?", filename); do { ch = toupper(getch()); } while (ch != 'Y' && ch != 'N' && ch != 27); printf("\n"); if (ch != 'Y') return(FALSE); } //End of if file exists if ((f = fopen(filename, "wb")) == NULL) return(FALSE); fputc(10, f); fputc(5, f); fputc(1, f); //Encoding? fputc(8, f); fputc(0, f); fputc(0, f); fputc(0, f); fputc(0, f); int_to_hex(pic->header.width - 1, &buffer[0]); //Write Width, height int_to_hex(pic->header.height - 1, &buffer[2]); fwrite(buffer, sizeof(char), 4, f); int_to_hex(360, &buffer[0]); fwrite(buffer, sizeof(char), 2, f); fwrite(buffer, sizeof(char), 2, f); for (x = 0; x < 48; x++) fputc (0, f); //EGA Palette fputc(0, f); fputc(1, f); //Color planes? int_to_hex(pic->header.width, &buffer[0]); //Write Width - Bytes/line fwrite(buffer, sizeof(char), 2, f); fputc (1, f); //256 color fputc (0, f); fputc (0, f); fputc(4, f); fputc(0, f); fputc(3, f); for (x = 0; x < 54; x++) fputc(0, f); //Padding temp_ptr = (pic->buffer + 2); image_size = pic->header.width * pic->header.height; pre = *temp_ptr; temp_ptr++; for (x = 0; x < image_size - 1; x++) { num = 1; while (*temp_ptr == pre && num < 63 && y != pic->header.width) { temp_ptr++; num++; x++; y++; } if ((unsigned char)pre < 192 && num == 1) fputc(pre, f); else if (num == 1) { fputc(193, f); fputc(pre, f); } else { //RLE... fputc((char)(192+num), f); fputc(pre, f); } if (y == pic->header.width) y = 0; pre = *temp_ptr; temp_ptr++; y++; } fputc(0x0C, f); //? //Write palette data for (x = 0; x < 256*3; x++) { fputc((*pal)*4, f); pal++; } fclose(f); return(TRUE); } //========== End of procedure save_pcx() ==================================== //========== Begin main program ============================================= int main (int argv, char *argc[]) { pbm_picture picture; //Pointer to hold picture data pcx_picture pcx_pic; char *temp_ptr; //Temp variables char *pal, pal_filename[80]; //Palette pointer and filename char *smalthin; //Hold font data char filename[80], pcx_filename[80]; //pcx filename and file to load char bak_filename[80]; //Temp string, backup filename int i; //Loop counters boolean pcx_file = FALSE, pbm_file = FALSE, display = FALSE; //Toggles boolean convert_to_pcx = FALSE, pal_file = FALSE; load_config("pcx2pbm.cfg"); strcpy(pal_filename, pal_path); strcat(pal_filename, "default.pal"); strcpy(filename, "NULL"); strcpy(pcx_filename, "NULL"); if (argv > 1) { //Make sure there are arguments //Check ARGs for commands for (i = 1; i < argv;i ++) { //Palette if ((temp_ptr = strstr(strupr(argc[i]), "/P:")) != NULL) { if (strlen(argc[i]) > 3) { strcpy(pal_filename, pal_path); strcat(pal_filename, temp_ptr + 3); //Move to start of palette filename pal_file = TRUE; } } //Don't display image else if ((temp_ptr = strstr(strupr(argc[i]), "/D")) != NULL && !display) { display = TRUE; } //Convert to PBM/PCX? else if ((temp_ptr = strstr(strupr(argc[i]), "/2")) != NULL && !convert_to_pcx) { if (strlen(temp_ptr) > 2) { //Make sure we have a proper string... temp_ptr += 2; if (stricmp(temp_ptr, "pcx") == 0) convert_to_pcx = TRUE; else if (stricmp(temp_ptr, "pbm") == 0) convert_to_pcx = FALSE; } } //End of convert pcx //Specify PCX name else if ((temp_ptr = strstr(strupr(argc[i]), "/B:")) != NULL && !pcx_file) { if (strlen(argc[i]) > 3) { strcpy(pcx_filename, pcx_path); strcat(pcx_filename, temp_ptr + 3); pcx_file = TRUE; } } //end of if /B: //Help screen else if (strchr(argc[i], '?') != NULL) { display_help(); exit(0); } else if (!pbm_file) { //Must be image filename strcpy(bak_filename, bak_path); strcat(bak_filename, argc[i]); strcpy(filename, pbm_path); strcat(filename, argc[i]); pbm_file = TRUE; } } //End of for arg loop if (display && pbm_file && !pcx_file) convert_to_pcx = TRUE; if ((pal = (char *) malloc (800)) == NULL) bug("Could not allocate 800 Bytes!", NULL); if (!convert_to_pcx) { //Convert from PCX to PBM... if (pcx_file) { //Load PCX if (!load_pcx(pcx_filename, &pcx_pic, pal)) bug("Failed to read PCX file!", pcx_filename); if (display) { if ((smalthin = (char *) malloc(800)) == NULL) bug("Could not allocate 800 Bytes!", NULL); if (!load_font(smalthin)) bug("Could not load font file!", NULL); c = find_color(pal); if (x_set_mode (8, 360) == -1) bug("Error: Could not initialize graphics mode!", NULL); x_text_init(); //Setup the text functions x_register_userfont(smalthin); x_set_font(2); x_put_pal_raw ((unsigned char *) pal, 256, 0); temp_ptr = &pcx_pic.buffer[0]; x_rect_fill(0, 0, pcx_pic.header.width + 2, pcx_pic.header.height + 2, VisiblePageOffs, c); //Display image bounding box put_pcx (1, 1, pcx_pic.header.width, pcx_pic.header.height, temp_ptr); x_printf(1, 180, VisiblePageOffs, c, "%s - %d x %d", pcx_filename, pcx_pic.header.width, pcx_pic.header.height); x_printf (1, 190, VisiblePageOffs, c, "Press any key to Continue...."); getch(); x_text_mode(); free (smalthin); } //Make sure we have a filename to convert to if (!pbm_file) bug("Must specify PBM file to save PCX as!", NULL); //Allocate memory for PBM if ((picture.data = (char far *) farmalloc(pcx_pic.header.width * pcx_pic.header.height + 3)) == NULL) bug("Could not allocate PBM picture!", NULL); picture.image_size = pcx_pic.header.width * pcx_pic.header.height; picture.width = pcx_pic.header.width; picture.height = pcx_pic.header.height; if (x_bm_to_pbm(&pcx_pic.buffer[0], picture.data) != 0) bug("Failed to convert PCX to PBM!", pcx_filename); if (save_pbm(filename, &picture)) printf("\n%s successfully converted to %s.\n", pcx_filename, filename); else printf("\n%s WAS NOT successfully converted to %s!\n", pcx_filename, filename); if (pal_file) { if (save_pal(pal, pal_filename)) printf("\n%s's palette successfully converted to %s.\n", pcx_filename, pal_filename); else printf("\n%s's palette WAS NOT successfully converted to %s!\n", pcx_filename, pal_filename); } printf("\n"); } else bug("Must specify PCX file to convert!", NULL); } //End of if (convert_pcx) else { //Convert from PBM to PCX if (pbm_file) { //Load PBM and Pal if (!load_pbm(&picture, filename)) bug("Could not load image!", filename); if (!load_pal(pal, pal_filename)) bug("Could not load palette!", pal_filename); //Load the palette if (display) { if ((smalthin = (char *) malloc(800)) == NULL) bug("Could not allocate 800 Bytes!", NULL); if (!load_font(smalthin)) bug("Could not load font file!", NULL); c = find_color(pal); if (x_set_mode (8, 360) == -1) bug("Error: Could not initialize graphics mode!", NULL); x_text_init(); //Setup the text functions x_register_userfont(smalthin); x_set_font(2); x_put_pal_raw ((unsigned char *) pal, 256, 0); x_rect_fill(0, 0, picture.width + 2, picture.height + 2, VisiblePageOffs, c); //Display image bounding box x_put_pbm(1, 1, VisiblePageOffs, (unsigned char *) picture.data); x_printf(1, 180, VisiblePageOffs, c, "%s - %d x %d", filename, picture.width, picture.height); x_printf (1, 190, VisiblePageOffs, c, "Press any key to Continue...."); getch(); x_text_mode(); free (smalthin); } if (!pcx_file) bug("Must specify PCX file to save as!", NULL); if ((pcx_pic.buffer = (char far *) farmalloc(picture.width * picture.height + 3)) == NULL) bug("Could not allocate PCX buffer!", NULL); pcx_pic.header.width = picture.width; pcx_pic.header.height = picture.height; if (x_pbm_to_bm(picture.data, pcx_pic.buffer) != 0) bug("Failed to convert PBM to PCX!", pcx_filename); if (save_pcx(&pcx_pic, pal, pcx_filename)) printf("\n%s successfully converted to %s.\n\n", filename, pcx_filename); else printf("\n%s WAS NOT successfully converted to %s!\n\n", filename, pcx_filename); } else bug("Must specify PBM file to convert!", NULL); } //End of else (!convert_pcx) farfree (picture.data); farfree (pcx_pic.buffer); free (pal); } else { //No arguments display_help(); } printf ("Farheapcheck() = %d\n\n", farheapcheck()); return (TRUE); } //========== End of program =================================================