Making PNG using data from ReadPixels results in garbage output

Update3: I’ve posted a tutorial on taking screen shots and have posted my entire code for my own custom screen shot save system that is BP friendly, and you can choose base filename and save directory from the BP.

[Complete Game Feature Code: My Custom Screen Shot Save System][1]

Update2: I have it almost fully working! I got rid of that black border, but I am still having to pass through the entire color buffer and manually set the alpha to 255


surely there is a setting somewhere in viewport client or some function I can run first

so that the alpha gets set to 255 during ReadPixels


so I dont have to pass through the huge buffer a second time to set the alpha to 255 ?


Update: I achieved major progress by manually changing the alpha channel to 255, I probably should not have to do this, but it mostly works, clearly I have some format non-understanding here, what’s the fast way to adjust all this?

I am manually going through color buffer (a 2nd pass from its creation, double processing time), and setting alpha to 255

//set alpha back to 255
int32 total2 = viewportSize.X * viewportSize.Y;
for (int32 i = 0; i < total2; i++  )
{
	VictoryPC->PNGScreenShot_ColorBuffer[i].A = 255;
}

Result:

majorprogress.jpg


Dear Friends at Epic,

Hi there!

I hope you can spare a moment or 2 to look for any errors in my logic, or maybe I am missing some fancy parameters somewhere I dont know about.

Thanks for taking the time to read this!


My Goal:

-I am trying to use readpixels to get a portion of the viewport client window

-put this info in a color buffer

-compress this color buffer to png format, binary array

-write out the binary array to file


When I output my color buffer pre-compression it looks quite reasonable for what is on the screen, as you will see in pics below

But the png is quite clearly meaningless garbage that does not even reflect the contents of the color buffer

the only oddities is the occasional completely zeroed FColor pixel in the color buffer and the alpha channel being 0

Here’s the area of screen I am screen shotting:

the_captured_area.jpg

Here’s the color buffer output to my console

Again there’s a few odd 0s and the fact that alpha is always 0,

but it certainly does not look like the output I get in the PNG file at all: (well actually it does because alpha is getting set to 0 some reason)

Here’s my code, I left out the logic of how I choose a filename, and I am only getting the portion of the screen in rectangle (0,0,25,25)

//viewport client
void UVictoryGameViewport::VictoryTakeScreenShot()
{
	if (!VictoryPC) return;
	if (!Viewport) return;
	
	//if (!VictoryColorBuffer) return;
	
	//~~~~~~~~~~~~~~~~~~~~~~
	
	//get viewport size
	FVector2D viewportSize;
	GetViewportSize(viewportSize);
	
	//output viewport dimensions
	FString text = "x= ";
	text += FString::FromInt(viewportSize.X);
	text += "y= ";
	text += FString::FromInt(viewportSize.Y);
	VictoryPC->Optimize(text);
	
	
	//~~~ Invalid View Port Size ~~~
	if (viewportSize.X <= 0 || viewportSize.Y <= 0) return;
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	
	//entire buffer invalidated if exceed viewport size
	viewportSize.X=25;
	viewportSize.Y=25;
	
	//Adjusted Image Size
	VictoryPC->PNG_Width = viewportSize.X; 
	VictoryPC->PNG_Height = viewportSize.Y; 
	
	//~~~~~~~~~~~~~~~~~~~~~~~~
	//~~~ Empty Color Buffer ~~~
	VictoryPC->PNGScreenShot_ColorBuffer.Empty();	
	//~~~~~~~~~~~~~~~~~~~~~~~~

	//
	//Get Screen Shot!
	if (!Viewport->ReadPixels(
		VictoryPC->PNGScreenShot_ColorBuffer,
		FReadSurfaceDataFlags(),
		FIntRect(0,0,viewportSize.X,viewportSize.Y)
	)){
		VictoryPC->Optimize("Failed to ReadPixels");
		return;
		//~~~~~~~~~~~~~~~~~~~~~~~~~
	}
	
	//pixels read
	VictoryPC->OptInt("Success!!!!", VictoryPC->PNGScreenShot_ColorBuffer.Num() );
	
	//Start timer
	VictoryPC->StartScreenShotSaveToDiskTimer();
	
	//print image to console
	
	int32 total = viewportSize.X * viewportSize.Y;
	for (int32 i = 0; i < total; i++  )
	{
		VictoryPC->Optimize(VictoryPC->PNGScreenShot_ColorBuffer[i].ToString());
	}
	
}

Here is my color buffer → PNG binary array → to disk code

//saving to disk in controller class (VictoryPC)
void saveColorBufferAsPNG
{

Optimize("SaveScreenshotToDisk ran!");

//~~~ Temp Data ~~~
TArray PNG_Compressed_ImageData;

//~~~~~~~~~~~~~~~~
// Compress to PNG
//~~~~~~~~~~~~~~~~
FImageUtils::CompressImageArray(
	PNG_Width,
	PNG_Height,
	PNGScreenShot_ColorBuffer,
	PNG_Compressed_ImageData
);

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//					Save binary array PNG image file to disk! 
FFileHelper::SaveArrayToFile(
	PNG_Compressed_ImageData, 
	*PNGFileName
);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

//~~~ Empty PNG Buffer ~~~
PNG_Compressed_ImageData.Empty();
//~~~~~~~~~~~~~~~~~~~~~~~~

//~~~ Empty Color Buffer ~~~
PNGScreenShot_ColorBuffer.Empty();	
//~~~~~~~~~~~~~~~~~~~~~~~~

}

I am hoping I am missing some sort of parameter setting or dont understand the format of what Readpixels takes in vs what comes back out?


Why is the Alpha 0 in color buffer?


I dont know much about the internal working of readpixels or what format the PNG compressing function is expecting,

any ideas?

Thanks!

Rama

does the ReadPixels format, RGBA8:

/**
	* Reads the viewport's displayed pixels into a preallocated color buffer.
	* @param OutImageData - RGBA8 values will be stored in this buffer
	* @param InRect - source rect of the image to capture
	* @return True if the read succeeded.
	*/
	ENGINE_API bool ReadPixels

need to be adjust before compressing to PNG ?

Update4: I’ve posted a tutorial on taking screen shots and have posted my entire code for my own custom screen shot save system that is BP friendly, and you can choose base filename and save directory from the BP.

http://forums.epicgames.com/threads/972861-TUTORIALS-C-for-UE4-gt-gt-New-VIDEO-Entire-Projectile-Class-Code-Accel-amp-Bounces?p=31676249&viewfull=1#post31676249

Update3: Okay nvm, taking the screen shot via readpixels and manually running through the buffer to set the alpha to 255 actually takes a mere instant, I just took a screen shot, converted it into a texture 2d, and turned my in-game cursor into the picture, so I was moving around that image you see in-game as my new fancy cursor :slight_smile:

What takes all the time is compressing the whole array at once to png, will try to do it in pieces and see how far I get :slight_smile:


Still dont know why I have to set the alpha to 255 manually but it actually is not a performance issue.


thanks for tuning in

have a nice day

problem solved hee hee

will write tutorial on this on the forum soon

Hi, any chance that you can post your tutorial somewhere more accessible? I keep getting the message ‘you do not have permission to access this page’, despite having created an account on their forums ;(

Thanks