How to set the file target for a high res screenshot

Hey Guys,

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:

 `FScreenshotRequest::RequestScreenshot( bShowUI, TEXT("png") );`

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?

Did you find a solution for this?

The problem is in

void FScreenshotRequest::CreateViewportScreenShotFilename(FString& InOutFilename)
{
	FString TypeName;

	if(GIsDumpingMovie)
	{
		TypeName = TEXT("MovieFrame");

		if(GIsDumpingMovie > 0)
		{
			// <=0:off (default), <0:remains on, >0:remains on for n frames (n is the number specified)
			--GIsDumpingMovie;
		}
	}
	else if(GIsHighResScreenshot)
	{
		TypeName = TEXT("HighresScreenshot");
	}
	else
	{
		TypeName = InOutFilename.IsEmpty() ? TEXT("ScreenShot") : InOutFilename;
	}
	check(!TypeName.IsEmpty());

	//default to using the path that is given
	InOutFilename = TypeName;
	if (!TypeName.Contains(TEXT("/")))
	{
		InOutFilename = FPaths::ScreenShotDir() / TypeName;
	}
}

that function is called by FScreenshotRequest::RequestScreenshot

	FString GeneratedFilename = InFilename;
	CreateViewportScreenShotFilename(GeneratedFilename);

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)

And this is how you basically do it:

		UGameViewportClient* ViewportClient = TheWorld->GetGameViewport();
		ViewportClient->OnScreenshotCaptured().Clear();
		ViewportClient->OnScreenshotCaptured().AddLambda(
			[ScreenshotFilePath](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, *ScreenshotFilePath);
		});

Man, thank you very much. The body of your lambda function works perfectly.

you are welcome!

ScreenshotFilePath and CleanSlotFileName error?

Is there a way I can do this? with BluePrints? Please help

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();

Check this: How to take a High Res Screenshot in Play Mode (UE4) | Chiaro's

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:

FString FullFileName = "C:/Temp/temp.png";
GIsHighResScreenshot = true;
GetHighResScreenshotConfig().SetFilename(FullFileName);
FScreenshotRequest::RequestScreenshot(FullFileName, false, false);