HighResShot fails to take a screenshot at specified resolution

I just tested console cmd HighResShot and with value 0.5 and it took screenshot half-resolution I was running. However if I use HighResShot 640x360, it takes a shot at 640x360, but it’s pitch black.

This functionality is required for saving screenshots of the locations for save/load game system (to be displayed in the menu).

I believe taking screenshots in a specific resolution from C++ game code is also broken.

Also taking HighResShots in VR is still broken too as far as I know.

Hey motorsep,

Can you test this in a new blank blueprint project?

Are you running a C++ or Blueprint based project?

Do you get the same results using the HRST (High Res Screenshot Tool)?

I am not getting the same results when I use the HighResShot console command and entering a custom resolution. I was able to take a screenshot at 1600x1200 and 640x360 while in the editor viewport.

Let me know if you have further questions or need additional assistance.

Cheers,

Andrew Hurley

I tried doing this with a blank (or scratch based on a template) BP projects and indeed it worked.

I asked another dev, who is C++ savvy, to test it with C++. He claims that when doing the same from C++, it doesn’t work.

Did he test using a source build or did he test with a C++ project from the launcher?

Thanks,

Andrew H

Hello, I tried several ways to take screenshots and the Console commands DO work properly; however have no way to set the output file name neither the directory of saved screenshot when using console commands.

To save a screenshot in a given directory with custom file name, I did try this:

GetHighResScreenshotConfig().ResolutionMultiplier = 0.3f;
FScreenshotRequest::RequestScreenshot(ImagePath,false,false);

And also this:

GScreenshotResolutionX = 640; GScreenshotResolutionY = 360;
FScreenshotRequest::RequestScreenshot(ImagePath,false,false);

The screenshot saves with correct name I give them, and also at correct folder; But in both cases, the RequestScreenshot function ignores the resolution I ask. It is always outputting the screenshot in full screen resolution…

And then if I set GIsHighResScreenshot = true; the resolution works correctly… but now it ignores completly the ImagePath I give and generates a name with prefixes that I cannot track (need to load back the screenshot).

Hey BrUnO XaVIeR,

When it comes to taking a screenshot at a resolution, it’s as simple as:

[.h]

UFUNCTION( BlueprintCallable, Category="Character|TakeScreenshot")
void TakeScreenshot( int X, int Y );

[.cpp]

void AAH474137Character::TakeScreenshot( int X, int Y )
{
	if( GEngine )
	{
		UGameViewportClient *GameViewport = GEngine->GameViewport;
		if( GameViewport )
		{
			FViewport *Viewport = GameViewport->Viewport;
			if( Viewport )
			{
				GScreenshotResolutionX = X;
				GScreenshotResolutionY = Y;
				Viewport->TakeHighResScreenShot( );
			}
		}
	}
}

Now, changing where this screenshot gets saved is a whole other issue. Because of how this functionality is introduced, it uses a static function in Paths.cpp, called ScreenShotDir( ), which returns:

return FPaths::GameSavedDir() + TEXT("Screenshots/") + FPlatformProperties::PlatformName() + TEXT("/");

I suppose you could change this but the better bet is to dive into UnrealClient.cpp, HighResScreenshot.cpp, and EditorViewportClient.cpp, specifically:

FEditorViewportClient::TakeScreenshot(FViewport* InViewport, bool bInValidatViewport)

If I can, I will poke around and see what other options there are but currently, from what I can see, there isn’t any type of “easy” functionality to save screenshot during game play to be used in another level.

Thank you for submitting a bug report, however at this time we believe that the issue you are describing is not actually a bug with the Unreal Engine, and so we are not able to take any further action on this. If you still believe this may be a bug, please provide steps for us to reproduce the issue, and we will continue our investigation.

Sounds like engine changes. Are you guys going to fix this for 4.13 or 4.14 ? People need this for Auto-Save plugin.

Okay… So, without checks etc, just for testing.
I’ve managed to take a screenshot and give it the name I want, save to the folder I need. Cropped into a region of the screen, thanks to Kyle’s tips:

if(GEngine) {
		FHighResScreenshotConfig &HighResScreenshotConfig = GetHighResScreenshotConfig();
		UGameViewportClient* GameViewport = GEngine->GameViewport;
		if(GameViewport) {
			HighResScreenshotConfig.SetHDRCapture(false);
			FViewport *Viewport = GameViewport->Viewport;
			if (Viewport) {
				Viewport->Invalidate();
				TArray<FColor>Bitmap;
				if(Viewport->ReadPixels(Bitmap,FReadSurfaceDataFlags(RCM_UNorm,CubeFace_MAX),FIntRect(0,0,640,360))) {
					for (auto& Pixel : Bitmap) {Pixel.A = 255;}
					HighResScreenshotConfig.SaveImage(ImagePath,Bitmap,FIntPoint(640,360));
				}
			}
		}
	}

