I’m trying to save a high resolution screenshot to a user-specified file path (Something I’ve tried a number of times before). I can save a regular screenshot to a location, and I can save a high-res screenshot to the default Screenshot directory, but I can’t seem to do both at once.
Here’s my code at the moment:
FScreenshotRequest::RequestScreenshot(filePath, false); //Sets my custom file path
GetHighResScreenshotConfig().ResolutionMultiplier = 4; //Sets the res multiplier
GetWorld()->GetGameViewport()->Viewport->TakeHighResScreenShot(); //Sets the flag in the viewport to take the high-res shot.
As far as I can tell, it’s because FViewport::TakeHighResScreenShot() just sets a flag that tells the Draw function to then call the FViewport::HighResScreenshot(), but that means it always calls:
Which resets the file path I set up previously. Is there any way around this? Is there a reason HighResScreenshot() is protected? Is there a way I can change the default Screenshot directory on the fly?
Inside RequestScreenshot() it sets a private variable “FileName” that is used to take screenshots. Thus, for high res screenshots file name will be always “HighresScreenshot” and placed in a default directory. And there is no way to change it…
The only solution I’m thinking of is to subscribe to OnScreenshotCaptured delegate and replace files once screenshot is taken.
Actually, if you set up a delegate there will be no saving, but you will get a bit map and its size. Like that you can handle saving yourself.
See code: void UGameViewportClient::ProcessScreenShots(FViewport* InViewport)
I have used Flash7’s solution but don’t have a good c++/UE background so here’s my (possibly mistaken!) interpretation of what’s happening for anyone else who is struggling to understand how to use the provided solution:
The aim is to record high-resolution images from the Unreal Engine viewport. It’s possible to move the viewport view to a specified camera by calling the SetViewTarget method on a player controller, so by placing a camera in the game you can move to that camera and record the corresponding image.
As outlined in the original question,
I can save a regular screenshot to a location, and I can save a high-res screenshot to the default Screenshot directory, but I can’t seem to do both at once.
(If anyone can clarify this further please do) The solution is to add a lambda function (good outline of lambda functions here) to the OnScreenCaptured method of the GameViewportClient (the engine’s interface to a game viewport). The lambda function essentially takes the gameviewport image as a bitmap and then saves it to a specified file path when a screenshot request is made. When GetWorld()->GetGameViewport()->Viewport->TakeHighResScreenShot(); is called, the onscreenshotcaptured method (an Accessor for delegate called when a screenshot is captured) is called, which executes the code in the lambda function as outlined above.
Here is some sample code that seems to work for my project:
std::string fpath = "C:\UnrealEngineProjects\SampleProject\SampleImage.png"
FString filePath(fpath.c_str());
GIsHighResScreenshot = true;
GetHighResScreenshotConfig().ResolutionMultiplier = 6; //Sets the res multiplier
UGameViewportClient* ViewportClient = GetWorld()->GetGameViewport();
ViewportClient->OnScreenshotCaptured().Clear();
//can't use filePath as a function parameter, therefore need to 'capture' it (Capturing an object by name makes a lambda-local copy of the object.)
ViewportClient->OnScreenshotCaptured().AddLambda(
[filePath](int32 SizeX, int32 SizeY, const TArray<FColor>& Bitmap)
{
// Make sure that all alpha values are opaque.
TArray<FColor>& RefBitmap = const_cast<TArray<FColor>&>(Bitmap);
for (auto& Color : RefBitmap)
Color.A = 255;
TArray<uint8> CompressedBitmap;
FImageUtils::CompressImageArray(SizeX, SizeY, RefBitmap, CompressedBitmap);
//FString ScreenshotFilePath = GetScreenshotFilePath(CleanSlotFileName);
FFileHelper::SaveArrayToFile(CompressedBitmap, *filePath);
});
GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Yellow, TEXT("Saving a high res screenshot at location " + fpath));
FScreenshotRequest::RequestScreenshot(filePath, false);
GetWorld()->GetGameViewport()->Viewport->TakeHighResScreenShot();
I do not know if this is still relevant, but I’ve found another way (probably a change of 4.25)
There is an option to override file name in the GetHighResScreenshotConfig()
here is an working example:
This Post has greatly helped me. A few Years have gone by, its 2024, and Unreal 5.4 just came out. Here is some updated code for my fellow dev looking to make this work.
#include "Engine.h"
#include "HighResScreenshot.h"
#include "ImageUtils.h"
#include "Misc/FileHelper.h"
#include "Containers/ArrayView.h"
void AGimbal_Core::takeGimbalHighResCapture(FString filePath)
{
GIsHighResScreenshot = true;
GetHighResScreenshotConfig().ResolutionMultiplier = 2;
//Configure High Res Screenshot. Include params if desired...
UGameViewportClient* ViewportClient = GetWorld()->GetGameViewport();
//Prevents the overwrite of previously taken HighResScreenshots.
ViewportClient->OnScreenshotCaptured().Clear();
//Cant use filePath as a function parameter, therefore need to 'capture' it (Captureing an object by name makes a lambda-local copy of the object.)
ViewportClient->OnScreenshotCaptured().AddLambda([filePath](int32 SizeX, int32 SizeY, const TArray<FColor>& Bitmap)
{
//Make sure that all alpha values are opaque.
TArray<FColor>& RefBitmap = const_cast<TArray<FColor>&>(Bitmap);
for (auto& Color : RefBitmap)
Color.A = 255;
TArray64<uint8> compressedBitmap;
FImageUtils::PNGCompressImageArray(SizeX, SizeY, RefBitmap, compressedBitmap);
FFileHelper::SaveArrayToFile(TArrayView<const uint8>(compressedBitmap), *filePath, &IFileManager::Get(), static_cast<uint32>(0));
});
GAreScreenMessagesEnabled = true;
GetWorld()->GetGameViewport()->Viewport->TakeHighResScreenShot();
}