Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Web Image Downloader For Unreal Engine 4 -- Do not forget to change the include and API key in your own classs, if you simply copy-pasting this.
// (c) 2016 Markakod
#include "HitMe.h"
#include "WebImageDownloader.h"
UWebImageDownloader* UWebImageDownloader::GetWebImageDownloader(FString WebImageName, FString URL, bool& IsValid)
{
IsValid = false;
UWebImageDownloader *Object = NewObject<UWebImageDownloader>();
if (!Object) {
UE_LOG(HITMELOG, Error, TEXT("[UWebImageDownloader::GetWebImageDownloader] Could not be created"));
return NULL;
}
if (!Object->IsValidLowLevel()) {
UE_LOG(HITMELOG, Error, TEXT("[UWebImageDownloader::GetWebImageDownloader] Created object is not valid"));
return NULL;
}
UE_LOG(HITMELOG, Warning, TEXT("[UWebImageDownloader::GetWebImageDownloader] An instance is created successfully"));
Object->OriginalWebImageName = FString(WebImageName);
Object->OriginalURL = FString(URL);
IsValid = true;
return Object;
}
FString UWebImageDownloader::WebImageFolder()
{
FString FileDir = FPaths::GamePersistentDownloadDir() + "/Image/";
FPaths::NormalizeDirectoryName(FileDir);
return FString(FPaths::ConvertRelativePathToFull(FileDir));
}
bool UWebImageDownloader::CreateWebImageFolder()
{
FDirWebImageRecursiveDownloader RFolder = FDirWebImageRecursiveDownloader::CreateLambda([=](FString Folder)
{
const int32 MAX_LOOP_ITR = 3000;
FPaths::NormalizeDirectoryName(Folder);
Folder += "/";
FString Base;
FString Left;
FString Remaining;
Folder.Split(TEXT("/"), &Base, &Remaining);
Base += "/";
int32 LoopItr = 0;
while (Remaining != "" && LoopItr < MAX_LOOP_ITR)
{
Remaining.Split(TEXT("/"), &Left, &Remaining);
Base += Left + FString("/");
FPlatformFileManager::Get().GetPlatformFile().CreateDirectory(*Base);
UE_LOG(HITMELOG, Warning, TEXT("[UWebImageDownloader::CreateWebImageFolder] Creating %s"), *Base);
LoopItr++;
}
});
FString FileDir = WebImageFolder();
IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile();
if (!PlatformFile.DirectoryExists(*FileDir)) {
RFolder.Execute(FileDir);
if (!PlatformFile.DirectoryExists(*FileDir)) {
UE_LOG(HITMELOG, Error, TEXT("[UWebImageDownloader::CreateWebImageFolder] Cannot create folder %s"), *FileDir);
return false;
}
UE_LOG(HITMELOG, Error, TEXT("[UWebImageDownloader::CreateWebImageFolder] Created folder %s"), *FileDir);
}
return true;
}
TArray<FString> UWebImageDownloader::DownloadedWebImagesList()
{
FString folder = WebImageFolder() + "/*.*";
IFileManager& FileManager = IFileManager::Get();
TArray<FString>files;
FileManager.FindFiles(files, *folder, true, false);
for (int i = 0; i < files.Num(); i++) {
FString str = files[i];
files[i] = str.Replace(TEXT(".jpg"), TEXT(""), ESearchCase::IgnoreCase);
}
return files;
}
void UWebImageDownloader::IsWebImageDownloaded(FString WebImageName, bool& isDownloaded)
{
if (!CreateWebImageFolder())
{
isDownloaded = false;
return;
}
FString dataFile = WebImageFolder() + "/" + WebImageName + ".jpg";
IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile();
isDownloaded = PlatformFile.FileExists(*dataFile);
}
void UWebImageDownloader::DeleteWebImageFile(FString WebImageName, bool &isDeleted)
{
FString dataFile = WebImageFolder() + "/" + WebImageName + ".jpg";
IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile();
if (!PlatformFile.FileExists(*dataFile))
{
isDeleted = true;
return;
}
isDeleted = PlatformFile.DeleteFile(*dataFile);
}
void UWebImageDownloader::CheckIfWebImageHasUpdate()
{
UE_LOG(HITMELOG, Warning, TEXT("[UWebImageDownloader::DoesWebImageHaveUpdate] Checking for update %s"), *OriginalWebImageName);
FString dataFile = WebImageFolder() + "/" + OriginalWebImageName + ".jpg";
IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile();
if (!PlatformFile.FileExists(*dataFile))
{
UE_LOG(HITMELOG, Warning, TEXT("[UWebImageDownloader::DoesWebImageHaveUpdate] WebImage not downloaded yet %s"), *OriginalWebImageName);
OnUpdateCheckCompleted.Broadcast(OriginalWebImageName, true);
return;
}
RequestSize = -1;
RequestUrl = OriginalURL + "/" + OriginalWebImageName + ".jpg";
UE_LOG(HITMELOG, Warning, TEXT("[UWebImageDownloader::DoesWebImageHaveUpdate] Requesting headers for %s from %s"), *OriginalWebImageName, *RequestUrl);
FHttpModule* Http = &FHttpModule::Get();
TSharedRef<IHttpRequest> HttpRequest = Http->CreateRequest();
UpdateRequest = HttpRequest;
HttpRequest->SetVerb(TEXT("HEAD"));
HttpRequest->SetURL(RequestUrl);
HttpRequest->OnProcessRequestComplete().BindUObject(this, &UWebImageDownloader::UpdateCheckHttpRequestComplete);
if (!HttpRequest->ProcessRequest())
{
OnUpdateCheckCompleted.Broadcast(OriginalWebImageName, false);
}
}
void UWebImageDownloader::UpdateCheckHttpRequestComplete(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful)
{
UpdateRequest.Reset();
if (!Response.IsValid()) {
UE_LOG(HITMELOG, Error, TEXT("[UWebImageDownloader::UpdateCheckHttpRequestComplete] Could not connect to %s"), *RequestUrl);
OnUpdateCheckCompleted.Broadcast(OriginalWebImageName, false);
return;
}
if (!bWasSuccessful) {
UE_LOG(HITMELOG, Error, TEXT("[UWebImageDownloader::UpdateCheckHttpRequestComplete] Could not connect to %s"), *RequestUrl);
OnUpdateCheckCompleted.Broadcast(OriginalWebImageName, false);
return;
}
FString dataFile = WebImageFolder() + "/" + OriginalWebImageName + ".jpg";
IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile();
FFileStatData statData = PlatformFile.GetStatData(*dataFile);
bool isSizeDifferent = false;
bool isModDateDifferent = false;
int64 fileSize = 0;
int64 modDate = 0;
{
int32 StatusCode = Response->GetResponseCode();
if (StatusCode / 100 != 2)
{
UE_LOG(HITMELOG, Error, TEXT("[UWebImageDownloader::UpdateCheckHttpRequestComplete] %s HTTP response %d, for %s"), *OriginalWebImageName, StatusCode, *RequestUrl);
OnUpdateCheckCompleted.Broadcast(OriginalWebImageName, false);
return;
}
TArray<FString> headers = Response->GetAllHeaders();
for (FString h : headers) {
UE_LOG(HITMELOG, Warning, TEXT("[UWebImageDownloader::UpdateCheckHttpRequestComplete] %s Header: %s"), *OriginalWebImageName, *h);
}
for (FString h : headers) {
if (h.Contains("x-file-size", ESearchCase::IgnoreCase) || h.Contains("Content-Length", ESearchCase::IgnoreCase)) {
FString left;
FString right;
h.Split(":", &left, &right, ESearchCase::IgnoreCase, ESearchDir::FromStart);
if (right.Len())
{
fileSize = FCString::Atoi(*right);
}
}
if (h.Contains("x-file-mod", ESearchCase::IgnoreCase)) {
FString left;
FString right;
h.Split(":", &left, &right, ESearchCase::IgnoreCase, ESearchDir::FromStart);
if (right.Len())
{
modDate = FCString::Atoi(*right);
}
}
if (h.Contains("Last-Modified", ESearchCase::IgnoreCase)) {
FString left;
FString right;
h.Split(":", &left, &right, ESearchCase::IgnoreCase, ESearchDir::FromStart);
if (right.Len())
{
right = right.Trim().TrimTrailing();
FDateTime date;
FDateTime::ParseHttpDate(right, date);
modDate = date.ToUnixTimestamp();
}
}
}
Request.Reset();
}
UE_LOG(HITMELOG, Warning, TEXT("[UWebImageDownloader::UpdateCheckHttpRequestComplete] %s - REMOTE: File size %i Mod date %i"), *OriginalWebImageName, fileSize, modDate);
UE_LOG(HITMELOG, Warning, TEXT("[UWebImageDownloader::UpdateCheckHttpRequestComplete] %s - LOCAL: File size %i Mod date %i"), *OriginalWebImageName, statData.FileSize, statData.ModificationTime.ToUnixTimestamp());
isSizeDifferent = fileSize > 0 && statData.FileSize != fileSize;
isModDateDifferent = modDate > 0 && modDate > statData.ModificationTime.ToUnixTimestamp();
OnUpdateCheckCompleted.Broadcast(OriginalWebImageName, isSizeDifferent || isModDateDifferent);
}
void UWebImageDownloader::DownloadWebImage()
{
CreateWebImageFolder();
RequestSize = -1;
RequestUrl = OriginalURL + "/" + OriginalWebImageName + ".jpg";
UE_LOG(HITMELOG, Warning, TEXT("[UWebImageDownloader::DownloadWebImage] %s Requesting headers for %s"), *OriginalWebImageName, *RequestUrl);
FHttpModule* Http = &FHttpModule::Get();
TSharedRef<IHttpRequest> HttpRequest = Http->CreateRequest();
DownloadRequest = HttpRequest;
HttpRequest->SetVerb(TEXT("HEAD"));
HttpRequest->SetURL(RequestUrl);
HttpRequest->OnProcessRequestComplete().BindUObject(this, &UWebImageDownloader::HttpRequestComplete);
if (!HttpRequest->ProcessRequest())
{
OnWebImageDownloadError.Broadcast(OriginalWebImageName);
}
}
void UWebImageDownloader::HttpRequestProgress(FHttpRequestPtr Request, int32 bytesSent, int32 bytesReceived)
{
if (RequestSize <= 0) return;
float percent = (float)bytesReceived / (float)RequestSize;
OnWebImageDownloadProgress.Broadcast(OriginalWebImageName, (int32)(percent * 100));
}
void UWebImageDownloader::HttpRequestComplete(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful)
{
DownloadRequest.Reset();
if (!Response.IsValid()) {
UE_LOG(HITMELOG, Error, TEXT("[UWebImageDownloader::HttpRequestComplete] Could not connect to %s"), *RequestUrl);
OnWebImageDownloadError.Broadcast(OriginalWebImageName);
return;
}
if (!bWasSuccessful) {
UE_LOG(HITMELOG, Error, TEXT("[UWebImageDownloader::HttpRequestComplete] Could not connect to %s"), *RequestUrl);
OnWebImageDownloadError.Broadcast(OriginalWebImageName);
return;
}
UE_LOG(HITMELOG, Warning, TEXT("[UWebImageDownloader::HttpRequestComplete] %s Starting download of %s"), *OriginalWebImageName, *RequestUrl);
// Finding size of the requested file
{
int32 StatusCode = Response->GetResponseCode();
if (StatusCode / 100 != 2)
{
UE_LOG(HITMELOG, Error, TEXT("[UWebImageDownloader::HttpRequestComplete] %s HTTP response %d, for %s"), *OriginalWebImageName, StatusCode, *RequestUrl);
OnWebImageDownloadError.Broadcast(OriginalWebImageName);
return;
}
TArray<FString> headers = Response->GetAllHeaders();
for (FString h : headers) {
UE_LOG(HITMELOG, Warning, TEXT("[UWebImageDownloader::HttpRequestComplete] %s Header: %s"), *OriginalWebImageName, *h);
}
for (FString h : headers) {
if (h.Contains("x-file-size", ESearchCase::IgnoreCase) || h.Contains("Content-Length", ESearchCase::IgnoreCase)) {
FString left;
FString right;
h.Split(":", &left, &right, ESearchCase::IgnoreCase, ESearchDir::FromStart);
if (right.Len())
{
RequestSize = FCString::Atoi(*right);
}
break;
}
}
Request.Reset();
}
FHttpModule* Http = &FHttpModule::Get();
TSharedRef<IHttpRequest> HttpRequest = Http->CreateRequest();
DownloadRequest = HttpRequest;
HttpRequest->SetVerb(TEXT("GET"));
HttpRequest->SetURL(RequestUrl);
HttpRequest->OnRequestProgress().BindUObject(this, &UWebImageDownloader::HttpRequestProgress);
HttpRequest->OnProcessRequestComplete().BindUObject(this, &UWebImageDownloader::HttpDownloadComplete);
if (!HttpRequest->ProcessRequest())
{
OnWebImageDownloadError.Broadcast(OriginalWebImageName);
}
}
void UWebImageDownloader::HttpDownloadComplete(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful)
{
DownloadRequest.Reset();
if (!Response.IsValid()) {
UE_LOG(HITMELOG, Error, TEXT("[UWebImageDownloader::HttpDownloadComplete] Could not connect to %s"), *RequestUrl);
OnWebImageDownloadError.Broadcast(OriginalWebImageName);
return;
}
if (!bWasSuccessful) {
UE_LOG(HITMELOG, Error, TEXT("[UWebImageDownloader::HttpDownloadComplete] Could not connect to %s"), *RequestUrl);
OnWebImageDownloadError.Broadcast(OriginalWebImageName);
return;
}
UE_LOG(HITMELOG, Warning, TEXT("[UWebImageDownloader::HttpDownloadComplete] Download completed for %s from %s"), *OriginalWebImageName, *RequestUrl);
int32 StatusCode = Response->GetResponseCode();
if (StatusCode / 100 != 2)
{
UE_LOG(HITMELOG, Error, TEXT("[UWebImageDownloader::HttpDownloadComplete] %s HTTP response %d, for %s"), *OriginalWebImageName, StatusCode, *RequestUrl);
OnWebImageDownloadError.Broadcast(OriginalWebImageName);
return;
}
TArray<FString> headers = Response->GetAllHeaders();
for (FString h : headers) {
UE_LOG(HITMELOG, Warning, TEXT("UExpoSocket::HttpDownloadComplete] %s Header: %s"), *OriginalWebImageName, *h);
}
const TArray<uint8>& Content = Response->GetContent();
FString Filename = WebImageFolder() + "/" + OriginalWebImageName + ".jpg";
if (FFileHelper::SaveArrayToFile(Content, *Filename))
{
OnWebImageDownloadCompleted.Broadcast(OriginalWebImageName);
}
else
{
UE_LOG(HITMELOG, Error, TEXT("[UWebImageDownloader::HttpDownloadComplete] %s Could not write %s to disk "), *OriginalWebImageName, *Filename);
OnWebImageDownloadError.Broadcast(OriginalWebImageName);
}
}
void UWebImageDownloader::CancelDownload()
{
UE_LOG(HITMELOG, Error, TEXT("[UWebImageDownloader::CancelDownload] Cancelling request for %s"), *RequestUrl);
if (UpdateRequest.IsValid()) {
if (UpdateRequest->OnProcessRequestComplete().IsBound())
UpdateRequest->OnProcessRequestComplete().Unbind();
UpdateRequest->CancelRequest();
UpdateRequest.Reset();
}
if (DownloadRequest.IsValid()) {
if (DownloadRequest->OnProcessRequestComplete().IsBound())
DownloadRequest->OnProcessRequestComplete().Unbind();
DownloadRequest->CancelRequest();
DownloadRequest.Reset();
}
}
#pragma once
#include "Object.h"
#include "Runtime/Online/HTTP/Public/Http.h"
#include "Runtime/Online/HTTP/Public/HttpManager.h"
#include "WebImageDownloader.generated.h"
DECLARE_DELEGATE_OneParam(FDirWebImageRecursiveDownloader, FString);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FWebImageDownloader_OnDownloadComplete, FString, imageName);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FWebImageDownloader_OnDownloadError, FString, imageName);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FWebImageDownloader_OnDownloadProgress, FString, imageName, int32, progress);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FWebImageDownloader_OnUpdateCheckCompleted, FString, imageName, bool, hasUpdate);
UCLASS(Blueprintable, BlueprintType)
class HITME_API UWebImageDownloader : public UObject
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintPure, Category = "WebImage Downloader", Meta = (DisplayName = "Get A Web Image Downloader"))
static UWebImageDownloader* GetWebImageDownloader(FString WebImageName, FString URL, bool& IsValid);
UFUNCTION(BlueprintPure, Category = "WebImage Downloader", Meta = (DisplayName = "Downloaded Web Images List"))
static TArray<FString> DownloadedWebImagesList();
UFUNCTION(BlueprintPure, Category = "WebImage Downloader", Meta = (DisplayName = "Delete Web Image File"))
static void DeleteWebImageFile(FString WebImageName, bool &isDeleted);
UFUNCTION(BlueprintPure, Category = "WebImage Downloader", Meta = (DisplayName = "Is Web Image Already Downloaded"))
static void IsWebImageDownloaded(FString WebImageName, bool &isDownloaded);
UPROPERTY(BlueprintAssignable, Category = "WebImage Downloader")
FWebImageDownloader_OnDownloadComplete OnWebImageDownloadCompleted;
UPROPERTY(BlueprintAssignable, Category = "WebImage Downloader")
FWebImageDownloader_OnDownloadError OnWebImageDownloadError;
UPROPERTY(BlueprintAssignable, Category = "WebImage Downloader")
FWebImageDownloader_OnDownloadProgress OnWebImageDownloadProgress;
UPROPERTY(BlueprintAssignable, Category = "WebImage Downloader")
FWebImageDownloader_OnUpdateCheckCompleted OnUpdateCheckCompleted;
UFUNCTION(BlueprintCallable, Category = "WebImage Downloader", Meta = (DisplayName = "Does Web Image Have Update"))
void CheckIfWebImageHasUpdate();
UFUNCTION(BlueprintCallable, Category = "WebImage Downloader", Meta = (DisplayName = "Download Web Image"))
void DownloadWebImage();
UFUNCTION(BlueprintCallable, Category = "WebImage Downloader", Meta = (DisplayName = "Cancel Download"))
void CancelDownload();
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "WebImage Downloader", Meta = (DisplayName = "Web Image Name"))
FString OriginalWebImageName;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "WebImage Downloader", Meta = (DisplayName = "Server URL"))
FString OriginalURL;
static FString WebImageFolder();
static bool CreateWebImageFolder();
private:
void HttpRequestComplete(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful);
void HttpDownloadComplete(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful);
void HttpRequestProgress(FHttpRequestPtr Request, int32 bytesSent, int32 bytesReceived);
void UpdateCheckHttpRequestComplete(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful);
int32 RequestSize;
FString RequestUrl;
TSharedPtr<IHttpRequest> UpdateRequest;
TSharedPtr<IHttpRequest> DownloadRequest;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment