/*========================================================================= * * PCX.CPP - 1 December 1998, Dave Humphrey * * General routines for handlign PCX files. * *=======================================================================*/ /* Required Includes */ #include "pcx.h" /*========================================================================= * * Class PCXHeader Method - void destroy (void); * *=======================================================================*/ void PCXHeader::destroy (void) { manufacturer = 10; version = 5; encoding = 1; bits_per_pixel = 8; x = y = 0; width = height = 0; horz_res = vert_res = 150; reserved = 0; num_color_planes = 1; bytes_per_line = 0; palette_type = 1; memset (ega_palette, 0, 48); memset (padding, 0, 58); padding[0] = 0; padding[1] = 4; padding[2] = 0; padding[3] = 3; } /*========================================================================= * End of Class Method PCXHeader::destroy() *=======================================================================*/ /*========================================================================= * * Class PCXHeader Method - boolean read (f); * * Attempts to read in the header from the given file handle. Returns * FALSE on any error. * *=======================================================================*/ boolean PCXHeader::read (FILE *f) { /* Load the header all at once */ if (fread (this, sizeof(char), 128, f) != 128) { err_code = ERR_READ; return (FALSE); } /* Adjust to make life easier */ width++; height++; return (TRUE); } /*========================================================================= * End of Class Method PCXHeader::read() *=======================================================================*/ /*========================================================================= * * Class PCXHeader Method - boolean write (f); * * Attempts to write the header to the given file handle. Returns * FALSE on any error. * *=======================================================================*/ boolean PCXHeader::write (FILE *f) { /* Adjust to make life easier */ width--; height--; /* Write the header all at once */ if (fwrite (this, sizeof(char), 128, f) != 128) { err_code = ERR_WRITE; return (FALSE); } /* Readjust */ width++; height++; return (TRUE); } /*========================================================================= * End of Class Method PCXHeader::write() *=======================================================================*/ /*========================================================================= * * Class PCXImage Destructor * *=======================================================================*/ void PCXImage::destroy (void) { /* Delete the allocate image, if any */ DESTROY(data); /* Clear the header info */ header.destroy(); } /*========================================================================= * End of Class PCXImage Destructor *=======================================================================*/ /*========================================================================= * * Class PCXImage Method - boolean export (file, width, height, image, pal); * * Use this function for exporting a LBM image format to a PCX file. * The image is a Linear-BitMap, the pixels lie one after another in a * linear fashion (total length is width*height). The palette is a RGB * color entries at least 256 colors in size (768 bytes). The current * PCX image is destroyed, if any. Returns FALSE on any error. * *=======================================================================*/ boolean PCXImage::export (const char *filename, const short width, const short height, unsigned char *image, const unsigned char *pal) { /* Make sure all the pointers are valid */ if (!filename || !image || !pal || !width || !height) { err_code = ERR_NULL; return (FALSE); } /* Destroy the current image */ destroy(); /* Set the appropiate values */ header.width = width; header.height = height; header.bytes_per_line = width; data = image; memcpy (palette, pal, 768); /* Attempt to save the image */ if (!save (filename)) { data = NULL; destroy(); return (FALSE); } data = NULL; destroy(); return (TRUE); } /*========================================================================= * *=======================================================================*/ /*========================================================================= * * Class PCXImage Method - boolean load (filename); * * Attempts to read in the specified PCX file. Returns FALSE on any error. * *=======================================================================*/ boolean PCXImage::load (const char *filename) { FILE *f; /* File pointer */ unsigned long image_size; size_t count = 0; int i = 0, row_diff = 0; int row = 0, bytes = 0; int num_bytes, ch; /* Attempt to open the file for input */ if (!(f = openfile (filename, "rb"))) return (FALSE); /* Clear the current image contents, if any */ destroy(); /* Read in the header */ if (!header.read(f)) { fclose (f); return (FALSE); } /* Make sure the image is small enough to fit */ image_size = ((unsigned long)header.width) * ((unsigned long)header.height) + 1; if (image_size > UINT_MAX) { err_code = ERR_64KB; fclose (f); return (FALSE); } /* Attempt to allocate the image data */ data = (unsigned char *) create_ptr ((size_t)image_size); /* Read in the image data */ row_diff = header.bytes_per_line - header.width; while (count <= image_size) { /* Remove any row padding */ if (row_diff > 0 && i >= header.width) { if (i == header.bytes_per_line) { i = 0; row++; count--; } else if (i >= header.width) { i = 0; row++; while (i != row_diff) { ch = fgetc(f); bytes++; if (ch >= 192) { ch = fgetc(f); bytes++; } i++; } i = 0; } } else { /* Get some data */ ch = fgetc(f); bytes++; /* Is this byte a RLE code? */ if (ch >= 192) { /* How many bytes in run? */ num_bytes = ch - 192; /* Get the actual data for the run */ ch = fgetc(f); bytes++; /* Replicate data in image buffer */ while (num_bytes-- > 0) { data[count] = (unsigned char) ch; count++; i++; } } /* Copy data into image buffer */ else { data[count] = (unsigned char) ch; count++; i++; } } } /* End while loop */ /* Read in the image palette */ fseek (f, -768l, SEEK_END); if (fread(palette, sizeof(char), 768, f) != 768) { err_code = ERR_READ; return (FALSE); } /* Close the file and return success */ fclose (f); return (TRUE); } /*========================================================================= * End of Class Method PCXImage::load() *=======================================================================*/ /*========================================================================= * * Class PCXImage Method - boolean save (filename); * * Attempts to save the PCX image to the specified file. Returns FALSE * on any error. * *=======================================================================*/ boolean PCXImage::save (const char *filename) { FILE *f; /* File pointer */ unsigned char *ptr, pre; size_t image_size, i; int y = 1, count; /* Attempt to open the file for output */ if (!(f = openfile (filename, "wb"))) return (FALSE); /* Write the header information */ if (!header.write(f)) { fclose (f); return (FALSE); } /* Compute the image size */ image_size = header.width * header.height; ptr = data; pre = *ptr; ptr++; /* Write the main image */ for (i = 0; i < image_size; i++) { count = 1; while (*ptr == pre && count < 63 && y != header.width) { ptr++; count++; i++; y++; } if (pre < 192 && count == 1) fputc(pre, f); else if (count == 1) { fputc(193, f); fputc(pre, f); } else { /* RLE encoded bytes */ fputc ((unsigned char)(192+count), f); fputc (pre, f); } if (y == header.width) y = 0; pre = *ptr; ptr++; y++; } /* Need this for some reason? */ fputc(0x0C, f); /* Write palette data */ if (fwrite (palette, sizeof(char), 768, f) != 768) { fclose (f); err_code = ERR_WRITE; return (FALSE); } /* Close the file and return success */ fclose (f); return (TRUE); } /*========================================================================= * End of Class Method PCXImage::save() *=======================================================================*/