/*========================================================================= * * PCX.CPP - 1 December 1998, Dave Humphrey * * General routines for handling PCX files. * *=======================================================================*/ /* Required Includes */ #include "pcx.h" /*========================================================================= * * Class CPCXHeader Method - void Destroy (void); * *=======================================================================*/ void CPCXHeader::Destroy (void) { Manufacturer = 10; Version = 5; Encoding = 1; BitsPerPixel = 8; X = Y = 0; Width = Height = 0; HorzResolution = VertResolution = 150; Reserved = 0; NumColorPlanes = 1; BytesPerLine = 0; PaletteType = 1; memset (EGAPalette, 0, 48); memset (Padding, 0, 58); Padding[0] = 0; Padding[1] = 4; Padding[2] = 0; Padding[3] = 3; } /*========================================================================= * End of Class Method CPCXHeader::Destroy() *=======================================================================*/ /*========================================================================= * * Class CPCXHeader Method - boolean Read (pFileHandle); * * Attempts to read in the header from the given file handle. Returns * FALSE on any error. * *=======================================================================*/ boolean CPCXHeader::Read (FILE* pFileHandle) { int Result; /* Load the header all at once */ Result = fread (&Manufacturer, sizeof(char), 128, pFileHandle); if (Result != 128) { SET_EXT_ERROR(ERR_READ); return (FALSE); } /* Adjust now to make life easier */ Width++; Height++; return (TRUE); } /*========================================================================= * End of Class Method CPCXHeader::Read() *=======================================================================*/ /*========================================================================= * * Class CPCXHeader Method - boolean Write (pFileHandle); * * Attempts to write the header to the given file handle. Returns * FALSE on any error. * *=======================================================================*/ boolean CPCXHeader::Write (FILE* pFileHandle) { int Result; /* Adjust to make life easier */ Width--; Height--; /* Write the header all at once */ Result = fwrite (&Manufacturer, sizeof(char), 128, pFileHandle); if (Result != 128) { SET_EXT_ERROR(ERR_WRITE); return (FALSE); } /* Readjust */ Width++; Height++; return (TRUE); } /*========================================================================= * End of Class Method CPCXHeader::Write() *=======================================================================*/ /*========================================================================= * * Class CPCXImage Destructor * *=======================================================================*/ void CPCXImage::Destroy (void) { /* Delete the allocated image, if any */ DestroyPointer(pData); /* Clear the header info */ Header.Destroy(); } /*========================================================================= * End of Class CPCXImage Destructor *=======================================================================*/ /*========================================================================= * * Class PCXImage Method - boolean ExportLBM (pFilename, Width, Height, pImage, pPalette); * * Allows the specification of a custom palette when saving the PCX. * The palette is a RGB color entries at least 256 colors in size (768 bytes). * *=======================================================================*/ boolean CPCXImage::ExportLBM (const char* pFilename, const int Width, const int Height, byte* pImage, const byte* pPalette) { /* Make sure all the pointers and inputs are valid */ if (!pPalette) { SET_EXT_ERROR(ERR_NULL); return (FALSE); } /* Set the appropiate values */ memcpy ((void*)pPalette, Palette, 768); /* Call the non-palette version */ return (ExportLBM(pFilename, Width, Height, pImage)); } /*========================================================================= * End of Class Method CPCXImage::ExportLBM() *=======================================================================*/ /*========================================================================= * * Class PCXImage Method - boolean ExportLBM (pFilename, Width, Height, pImage); * * 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 current * PCX image is destroyed, if any. Returns FALSE on any error. * *=======================================================================*/ boolean CPCXImage::ExportLBM (const char* pFilename, const int Width, const int Height, byte* pImage) { /* Make sure all the pointers and inputs are valid */ if (!pFilename || !pImage || !Width || !Height) { SET_EXT_ERROR(ERR_NULL); return (FALSE); } /* Destroy the current image */ Destroy(); /* Set the appropiate values */ Header.Width = Width; Header.Height = Height; Header.BytesPerLine = Width; pData = pImage; /* Reference image pointer _temporarily_ */ /* Attempt to save the image */ if (!Save(pFilename)) { pData = NULL; Destroy(); return (FALSE); } pData = NULL; Destroy(); return (TRUE); } /*========================================================================= * End of Class Method CPCXImage::ExportLBM() *=======================================================================*/ /*========================================================================= * * Class CPCXImage Method - boolean Load (pFilename); * * Attempts to read in the specified PCX file. Returns FALSE on any error. * *=======================================================================*/ boolean CPCXImage::Load (const char* pFilename) { FILE* pFileHandle; unsigned long ImageSize; size_t Count = 0; int i = 0; int RowDiff = 0; int Row = 0; int Bytes = 0; int NumBytes; int Result; int ch; /* Attempt to open the file for input */ pFileHandle = openfile (pFilename, "rb"); if (pFileHandle == NULL) return (FALSE); /* Clear the current image contents, if any */ Destroy(); /* Read in the header */ if (!Header.Read(pFileHandle)) { fclose (pFileHandle); return (FALSE); } /* Make sure the image is small enough to fit */ ImageSize = ((unsigned long)Header.Width) * ((unsigned long)Header.Height) + 1; if (ImageSize > UINT_MAX) { SET_EXT_ERROR(ERR_UINTMAX); fclose (pFileHandle); return (FALSE); } /* Attempt to allocate the image data */ CreatePointerArray(pData, byte, ImageSize); /* Read in the image data */ RowDiff = Header.BytesPerLine - Header.Width; while (Count <= ImageSize) { /* Remove any row padding */ if (RowDiff > 0 && i >= Header.Width) { if (i == Header.BytesPerLine) { i = 0; Row++; Count--; } else if (i >= Header.Width) { i = 0; Row++; while (i != RowDiff) { ch = fgetc(pFileHandle); Bytes++; if (ch >= 192) { ch = fgetc(pFileHandle); Bytes++; } i++; } i = 0; } } else { /* Get some data */ ch = fgetc(pFileHandle); Bytes++; /* Is this byte a RLE code? */ if (ch >= 192) { /* How many bytes in run? */ NumBytes = ch - 192; /* Get the actual data for the run */ ch = fgetc(pFileHandle); Bytes++; /* Replicate data in image buffer */ while (NumBytes-- > 0) { pData[Count] = (unsigned char) ch; Count++; i++; } } /* Copy data into image buffer */ else { pData[Count] = (unsigned char) ch; Count++; i++; } } } /* End while loop */ /* Read in the image palette */ fseek (pFileHandle, -768l, SEEK_END); Result = fread(Palette, sizeof(char), 768, pFileHandle); if (Result != 768) { SET_EXT_ERROR(ERR_READ); return (FALSE); } /* Close the file and return success */ fclose (pFileHandle); return (TRUE); } /*========================================================================= * End of Class Method CPCXImage::Load() *=======================================================================*/ /*========================================================================= * * Class CPCXImage Method - boolean Save (pFilename); * * Attempts to save the PCX image to the specified file. Returns FALSE * on any error. * *=======================================================================*/ boolean CPCXImage::Save (const char *pFilename) { FILE* pFileHandle; byte* pDataPtr; byte Pre; size_t ImageSize; size_t i; int X = 1; int Count; int Result; /* Attempt to open the file for output */ pFileHandle = openfile(pFilename, "wb"); if (pFileHandle == NULL) return (FALSE); /* Write the header information */ if (!Header.Write(pFileHandle)) { fclose (pFileHandle); return (FALSE); } /* Compute the image size */ ImageSize = Header.Width * Header.Height; pDataPtr = pData; Pre = *pDataPtr; pDataPtr++; /* Write the main image */ for (i = 0; i < ImageSize; i++) { Count = 1; while (*pDataPtr == Pre && Count < 63 && X != Header.Width) { pDataPtr++; Count++; i++; X++; } if (Pre < 192 && Count == 1) fputc (Pre, pFileHandle); else if (Count == 1) { fputc(193, pFileHandle); fputc(Pre, pFileHandle); } else { /* RLE encoded bytes */ fputc ((unsigned char)(192+Count), pFileHandle); fputc (Pre, pFileHandle); } if (X == Header.Width) X = 0; Pre = *pDataPtr; pDataPtr++; X++; } /* Need this for some reason? */ fputc(0x0C, pFileHandle); /* Write palette data */ Result = fwrite (Palette, sizeof(char), 768, pFileHandle); if (Result != 768) { fclose (pFileHandle); SET_EXT_ERROR(ERR_WRITE); return (FALSE); } /* Close the file and return success */ fclose (pFileHandle); return (TRUE); } /*========================================================================= * End of Class Method CPCXImage::Save() *=======================================================================*/ /*=========================================================================== * * Class CPCXImage Method - void SetVGAPalette (pVGAPal); * * Copies entries from the given VGA palette into the PCX palette. VGA * palette enries range from 0 to 63 so the values are multiplied by * 4 to range from 0 to 255 as a proper PCX palette. * *=========================================================================*/ void CPCXImage::SetVGAPalette (const byte* pVGAPal) { int LoopCounter; /* Ensure valid input */ if (pVGAPal == NULL) { SET_EXT_ERROR(ERR_NULL); return; } /* Translate all values */ for (LoopCounter = 0; LoopCounter < 256; LoopCounter++) { Palette[LoopCounter].R = (*pVGAPal * 4)&0xFF; pVGAPal++; Palette[LoopCounter].G = (*pVGAPal * 4)&0xFF; pVGAPal++; Palette[LoopCounter].B = (*pVGAPal * 4)&0xFF; pVGAPal++; } } /*=========================================================================== * End of Class Method CPCXImage::SetVGAPalette() *=========================================================================*/