How do I load an image via a URL in Unreal Engine 5?
This is going to be a short article, but I recently worked in the development of a Unreal plugin. Where it was necessary to load images from a URL on a web server. After several hours of research, I couldn't find a turnkey solution to do this in C++ (simple solutions do exist, but only in blueprint, the Unreal Engine's visual script editor).
So here's the resulting code:
UTexture2D* DownloadImage(const FString& URL)
{
UTexture2D* Texture;
TSharedPtr<IHttpRequest> HttpRequest = FHttpModule::Get().CreateRequest();
HttpRequest->SetVerb("GET");
HttpRequest->SetURL(URL);
HttpRequest->OnProcessRequestComplete().BindLambda([this, &Texture](FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful)
{
if (bWasSuccessful && Response.IsValid())
{
// Create an instance of the image wrapper module
IImageWrapperModule& ImageWrapperModule = FModuleManager::LoadModuleChecked<IImageWrapperModule>(FName("ImageWrapper"));
// Create an instance of the image wrapper
TArray<uint8> ImageData = Response->GetContent();
TSharedPtr<IImageWrapper> ImageWrapper = ImageWrapperModule.CreateImageWrapper(EImageFormat::JPEG);
if (ImageWrapper.IsValid() && ImageWrapper->SetCompressed(ImageData.GetData(), ImageData.Num()))
{
TArray<uint8> UncompressedImageData;
if (ImageWrapper->GetRaw(ERGBFormat::BGRA, 8, UncompressedImageData))
{
Texture = UTexture2D::CreateTransient(ImageWrapper->GetWidth(), ImageWrapper->GetHeight(), PF_B8G8R8A8);
Texture->UpdateResource();
FTexture2DMipMap& Mip = Texture->GetPlatformData()->Mips[0];
void* Data = Mip.BulkData.Lock(LOCK_READ_WRITE);
FMemory::Memcpy(Data, UncompressedImageData.GetData(), UncompressedImageData.Num());
Mip.BulkData.Unlock();
Texture->UpdateResource();
}
}
}
});
HttpRequest->ProcessRequest();
FHttpModule* Http = &FHttpModule::Get();
Http->GetHttpManager().Flush(EHttpFlushReason::FullFlush);
return Texture;
}
Note that you'll need the HTTP and Core modules.
How do I use it? Nothing could be simpler: you need a Brush and then an element to apply it to, such as a button.
SharedPtr<FDeferredCleanupSlateBrush> newTexture;
newTexture = FDeferredCleanupSlateBrush::CreateBrush(
Cast<UTexture>(DownloadImage(Project.background.url)),
FLinearColor(1.f, 1.f, 1.f),
ESlateBrushTileType::NoTile,
ESlateBrushImageType::FullColor
);
...
SNew(SImage)
.Image(BrushImgTexture->GetSlateBrush())
.DesiredSizeOverride(FVector2D(195, 95))
That's it! Please note that the code shown here loads the image synchronously. Not asynchronous. So it may have an impact on performance.