Would be great though to find a way to actually resize the Bitmap instead of cutting the image :stuck_out_tongue:

105017-slotss.jpg

Nevermind… I’ve found a way to predict which will be the name of the next HighResScreenshot file name, generate a string of relative path equal to the path the next screenshot will be saved to then store that file path to the Game’s INI.
When looking for the correct screenshot I then lookup inside the Config to check which Screenshot file is supposed to be the one assigned to the Slot thumbnail and load it back. And this will work on packaged games too yay!

As long as the player doesn’t have more than 10.000 screenshots in folder, it works…

Saving Game with Screenshot (path goes into a Config UObject):

bool USVLibrary::SVL_SaveWithScreenShot(ASaver* Saver, int32 SlotID, int32 Width, int32 Height, bool Overwrite) {
	const auto &Settings = GetMutableDefault<USaviorSettings>();
	if (Saver == NULL || !Saver->Savior->Slots.IsValidIndex(SlotID) || Settings == NULL || !GEngine) {return false;}
	bool Saved = Saver->SaveGameToSlot(SlotID);
	//
	if (Saver->Savior->Slots.Num() > Settings->SlotThumbnails.Num()) {
		for (int32 I=0; I<(Saver->Savior->Slots.Num()-Settings->SlotThumbnails.Num()); ++I) {
			Settings->SlotThumbnails.Add(TEXT(""));
		}
	} FString Thumbnail; FString Previous;
	if (Settings->SlotThumbnails.IsValidIndex(SlotID)) {Thumbnail = Settings->SlotThumbnails[SlotID];}
	//
	FHighResScreenshotConfig &HighResScreenshotConfig = GetHighResScreenshotConfig();
	UGameViewportClient* GameViewport = GEngine->GameViewport;
	//
	if (GameViewport) {
		HighResScreenshotConfig.SetHDRCapture(false);
		FViewport *Viewport = GameViewport->Viewport;
		if (Viewport) {
			Previous = Thumbnail;
			IFileManager* FM = &IFileManager::Get();
			for (int32 BMP=1; BMP<10000; ++BMP) {
				FString File = FString::Printf(TEXT("%s%05i.%s"),*(FPaths::ScreenShotDir()/TEXT("HighresScreenshot")),BMP,TEXT("png"));
				if (!FM->FileExists(*File)) {
					GScreenshotBitmapIndex = BMP-1; Thumbnail = File;
				break;}
			} Settings->SlotThumbnails[SlotID] = Thumbnail; Settings->SaveConfig();
			if (Overwrite && (Previous.Len()>0 && FM->FileExists(*Previous))) {FM->Delete(*Previous,false,true,true);}
			//
			GScreenshotResolutionX = Width; GScreenshotResolutionY = Height;
			Viewport->TakeHighResScreenShot();
	}} return Saved;
}

Loading the Screenshot back based on the path stored in the Config UObject:

UTexture2D* USVLibrary::SVL_LoadScreenShot(ASaver* Saver, int32 SlotID) {
	const auto &Settings = GetMutableDefault<USaviorSettings>();
	if (Saver == NULL || !Saver->Savior->Slots.IsValidIndex(SlotID) || Settings == NULL || !GEngine) {return nullptr;}
	//
	FString Thumbnail;
	if (Settings->SlotThumbnails.IsValidIndex(SlotID)) {Thumbnail = Settings->SlotThumbnails[SlotID];}
	//
	TArray<uint8> RawFileData;
	UTexture2D* Texture = nullptr;
	//
	if (FFileHelper::LoadFileToArray(RawFileData,*Thumbnail)) {
		IImageWrapperModule& ImageWrapperModule = FModuleManager::LoadModuleChecked<IImageWrapperModule>(FName("ImageWrapper"));
		IImageWrapperPtr ImageWrapper = ImageWrapperModule.CreateImageWrapper(EImageFormat::PNG);
		if (FFileHelper::LoadFileToArray(RawFileData,*Thumbnail)) {
			if (ImageWrapper.IsValid() && ImageWrapper->SetCompressed(RawFileData.GetData(),RawFileData.Num())) {
				const TArray<uint8>* UncompressedBGRA = nullptr;
				if (ImageWrapper->GetRaw(ERGBFormat::BGRA,8,UncompressedBGRA)) {
					Texture = UTexture2D::CreateTransient(ImageWrapper->GetWidth(),ImageWrapper->GetHeight(),PF_B8G8R8A8);
					void* TextureData = Texture->PlatformData->Mips[0].BulkData.Lock(LOCK_READ_WRITE);
					FMemory::Memcpy(TextureData, UncompressedBGRA->GetData(), UncompressedBGRA->Num());
					Texture->PlatformData->Mips[0].BulkData.Unlock();
				Texture->UpdateResource();
	}}}} return Texture;
}