almost finish CKBitmapData read
This commit is contained in:
@ -10,14 +10,117 @@ namespace LibCmo::CK2 {
|
||||
#pragma region Assist RW Functions
|
||||
|
||||
bool CKBitmapData::ReadSpecificFormatBitmap(CKStateChunk* chk, VxMath::VxImageDescEx* slot) {
|
||||
return false;
|
||||
// read transparent prop
|
||||
CKDWORD transprop;
|
||||
chk->ReadStruct(transprop);
|
||||
|
||||
// get ext and guid to find correct guid
|
||||
CKCHAR filerawext[4];
|
||||
CKGUID fileguid;
|
||||
chk->ReadNoSizeBuffer(CKSizeof(filerawext), filerawext);
|
||||
chk->ReadStruct(fileguid);
|
||||
CKFileExtension fileext(filerawext);
|
||||
auto reader = DataHandlers::CKBitmapHandler::GetBitmapHandlerWrapper(fileext, fileguid);
|
||||
if (reader == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// read image size
|
||||
CKDWORD imgbytesize;
|
||||
chk->ReadStruct(imgbytesize);
|
||||
if (imgbytesize != 0) {
|
||||
// get image data ptr
|
||||
const void* imgdata = nullptr;
|
||||
if (!chk->ReadDryBuffer(&imgdata, imgbytesize)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// parse image
|
||||
VxMath::VxImageDescEx cache;
|
||||
if (!reader->ReadMemory(imgdata, imgbytesize, &cache)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// post proc image (copy to slot)
|
||||
VxMath::VxDoBlit(&cache, slot);
|
||||
|
||||
// proc image alpha
|
||||
if (transprop == 2) {
|
||||
CKDWORD alphacount;
|
||||
chk->ReadStruct(alphacount);
|
||||
if (alphacount == 1) {
|
||||
CKDWORD globalalpha;
|
||||
chk->ReadStruct(globalalpha);
|
||||
VxMath::VxDoAlphaBlit(slot, static_cast<CKBYTE>(globalalpha));
|
||||
} else {
|
||||
CKStateChunk::TBuffer alphabuf;
|
||||
CKDWORD buflen;
|
||||
chk->ReadBufferWrapper(&alphabuf, &buflen);
|
||||
VxMath::VxDoAlphaBlit(slot, reinterpret_cast<CKBYTE*>(alphabuf.get()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CKBitmapData::ReadRawBitmap(CKStateChunk* chk, VxMath::VxImageDescEx* slot) {
|
||||
return false;
|
||||
CKDWORD bytePerPixel, width, height, redMask, greenMask, blueMask, alphaMask;
|
||||
chk->ReadStruct(bytePerPixel); // not used
|
||||
if (bytePerPixel == 0) return false;
|
||||
|
||||
chk->ReadStruct(width);
|
||||
chk->ReadStruct(height);
|
||||
chk->ReadStruct(alphaMask);
|
||||
chk->ReadStruct(redMask);
|
||||
chk->ReadStruct(greenMask);
|
||||
chk->ReadStruct(blueMask);
|
||||
|
||||
// read RGBA buffer
|
||||
CKStateChunk::TBuffer redBuffer, greenBuffer, blueBuffer, alphaBuffer;
|
||||
CKDWORD bufsize;
|
||||
CKDWORD bufopt;
|
||||
chk->ReadStruct(bufopt);
|
||||
bufopt &= 0xFu;
|
||||
if (bufopt != 0) {
|
||||
// MARK: not supported CCompressionTools::jpegDecode()
|
||||
// There are some shitty jpeg decode function.
|
||||
// I do not want to touch them because all of my work do not related to them
|
||||
// so return false simply
|
||||
return false;
|
||||
} else {
|
||||
chk->ReadBufferWrapper(&redBuffer, &bufsize);
|
||||
chk->ReadBufferWrapper(&greenBuffer, &bufsize);
|
||||
chk->ReadBufferWrapper(&blueBuffer, &bufsize);
|
||||
}
|
||||
chk->ReadBufferWrapper(&alphaBuffer, &bufsize);
|
||||
|
||||
// write into file
|
||||
if (redBuffer != nullptr && greenBuffer != nullptr && blueBuffer != nullptr) {
|
||||
// create image
|
||||
slot->CreateImage(width, height);
|
||||
// get essential data
|
||||
CKDWORD pixelcount = slot->GetPixelCount();
|
||||
CKBYTE* dst = slot->GetMutableImage(),
|
||||
* redSrc = reinterpret_cast<CKBYTE*>(redBuffer.get()),
|
||||
* greenSrc = reinterpret_cast<CKBYTE*>(greenBuffer.get()),
|
||||
* blueSrc = reinterpret_cast<CKBYTE*>(blueBuffer.get()),
|
||||
* alphaSrc = reinterpret_cast<CKBYTE*>(alphaBuffer.get());
|
||||
for (CKDWORD p = 0; p < pixelcount; ++p) {
|
||||
// if no alpha data, set to 0xFF
|
||||
*(dst++) = (alphaBuffer != nullptr ? (*(alphaSrc++)) : 0xFFu);
|
||||
*(dst++) = *(redSrc++);
|
||||
*(dst++) = *(greenSrc++);
|
||||
*(dst++) = *(blueSrc++);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CKBitmapData::ReadOldRawBitmap(CKStateChunk* chk, VxMath::VxImageDescEx* slot) {
|
||||
// MARK: not supported because all of my work do not involve this function.
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -37,6 +140,9 @@ namespace LibCmo::CK2 {
|
||||
XContainer::XBitArray notReadSlot;
|
||||
|
||||
// check 3 types enbedded image
|
||||
// MARK: i think there is a potential vulnerable issue.
|
||||
// if a slot failed, all following slot will read data from a wrong position.
|
||||
// thus the program will crash or allocated massive garbage data.
|
||||
if (chunk->SeekIdentifierDword(identifiers.m_SpecificFormat)) {
|
||||
// specific format
|
||||
CKDWORD slotcount, width, height, bpp;
|
||||
@ -48,6 +154,10 @@ namespace LibCmo::CK2 {
|
||||
SetSlotCount(slotcount);
|
||||
notReadSlot.resize(slotcount, false);
|
||||
|
||||
// the height and width is written outside of specific format
|
||||
// so we create image first for it.
|
||||
// and let reader to read data.
|
||||
// and free image if is is failed.
|
||||
if (width > 0 && height > 0) {
|
||||
for (CKDWORD i = 0; i < slotcount; ++i) {
|
||||
CreateImage(width, height, i);
|
||||
@ -67,11 +177,17 @@ namespace LibCmo::CK2 {
|
||||
SetSlotCount(slotcount);
|
||||
notReadSlot.resize(slotcount, false);
|
||||
|
||||
// the height and width is read by raw data function self.
|
||||
// so we pass a cache variable to reader and do some modification
|
||||
// if it is success.
|
||||
for (CKDWORD i = 0; i < slotcount; ++i) {
|
||||
if (ReadRawBitmap(chunk, GetImageDesc(i))) {
|
||||
VxMath::VxImageDescEx rawcache;
|
||||
if (ReadRawBitmap(chunk, &rawcache)) {
|
||||
notReadSlot[i] = true;
|
||||
} else {
|
||||
ReleaseImage(i);
|
||||
|
||||
// do upside down blit
|
||||
CreateImage(rawcache.GetWidth(), rawcache.GetHeight(), i);
|
||||
VxMath::VxDoBlitUpsideDown(&rawcache, GetImageDesc(i));
|
||||
}
|
||||
}
|
||||
|
||||
@ -83,6 +199,7 @@ namespace LibCmo::CK2 {
|
||||
SetSlotCount(slotcount);
|
||||
notReadSlot.resize(slotcount, false);
|
||||
|
||||
// MARK: a rough implement because we do not support this identifier
|
||||
for (CKDWORD i = 0; i < slotcount; ++i) {
|
||||
if (ReadOldRawBitmap(chunk, GetImageDesc(i))) {
|
||||
notReadSlot[i] = true;
|
||||
@ -105,17 +222,23 @@ namespace LibCmo::CK2 {
|
||||
for (CKDWORD i = 0; i < slotcount; ++i) {
|
||||
std::string filename;
|
||||
chunk->ReadString(filename);
|
||||
if (filename.empty()) return;
|
||||
|
||||
// set
|
||||
SetSlotFileName(i, filename.c_str());
|
||||
|
||||
// if not loaded, and suc in resolve file path.
|
||||
// load it
|
||||
if (filename.empty()) continue;
|
||||
|
||||
bool isNotLoaded = i >= notReadSlot.size() || notReadSlot[i];
|
||||
if (isNotLoaded && m_Context->GetPathManager()->ResolveFileName(filename)) {
|
||||
LoadImage(filename.c_str(), i);
|
||||
if (isNotLoaded) {
|
||||
// if this image is not loaded.
|
||||
// try resolve its file name and load it.
|
||||
// and set resolved filename for it.
|
||||
if (m_Context->GetPathManager()->ResolveFileName(filename)) {
|
||||
if (LoadImage(filename.c_str(), i)) {
|
||||
SetSlotFileName(i, filename.c_str());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// otherwise, set filename simply
|
||||
SetSlotFileName(i, filename.c_str());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -124,6 +247,7 @@ namespace LibCmo::CK2 {
|
||||
// MARK: movie is not implemented here.
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CKBitmapData::DumpToChunk(CKStateChunk* chunk, CKFileVisitor* file, const CKBitmapDataWriteIdentifiers& identifiers) {
|
||||
@ -176,29 +300,45 @@ namespace LibCmo::CK2 {
|
||||
// get extension of file. then get corresponding reader
|
||||
std::string ext(filename);
|
||||
m_Context->GetPathManager()->GetExtension(ext);
|
||||
std::unique_ptr<DataHandlers::CKBitmapHandler, DataHandlers::CKBitmapHandlerDeleter> reader(
|
||||
DataHandlers::CKBitmapHandler::GetBitmapHandler(CKFileExtension(ext.c_str()), CKGUID())
|
||||
);
|
||||
auto reader = DataHandlers::CKBitmapHandler::GetBitmapHandlerWrapper(CKFileExtension(ext.c_str()), CKGUID());
|
||||
if (reader == nullptr) return false;
|
||||
|
||||
// get desc
|
||||
VxMath::VxImageDescEx* desc = GetImageDesc(slot);
|
||||
if (desc == nullptr) return false;
|
||||
|
||||
// read data
|
||||
if (!reader->ReadFile(filename, desc)) {
|
||||
// get desc and read data
|
||||
if (!reader->ReadFile(filename, GetImageDesc(slot))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// free reader
|
||||
reader.reset();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CKBitmapData::SaveImage(CKSTRING filename, CKDWORD slot) {
|
||||
bool CKBitmapData::SaveImage(CKSTRING filename, CKDWORD slot, bool isForceThisFmt) {
|
||||
if (filename == nullptr) return false;
|
||||
if (slot >= m_Slots.size()) return false;
|
||||
|
||||
// prepare save format
|
||||
CKBitmapProperties savefmt;
|
||||
if (isForceThisFmt) {
|
||||
savefmt = this->m_SaveProperties;
|
||||
} else {
|
||||
std::string ext(filename);
|
||||
m_Context->GetPathManager()->GetExtension(ext);
|
||||
if (ext.empty()) {
|
||||
// fallback to this fmt
|
||||
savefmt = this->m_SaveProperties;
|
||||
} else {
|
||||
savefmt.m_Ext.SetExt(ext.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// get reader by format
|
||||
auto reader = DataHandlers::CKBitmapHandler::GetBitmapHandlerWrapper(savefmt.m_Ext, savefmt.m_ReaderGuid);
|
||||
if (reader == nullptr) return false;
|
||||
|
||||
// save file
|
||||
if (!reader->SaveFile(filename, GetImageDesc(slot), savefmt)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -240,7 +380,11 @@ namespace LibCmo::CK2 {
|
||||
}
|
||||
|
||||
void CKBitmapData::SetTransparent(bool Transparency) {
|
||||
EnumsHelper::Add(m_BitmapFlags, CK_BITMAPDATA_FLAGS::CKBITMAPDATA_TRANSPARENT);
|
||||
if (Transparency) {
|
||||
EnumsHelper::Add(m_BitmapFlags, CK_BITMAPDATA_FLAGS::CKBITMAPDATA_TRANSPARENT);
|
||||
} else {
|
||||
EnumsHelper::Rm(m_BitmapFlags, CK_BITMAPDATA_FLAGS::CKBITMAPDATA_TRANSPARENT);
|
||||
}
|
||||
}
|
||||
|
||||
bool CKBitmapData::IsTransparent() {
|
||||
|
Reference in New Issue
Block a user