/*********************************************************************************************** * * Copyright (c) 1996 DreamWorks Interactive, 1996 * * Contents: * * Bugs: * * To do: * *********************************************************************************************** * * $Log:: /JP2_PC/Source/Tools/GroffExp/Bitmap.cpp $ * * 5 12/16/96 11:22a Gstull * Made changes to support quantization to a single palette. * * 4 11/15/96 11:08a Gstull * Added substantial changes to the GroffExporter including for support of mutiple section * files. * * 3 11/06/96 7:28p Gstull * Added a Copy function to the bitmap IO classes. * * 2 11/04/96 8:34p Gstull * Latest version of the new bitmap exporter stuff. * **********************************************************************************************/ #include #include #include #include #include #include "max.h" #include "bmmlib.h" #include "StandardTypes.hpp" #include "Lib/Sys/SmartBuffer.hpp" #include "Bitmap.hpp" //********************************************************************************************** // CBitmapInfo::CBitmapInfo() { // Initialize the text fields to null. strBitmapName[0] = 0; strBitmapDescription = 0; // Call the generic initialization function. Initialize(); } //********************************************************************************************** // CBitmapInfo::~CBitmapInfo() { // Call the generic initialize function. Initialize(); } //********************************************************************************************** // void CBitmapInfo::Initialize() { // Set the bitmap file format to undefined, fmtFileFormat = EFMT_UNDEFINED; // Set the generic bitmap parameters to some initial values. uBitmapWidth = 0; uBitmapHeight = 0; uBitmapDepth = 0; fBitmapAspect = 1.0f; fBitmapGamma = 1.0f; // Initialize the palette information to empty values. uBitmapPaletteSize = 0; uBitmapPaletteEntries = 0; // Initialize the bitmap name to null. strBitmapName[0] = 0; // If there is any memory allocated to the strings, return it. Is there any? if (strBitmapDescription != 0) { // There is memory here so deallocate it. delete [] strBitmapDescription; // Initialize the pointers to null. strBitmapDescription = 0; } } //********************************************************************************************** // bool CBitmapInfo::bIsValidDefinition() const { // // First check for error conditions, then check for warning conditions. // // Is the width reasonable? if (uBitmapWidth < 1 || uBitmapWidth > MAX_BITMAP_WIDTH) { // Return an error. return false; } // Is the height reasonable? if (uBitmapHeight < 1 || uBitmapHeight > MAX_BITMAP_HEIGHT) { // Return an error. return false; } // Is the bitmap depth reasonable? switch (uBitmapDepth) { case 1: // Is the palette size correct? if (uBitmapPaletteSize != 2) { // No! Return an error. return false; } // Is the palette entries in range.? if (uBitmapPaletteEntries > 2) { // No! Return an error. return false; } break; case 4: // Is the palette size correct? if (uBitmapPaletteSize != 16) { // No! Return an error. return false; } // Is the palette entries in range.? if (uBitmapPaletteEntries > 16) { // No! Return an error. return false; } break; case 8: // Is the palette size correct? if (uBitmapPaletteSize != 256) { // No! Return an error. return false; } // Is the palette entries in range.? if (uBitmapPaletteEntries > 256) { // No! Return an error. return false; } break; case 24: break; default: // Return an error. return false; } // We have enough correct information to build a valid bitmap. return true; } //********************************************************************************************** // bool CBitmapInfo::bIsValidRepresentation() const { // // First check for error conditions, then check for warning conditions. // // Are the basic parameters valid? if (!bIsValidDefinition()) { // No! Return an error. return false; } // Is the bitmap depth reasonable? switch (uBitmapDepth) { case 1: // Is the palette size correct? if (uBitmapPaletteSize != 2) { // No! Return an error. return false; } // Is the palette entries in range.? if (uBitmapPaletteEntries > 2) { // No! Return an error. return false; } break; case 4: // Is the palette size correct? if (uBitmapPaletteSize != 16) { // No! Return an error. return false; } // Is the palette entries in range.? if (uBitmapPaletteEntries > 16) { // No! Return an error. return false; } break; case 8: // Is the palette size correct? if (uBitmapPaletteSize != 256) { // No! Return an error. return false; } // Is the palette entries in range.? if (uBitmapPaletteEntries > 256) { // No! Return an error. return false; } break; case 24: break; default: // Return an error. return false; } // We have enough correct information to build a valid bitmap. return true; } //********************************************************************************************** // void CBitmapInfo::Name(const char* str_bitmap_name) { // Is the user string in range? if (strlen(str_bitmap_name) >= MAX_NAME_LENGTH) return; // Copy the string. strcpy(&strBitmapName[0], str_bitmap_name); } //********************************************************************************************** // bool CBitmapInfo::bDescription(const char* str_description) { // Is there already memory allocated to the string? if (strBitmapDescription != 0) { // Yes! Deallocate it. delete [] strBitmapDescription; } // Did the user supply a valid string? if (str_description != 0) { // Allocate memory for the new string. strBitmapDescription = new char[strlen(str_description)+1]; // Were we successful? if (strBitmapDescription == 0) { // No! Return a failure result. return false; } // Now copy the string. strcpy(strBitmapDescription, str_description); } // Return a successful result. return true; } //********************************************************************************************** // void CBitmapInfo::BitmapFormat(EBitmapFormat fmt_file_format) { // Assign the file format. fmtFileFormat = fmt_file_format; } //********************************************************************************************** // void CBitmapInfo::Width(uint u_width) { // Is the new width within a reasonable range? if (u_width > 0 && u_width < MAX_BITMAP_WIDTH) { // Yes! Then assign it to the member variable. uBitmapWidth = u_width; } } //********************************************************************************************** // void CBitmapInfo::Height(uint u_height) { // Is the new width within a reasonable range? if (u_height > 0 && u_height < MAX_BITMAP_HEIGHT) { // Yes! Then assign it to the member variable. uBitmapHeight = u_height; } } //********************************************************************************************** // void CBitmapInfo::Depth(uint u_depth) { // Is this a valid supported bitmap depth? switch (u_depth) { case 1: uBitmapDepth = 1; uBitmapPaletteSize = 2; break; case 4: uBitmapDepth = 4; uBitmapPaletteSize = 16; break; case 8: uBitmapDepth = 8; uBitmapPaletteSize = 256; break; case 24: // Yes! Then assign it to the member variable. uBitmapDepth = u_depth; } // Make sure the new depth doesn't create an illegal condition regarding the maximum number // of palette entries. switch (u_depth) { case 1: case 4: case 8: uBitmapPaletteSize = 256; break; // Is the bitmap palette entry count greater than the size? if (uBitmapPaletteEntries > uBitmapPaletteSize) { // Yes! Then truncate the entry count. uBitmapPaletteEntries = uBitmapPaletteSize; } } } //********************************************************************************************** // void CBitmapInfo::PaletteEntries(uint u_palette_entries) { // Is the requested number of palette entries in range? if (u_palette_entries <= uBitmapPaletteSize) { // Yes! Then assign it to the member variable. uBitmapPaletteEntries = u_palette_entries; } } //********************************************************************************************** // void CBitmapInfo::Gamma(float f_gamma) { // Is the requested gamma value in range? if (f_gamma > 0.1f && f_gamma < 10.0f) { // Yes! Then assign it to the member variable. fBitmapGamma = f_gamma; } } //********************************************************************************************** // void CBitmapInfo::Aspect(float f_aspect) { // Is the requested gamma value in range? if (f_aspect > 0.5f && f_aspect < 2.0f) { // Yes! Then assign it to the member variable. fBitmapAspect = f_aspect; } } //********************************************************************************************** // const char* CBitmapInfo::strName() const { // Return a pointer to the string. return &strBitmapName[0]; } //********************************************************************************************** // const char* CBitmapInfo::strDescription() const { // Return a pointer to the string. return &strBitmapDescription[0]; } //********************************************************************************************** // EBitmapFormat CBitmapInfo::fmtBitmapFormat() const { // Return the current file type. return fmtFileFormat; } //********************************************************************************************** // uint CBitmapInfo::uWidth() const { // Return the bitmap width. return uBitmapWidth; } //********************************************************************************************** // uint CBitmapInfo::uHeight() const { // Return the bitmap height. return uBitmapHeight; } //********************************************************************************************** // uint CBitmapInfo::uDepth() const { // Return the bitmap depth. return uBitmapDepth; } //********************************************************************************************** // uint CBitmapInfo::uPaletteSize() const { // Return the size of the palette. return uBitmapPaletteSize; } //********************************************************************************************** // uint CBitmapInfo::uPaletteEntries() const { // Return the number of entries in the palette. return uBitmapPaletteEntries; } //********************************************************************************************** // float CBitmapInfo::fGamma() const { // Return the current gamma value. return fBitmapGamma; } //********************************************************************************************** // float CBitmapInfo::fAspect() const { // Return the current aspect ratio. return fBitmapAspect; } //********************************************************************************************** // CBitmapInfo& CBitmapInfo::operator =(CBitmapInfo& bi_src) { // Make sure we are not assigning to ourself. if (this != &bi_src) { // Duplicate all the members in the structure. fmtFileFormat = bi_src.fmtFileFormat; uBitmapWidth = bi_src.uBitmapWidth; uBitmapHeight = bi_src.uBitmapHeight; uBitmapDepth = bi_src.uBitmapDepth; fBitmapAspect = bi_src.fBitmapAspect; fBitmapGamma = bi_src.fBitmapGamma; uBitmapPaletteSize = bi_src.uBitmapPaletteSize; uBitmapPaletteEntries = bi_src.uBitmapPaletteEntries; // Copy the bitmap name to the target. strcpy(&strBitmapName[0], bi_src.strBitmapName); // Does a bitmap name exist in the dest? if (strBitmapDescription != 0) { // Deallocate it. delete [] strBitmapDescription; // Set the pointer to null. strBitmapDescription = 0; } // Does a bitmap name exist in the source? if (bi_src.strBitmapDescription != 0) { // Allocate the memory in the destination. strBitmapDescription = new char[strlen(bi_src.strBitmapDescription)+1]; // Copy the bitmap name to the destination. strcpy(strBitmapDescription, bi_src.strBitmapDescription); } } return *this; } //********************************************************************************************** // CBitmapImage::CBitmapImage() { // Initialize the image storage pointer. ac24TruePixels = 0; // Initialize the paletted pixel buffer. au1PalettedPixels = 0; // Set the buffer size to 0; uBufferSize = 0; } //********************************************************************************************** // CBitmapImage::~CBitmapImage() { // Call the generic initialization routine. Initialize(); } //********************************************************************************************** // void CBitmapImage::Initialize() { // Was there any memory used for the 24 bit storage? if (ac24TruePixels != 0) { // Yes! Then deallocate the memory. delete [] ac24TruePixels; // Set the pointer to null. ac24TruePixels = 0; } // Was there any memory used for indexed pixel storage? if (au1PalettedPixels != 0) { // Yes! Then deallocate the memory. delete [] au1PalettedPixels; // Set the pointer to null. au1PalettedPixels = 0; } // Set the buffer size to 0. uBufferSize = 0; // Initialize the bitmap info structure. biImageBitmapInfo.Initialize(); } //********************************************************************************************** // bool CBitmapImage::bCreate(CBitmapInfo& bi_src, bool b_initialize = false) { // Do we have a valid bitmap definition? if (!bi_src.bIsValidDefinition()) { // No! Something is wrong so return an error. return false; } // Make sure we are starting out with a clean structure. Initialize(); // Start out by determining how much memory we need. int i_pixels = bi_src.uWidth() * bi_src.uHeight(); // // We are all ready to start filling in the bitmap info structure and allocating // storage for our new bitmap. // biImageBitmapInfo = bi_src; // Setup the width and height fields sice // Is this a paletted or true color bitmap? if (bi_src.uDepth() > 8) { // Must be true color. Attempt to allocate the memory to the bitmap buffer. ac24TruePixels = new SColor24[i_pixels]; // Were we successful? if (ac24TruePixels == 0) { // No! Then return an error. return false; } // Setup the size of the buffer. uBufferSize = (uint) i_pixels * sizeof(SColor24); // Did the user request for the bitmap storage to be cleared? if (b_initialize) { // Initialize the bitmap and palette storage. memset(ac24TruePixels, 0, i_pixels * sizeof(SColor24)); } } else { // Must be paletted. Attempt to allocate the memory for the bitmap buffer. au1PalettedPixels = new uint8[i_pixels]; // Were we successful? if (au1PalettedPixels == 0) { // No! Then return an error. return false; } // Setup the size of the buffer. uBufferSize = (uint) i_pixels; // Set the palette entry count to 0 since this is a new palette. biImageBitmapInfo.PaletteEntries(0); // Did the user request the bitmap and palette storage to be cleared? if (b_initialize) { // Initialize the bitmap and palette storage. memset(au1PalettedPixels, 0, i_pixels); memset(ac24Palette, 0, MAX_PALETTE_SIZE * sizeof(SColor24)); } } // We were successful so return an error. return true; } //********************************************************************************************** // void CBitmapImage::bDestroy() { // Make sure we are starting out with a clean structure. Initialize(); } //********************************************************************************************** // bool CBitmapImage::bRangeCheckAndClip(uint u_width, uint u_x, uint& u_length) { // Is the starting point in the range? if (u_x >= u_width) { // No! The starting point is out of range. Nothing can be done. Return an error. return false; } // Is the length out of range? if (u_x + u_length > u_width) { // Adjust the length to it's maximum, legal value. u_length = (u_width - u_x); } // Return a successful result, since we now have useable coordinates. return true; } //********************************************************************************************** // uint CBitmapImage::uGetTruePixels(uint u_x, uint u_y, uint u_count, SColor24* ac24_pixels) { // Has a true color bitmap buffer been allocated for the bitmap? if (ac24TruePixels == 0) { // No! Return a count of 0. return 0; } // Do we have good parameters? if (!bRangeCheckAndClip(biImageBitmapInfo.uWidth(), u_x, u_count)) { // No! Return a count of 0. return 0; } // Setup the offset into the bitmap. uint u_offset = u_y * biImageBitmapInfo.uWidth() + u_x; // Copy the pixels into the users buffer. memcpy(ac24_pixels, &ac24TruePixels[u_offset], u_count * sizeof(SColor24)); // Return the number of pixels read. return u_count; } //********************************************************************************************** // uint CBitmapImage::uSetTruePixels(uint u_x, uint u_y, uint u_count, SColor24* ac24_pixels) { // Has a true color bitmap buffer been allocated for the bitmap? if (ac24TruePixels == 0) { // No! Return a count of 0. return 0; } // Do we have good parameters? if (!bRangeCheckAndClip(biImageBitmapInfo.uWidth(), u_x, u_count)) { // No! Return a count of 0. return 0; } // Setup the offset into the bitmap. uint u_offset = u_y * biImageBitmapInfo.uWidth() + u_x; // Copy the pixels from the users buffer. memcpy(&ac24TruePixels[u_offset], ac24_pixels, u_count * sizeof(SColor24)); // Return the number of pixels set. return u_count; } //********************************************************************************************** // uint CBitmapImage::uGetPalettedPixels(uint u_x, uint u_y, uint u_count, uint8* au1_pixels) { // Has a true color bitmap buffer been allocated for the bitmap? if (au1PalettedPixels == 0) { // No! Return a count of 0. return 0; } // Do we have good parameters? if (!bRangeCheckAndClip(biImageBitmapInfo.uWidth(), u_x, u_count)) { // No! Return a count of 0. return 0; } // Setup the offset into the bitmap. uint u_offset = u_y * biImageBitmapInfo.uWidth() + u_x; // Copy the pixels into the users buffer. memcpy(au1_pixels, &au1PalettedPixels[u_offset], u_count); // Return the number of pixels read. return u_count; } //********************************************************************************************** // uint CBitmapImage::uSetPalettedPixels(uint u_x, uint u_y, uint u_count, uint8* au1_pixels) { // Do we have good parameters? if (!bRangeCheckAndClip(biImageBitmapInfo.uWidth(), u_x, u_count)) { // No! Return a count of 0. return 0; } // Setup the offset into the bitmap. uint u_offset = u_y * biImageBitmapInfo.uWidth() + u_x; // Copy the pixels into the users buffer. memcpy(&au1PalettedPixels[u_offset], au1_pixels, u_count); // Return the number of pixels read. return u_count; } //********************************************************************************************** // uint CBitmapImage::uGetPaletteEntries(uint u_start, uint u_count, SColor24* ac24_user_palette) { // Do we have good parameters? if (!bRangeCheckAndClip(biImageBitmapInfo.uPaletteSize(), u_start, u_count)) { // No! Return a count of 0. return 0; } // Copy the pixels into the users buffer. memcpy(ac24_user_palette, &ac24Palette[u_start], u_count * sizeof(SColor24)); // Return the number of palette entries read. return u_count; } //********************************************************************************************** // uint CBitmapImage::uSetPaletteEntries(uint u_start, uint u_count, SColor24* ac24_user_palette) { // Has a palette been allocated for this bitmap? if (ac24Palette == 0) { // No! Return a count of 0. return 0; } // Do we have good parameters? if (!bRangeCheckAndClip(biImageBitmapInfo.uPaletteSize(), u_start, u_count)) { // No! Return a count of 0. return 0; } // Copy the palette entries out of the users buffer. memcpy(&ac24Palette[u_start], ac24_user_palette, u_count * sizeof(SColor24)); // // Set the palette entries field to reflect the last written pixel. This is sort of a // hack because we really don't know if all of these palette entries are being used in // the actual image. For now it will cork just fine. // biImageBitmapInfo.PaletteEntries(u_start+u_count); // Return the number of palette entries set. return u_count; } //********************************************************************************************** // bool CBitmapImage::bBitmapInfo(CBitmapInfo& bi_bitmap_info) { // Only allow the user to modify a couple bitmap parameters (Name, Description, Format). biImageBitmapInfo.BitmapFormat(bi_bitmap_info.fmtBitmapFormat()); biImageBitmapInfo.Name(bi_bitmap_info.strName()); return biImageBitmapInfo.bDescription(bi_bitmap_info.strDescription()); } //********************************************************************************************** // CBitmapInfo& CBitmapImage::biBitmapInfo() { return biImageBitmapInfo; } //********************************************************************************************** // bool CBitmapImage::bIsPaletted() const { // All paletted bitmaps have a depth which is less than or equal to 8 bits. return biImageBitmapInfo.uDepth() <= 8; } //********************************************************************************************** // bool CBitmapImage::bIsValidImage() { // First check the bitmap information for reasonable values. if (!biImageBitmapInfo.bIsValidDefinition()) { // No! Either the width, height or depth is unreasonable, so return an error. return false; } // Make sure we have at least a string to represent our bitmap. if (!biImageBitmapInfo.strName()) { // No! The user has not requested a name for the bitmap. return false; } // Check to make sure the bitmap image is of the right dimensions. uint u_buff_size = biImageBitmapInfo.uWidth() * biImageBitmapInfo.uHeight(); // Determine the depth of the bitmap and perform any depth related checks. switch (biImageBitmapInfo.uDepth()) { // Later add code to handle 1 and 4 bit paletted bitmaps. case 1: case 4: case 8: // Make sure we have an storage allocated to the bitmap buffer. if (au1PalettedPixels == 0) { // We don't have any memory associated with the bitmap so return an error. return false; } // Make sure we have an storage allocated to the bitmap palette. if (ac24Palette == 0) { // We don't have any memory associated with the bitmap palette, so return an error. return false; } break; case 24: // Adjust the size of the pixel buffer for 24 bit pixels. u_buff_size *= 3; // Make sure we have an storage allocated to the bitmap buffer. if (ac24TruePixels == 0) { // We don't have any memory associated with bitmap so return an error. return false; } break; } // Check to determine if the pixel buffer is the correct size. Is it correct if (u_buff_size != uBufferSize) { // No! Return an error. return false; } // This bitmap can be successfully written to disk. return true; } //********************************************************************************************** // void* CBitmapImage::Data() const { // Are we in paletted mode? if (bIsPaletted()) { // Yes! We are int paletted mode. return (void *) &au1PalettedPixels[0]; } else { // No! We are in true color mode. return (void *) &ac24TruePixels[0]; } } //********************************************************************************************** // CBitmapImage& CBitmapImage::operator =(CBitmapImage& bmi_src) { // Make sure we are not assigning to outself. if (this != &bmi_src) { // Start out by making a duplicate of the bitmap image. if (!bCreate(bmi_src.biBitmapInfo())) { // Bad situation has occurred. We are out of heap memory. Blow up for now. Assert(0); } // Get a copy of the bitmap info for the host. CBitmapInfo bi_bitmap_info = bmi_src.biBitmapInfo(); // Is this bitmap true color or paletted? if (bi_bitmap_info.uDepth() > 8) { // This is a true color bitmap. So copy it. memcpy(ac24TruePixels, bmi_src.ac24TruePixels, bi_bitmap_info.uWidth() * bi_bitmap_info.uHeight() * sizeof(SColor24)); } else { // This is a paletted bitmap. So copy the bitmap and the palette. memcpy(ac24TruePixels, bmi_src.ac24TruePixels, bi_bitmap_info.uWidth() * bi_bitmap_info.uHeight()); memcpy(ac24Palette, bmi_src.ac24Palette, bi_bitmap_info.uPaletteSize() * sizeof(SColor24)); } } return *this; } //********************************************************************************************** // bool CBitmapIO::bLoad(const char* str_bitmap_name, CBitmapImage& bmi_bitmap_image) { CBmpBitmap bmp_bitmap; CGrfBitmap groff_bitmap; // // Invoke a series of bitmap sniffers to determine the bitmap type. // // Is this bitmap a windows BMP bitmap? if (bmp_bitmap.bDetectBitmap(str_bitmap_name)) { // Yes! Then attempt to load it, and return the result. return bmp_bitmap.bRead(str_bitmap_name, bmi_bitmap_image); } // Is it a groff file bitmap if (groff_bitmap.bDetectBitmap(str_bitmap_name)) { // Yes! Then attempt to load it, and return the result. return groff_bitmap.bRead(str_bitmap_name, bmi_bitmap_image); } // The bitmap was unable to be loaded so return an error. return false; } //********************************************************************************************** // bool CBitmapIO::bSave(CBitmapImage& bmi_bitmap_image) { CBmpBitmap bmp_bitmap; CGrfBitmap groff_bitmap; bool b_result = false; CBitmapInfo& bi_bitmap_info = bmi_bitmap_image.biBitmapInfo(); // Determine the type of file we are being requested to create. switch (bi_bitmap_info.fmtBitmapFormat()) { case EFMT_UNDEFINED: // Bummer! A file format must be specified for now. break; case EFMT_BMP: // Attempt to write it out. b_result = bmp_bitmap.bWrite(bmi_bitmap_image); break; case EFMT_GROFF: // Attempt to write it out. b_result = groff_bitmap.bWrite(bmi_bitmap_image); break; } // Return the result. return b_result; } //********************************************************************************************** // bool CBitmapIO::bCopy(const char* str_dst, const char* str_src) { CBitmapImage bmi_bitmap_image; // Attempt to load the bitmap. Were we successful? if (!bLoad(str_src, bmi_bitmap_image)) { // No! Return an error. return false; } // Change the bitmap name. CBitmapInfo bi_bitmap_info; bi_bitmap_info = bmi_bitmap_image.biBitmapInfo(); // Change the name in the bitmap image. Were we successful? bi_bitmap_info.Name(str_dst); if (!bmi_bitmap_image.bBitmapInfo(bi_bitmap_info)) { // No! Perhaps the destination name is invalid??? Return an unsuccessful result. return false; } // Attempt to save the bitmap and return the result. return bSave(bmi_bitmap_image); } /* //********************************************************************************************** // CBitmapUtil::CBitmapUtil() { // Set the quantizer structure to null. pqQuantizer = 0; // Set the size of the palette to 0. uPaletteSize = 0; // Set the color packer to null. pcpColorPacker = 0; // Set the transparency flag to null. bTransparency = false; } //********************************************************************************************** // CBitmapUtil::~CBitmapUtil() { // Was a quantizer allocated? if (pqQuantizer != 0) { // Yes! Delete the quantizer. pqQuantizer->DeleteThis(); // Set the quantizer to null. pqQuantizer = 0; } // Set the palette size to 0. uPaletteSize = 0; // Was a color packer allocated? if (pcpColorPacker != 0) { // Yes! Delete the color packer. pcpColorPacker->DeleteThis(); // Set the color packer structure to null. pcpColorPacker = 0; } } //********************************************************************************************** // bool CBitmapUtil::bExists(const char* str_bitmap_name) { // // Attempt to open the file to make sure it exists. // // Attempt to open the file and see if it exists. ifstream ifile(str_bitmap_name, ios::binary | ios::nocreate); // Were we able to open the file? if (!ifile) { // No! Return false. return false; } // Yes! So close the file and return true. ifile.close(); return true; } //********************************************************************************************** // bool CBitmapUtil::bCopy(const char* str_dst, const char* str_src) { CBitmapImage bmi_bitmap_image; // Attempt to load the bitmap. Were we successful? if (!bLoad(str_src, bmi_bitmap_image)) { // No! Return an error. return false; } // Change the bitmap name. CBitmapInfo bi_bitmap_info; bi_bitmap_info = bmi_bitmap_image.biBitmapInfo(); // Change the name in the bitmap image. Were we successful? bi_bitmap_info.Name(str_dst); if (!bmi_bitmap_image.bBitmapInfo(bi_bitmap_info)) { // No! Perhaps the destination name is invalid??? Return an unsuccessful result. return false; } // Attempt to save the bitmap and return the result. return bSave(bmi_bitmap_image); } //********************************************************************************************** // bool CBitmapUtil::bConfigureQuantizer(uint u_maximum_palette_entries) { // Is the requested palette size in range? if (u_maximum_palette_entries < 2 || u_maximum_palette_entries > 256) { // No! Return an error. return false; } // Setup the palette entry count. uPaletteSize = u_maximum_palette_entries; // Does a palette exist? If so, deallocate it. if (ac24Palette != 0) { // Yes! Delete the palette. delete [] ac24Palette; // Set the palette pointer to 0. ac24Palette = 0; } // Does a quantizer already exist? if (pqQuantizer != 0) { // Yes! Deallocate it. pqQuantizer->DeleteThis(); } // Attempt to allocate a histogram for the quantizer. Were we successful? if (!pqQuantizer->AllocHistogram()) { // No! Deallocate the quantizer and return an error. pqQuantizer->DeleteThis(); return false; } // Does a color packer exist? If so delete it. if (pcpColorPacker != 0) { // Yes! Deallocate it. pcpColorPacker->DeleteThis(); // Set the pointer to 0. pcpColorPacker = 0; } // Return a successful result. return true; } //********************************************************************************************** // bool CBitmapUtil::bQuantizePixels(CBitmapImage& bmi_bitmap_image) { // Does a quantizer exist? if (pqQuantizer == 0) { // No! Return an error. return false; } // Do we have a valid bitmap image? if (!bmi_bitmap_image.bIsValidImage()) { // No! Return an error. return false; } // Is this a paletted bitmap? if (bmi_bitmap_image.bIsPaletted()) { // Yes! Return an error since we don't support quantization of paletted bitmaps. return false; } // // We now know that we have a valid bitmap which is true color. We can then feed the individual // pixels in the bitmap into the quantizer. // // Get a copy of the bitmap info structure. CBitmapInfo bi_bitmap_info = bmi_bitmap_image.biBitmapInfo(); // Setup a pixel line buffer. SColor24* ac24_scanline = new SColor24[bi_bitmap_info.uWidth()]; // Were we successful? if (ac24_scanline == 0) { // No! Return an error. return false; } // Loop through all the rows in the bitmap. for (uint u_i = 0; u_i < bi_bitmap_info.uWidth(); u_i++) { } // Delete the scanline buffer. delete [] ac24_scanline; // Return a successful result. return true; } //********************************************************************************************** // bool CBitmapUtil::bPalettizeBitmap(CBitmapImage& bmi_dst, CBitmapImage& bmi_dst& u1_palette_size) { } //********************************************************************************************** // bool CBitmapUtil::bMerge(CBitmapImage& bmi_dst, CBitmapImage& bmi_texture, CBitmap bmi_opacity) { } //********************************************************************************************** // bool CBitmapUtil::bFlip(CBitmapImage& bmi_bitmap_image, bool b_vertical, bool b_horizontal) { } //********************************************************************************************** // bool CBitmapUtil::bMeanColor(CBitmapImage& bmi_bitmap_image, SColor24& c24_mean_color) { } */ //********************************************************************************************** // bool CBmpBitmap::bDetectBitmap(const char* str_bitmap_name) { // Attempt to open the file and see if it exists. std::ifstream ifile(str_bitmap_name, std::ios::binary | std::ios::_Nocreate); // Were we able to open the file? if (!ifile) { // No! So return an error. return false; } // Determine if we have a Windows BMP bitmap file. SFileHeader fh_file_header; // Read in the file header. ifile.read((char *) &fh_file_header, sizeof(SFileHeader)); ifile.close(); // Is this a Windows bitmap? return fh_file_header.u2FileType == WINDOWS_BMP_MAGIC_NUMBER; } //********************************************************************************************** // bool CBmpBitmap::bRead(const char* str_bitmap_name, CBitmapImage& bmi_bitmap_image) { // Do we have a possible string? if (str_bitmap_name == 0) { // No! This is a null string so return a failure result. return false; } // Attempt to open the bitmap file. std::ifstream ifile(str_bitmap_name, std::ios::binary | std::ios::_Nocreate); // Were we successful? if (!ifile) { // No! Return a failure result. return false; } // Determine if we have a Windows BMP bitmap file. SFileHeader fh_file_header; // Read in the file header. ifile.read((char *) &fh_file_header, sizeof(SFileHeader)); // Is this a Windows bitmap? if (fh_file_header.u2FileType != WINDOWS_BMP_MAGIC_NUMBER) { // No! CLose the file and return a failure result. ifile.close(); return false; } // Read in the bitmap header and verify we recognize the version. SBitmapHeader bmh_bitmap_header; // Read in the file header. ifile.read((char *) &bmh_bitmap_header, sizeof(SBitmapHeader)); // Is this a Windows bitmap? if (bmh_bitmap_header.uHeaderSize != sizeof(SBitmapHeader)) { // No! CLose the file and return a failure result. ifile.close(); return false; } // Make sure this is an uncompressed BMP file since this is all we can handle now. if (bmh_bitmap_header.uCompression != 0 || bmh_bitmap_header.u2Planes != 1) { // This type of bitmap is not yet supported, so close the file and return an error. ifile.close(); return false; } // Reset the file pointer to the beginning and read the entire bitmap into a smart buffer. CSmartBuffer sb_buffer; TBufferHandle bh_handle = sb_buffer.bhCreate(fh_file_header.uFileSize); // Were we successful? if (bh_handle == 0) { // No! Close the file and return an error. ifile.close(); return false; } // Setup the smart buffer to reflect an entire buffer full of data. if (sb_buffer.iLast(bh_handle, fh_file_header.uFileSize-1) == -1) { // This did not work so close the file and return an error. ifile.close(); return false; } // Get the buffer address. uint8* u1_buffer = (uint8 *) sb_buffer.Address(bh_handle); // Were we successful? if (u1_buffer == 0) { // No! Close the file and return an error. ifile.close(); return false; } // Seek to the start of the file. ifile.seekg(0); // Read in the entire file. ifile.read((char*)u1_buffer, fh_file_header.uFileSize); // Close the file since the image is now entirely located in the smart buffer. ifile.close(); // Verify the file size matches the smart buffer count. if (sb_buffer.iCount(bh_handle) != (int) fh_file_header.uFileSize) { // Return an error. return false; } // // We now have the entire bitmap in a smartbuffer, so start out by constructing a bitmap // info structure which can then be used to build the bitmap image. Fortunately, this // only requires a couple of fields out of the file header. // CBitmapInfo bi_bitmap_info; bi_bitmap_info.Width(bmh_bitmap_header.lWidth); bi_bitmap_info.Height(bmh_bitmap_header.lHeight); bi_bitmap_info.Depth(bmh_bitmap_header.u2BitsPerPixel); bi_bitmap_info.BitmapFormat(EFMT_BMP); bi_bitmap_info.Name(str_bitmap_name); // Attempt to allocate the storage for the bitmap. Were we successful? if (!bmi_bitmap_image.bCreate(bi_bitmap_info, true)) { // No! Return an error. return false; } // // We now have a valid bitmap image to store our bitmap in, so we now need to load the data // from the smart buffer into the image. This will largely depend on whether this bitmap // is a true color bitmap or a paletted bitmap. // // Is this a paletted bitmap? if (bmh_bitmap_header.u2BitsPerPixel <= 8) { // Make sure the number of colors field is properly setup. if (bmh_bitmap_header.uColorsUsed == 0) { switch (bmh_bitmap_header.u2BitsPerPixel) { case 1: bmh_bitmap_header.uColorsUsed = 2; bmh_bitmap_header.uColorsReqd = 2; break; case 4: bmh_bitmap_header.uColorsUsed = 16; bmh_bitmap_header.uColorsReqd = 16; break; case 8: bmh_bitmap_header.uColorsUsed = 256; bmh_bitmap_header.uColorsReqd = 256; break; } }; // This is a paletted bitmap. SPaletteEntry* pbple_palette = (SPaletteEntry *) (u1_buffer + sizeof(SFileHeader) + sizeof(SBitmapHeader)); SColor24 ac24_palette[256]; // Convert the Windows BMP palette entries into the internal format. for (uint u_i = 0; u_i < bmh_bitmap_header.uColorsUsed; u_i++) { ac24_palette[u_i].u1Red = pbple_palette[u_i].u1Red; ac24_palette[u_i].u1Green = pbple_palette[u_i].u1Green; ac24_palette[u_i].u1Blue = pbple_palette[u_i].u1Blue; } // Give the palette to the bitmap image. Were we successful? if (bmi_bitmap_image.uSetPaletteEntries(0, bmh_bitmap_header.uColorsUsed, &ac24_palette[0]) != bmh_bitmap_header.uColorsUsed) { // No! Return an error. return false; } // Determine how large the read chunks need to be. const int i_scanline_offset = (int) (bmh_bitmap_header.lWidth+3) >> 2; int* pi_buffer = (int *) (u1_buffer + fh_file_header.uBitmapOffset); // Loop through the scanlines and load them into the image data. for (uint u_i = 0; u_i < (uint) bmh_bitmap_header.lHeight; u_i++) { // Attempt to write the data into the bitmap image buffer. Were we successful? if (bmi_bitmap_image.uSetPalettedPixels(0, u_i, bmh_bitmap_header.lWidth, (uint8 *) pi_buffer) != (uint) bmh_bitmap_header.lWidth) { // No! Return an error; return false; } // Adavance the pointer to the next scanline. pi_buffer += i_scanline_offset; } } else { // Determine how large the read chunks need to be. const int i_scanline_offset = (int) ((bmh_bitmap_header.lWidth * sizeof(SPixelEntry))+3) >> 2; int* pi_buffer = (int *) (u1_buffer + fh_file_header.uBitmapOffset); // Loop through the scanlines and load them into the image data. for (uint u_i = 0; u_i < (uint) bmh_bitmap_header.lHeight; u_i++) { // Attempt to write the data into the bitmap image buffer. Were we successful? if (bmi_bitmap_image.uSetTruePixels(0, u_i, bmh_bitmap_header.lWidth, (SColor24 *) pi_buffer) != (uint) bmh_bitmap_header.lWidth) { // No! Return an error; return false; } // Adavance the pointer to the next scanline. pi_buffer += i_scanline_offset; } } // Return a successful result. return true; } //********************************************************************************************** // bool CBmpBitmap::bWrite(CBitmapImage& bmi_bitmap_image) { // Get a copy of the bitmap info record. CBitmapInfo bi_bitmap_info; bi_bitmap_info = bmi_bitmap_image.biBitmapInfo(); // Check the dimensions of the bitmap for correct ranges. if (!bi_bitmap_info.bIsValidDefinition()) { // No! Return an error. return false; } // Start out with the bitmap width in pixels. const uint u_bitmap_depth = bi_bitmap_info.uDepth(); const uint u_width = bi_bitmap_info.uWidth(); const uint u_height = bi_bitmap_info.uHeight(); const uint u_palette_entries = bi_bitmap_info.uPaletteEntries(); const uint u_palette_size = u_palette_entries * sizeof(SPaletteEntry); uint u_scanline_pad; uint u_image_size; // Determine the correction factor based upon the bitmap depth. switch(u_bitmap_depth) { case 1: case 4: // These are not handled for now, so store 2 or 16 color bitmaps as 256 color bitmaps. case 8: u_scanline_pad = ((u_width+3) & 0xFFFFFFFC) - u_width; // Determine the size of the image. u_image_size = u_height * (u_width + u_scanline_pad); break; case 24: // Calculate the padding factor required to 32 bit align the row. u_scanline_pad = (((u_width * sizeof(SColor24))+3) & 0xFFFFFFFC) - (u_width * sizeof(SColor24)); // Determine the size of the image. u_image_size = u_height * ((u_width * sizeof(SColor24)) + u_scanline_pad); break; } // Construct the DIB file image. SFileHeader fh_file_header; fh_file_header.u2FileType = WINDOWS_BMP_MAGIC_NUMBER; fh_file_header.uFileSize = sizeof(SFileHeader) + sizeof(SBitmapHeader) + u_palette_size + u_image_size; fh_file_header.uReserved1 = 0; fh_file_header.uReserved2 = 0; fh_file_header.uBitmapOffset = sizeof(SFileHeader) + sizeof(SBitmapHeader) + u_palette_size; // Construct the DIB bitmap header. SBitmapHeader bmh_bitmap_header; bmh_bitmap_header.uHeaderSize = sizeof(SBitmapHeader); bmh_bitmap_header.lWidth = u_width; bmh_bitmap_header.lHeight = u_height; bmh_bitmap_header.u2Planes = 1; bmh_bitmap_header.u2BitsPerPixel = u_bitmap_depth; bmh_bitmap_header.uCompression = 0; bmh_bitmap_header.uBitmapSize = 0; bmh_bitmap_header.uHorizRes = 0xAED; bmh_bitmap_header.uVerticalRes = 0xAED; bmh_bitmap_header.uColorsUsed = u_palette_entries; bmh_bitmap_header.uColorsReqd = u_palette_entries; // // We now have the headers constructed so we can write the bitmap to the file. // CSmartBuffer sb_buffer; // Construct a buffer to buildWrite out the header. TBufferHandle bh_handle = sb_buffer.bhCreate(fh_file_header.uFileSize); // Were we able to allocate a smart buffer? if (bh_handle == 0) { // No! Return an error. return false; } // Write out the file header. if (sb_buffer.iWrite(bh_handle, &fh_file_header, sizeof(SFileHeader)) != sizeof(SFileHeader)) { // No! Return an error. return false; } // Write out the bitmap header. Were we successful? if (sb_buffer.iWrite(bh_handle, &bmh_bitmap_header, sizeof(SBitmapHeader)) != sizeof(SBitmapHeader)) { // No! Return an error. return false; } // If this is a bitmap with a palette, write out the palette entries. if (u_palette_entries != 0) { // Get the palette in a local buffer. SColor24 c24_palette[256]; // Are we able to read the palette? if (bmi_bitmap_image.uGetPaletteEntries(0, u_palette_entries, &c24_palette[0]) != u_palette_entries) { // No! Return an error. return false; } // Convert each of the palette entries from a SColor24 value to a BMP palette entry. SPaletteEntry bple_palette[256]; for (uint u_i = 0; u_i < u_palette_entries; u_i++) { // Copy the values from one representation to another. bple_palette[u_i].u1Red = c24_palette[u_i].u1Red; bple_palette[u_i].u1Green = c24_palette[u_i].u1Green; bple_palette[u_i].u1Blue = c24_palette[u_i].u1Blue; bple_palette[u_i].u1Reserved = 0; } // Attempt to write the palette out to the file. Were we successful? if (sb_buffer.iWrite(bh_handle, &bple_palette[0], u_palette_size) != (int) u_palette_size) { // No! Return an error. return false; } } // // Write out the actual image data. // int i_zero = 0; // Is this a paletted or unpaletted bitmap? switch (u_bitmap_depth) { case 1: case 4: case 8: // For each row in the bitmap, write out the row and pad it to the smart buffer. uint u_i; for (u_i = 0; u_i < u_height; u_i++) { // Read the index pixels directly into the smart buffer. Were all the pixels read? uint8 u1_scanline[MAX_BITMAP_WIDTH]; // Were we able to read the indexed pixels? if (bmi_bitmap_image.uGetPalettedPixels(0, u_i, u_width, &u1_scanline[0]) != u_width) { // No! Return an error. return false; } // Write them to the bitmap file. Were we successful? if (sb_buffer.iWrite(bh_handle, &u1_scanline[0], u_width) != (int) u_width) { // No! Return an error. } // If the row is not properly aligned to a 32 bit boundry, adjust it. if (sb_buffer.iWrite(bh_handle, &i_zero, u_scanline_pad) != (int) u_scanline_pad) { // No! Return an error. return false; } } break; case 24: // For each row in the bitmap, write out the row and pad it to the smart buffer. for (u_i = 0; u_i < u_height; u_i++) { SColor24 ac24_scanline[MAX_BITMAP_WIDTH]; // Read the index pixels directly into the smart buffer. Were all the pixels read? if (bmi_bitmap_image.uGetTruePixels(0, u_i, u_width, &ac24_scanline[0]) != u_width) { // No! Return an error. return false; } // Write them to the bitmap file. Were we successful? if (sb_buffer.iWrite(bh_handle, &ac24_scanline[0], u_width * sizeof(SPixelEntry)) != (int) (u_width * sizeof(SPixelEntry))) { // No! Return an error. return false; } // If the row is not properly aligned to a 32 bit boundry, adjust it. if (sb_buffer.iWrite(bh_handle, &i_zero, u_scanline_pad) != (int) u_scanline_pad) { // No! Return an error. return false; } } break; } // Seek to the beginning of the smart buffer so it can be written to disk. if (sb_buffer.iSeek(bh_handle, 0) != 0) { // We cannot seek to the beginning of the smart buffer so return an error. return false; } // Get the address of the start of the buffer. void* buffer = sb_buffer.Address(bh_handle); // Were we successful? if (buffer == 0) { // No! Return and error. return false; } int i_count = sb_buffer.iCount(bh_handle); // Is this buffer the correct size? // Attempt to open the output file. std::ofstream ofile(bi_bitmap_info.strName(), std::ios::binary | std::ios::trunc); // Were we able to open the file? if (!ofile) { // No! Return an error. return false; } // Write the buffer contents to a file. ofile.write((const char *) buffer, i_count); // Close the file. ofile.close(); // Return a successful result. return true; } //********************************************************************************************** // bool CGrfBitmap::bDetectBitmap(const char* str_bitmap_name) { // Return an error for now. return false; } //********************************************************************************************** // bool CGrfBitmap::bRead(const char* str_bitmap_name, CBitmapImage& bmi_bitmap_image) { // Return an error for now. return false; } //********************************************************************************************** // bool CGrfBitmap::bWrite(CBitmapImage& bmi_bitmap_image) { // Return an error for now. return false; }