You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
FImage is now the standard preferred type for a bag of pixels FImageView can point at pixels without owning an allocation ERawImageFormat (FImage) converts to ETextureSourceFormat FImageUtils provides generic load/save and get/set from FImage major cleanup in the ImageWrappers new preferred API is through ImageWrapperModule Compress/Decompress SetRaw/GetRaw functions cleaned up to not have undefined behavior on unexpected formats ImageWrapper output added for HDR,BMP,TGA RGBA32F format added and supported throughout import/export EditorFactories import/export made more generic, most image types handled the same way using FImage now Deprecate old TSF RGBA order pixel formats Fix many crashes or bad handling of unusual pixel formats Pixel access functions should be used instead of switches on pixel type #preflight 6230ade7e65a7e65d68a187c #rb julien.stjean,martins.mozeiko,dan.thompson,fabian.giesen [CL 19397199 by charles bloom in ue5-main branch]
140 lines
4.2 KiB
C++
140 lines
4.2 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "ImageWriteTask.h"
|
|
#include "ImageWriteQueue.h"
|
|
#include "HAL/IConsoleManager.h"
|
|
#include "HAL/PlatformFileManager.h"
|
|
#include "HAL/FileManager.h"
|
|
#include "Misc/Paths.h"
|
|
#include "Misc/ScopeLock.h"
|
|
#include "Misc/FileHelper.h"
|
|
#include "Async/Async.h"
|
|
#include "Modules/ModuleManager.h"
|
|
#include "IImageWrapperModule.h"
|
|
|
|
bool FImageWriteTask::RunTask()
|
|
{
|
|
bool bSuccess = WriteToDisk();
|
|
|
|
if (OnCompleted)
|
|
{
|
|
AsyncTask(ENamedThreads::GameThread, [bSuccess, LocalOnCompleted = MoveTemp(OnCompleted)] { LocalOnCompleted(bSuccess); });
|
|
}
|
|
|
|
return bSuccess;
|
|
}
|
|
|
|
void FImageWriteTask::OnAbandoned()
|
|
{
|
|
if (OnCompleted)
|
|
{
|
|
AsyncTask(ENamedThreads::GameThread, [LocalOnCompleted = MoveTemp(OnCompleted)] { LocalOnCompleted(false); });
|
|
}
|
|
}
|
|
|
|
void FImageWriteTask::PreProcess()
|
|
{
|
|
TRACE_CPUPROFILER_EVENT_SCOPE(ImageWriteTask.PreProcess);
|
|
|
|
for (const FPixelPreProcessor& PreProcessor : PixelPreProcessors)
|
|
{
|
|
// PreProcessors are assumed to be valid. Fetch the Data pointer each time
|
|
// in case a pre-processor changes our pixel data.
|
|
FImagePixelData* Data = PixelData.Get();
|
|
PreProcessor(Data);
|
|
}
|
|
}
|
|
|
|
bool FImageWriteTask::WriteToDisk()
|
|
{
|
|
TRACE_CPUPROFILER_EVENT_SCOPE(ImageWriteTask.WriteToDisk);
|
|
|
|
static FName ImageWrapperName("ImageWrapper");
|
|
IImageWrapperModule& ImageWrapperModule = FModuleManager::LoadModuleChecked<IImageWrapperModule>(ImageWrapperName);
|
|
|
|
// Ensure that the payload filename has the correct extension for the format
|
|
if ( ImageWrapperModule.GetImageFormatFromExtension(*Filename) != Format )
|
|
{
|
|
const TCHAR* FormatExtension = ImageWrapperModule.GetExtension(Format);
|
|
Filename = FPaths::GetBaseFilename(Filename, false) + TEXT('.') + FormatExtension;
|
|
}
|
|
|
|
bool bSuccess = EnsureWritableFile();
|
|
|
|
if (bSuccess)
|
|
{
|
|
PreProcess();
|
|
|
|
FImagePixelData* Data = PixelData.Get();
|
|
FImageView Image = Data->GetImageView();
|
|
if ( Image.RawData == nullptr )
|
|
{
|
|
UE_LOG(LogImageWriteQueue, Error, TEXT("Failed to write image to '%s'. Couldn't get pixels."), *Filename);
|
|
return false;
|
|
}
|
|
|
|
TArray64<uint8> CompressedFile;
|
|
if ( ! ImageWrapperModule.CompressImage(CompressedFile,Format,Image,CompressionQuality) )
|
|
{
|
|
UE_LOG(LogImageWriteQueue, Error, TEXT("Failed to write image to '%s'. CompressImage failed."), *Filename);
|
|
return false;
|
|
}
|
|
|
|
uint64 TotalNumberOfBytes, NumberOfFreeBytes;
|
|
if (FPlatformMisc::GetDiskTotalAndFreeSpace(FPaths::GetPath(Filename), TotalNumberOfBytes, NumberOfFreeBytes))
|
|
{
|
|
const uint64 HeadRoom = 1024*1024;
|
|
if (NumberOfFreeBytes < (uint64)CompressedFile.Num() + HeadRoom)
|
|
{
|
|
UE_LOG(LogImageWriteQueue, Error, TEXT("Failed to write image to '%s'. There is not enough free space on the disk."), *Filename);
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
uint32 ErrorCode = FPlatformMisc::GetLastError();
|
|
TCHAR ErrorBuffer[1024];
|
|
FPlatformMisc::GetSystemErrorMessage(ErrorBuffer, 1024, ErrorCode);
|
|
UE_LOG(LogImageWriteQueue, Warning, TEXT("Failed to check free space for %s. Error: %u (%s)"), *FPaths::GetPath(Filename), ErrorCode, ErrorBuffer);
|
|
}
|
|
|
|
bSuccess = FFileHelper::SaveArrayToFile(CompressedFile, *Filename);
|
|
}
|
|
|
|
if (!bSuccess)
|
|
{
|
|
UE_LOG(LogImageWriteQueue, Error, TEXT("Failed to write image to '%s'. The pixel format may not be compatible with this image type, or there was an error writing to that filename."), *Filename);
|
|
}
|
|
|
|
return bSuccess;
|
|
}
|
|
|
|
bool FImageWriteTask::EnsureWritableFile()
|
|
{
|
|
FString Directory = FPaths::GetPath(Filename);
|
|
|
|
if (!IFileManager::Get().DirectoryExists(*Directory))
|
|
{
|
|
const bool bRecursive = true;
|
|
IFileManager::Get().MakeDirectory(*Directory, bRecursive);
|
|
}
|
|
|
|
// If the file doesn't exist, we're ok to continue
|
|
if (IFileManager::Get().FileSize(*Filename) == -1)
|
|
{
|
|
return true;
|
|
}
|
|
// If we're allowed to overwrite the file, and we deleted it ok, we can continue
|
|
else if (bOverwriteFile && FPlatformFileManager::Get().GetPlatformFile().DeleteFile(*Filename))
|
|
{
|
|
return true;
|
|
}
|
|
// We can't write to the file
|
|
else
|
|
{
|
|
UE_LOG(LogImageWriteQueue, Error, TEXT("Failed to write image to '%s'. Should Overwrite: %d - If we should have overwritten the file, we failed to delete the file. If we shouldn't have overwritten the file the file already exists so we can't replace it."), *Filename, bOverwriteFile);
|
|
return false;
|
|
}
|
|
}
|
|
|