Capturing and Uploading Screenshots in UE4

Posted December 20th, 2017 in game-development

For Estranged, I wanted the ability to capture the contents of the frame buffer, compress it, and upload it to a REST API. This allows users to attach screenshots to an in-game feedback window, to simplify the bug reporting process.

Unreal Engine 4 has APIs around all of those pieces, and in this post, I'll cover sticking them all together.

The full header and source file from the Estranged code is available as a GitHub gist. Below are the important excerpts.

Capturing a Screenshot

This is a two step process. First, you need to register a callback for when the screenshot is captured, then you request a screenshot:

void UEstScreenshotTaker::RequestScreenshot()
{
    GEngine->GameViewport->OnScreenshotCaptured().AddUObject(this, &UEstScreenshotTaker::AcceptScreenshot);
    FScreenshotRequest::RequestScreenshot(false); // False means don't include any UI
}

void UEstScreenshotTaker::AcceptScreenshot(int32 InSizeX, int32 InSizeY, const TArray<FColor>& InImageData)
{
    // See below
}

Compressing the Pixel Data

In the implementation of your AcceptScreenshot function, you can use the Image Wrapper module to process the image.

First, you need to get a pointer to the JPEG image wrapper, then load in your raw image data, and retrieve the compressed version.

// Load image wrapper module
IImageWrapperModule& ImageWrapperModule = FModuleManager::LoadModuleChecked<IImageWrapperModule>(FName("ImageWrapper"));
TSharedPtr<IImageWrapper> ImageWrapper = ImageWrapperModule.CreateImageWrapper(EImageFormat::JPEG);

// Provide image wrapper with raw pixels (TArray<FColor>)
ImageWrapper->SetRaw(&InImageData[0], InImageData.Num() * sizeof(FColor), InSizeX, InSizeY, ERGBFormat::BGRA, 8);

// Get the image using 90% JPEG compression
const TArray<uint8> CompressedImage = ImageWrapper->GetCompressed(90);

Uploading the Image

The array of uint8 that you get back from the GetCompressed method can be piped directly into a HttpRequest object.

TSharedRef<IHttpRequest> HttpRequest = FHttpModule::Get().CreateRequest();
HttpRequest->SetVerb("POST");
HttpRequest->SetHeader("Content-Type", "image/jpeg");
HttpRequest->SetContent(CompressedImage); // TArray<uint8>
HttpRequest->SetURL(FString("http://example.com/v1/screenshots"));
// Optionally assign HttpRequest->OnProcessRequestComplete() to get a callback when complete
HttpRequest->ProcessRequest();

Your backend can then process and store the JPEG image as appropriate - in my case an API over Amazon S3.

Tagged image screenshot estranged api data wrapper jpeg capture frame buffer

Comments

Please click here to load comments.