uint8* FTextureSource::LockMip(int32 MipIndex) { uint8* MipData = NULL; if (MipIndex < NumMips) { if (LockedMipData == NULL) { LockedMipData = (uint8*)BulkData.Lock(LOCK_READ_WRITE); if (bPNGCompressed) { bool bCanPngCompressFormat = (Format == TSF_G8 || Format == TSF_RGBA8 || Format == TSF_BGRA8 || Format == TSF_RGBA16); check(NumSlices == 1 && bCanPngCompressFormat); if (MipIndex != 0) { return NULL; } IImageWrapperModule& ImageWrapperModule = FModuleManager::LoadModuleChecked<IImageWrapperModule>( FName("ImageWrapper") ); IImageWrapperPtr ImageWrapper = ImageWrapperModule.CreateImageWrapper( EImageFormat::PNG ); if ( ImageWrapper.IsValid() && ImageWrapper->SetCompressed( LockedMipData, BulkData.GetBulkDataSize() ) ) { check( ImageWrapper->GetWidth() == SizeX ); check( ImageWrapper->GetHeight() == SizeY ); const TArray<uint8>* RawData = NULL; // TODO: TSF_BGRA8 is stored as RGBA, so the R and B channels are swapped in the internal png. Should we fix this? ERGBFormat::Type RawFormat = (Format == TSF_G8) ? ERGBFormat::Gray : ERGBFormat::RGBA; if (ImageWrapper->GetRaw( RawFormat, Format == TSF_RGBA16 ? 16 : 8, RawData )) { if (RawData->Num() > 0) { LockedMipData = (uint8*)FMemory::Malloc(RawData->Num()); // PVS-Studio does not understand that IImageWrapper::GetRaw's return value validates the pointer, so we disable // the warning that we are using the RawData pointer before checking for null: FMemory::Memcpy(LockedMipData, RawData->GetData(), RawData->Num()); //-V595 } } if (RawData == NULL || RawData->Num() == 0) { UE_LOG(LogTexture, Warning, TEXT("PNG decompression of source art failed")); } } else { UE_LOG(LogTexture, Log, TEXT("Only pngs are supported")); } } } MipData = LockedMipData + CalcMipOffset(MipIndex); LockedMips |= (1 << MipIndex); } return MipData; }
bool FTextureSource::GetMipData(TArray<uint8>& OutMipData, int32 MipIndex) { bool bSuccess = false; if (MipIndex < NumMips && BulkData.GetBulkDataSize() > 0) { void* RawSourceData = BulkData.Lock(LOCK_READ_ONLY); if (bPNGCompressed) { bool bCanPngCompressFormat = (Format == TSF_G8 || Format == TSF_RGBA8 || Format == TSF_BGRA8 || Format == TSF_RGBA16); if (MipIndex == 0 && NumSlices == 1 && bCanPngCompressFormat) { IImageWrapperModule& ImageWrapperModule = FModuleManager::LoadModuleChecked<IImageWrapperModule>( FName("ImageWrapper") ); IImageWrapperPtr ImageWrapper = ImageWrapperModule.CreateImageWrapper( EImageFormat::PNG ); if ( ImageWrapper.IsValid() && ImageWrapper->SetCompressed( RawSourceData, BulkData.GetBulkDataSize() ) ) { if (ImageWrapper->GetWidth() == SizeX && ImageWrapper->GetHeight() == SizeY) { const TArray<uint8>* RawData = NULL; // TODO: TSF_BGRA8 is stored as RGBA, so the R and B channels are swapped in the internal png. Should we fix this? ERGBFormat::Type RawFormat = (Format == TSF_G8) ? ERGBFormat::Gray : ERGBFormat::RGBA; if (ImageWrapper->GetRaw( RawFormat, Format == TSF_RGBA16 ? 16 : 8, RawData )) { OutMipData = *RawData; bSuccess = true; } else { UE_LOG(LogTexture, Warning, TEXT("PNG decompression of source art failed")); OutMipData.Empty(); } } else { UE_LOG(LogTexture, Warning, TEXT("PNG decompression of source art failed. ") TEXT("Source image should be %dx%d but is %dx%d"), SizeX, SizeY, ImageWrapper->GetWidth(), ImageWrapper->GetHeight() ); } } else { UE_LOG(LogTexture, Log, TEXT("Only pngs are supported")); } } } else { int32 MipOffset = CalcMipOffset(MipIndex); int32 MipSize = CalcMipSize(MipIndex); if (BulkData.GetBulkDataSize() >= MipOffset + MipSize) { OutMipData.Empty(MipSize); OutMipData.AddUninitialized(MipSize); FMemory::Memcpy( OutMipData.GetTypedData(), (uint8*)RawSourceData + MipOffset, MipSize ); } bSuccess = true; } BulkData.Unlock(); } return bSuccess; }