#include "PngLoader.h" #include "FileMan.h" #include "DEBUG.H" #include "vobject.h" #include "STIConvert.h" #include "MemMan.h" #include #include #include #include #include #include #include "XML_Parser.h" namespace png { # include } #include "sgp_auto_memory.h" const vfs::String::str_t CONST_DOTPNG(L".png"); const vfs::String::str_t CONST_DOTXML(L".xml"); void Load24bppPNGImage(HIMAGE hImage, png::png_bytepp rows, png::png_infop info); void Load32bppPNGImage(HIMAGE hImage, png::png_bytepp rows, png::png_infop info); void LoadPalettedPNGImage(HIMAGE hImage, png::png_bytepp rows, png::png_infop info); void user_read_data(png::png_structp png_ptr, png::png_bytep data, png::png_size_t length) { SGP_TRYCATCH_RETHROW( static_cast(png_ptr->io_ptr)->read((vfs::Byte*)data,length), L"error during png file reading"); } /*******************************************************************************/ /*******************************************************************************/ class IndexedSTIImage { public: IndexedSTIImage(); ~IndexedSTIImage(); bool setPalette(SGPPaletteEntry *pPal, int iSize); bool setPalette(png::png_colorp pPal, int iSize); bool addImage(UINT8 *data, UINT32 data_size, UINT32 image_width, UINT32 image_height, INT32 image_offset_x, INT32 image_offset_y, UINT8 *original_compressed=NULL, UINT32 original_compressed_size=0); bool addCompressedImage(UINT8 *data, UINT32 data_size, UINT32 image_width, UINT32 image_height, INT32 image_offset_x, INT32 image_offset_y); bool readAppDataFromXMLFile(HIMAGE hImage, vfs::tReadableFile* pFile); bool writeImage(vfs::tWritableFile* pFile); bool writeToHIMAGE(HIMAGE pImage); private: STCIHeader _header; STCIPaletteElement* _palette; int _pal_size; std::vector _images; std::vector > _compressed_images; }; IndexedSTIImage::IndexedSTIImage() : _palette(NULL) { memset(&_header, 0, sizeof(STCIHeader)); } IndexedSTIImage::~IndexedSTIImage() { if(_palette) { delete[] _palette; } for(unsigned int i=0; i < _compressed_images.size(); ++i) { //delete[] _compressed_images[i]; } } bool IndexedSTIImage::setPalette(SGPPaletteEntry *pPal, int iSize) { if(iSize < 0 ||iSize > 1024) { return false; } _pal_size = iSize; _palette = new STCIPaletteElement[iSize]; for(int i=0; i 1024) { return false; } _pal_size = iSize; _palette = new STCIPaletteElement[iSize]; for(int i=0; i 0, L"not enough space reserved for ETRLE compression"); subimage.sOffsetX = image_offset_x; subimage.sOffsetY = image_offset_y; //subimage.uiDataLength = compressed_size; //_header.uiStoredSize += compressed_size; subimage.uiDataLength = etrle_size; _header.uiStoredSize += etrle_size; _images.push_back(subimage); // _compressed_images.push_back(compressed_start); _header.uiOriginalSize += data_size; _header.Indexed.usNumberOfSubImages += 1; return true; } static inline void setFlag(UINT8 &flags, char const* sFlag) { /*0x01*/ if (strcmp(sFlag, "AUX_FULL_TILE") == 0) flags |= AUX_FULL_TILE; /*0x02*/ else if(strcmp(sFlag, "AUX_ANIMATED_TILE") == 0) flags |= AUX_ANIMATED_TILE; /*0x04*/ else if(strcmp(sFlag, "AUX_DYNAMIC_TILE") == 0) flags |= AUX_DYNAMIC_TILE; /*0x08*/ else if(strcmp(sFlag, "AUX_INTERACTIVE_TILE") == 0) flags |= AUX_INTERACTIVE_TILE; /*0x10*/ else if(strcmp(sFlag, "AUX_IGNORES_HEIGHT") == 0) flags |= AUX_IGNORES_HEIGHT; /*0x20*/ else if(strcmp(sFlag, "AUX_USES_LAND_Z") == 0) flags |= AUX_USES_LAND_Z; else { std::wstringstream wss; wss << L"Unknown flag [" << vfs::String::as_utf16(sFlag) << L"]"; SGP_THROW(wss.str().c_str()); } } class CAppDataParser : public IXMLParser { enum DOM_OBJECT { DO_ELEMENT_NONE, DO_ELEMENT_ImageData, DO_ELEMENT_SubImage, DO_ELEMENT_offset, DO_ELEMENT_AuxData, DO_ELEMENT_flags, DO_ELEMENT_properties, }; public: CAppDataParser(XML_Parser &parser, IXMLParser* caller=NULL) : IXMLParser("ImageData", &parser, caller), current_state(DO_ELEMENT_NONE), m_hImage(NULL), m_iCurrentIndex(-1) { } virtual ~CAppDataParser() {}; virtual void onStartElement(const XML_Char* name, const XML_Char** atts); virtual void onEndElement(const XML_Char* name); virtual void onTextElement(const XML_Char *str, int len); void setImage(HIMAGE hImage) { m_hImage = hImage; if(m_hImage) { m_vAppData.resize(m_hImage->usNumberOfObjects); } } private: DOM_OBJECT current_state; HIMAGE m_hImage; struct SubImage{ SubImage() { memset(&aux,0,sizeof(AuxObjectData)); offset._override = false; offset.x = 0; offset.y = 0; }; AuxObjectData aux; struct{ int x,y; bool _override; } offset; }; std::vector m_vAppData; int m_iCurrentIndex; }; void CAppDataParser::onStartElement(const XML_Char* name, const XML_Char** atts) { if( current_state == DO_ELEMENT_NONE && strcmp(name, this->ElementName) == 0 ) { current_state = DO_ELEMENT_ImageData; } else if(current_state == DO_ELEMENT_ImageData && strcmp(name, "SubImage") == 0) { int index = -1; SGP_THROW_IFFALSE(getAttributeAsInt("index",atts,index), L"could not read attribute \"index\""); m_iCurrentIndex = index; if(index >= (int)m_vAppData.size()) { m_vAppData.resize(index+1); } current_state = DO_ELEMENT_SubImage; } else if(current_state == DO_ELEMENT_SubImage && strcmp(name, "offset") == 0) { int offset_x = 0, offset_y = 0; if(getAttributeAsInt("x",atts,offset_x)) { m_vAppData[m_iCurrentIndex].offset.x = offset_x; m_vAppData[m_iCurrentIndex].offset._override = true; } if(getAttributeAsInt("y",atts,offset_y)) { m_vAppData[m_iCurrentIndex].offset.y = offset_y; m_vAppData[m_iCurrentIndex].offset._override = true; } current_state = DO_ELEMENT_offset; } else if(current_state == DO_ELEMENT_SubImage && strcmp(name, "AuxObjectData") == 0) { current_state = DO_ELEMENT_AuxData; } else if(current_state == DO_ELEMENT_AuxData && strcmp(name, "flags") == 0) { current_state = DO_ELEMENT_flags; } else if(current_state == DO_ELEMENT_flags) { setFlag(m_vAppData[m_iCurrentIndex].aux.fFlags, name); } else if(current_state == DO_ELEMENT_AuxData && ( strcmp(name, "ubCurrentFrame") == 0 || strcmp(name, "ubNumberOfFrames") == 0 || strcmp(name, "ubNumberOfTiles") == 0 || strcmp(name, "ubWallOrientation") == 0 || strcmp(name, "usTileLocIndex") == 0 ) ) { current_state = DO_ELEMENT_properties; } sCharData = ""; } void CAppDataParser::onEndElement(const XML_Char* name) { char *p; if( strcmp(name, "usTileLocIndex") == 0 && current_state == DO_ELEMENT_properties) { m_vAppData[m_iCurrentIndex].aux.usTileLocIndex = (UINT16)strtoul( sCharData.c_str(),&p,10); current_state = DO_ELEMENT_AuxData; } else if( strcmp(name, "ubWallOrientation") == 0 && current_state == DO_ELEMENT_properties) { m_vAppData[m_iCurrentIndex].aux.ubWallOrientation = (UINT8)strtoul(sCharData.c_str(),&p,10); current_state = DO_ELEMENT_AuxData; } else if( strcmp(name, "ubNumberOfTiles") == 0 && current_state == DO_ELEMENT_properties) { m_vAppData[m_iCurrentIndex].aux.ubNumberOfTiles = (UINT8)strtoul(sCharData.c_str(),&p,10); current_state = DO_ELEMENT_AuxData; } else if( strcmp(name, "ubNumberOfFrames") == 0 && current_state == DO_ELEMENT_properties) { m_vAppData[m_iCurrentIndex].aux.ubNumberOfFrames = (UINT)strtoul(sCharData.c_str(),&p,10); current_state = DO_ELEMENT_AuxData; } else if( strcmp(name, "ubCurrentFrame") == 0 && current_state == DO_ELEMENT_properties) { m_vAppData[m_iCurrentIndex].aux.ubCurrentFrame = (UINT8)strtoul(sCharData.c_str(),&p,10); current_state = DO_ELEMENT_AuxData; } else if( strcmp(name, "flags") == 0 && current_state == DO_ELEMENT_flags) { current_state = DO_ELEMENT_AuxData; } else if( strcmp(name, "offset") == 0 && current_state == DO_ELEMENT_offset) { current_state = DO_ELEMENT_SubImage; } else if( strcmp(name, "AuxObjectData") == 0 && current_state == DO_ELEMENT_AuxData) { current_state = DO_ELEMENT_SubImage; } else if( strcmp(name, "SubImage") == 0 && current_state == DO_ELEMENT_SubImage) { current_state = DO_ELEMENT_ImageData; } else if( strcmp(name, this->ElementName) == 0 && current_state == DO_ELEMENT_ImageData) { unsigned int sum_frames = 0; for(unsigned int i = 0; i < m_vAppData.size(); ++i) { sum_frames += m_vAppData[i].aux.ubNumberOfFrames; } SGP_THROW_IFFALSE(sum_frames <= m_vAppData.size(), L"Sum of animation frames doesn't match the total number of frames"); int iAppDataSize = m_vAppData.size()*sizeof(AuxObjectData); m_hImage->pAppData = (UINT8*) MemAlloc( iAppDataSize ); for(unsigned int i = 0; i < m_vAppData.size(); ++i) { memcpy(&((AuxObjectData*)m_hImage->pAppData)[i],&m_vAppData[i],sizeof(AuxObjectData)); } m_hImage->uiAppDataSize = iAppDataSize; unsigned int aaa = std::max(m_hImage->usNumberOfObjects,m_vAppData.size()); for(unsigned int i = 0; i < aaa; ++i) { if(m_vAppData[i].offset._override) { m_hImage->pETRLEObject[i].sOffsetX = m_vAppData[i].offset.x; m_hImage->pETRLEObject[i].sOffsetY = m_vAppData[i].offset.y; } } m_hImage->fFlags |= IMAGE_APPDATA; current_state = DO_ELEMENT_NONE; } } void CAppDataParser::onTextElement(const XML_Char *str, int len) { // handle only this special case; everything else does not matter for now if(current_state == DO_ELEMENT_properties) { sCharData.append(str,len); } } bool IndexedSTIImage::readAppDataFromXMLFile(HIMAGE hImage, vfs::tReadableFile* pFile) { if(!pFile) { return false; } std::vector vBuffer; UINT32 uiSize = 0; try { vfs::COpenReadFile oFile(pFile); uiSize = oFile->getSize(); vBuffer.resize(uiSize+1); SGP_THROW_IFFALSE(uiSize == oFile->read(&vBuffer[0],uiSize), L"Could not read XML file"); vBuffer[uiSize] = 0; oFile->close(); } catch(std::exception& ex) { SGP_RETHROW(L"", ex); } XML_Parser parser = XML_ParserCreate(NULL); CAppDataParser adp(parser); adp.grabParser(); adp.setImage(hImage); try { if(!XML_Parse(parser, &vBuffer[0], uiSize, TRUE)) { std::wstringstream wss; wss << L"XML Parser Error in Groups.xml: " << vfs::String(XML_ErrorString(XML_GetErrorCode(parser))).c_wcs() << L" at line " << XML_GetCurrentLineNumber(parser); SGP_THROW(wss.str().c_str()); } } catch(std::exception &ex) { SGP_RETHROW(L"Could not load xml file", ex); } return true; } bool IndexedSTIImage::writeToHIMAGE(HIMAGE pImage) { if(!pImage) { return false; } pImage->usNumberOfObjects = _compressed_images.size(); pImage->usWidth = 640; pImage->usHeight = 480; pImage->ubBitDepth = 8; // pImage->fFlags = STCI_ETRLE_COMPRESSED | STCI_INDEXED | STCI_TRANSPARENT; pImage->fFlags |= IMAGE_TRLECOMPRESSED; pImage->fFlags |= IMAGE_BITMAPDATA; //strncat(pImage->ImageFile,"test",4); pImage->iFileLoader = -1; pImage->pui16BPPPalette = NULL; pImage->pPalette = new SGPPaletteEntry[256]; for(int j=0; j<256; ++j) { pImage->pPalette[j].peRed = _palette[j].ubRed; pImage->pPalette[j].peGreen = _palette[j].ubGreen; pImage->pPalette[j].peBlue = _palette[j].ubBlue; pImage->pPalette[j].peFlags = 0; } pImage->pETRLEObject = new ETRLEObject[pImage->usNumberOfObjects]; UINT32 offset=0; // == size for(unsigned int i=0; i<_images.size(); ++i) { pImage->pETRLEObject[i].sOffsetX = _images[i].sOffsetX; pImage->pETRLEObject[i].sOffsetY = _images[i].sOffsetY; pImage->pETRLEObject[i].usHeight = _images[i].usHeight; pImage->pETRLEObject[i].usWidth = _images[i].usWidth; pImage->pETRLEObject[i].uiDataOffset = offset; pImage->pETRLEObject[i].uiDataLength = _images[i].uiDataLength; offset += _images[i].uiDataLength; } pImage->uiSizePixData = offset; pImage->pPixData8 = new UINT8[offset]; // write sub-images for(unsigned int i=0; i<_compressed_images.size(); ++i) { memcpy( &pImage->pPixData8[pImage->pETRLEObject[i].uiDataOffset], &_compressed_images[i][0], pImage->pETRLEObject[i].uiDataLength); } //pImage->uiAppDataSize = pImage->usNumberOfObjects * sizeof(AuxObjectData); //pImage->pAppData = (UINT8*)(new AuxObjectData[pImage->usNumberOfObjects]); //memset(pImage->pAppData,0,pImage->uiAppDataSize); //// write application data //int frames = _compressed_images.size()/8; // 8 = number of directions //for(unsigned int i=0; iusNumberOfObjects; ++i) //{ // if(i % frames == 0) // { // AuxObjectData &aod = *((AuxObjectData*)(&pImage->pAppData[i*sizeof(AuxObjectData)])); // aod.ubNumberOfFrames = frames; // aod.fFlags = AUX_ANIMATED_TILE; // } //} return true; } /*******************************************************************************/ /*******************************************************************************/ class LoadPngFile { public: LoadPngFile(vfs::Path const& sFile) : _file(NULL), _struct(NULL), _info(NULL), _row_ptr(NULL) { // Open and read in the file vfs::COpenReadFile oFile(sFile); _file = &oFile.file(); oFile.release(); } LoadPngFile(vfs::tReadableFile* pFile) : _file(pFile), _struct(NULL), _info(NULL), _row_ptr(NULL) { SGP_THROW_IFFALSE(_file, L"file pointer is NULL"); } bool Load() { png::png_error_ptr user_error_ptr = NULL; png::png_error_ptr user_error_fn = NULL; png::png_error_ptr user_warning_fn = NULL; _struct = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png::png_voidp)user_error_ptr, user_error_fn, user_warning_fn); if (!_struct) { return false; } _info = png_create_info_struct(_struct); if (!_info) { png_destroy_read_struct(&_struct, (png::png_infopp)NULL, (png::png_infopp)NULL); return false; } png::png_infop end_info = png_create_info_struct(_struct); if (!end_info) { png_destroy_read_struct(&_struct, &_info, (png::png_infopp)NULL); return false; } // push file handle png_set_read_fn(_struct, _file, user_read_data); int png_transforms = PNG_TRANSFORM_IDENTITY; png_read_png(_struct, _info, png_transforms, NULL); // png_read_end(_struct,_info); _row_ptr = png_get_rows(_struct, _info); return _row_ptr != NULL; } ~LoadPngFile() { if(_file) { _file->close(); } if(_struct && _info) { png_destroy_info_struct(_struct, &_info); _info = NULL; } if(_struct) { png_destroy_read_struct(&_struct, (png::png_infopp)_info, (png::png_infopp)NULL); } //if(_row_ptr) //{ // int i=0; //} } png::png_bytepp Rows() { return _row_ptr; } png::png_infop Info() { return _info; } private: vfs::tReadableFile* _file; png::png_structp _struct; png::png_infop _info; png::png_bytepp _row_ptr; png::png_bytep _data; }; bool LoadPNGFileToImage(HIMAGE hImage, UINT16 fContents) { LoadPngFile fpng(hImage->ImageFile); if(!fpng.Load()) { return false; } if(fpng.Info()->channels == 4 && fpng.Info()->bit_depth == 8) { Load32bppPNGImage(hImage, fpng.Rows(), fpng.Info()); } else if(fpng.Info()->channels == 3 && fpng.Info()->bit_depth == 8) { Load24bppPNGImage(hImage, fpng.Rows(), fpng.Info()); } else if(fpng.Info()->channels == 1 && fpng.Info()->bit_depth == 8) { LoadPalettedPNGImage(hImage, fpng.Rows(), fpng.Info()); } else { std::wstringstream wss; wss << L"Unknown image datatype : channels = " << (int)(fpng.Info()->channels) << L", bit depth = " << (int)(fpng.Info()->bit_depth); SGP_THROW(wss.str().c_str()); } // data was copied to hImage, need to clean up here // ... return true; } bool LoadJPCFileToImage(HIMAGE hImage, UINT16 fContents) { if(!getVFS()->fileExists(hImage->ImageFile)) { return false; } vfs::CBufferFile oBuffer(""); vfs::COpenReadFile oFile(hImage->ImageFile); SGP_TRYCATCH_RETHROW(oBuffer.copyToBuffer(oFile.file()), L"Could not copy file to buffer"); oBuffer.close(); //vfs::CUncompressed7zLibrary oLib(&oFile.file(),""); vfs::ObjBlockAllocator allocator(128); vfs::CUncompressed7zLibrary oLib(vfs::tReadableFile::cast(&oBuffer),"",false, &allocator); if(!oLib.init()) { return false; } IndexedSTIImage image; std::vector vFiles; int count_files = 0; vfs::CUncompressed7zLibrary::Iterator it = oLib.begin(); for(; !it.end(); it.next()) { count_files++; } vFiles.resize(count_files); it = oLib.begin(); vfs::tReadableFile* appdata_file = NULL; for(; !it.end(); it.next()) { // check extension vfs::String::str_t const& fname = it.value()->getName().c_wcs(); vfs::String::size_t dot = fname.find_last_of(vfs::Const::DOT()); if(dot != vfs::String::str_t::npos) { if( vfs::StrCmp::Equal(fname.substr(dot,fname.length()-dot), CONST_DOTPNG) ) { std::wstringstream bss; bss.str( fname.substr(0,dot) ); int index; bss >> index; if(index >= 0 && index < count_files) { vFiles[index] = it.value(); } else { SGP_THROW(L"invalid index"); } } else if (vfs::StrCmp::Equal(fname.substr(dot,fname.length()-dot), CONST_DOTXML) ) { appdata_file = vfs::tReadableFile::cast(it.value()); } } } bool bHasPalette = false; std::vector::iterator fit = vFiles.begin(); if(vFiles.size() == 1) { try { // VR r2348 fix - loading .jpc.7z with a single image would cause exception as file was not considered open (by anv) //LoadPngFile lpng(vfs::tReadableFile::cast(vFiles[0])); vfs::CBufferFile oTempFile(""); oTempFile.copyToBuffer(*vfs::tReadableFile::cast(vFiles[0])); LoadPngFile lpng(vfs::tReadableFile::cast(&oTempFile)); bool bLoadS = lpng.Load(); if(bLoadS) { if(lpng.Info()->channels == 4 && lpng.Info()->bit_depth == 8) { Load32bppPNGImage(hImage, lpng.Rows(), lpng.Info()); } else if(lpng.Info()->channels == 3 && lpng.Info()->bit_depth == 8) { Load24bppPNGImage(hImage, lpng.Rows(), lpng.Info()); } else if(lpng.Info()->channels == 1 && lpng.Info()->bit_depth == 8) { LoadPalettedPNGImage(hImage, lpng.Rows(), lpng.Info()); } else { std::wstringstream wss; wss << L"Unknown image datatype : channels = " << (int)(lpng.Info()->channels) << L", bit depth = " << (int)(lpng.Info()->bit_depth); SGP_THROW(wss.str().c_str()); } return true; } } catch(std::exception &ex) { std::wstringstream wss; wss << L"Loading PNG image from file '" << oFile->getPath().c_wcs() << L"' failed"; SGP_RETHROW(wss.str().c_str(), ex); } return false; } else { for(int findex = 0; fit != vFiles.end(); ++fit, ++findex) { if(*fit == NULL) { // probably not a PNG file continue; } try { vfs::CBufferFile oTempFile(""); oTempFile.copyToBuffer( *vfs::tReadableFile::cast(*fit) ); // LoadPngFile lpng( vfs::tReadableFile::cast(*fit) ); LoadPngFile lpng( vfs::tReadableFile::cast(&oTempFile) ); bool bLoadS = lpng.Load(); if(bLoadS) { if(lpng.Info()->channels == 1 && lpng.Info()->bit_depth == 8) { if(!bHasPalette) { SGP_THROW_IFFALSE(lpng.Info()->num_palette == 256, L"size of palette is not 256"); image.setPalette(lpng.Info()->palette, lpng.Info()->num_palette); bHasPalette = true; } UINT32 SIZE = lpng.Info()->height * lpng.Info()->width; std::vector data(SIZE,0); for(unsigned int i = 0; i < lpng.Info()->height; ++i) { memcpy(&data[i*lpng.Info()->width],lpng.Rows()[i],lpng.Info()->width); } image.addImage(&data[0], SIZE, lpng.Info()->width, lpng.Info()->height, lpng.Info()->x_offset, lpng.Info()->y_offset); } else { std::wstringstream wss; wss << L"PNG file '" << (*fit)->getName()() << L" @ " << oFile->getPath()() << L"' is not a paletted image"; SGP_THROW(wss.str().c_str()); } } } catch(std::exception& ex) { std::wstringstream wss; wss << L"Loading PNG image [" << findex << L"] from file '" << oFile->getPath().c_wcs() << L"' failed"; SGP_RETHROW(wss.str().c_str(), ex); } } } bool success = image.writeToHIMAGE(hImage); if(appdata_file) { success &= image.readAppDataFromXMLFile(hImage, appdata_file); } return success; } void Load32bppPNGImage(HIMAGE hImage, png::png_bytepp rows, png::png_infop info) { hImage->pETRLEObject = (ETRLEObject*)MemAlloc(1 * sizeof(ETRLEObject)); if(!hImage->pETRLEObject) { SGP_THROW(L"bad alloc"); } memset(hImage->pETRLEObject, 0, sizeof(ETRLEObject)); hImage->usNumberOfObjects = 1; hImage->pETRLEObject[0].usHeight = (UINT16)info->height; hImage->pETRLEObject[0].usWidth = (UINT16)info->width; hImage->pETRLEObject[0].sOffsetX = (INT16)info->x_offset; hImage->pETRLEObject[0].sOffsetY = (INT16)info->y_offset; hImage->usHeight = (UINT16)info->height; hImage->usWidth = (UINT16)info->width; hImage->ubBitDepth = 32; UINT32 SIZE = info->height * info->width * sizeof(UINT32); hImage->p32BPPData = (UINT32*)MemAlloc(SIZE); if(!hImage->p32BPPData) { MemFree(hImage->pETRLEObject); SGP_THROW(L"bad alloc"); } memset(hImage->p32BPPData, 0, SIZE); UINT32* dest_row = NULL; UINT32 rgbcolor = 0; for(unsigned int i=0; iheight; ++i) { dest_row = &(hImage->p32BPPData[i*info->width]); png::png_bytep row_i = rows[i]; memcpy(dest_row,row_i,info->width * sizeof(UINT32)); } hImage->fFlags |= IMAGE_BITMAPDATA; } void Load24bppPNGImage(HIMAGE hImage, png::png_bytepp rows, png::png_infop info) { hImage->pETRLEObject = (ETRLEObject*)MemAlloc(1 * sizeof(ETRLEObject)); if(!hImage->pETRLEObject) { SGP_THROW(L"bad alloc"); } memset(hImage->pETRLEObject, 0, sizeof(ETRLEObject)); hImage->usNumberOfObjects = 1; hImage->pETRLEObject[0].usHeight = (UINT16)info->height; hImage->pETRLEObject[0].usWidth = (UINT16)info->width; hImage->pETRLEObject[0].sOffsetX = (UINT16)info->x_offset; hImage->pETRLEObject[0].sOffsetY = (UINT16)info->y_offset; hImage->usHeight = (UINT16)info->height; hImage->usWidth = (UINT16)info->width; hImage->ubBitDepth = 16; UINT32 SIZE = info->height * info->width * sizeof(UINT16); hImage->p16BPPData = (UINT16*)MemAlloc(SIZE); if(!hImage->p16BPPData) { MemFree(hImage->pETRLEObject); SGP_THROW(L"bad alloc"); } memset(hImage->p16BPPData, 0, SIZE); UINT16* dest_row = NULL; UINT32 rgbcolor = 0; for(unsigned int i=0; iheight; ++i) { dest_row = &(hImage->p16BPPData[i*info->width]); png::png_bytep row_i = rows[i]; for(unsigned int sx = 0, dx = 0; sx < 3*info->width; sx+=3, dx+=1) { dest_row[dx] = Get16BPPColor( FROMRGB(row_i[sx], row_i[sx+1], row_i[sx+2]) ); } } hImage->fFlags |= IMAGE_BITMAPDATA; } void LoadPalettedPNGImage(HIMAGE hImage, png::png_bytepp rows, png::png_infop info) { UINT32 SIZE = info->height * info->width * sizeof(UINT8); UINT8 *data = (UINT8*)MemAlloc(SIZE); if(!data) { SGP_THROW(L"bad alloc"); } memset(data,0,SIZE); for(unsigned int i = 0; i < info->height; ++i) { memcpy(&data[i*info->width],rows[i],info->width); } hImage->usNumberOfObjects = 1; hImage->pETRLEObject = (ETRLEObject*)MemAlloc(hImage->usNumberOfObjects * sizeof(ETRLEObject)); if(!hImage->pETRLEObject) { MemFree(data); SGP_THROW(L"bad alloc"); } memset(hImage->pETRLEObject,0, hImage->usNumberOfObjects * sizeof(ETRLEObject)); ETRLEObject &subimage = hImage->pETRLEObject[0]; subimage.sOffsetX = (INT16) info->x_offset;; subimage.sOffsetY = (INT16) info->y_offset; subimage.usWidth = (UINT16) info->width; subimage.usHeight = (UINT16) info->height; // why allocate so much? because in in the worst case we need one TAG and one DATAVALUE per pixel UINT32 RESIZE = 3*SIZE; hImage->p8BPPData = (UINT8*)MemAlloc( RESIZE ); if(!hImage->p8BPPData) { MemFree(hImage->pETRLEObject); MemFree(data); SGP_THROW(L"bad alloc"); } UINT8 *compressed = hImage->p8BPPData; memset(hImage->p8BPPData,0,RESIZE); UINT32 compressed_size = 0; STCISubImage subim; memset(&subim,0,sizeof(STCISubImage)); subim.uiDataLength = subimage.uiDataLength; subim.uiDataOffset = subimage.uiDataOffset; subim.usHeight = subimage.usHeight; subim.usWidth = subimage.usWidth; UINT32 etrle_size = ETRLECompressSubImage( hImage->p8BPPData, RESIZE, data, (UINT16)info->width, (UINT16)info->height, &subim); SGP_THROW_IFFALSE( etrle_size > 0, L"ETRLE compression of PNG image failed" ); subim.sOffsetX = subimage.sOffsetX; subim.sOffsetY = subimage.sOffsetY; //subimage.uiDataLength = compressed_size; subimage.uiDataLength = etrle_size; subimage.uiDataOffset = 0; hImage->ubBitDepth = 8; //hImage->uiSizePixData = compressed_size; hImage->uiSizePixData = etrle_size; hImage->usHeight = (UINT16)info->height; hImage->usWidth = (UINT16)info->width; hImage->fFlags |= IMAGE_TRLECOMPRESSED; hImage->fFlags |= IMAGE_BITMAPDATA; // palette SGP_THROW_IFFALSE(info->num_palette == 256, L"palette has size != 256"); hImage->pPalette = (SGPPaletteEntry*)MemAlloc(sizeof(SGPPaletteEntry) *256); for(int i=0; i<256; ++i) { hImage->pPalette[i].peRed = info->palette[i].red; hImage->pPalette[i].peGreen = info->palette[i].green; hImage->pPalette[i].peBlue = info->palette[i].blue; hImage->pPalette[i].peFlags = 0; } hImage->fFlags |= IMAGE_PALETTE; }