Hey friends!
Guess what? After hours of banging my head against the keyboard, I finally cracked the code conundrum that was haunting me. I scoured the internet, dove deep into research, and voila! I’ve got this neat piece of code that lets you pop open a “File Dialogue,” pick an image file, and smoothly import it into your game as a Texture2D. And the best part? It works like a charm in runtime!
Check it out:
.h
UCLASS()
class MYPROJECT_API YOURCLASSNAME : public UBlueprintFunctionLibrary
{
GENERATED_BODY()
UFUNCTION(BlueprintCallable)
static UTexture2D* OpenFileDialogueAndLoadImage();
};
.cpp clean
UTexture2D* YOURCLASSNAME::OpenFileDialogueAndLoadImage()
{
IDesktopPlatform* DesktopPlatform = FDesktopPlatformModule::Get();
if (DesktopPlatform)
{
TArray<FString> OutFilenames;
bool bOpened = DesktopPlatform->OpenFileDialog
(
nullptr,
TEXT("Choose Image"),
FPaths::ProjectContentDir(),
TEXT(""),
TEXT("Image Files (*.png; *.jpg| *.png;*.jpg)"),
EFileDialogFlags::None,
OutFilenames
);
if (bOpened && OutFilenames.Num() > 0)
{
FString SelectedImagePath = OutFilenames[0];
TArray <uint8> ImageData;
if (FFileHelper::LoadFileToArray(ImageData, *SelectedImagePath))
{
IImageWrapperModule& ImageWrapperModule = FModuleManager::LoadModuleChecked<IImageWrapperModule>(FName("ImageWrapper"));
EImageFormat ImageFormat = ImageWrapperModule.DetectImageFormat(ImageData.GetData(), ImageData.Num());
TSharedPtr<IImageWrapper> ImageWrapper = ImageWrapperModule.CreateImageWrapper(ImageFormat);
if (ImageWrapper.IsValid() && ImageWrapper->SetCompressed(ImageData.GetData(), ImageData.Num()))
{
TArray64<uint8> RawData;
if(ImageWrapper->GetRaw(ERGBFormat::RGBA, 8, RawData))
{
TArray64<uint8>* RawDataProcessed = &RawData;
UTexture2D* Texture = UTexture2D::CreateTransient(ImageWrapper->GetWidth(), ImageWrapper->GetHeight(), PF_R8G8B8A8);
if (Texture)
{
FTexture2DMipMap& Mip = Texture->GetPlatformData()->Mips[0];//
void* Data = Mip.BulkData.Lock(LOCK_READ_WRITE);
FMemory::Memcpy(Data, RawDataProcessed->GetData(), RawDataProcessed->Num());
Mip.BulkData.Unlock();
Texture->GetPlatformData()->SetNumSlices(1);
Texture->NeverStream = true;
Texture->UpdateResource();
return Texture;
}
}
}
}
}
}
return nullptr;
}
.cpp with my comments
UTexture2D* YOURCLASSHERE::OpenFileDialogueAndLoadImage()
{
//Here we initialize a pointer to the Desktop Platform Module, so we can open the file dialog.
//Dont forget to include "DesktopPlatform" in the Build.cs
IDesktopPlatform* DesktopPlatform = FDesktopPlatformModule::Get();
if (DesktopPlatform)
{
TArray<FString> OutFilenames; //This stores the file path
bool bOpened = DesktopPlatform->OpenFileDialog // File Dialogue so we can choose a file
(
nullptr,
TEXT("Choose Image"),
FPaths::ProjectContentDir(),
TEXT(""),
TEXT("Image Files (*.png; *.jpg| *.png;*.jpg)"),
EFileDialogFlags::None,
OutFilenames
);
if (bOpened && OutFilenames.Num() > 0) //if we managed to open the dialogue and we chose at least one file
{
FString SelectedImagePath = OutFilenames[0];
TArray <uint8> ImageData; // this will be our image
if (FFileHelper::LoadFileToArray(ImageData, *SelectedImagePath)) //here we load the data
{
IImageWrapperModule& ImageWrapperModule = FModuleManager::LoadModuleChecked<IImageWrapperModule>(FName("ImageWrapper"));//Get a reference to the wrapper module
EImageFormat ImageFormat = ImageWrapperModule.DetectImageFormat(ImageData.GetData(), ImageData.Num()); // Here i wanted to get the Image format, JPG, PNG and so on so that we could create an appropriate wrapper for it
TSharedPtr<IImageWrapper> ImageWrapper = ImageWrapperModule.CreateImageWrapper(ImageFormat); // here we create an image wrapper for the given format
if (ImageWrapper.IsValid() && ImageWrapper->SetCompressed(ImageData.GetData(), ImageData.Num()))
{
TArray64<uint8> RawData;
if(ImageWrapper->GetRaw(ERGBFormat::RGBA, 8, RawData))// we want to take the raw data from the wrapper and put it in the raw data variable
{
TArray64<uint8>* RawDataProcessed = &RawData;
UTexture2D* Texture = UTexture2D::CreateTransient(ImageWrapper->GetWidth(), ImageWrapper->GetHeight(), PF_R8G8B8A8);// we want to make a transient Texture object we can modify in code
// we also get the widht and height from the wrapper and set the pixel format
if (Texture)
{
FTexture2DMipMap& Mip = Texture->GetPlatformData()->Mips[0];// we get platform specific data for the texture and select the firt mipmap
void* Data = Mip.BulkData.Lock(LOCK_READ_WRITE); //bulk data contains well... the bulk data of the mipmap and we want to write to it, we lock it so nothing accesses it now
FMemory::Memcpy(Data, RawDataProcessed->GetData(), RawDataProcessed->Num()); // this copies memory data from one place to another, so we copy the image data
Mip.BulkData.Unlock(); // we unlock it so it can be accessed again
Texture->GetPlatformData()->SetNumSlices(1); //we dont really need more but you can set it to more
Texture->NeverStream = true; //if you want it streamed
Texture->UpdateResource(); //update
return Texture;
}
}
}
}
}
}
return nullptr;
}
Pics for proof!
Hope you all have a great day!
Cheers.