diff --git a/LibCmo/CK2/CKContext.cpp b/LibCmo/CK2/CKContext.cpp index 5fb86cd..3e9a06f 100644 --- a/LibCmo/CK2/CKContext.cpp +++ b/LibCmo/CK2/CKContext.cpp @@ -21,11 +21,14 @@ namespace LibCmo::CK2 { m_FileWriteMode(CK_FILE_WRITEMODE::CKFILE_UNCOMPRESSED), m_GlobalImagesSaveOptions(CK_TEXTURE_SAVEOPTIONS::CKTEXTURE_RAWDATA), m_GlobalSoundsSaveOptions(CK_SOUND_SAVEOPTIONS::CKSOUND_EXTERNAL), - m_GlobalImagesSaveFormat(nullptr), // todo: setup save format + m_GlobalImagesSaveFormat(), // misc init m_NameEncoding(), m_OutputCallback(nullptr) { + // setup save format + m_GlobalImagesSaveFormat.m_Ext.SetExt("bmp"); + // setup managers m_ObjectManager = new MgrImpls::CKObjectManager(this); m_ManagerList.emplace_back(m_ObjectManager); @@ -225,12 +228,12 @@ namespace LibCmo::CK2 { } } - const CKBitmapProperties* CKContext::GetGlobalImagesSaveFormat() { + const CKBitmapProperties& CKContext::GetGlobalImagesSaveFormat() { return m_GlobalImagesSaveFormat; } - void CKContext::SetGlobalImagesSaveFormat(const CKBitmapProperties* Format) { - // todo: copy CKBitmapProperties + void CKContext::SetGlobalImagesSaveFormat(const CKBitmapProperties& Format) { + m_GlobalImagesSaveFormat = Format; } CK_SOUND_SAVEOPTIONS CKContext::GetGlobalSoundsSaveOptions() { diff --git a/LibCmo/CK2/CKContext.hpp b/LibCmo/CK2/CKContext.hpp index e3bfd0f..7b7f71e 100644 --- a/LibCmo/CK2/CKContext.hpp +++ b/LibCmo/CK2/CKContext.hpp @@ -85,8 +85,8 @@ namespace LibCmo::CK2 { CK_TEXTURE_SAVEOPTIONS GetGlobalImagesSaveOptions(); void SetGlobalImagesSaveOptions(CK_TEXTURE_SAVEOPTIONS Options); - const CKBitmapProperties* GetGlobalImagesSaveFormat(); - void SetGlobalImagesSaveFormat(const CKBitmapProperties* Format); + const CKBitmapProperties& GetGlobalImagesSaveFormat(); + void SetGlobalImagesSaveFormat(const CKBitmapProperties& Format); CK_SOUND_SAVEOPTIONS GetGlobalSoundsSaveOptions(); void SetGlobalSoundsSaveOptions(CK_SOUND_SAVEOPTIONS Options); @@ -96,7 +96,7 @@ namespace LibCmo::CK2 { CK_FILE_WRITEMODE m_FileWriteMode; CK_TEXTURE_SAVEOPTIONS m_GlobalImagesSaveOptions; CK_SOUND_SAVEOPTIONS m_GlobalSoundsSaveOptions; - CKBitmapProperties* m_GlobalImagesSaveFormat; + CKBitmapProperties m_GlobalImagesSaveFormat; // ========== Encoding utilities ========== public: diff --git a/LibCmo/CK2/CKGlobals.cpp b/LibCmo/CK2/CKGlobals.cpp index 23eb8e0..e3326a4 100644 --- a/LibCmo/CK2/CKGlobals.cpp +++ b/LibCmo/CK2/CKGlobals.cpp @@ -78,6 +78,32 @@ namespace LibCmo::CK2 { } } + bool CKStrEqualI(CKSTRING str1, CKSTRING str2) { + if (str1 == nullptr) { + if (str2 == nullptr) return true; + else return false; + } else { + if (str2 == nullptr) return false; + else { + // do real cmp + size_t i = 0; + while (str1[i] != '\0' && str2[i] != '\0') { + if (std::tolower(str1[i]) != std::tolower(str2[i])) return false; + ++str1; + ++str2; + } + + // !XOR the result, if both of them is zero, return true(1) + return !((str1[i] != '\0') ^ (str2[i] != '\0')); + } + } + } + + bool CKStrEmpty(CKSTRING strl) { + if (strl == nullptr) return true; + return strl[0] == '\0'; + } + #pragma endregion #pragma region CKClass Registration diff --git a/LibCmo/CK2/CKGlobals.hpp b/LibCmo/CK2/CKGlobals.hpp index a03a22d..a5e3651 100644 --- a/LibCmo/CK2/CKGlobals.hpp +++ b/LibCmo/CK2/CKGlobals.hpp @@ -47,7 +47,28 @@ namespace LibCmo::CK2 { // ========== String Utilities ========== + /** + * @brief Check whether 2 string is equal. Case senstive. + * @param str1[in] String 1 + * @param str2[in] String 2 + * @return True if 2 string is equal. + * @see CKStrIEqual + */ bool CKStrEqual(CKSTRING str1, CKSTRING str2); + /** + * @brief Check whther 2 string is equal. Case insenstive. + * @param str1 + * @param str2 + * @return True if 2 string is equal. + * @see CKStrEqual + */ + bool CKStrEqualI(CKSTRING str1, CKSTRING str2); + /** + * @brief Check whether string is empty + * @param strl + * @return True if string is empty. + */ + bool CKStrEmpty(CKSTRING strl); // ========== Numberic Utilities ========== diff --git a/LibCmo/CK2/CKTypes.hpp b/LibCmo/CK2/CKTypes.hpp index cd7957c..2c1fa86 100644 --- a/LibCmo/CK2/CKTypes.hpp +++ b/LibCmo/CK2/CKTypes.hpp @@ -366,6 +366,55 @@ namespace LibCmo::CK2 { } }; + /** + * @brief Storage class for filename extensions + */ + class CKFileExtension { + public: + CKFileExtension() : m_Data() { + std::memset(m_Data, 0, c_DataLen); + } + CKFileExtension(CKSTRING s) : CKFileExtension() { + SetExt(s); + } + CKFileExtension(const CKFileExtension& rhs) : CKFileExtension() { + std::memcpy(m_Data, rhs.m_Data, c_DataLen); + } + CKFileExtension(CKFileExtension&& rhs) : CKFileExtension() { + std::memmove(m_Data, rhs.m_Data, c_DataLen); + std::memset(rhs.m_Data, 0, c_DataLen); + } + CKFileExtension& operator=(const CKFileExtension& rhs) { + std::memcpy(m_Data, rhs.m_Data, c_DataLen); + } + CKFileExtension& operator=(CKFileExtension&& rhs) { + std::memmove(m_Data, rhs.m_Data, c_DataLen); + std::memset(rhs.m_Data, 0, c_DataLen); + } + + void SetExt(CKSTRING s) { + if (s == nullptr) { + m_Data[0] = '\0'; + } else { + if (s[0] == '.') ++s; // skip dot + size_t len = std::strlen(s); + if (len > (c_DataLen - 1)) len = c_DataLen - 1; + std::memcpy(m_Data, s, len); + } + } + + CKSTRING GetExt() const { + return m_Data; + } + + bool operator==(const CKFileExtension& rhs) const { + return CKStrEqualI(m_Data, rhs.m_Data); + } + + protected: + static const size_t c_DataLen = 4u; + CKCHAR m_Data[c_DataLen]; + }; /** * The struct describe the bitmap handler's infomation, @@ -374,32 +423,16 @@ namespace LibCmo::CK2 { * such as jpeg compress level and etc. But currently there are no * such parameters. */ - struct CKBitmapProperties { + class CKBitmapProperties { + public: CKBitmapProperties() : - m_ReaderGuid(), m_Ext(3, '\0') {} - CKBitmapProperties(CKGUID& guid, const char* ext) : - m_ReaderGuid(guid), m_Ext(3, '\0') { - SetExt(ext); - } + m_ReaderGuid(), m_Ext() {} + CKBitmapProperties(const CKGUID& guid, CKSTRING ext) : + m_ReaderGuid(guid), m_Ext(ext) {} LIBCMO_DEFAULT_COPY_MOVE(CKBitmapProperties); - void SetExt(const char* s) { - if (s == nullptr) { - m_Ext[0] = '\0'; - } else { - if (s[0] == '.') ++s; // skip dot - size_t len = std::strlen(s); - if (len > m_Ext.size()) len = m_Ext.size(); - std::memcpy(m_Ext.data(), s, len); - } - } - - CKSTRING ExtToCKSTRING() { - return m_Ext.c_str(); - } - CKGUID m_ReaderGuid; /**< CKGUID that uniquely identifies the reader that created this properties structure */ - std::string m_Ext; /**< File Extension of the image being described by this structure */ + CKFileExtension m_Ext; /**< File Extension of the image being described by this structure */ }; diff --git a/LibCmo/CK2/DataHandlers/CKBitmapHandler.cpp b/LibCmo/CK2/DataHandlers/CKBitmapHandler.cpp index 7cbec6b..49db592 100644 --- a/LibCmo/CK2/DataHandlers/CKBitmapHandler.cpp +++ b/LibCmo/CK2/DataHandlers/CKBitmapHandler.cpp @@ -5,6 +5,8 @@ namespace LibCmo::CK2::DataHandlers { +#pragma region Help Functions + static void RGBAToARGB(CK2::CKDWORD count, const void* _rgba, void* _argb) { const char* rgba = reinterpret_cast(_rgba); char* argb = reinterpret_cast(_argb); @@ -66,12 +68,12 @@ namespace LibCmo::CK2::DataHandlers { STBIR_COLORSPACE_SRGB, nullptr ); // copy data - RGBAToARGB(read_image->GetPixelCount(), newdata, read_image->GetImage()); + RGBAToARGB(read_image->GetPixelCount(), newdata, read_image->GetMutableImage()); // free delete[] newdata; } else { // copy data RGBA -> ARGB - RGBAToARGB(read_image->GetPixelCount(), data, read_image->GetImage()); + RGBAToARGB(read_image->GetPixelCount(), data, read_image->GetMutableImage()); } } static bool StbReadFile(CKSTRING u8filename, VxMath::VxImageDescEx* read_image) { @@ -145,18 +147,17 @@ namespace LibCmo::CK2::DataHandlers { static bool StbSaveFile(CKSTRING u8filename, const VxMath::VxImageDescEx* write_image, SaveOperation oper) { if (u8filename == nullptr || write_image == nullptr) return false; FILE* fs = EncodingHelper::U8FOpen(u8filename, "wb"); - if (fs == nullptr) return; + if (fs == nullptr) return false; // allocate buffer and convert data from ARGB to RGBA - VxMath::VxImageDescEx* wi = const_cast(write_image); CKBYTE* data = new CKBYTE[write_image->GetImageSize()]; - ARGBToRGBA(write_image->GetPixelCount(), wi->GetImage(), data); + ARGBToRGBA(write_image->GetPixelCount(), write_image->GetImage(), data); // write data FileSaveContext* ctx = new FileSaveContext(fs); int ret = oper( &FileWriteFunction, ctx, - static_cast(wi->GetWidth()), static_cast(wi->GetHeight()), + static_cast(write_image->GetWidth()), static_cast(write_image->GetHeight()), 4, data // 4 == RGBA8888 ); @@ -171,15 +172,14 @@ namespace LibCmo::CK2::DataHandlers { if (write_image == nullptr) return 0; // allocate buffer and convert data from ARGB to RGBA - VxMath::VxImageDescEx* wi = const_cast(write_image); CKBYTE* data = new CKBYTE[write_image->GetImageSize()]; - ARGBToRGBA(write_image->GetPixelCount(), wi->GetImage(), data); + ARGBToRGBA(write_image->GetPixelCount(), write_image->GetImage(), data); // write data MemorySaveContext* ctx = new MemorySaveContext(memory); int ret = oper( &FileWriteFunction, ctx, - static_cast(wi->GetWidth()), static_cast(wi->GetHeight()), + static_cast(write_image->GetWidth()), static_cast(write_image->GetHeight()), 4, data // 4 == RGBA8888 ); @@ -191,20 +191,20 @@ namespace LibCmo::CK2::DataHandlers { if (ret == 0) return 0; else return expected; } + +#pragma endregion #pragma region CKBitmapBMPHandler + static const CKBitmapProperties g_BMPProperties(CKGUID(0xBCA97223u, 0x48578BCAu), "Bmp"); + CKBitmapBMPHandler::CKBitmapBMPHandler() : - CKBitmapHandler(), c_DefaultProp() { - c_DefaultProp.SetExt("Tga"); - c_DefaultProp.m_ReaderGuid.d1 = 0xBCA97223u; - c_DefaultProp.m_ReaderGuid.d2 = 0x48578BCAu; - } + CKBitmapHandler() {} CKBitmapBMPHandler::~CKBitmapBMPHandler() {} const CKBitmapProperties& CKBitmapBMPHandler::GetBitmapDefaultProperties() { - return c_DefaultProp; + return g_BMPProperties; } bool CKBitmapBMPHandler::ReadFile(CKSTRING u8filename, VxMath::VxImageDescEx* read_image) { @@ -232,18 +232,16 @@ namespace LibCmo::CK2::DataHandlers { #pragma endregion #pragma region CKBitmapTGAHandler + + static const CKBitmapProperties g_TGAProperties(CKGUID(0x585C7216u, 0x33302657u), "Tga"); CKBitmapTGAHandler::CKBitmapTGAHandler() : - CKBitmapHandler(), c_DefaultProp() { - c_DefaultProp.SetExt("Tga"); - c_DefaultProp.m_ReaderGuid.d1 = 0x585C7216u; - c_DefaultProp.m_ReaderGuid.d2 = 0x33302657u; - } + CKBitmapHandler() {} CKBitmapTGAHandler::~CKBitmapTGAHandler() {} const CKBitmapProperties& CKBitmapTGAHandler::GetBitmapDefaultProperties() { - return c_DefaultProp; + return g_TGAProperties; } bool CKBitmapTGAHandler::ReadFile(CKSTRING u8filename, VxMath::VxImageDescEx* read_image) { @@ -257,18 +255,51 @@ namespace LibCmo::CK2::DataHandlers { bool CKBitmapTGAHandler::SaveFile(CKSTRING u8filename, const VxMath::VxImageDescEx* write_image, const CKBitmapProperties& codec_param) { return StbSaveFile(u8filename, write_image, [&codec_param](stbi_write_func* func, void* context, int w, int h, int comp, const void* data) -> int { - return stbi_write_bmp_to_func(func, context, w, h, comp, data); + return stbi_write_tga_to_func(func, context, w, h, comp, data); }); } CKDWORD CKBitmapTGAHandler::SaveMemory(void* memory, const VxMath::VxImageDescEx* write_image, const CKBitmapProperties& codec_param) { return StbSaveMemory(memory, write_image, [&codec_param](stbi_write_func* func, void* context, int w, int h, int comp, const void* data) -> int { - return stbi_write_bmp_to_func(func, context, w, h, comp, data); + return stbi_write_tga_to_func(func, context, w, h, comp, data); }); } #pragma endregion + +#pragma region General Getter Freer + static CKBitmapHandler* FindHandlerByExt(const CKFileExtension& ext) { + if (ext == g_BMPProperties.m_Ext) return new CKBitmapBMPHandler(); + if (ext == g_TGAProperties.m_Ext) return new CKBitmapTGAHandler(); + return nullptr; + } + + static CKBitmapHandler* FindHandlerByGuid(const CKGUID& guid) { + if (guid == g_BMPProperties.m_ReaderGuid) return new CKBitmapBMPHandler(); + if (guid == g_TGAProperties.m_ReaderGuid) return new CKBitmapTGAHandler(); + return nullptr; + } + + CKBitmapHandler* CKBitmapHandler::GetBitmapHandler(const CKFileExtension& ext, const CKGUID& guid) { + CKBitmapHandler* handler = nullptr; + + // check ext first + handler = FindHandlerByExt(ext); + if (handler != nullptr) return handler; + + // check guid + handler = FindHandlerByGuid(guid); + if (handler != nullptr) return handler; + + return nullptr; + } + + void CKBitmapHandler::ReleaseBitmapHandler(CKBitmapHandler* handler) { + if (handler != nullptr) delete handler; + } + +#pragma endregion } diff --git a/LibCmo/CK2/DataHandlers/CKBitmapHandler.hpp b/LibCmo/CK2/DataHandlers/CKBitmapHandler.hpp index 9307493..062669b 100644 --- a/LibCmo/CK2/DataHandlers/CKBitmapHandler.hpp +++ b/LibCmo/CK2/DataHandlers/CKBitmapHandler.hpp @@ -15,6 +15,22 @@ namespace LibCmo::CK2::DataHandlers { virtual ~CKBitmapHandler() {} LIBCMO_DISABLE_COPY_MOVE(CKBitmapHandler); + /** + * @brief General CKBitmapHandler getter. + * @param ext[in] The file extention help finding corresponding bitmap handler. + * @param guid[in] The GUID of bitmap handler used in fall back finding. + * @remark + * + Returns a reader capable of reading file with the given extension ext + * + It may be several plugins that support the same extension, in which case a preferedGUID identifying the reader that should be returned can be given (optionnal). + * @return The pointer to CKBitmapHandler. nullptr if fail to find. + */ + static CKBitmapHandler* GetBitmapHandler(const CKFileExtension& ext, const CKGUID& guid); + /** + * @brief General CKBitmapHandler disposer + * @param handler[in] The handler need to be free. + */ + static void ReleaseBitmapHandler(CKBitmapHandler* handler); + /** * @brief Returns the current default bitmap options. * @return Current default bitmap options @@ -75,8 +91,6 @@ namespace LibCmo::CK2::DataHandlers { virtual bool SaveFile(CKSTRING u8filename, const VxMath::VxImageDescEx* write_image, const CKBitmapProperties& codec_param) override; virtual CKDWORD SaveMemory(void* memory, const VxMath::VxImageDescEx* write_image, const CKBitmapProperties& codec_param) override; - protected: - CKBitmapProperties c_DefaultProp; }; class CKBitmapTGAHandler : public CKBitmapHandler { @@ -91,8 +105,6 @@ namespace LibCmo::CK2::DataHandlers { virtual bool SaveFile(CKSTRING u8filename, const VxMath::VxImageDescEx* write_image, const CKBitmapProperties& codec_param) override; virtual CKDWORD SaveMemory(void* memory, const VxMath::VxImageDescEx* write_image, const CKBitmapProperties& codec_param) override; - protected: - CKBitmapProperties c_DefaultProp; }; } diff --git a/LibCmo/CK2/MgrImpls/CKPathManager.cpp b/LibCmo/CK2/MgrImpls/CKPathManager.cpp index 42365e4..6904e34 100644 --- a/LibCmo/CK2/MgrImpls/CKPathManager.cpp +++ b/LibCmo/CK2/MgrImpls/CKPathManager.cpp @@ -10,7 +10,7 @@ namespace LibCmo::CK2::MgrImpls { CKPathManager::CKPathManager(CKContext* ctx) : CKBaseManager(ctx, PATH_MANAGER_GUID, "Path Manager"), - m_TempFolder() { + m_TempFolder(), m_ExtraPathes() { // preset for temp folder // todo: add current CKContext pointer as the part of temp path. // thus multiple CKContext can work. @@ -21,8 +21,15 @@ namespace LibCmo::CK2::MgrImpls { } CKPathManager::~CKPathManager() {} - void CKPathManager::SetTempFolder(CKSTRING u8_temp) { - EncodingHelper::U8PathToStdPath(this->m_TempFolder, u8_temp); + bool CKPathManager::SetTempFolder(CKSTRING u8_temp) { + std::filesystem::path cache; + EncodingHelper::U8PathToStdPath(cache, u8_temp); + if (std::filesystem::is_directory(cache)) { + m_TempFolder = cache; + return true; + } else { + return false; + } } std::string CKPathManager::GetTempFolder() { @@ -41,8 +48,49 @@ namespace LibCmo::CK2::MgrImpls { return result; } + bool CKPathManager::AddPath(CKSTRING u8path) { + if (u8path == nullptr) return; + std::filesystem::path newpath; + EncodingHelper::U8PathToStdPath(newpath, u8path); + if (std::filesystem::is_directory(newpath)) { + m_ExtraPathes.emplace_back(std::move(newpath)); + return true; + } else { + return false; + } + } + + void CKPathManager::ClearPath() { + m_ExtraPathes.clear(); + } + bool CKPathManager::ResolveFileName(std::string& u8_filename) { - // todo: finish resolve file name + std::filesystem::path filepath; + EncodingHelper::U8PathToStdPath(filepath, u8_filename.c_str()); + + // if it is absolute path, return it directly + if (filepath.is_absolute()) { + return true; + } + + // otherwise check it in extra path + for (const auto& extrapath : m_ExtraPathes) { + auto combinedpath = extrapath / filepath; + if (std::filesystem::is_regular_file(combinedpath)) { + // this is correct + EncodingHelper::StdPathToU8Path(u8_filename, combinedpath); + return true; + } + } + + // test in temp folder + auto tempfile = m_TempFolder / filepath; + if (std::filesystem::is_regular_file(tempfile)) { + EncodingHelper::StdPathToU8Path(u8_filename, combinedpath); + return true; + } + + // failed return false; } diff --git a/LibCmo/CK2/MgrImpls/CKPathManager.hpp b/LibCmo/CK2/MgrImpls/CKPathManager.hpp index 8a9de29..e34614e 100644 --- a/LibCmo/CK2/MgrImpls/CKPathManager.hpp +++ b/LibCmo/CK2/MgrImpls/CKPathManager.hpp @@ -14,9 +14,10 @@ namespace LibCmo::CK2::MgrImpls { /** * @brief Set the temp folder of current context. - * @param u8_temp + * @param u8_temp The temp folder you need to assign + * @return true if success. */ - void SetTempFolder(CKSTRING u8_temp); + bool SetTempFolder(CKSTRING u8_temp); /** * @brief Get current temp folder. * @return @@ -29,15 +30,32 @@ namespace LibCmo::CK2::MgrImpls { */ std::string GetTempFilePath(CKSTRING u8_filename); + /** + * @brief Add extra path for ResolveFileName + * @param u8path The added path. + * @return true if success. + */ + bool AddPath(CKSTRING u8path); + /** + * @brief Clear all extra path. + */ + void ClearPath(); + /** * @brief Finds a file in the paths * @param u8_filename[inout] The given file path. overwritten by the final path if success. + * @remark + * We match file in following order. + * + Whether given file is absolute path. return if true. + * + User provided extra path. + * + Virtools temp folder. * @return true if success */ bool ResolveFileName(std::string& u8_filename); protected: std::filesystem::path m_TempFolder; + XContainer::XArray m_ExtraPathes; }; } diff --git a/LibCmo/VxMath/VxMath.cpp b/LibCmo/VxMath/VxMath.cpp index 5ba33d5..70e586c 100644 --- a/LibCmo/VxMath/VxMath.cpp +++ b/LibCmo/VxMath/VxMath.cpp @@ -57,7 +57,7 @@ namespace LibCmo::VxMath { void VxDoAlphaBlit(VxImageDescEx* dst_desc, CK2::CKBYTE AlphaValue) { if (dst_desc == nullptr) return; - CK2::CKDWORD* pixels = dst_desc->GetPixels(); + CK2::CKDWORD* pixels = dst_desc->GetMutablePixels(); CK2::CKDWORD pixelcount = dst_desc->GetPixelCount(); for (CK2::CKDWORD i = 0; i < pixelcount; ++i) { @@ -81,7 +81,7 @@ namespace LibCmo::VxMath { void VxDoAlphaBlit(VxImageDescEx* dst_desc, CK2::CKBYTE* AlphaValues) { if (dst_desc == nullptr) return; - CK2::CKDWORD* pixels = dst_desc->GetPixels(); + CK2::CKDWORD* pixels = dst_desc->GetMutablePixels(); CK2::CKDWORD pixelcount = dst_desc->GetPixelCount(); for (CK2::CKDWORD i = 0; i < pixelcount; ++i) { diff --git a/LibCmo/VxMath/VxTypes.hpp b/LibCmo/VxMath/VxTypes.hpp index e452b8c..455af8b 100644 --- a/LibCmo/VxMath/VxTypes.hpp +++ b/LibCmo/VxMath/VxTypes.hpp @@ -92,14 +92,20 @@ namespace LibCmo::VxMath { CK2::CKDWORD GetImageSize() const { return static_cast(sizeof(uint32_t) * m_Width * m_Height); } - CK2::CKBYTE* GetImage() { + const CK2::CKBYTE* GetImage() const { + return m_Image; + } + CK2::CKBYTE* GetMutableImage() { return m_Image; } CK2::CKDWORD GetPixelCount() const { return static_cast(m_Width * m_Height); } - CK2::CKDWORD* GetPixels() { + const CK2::CKDWORD* GetPixels() const { + return reinterpret_cast(m_Image); + } + CK2::CKDWORD* GetMutablePixels() { return reinterpret_cast(m_Image); }