How to save UTexture2D to PNG file?

I made a tool to generate a simple texture on runtime.(a Verify Pic)

now I need save to PNG file…

But I don’t know how to save the UTexture2D to PNG file. (Windows platform)

Should call UTexture2D::Serialize(…) to save it ?
And how?

plz help me, thanks

Hi I think I have 2 functions that will solve your problem

They are almost identical, I used it to debug my CEF3 embedding implementation.

I hope this is of use for you.


void SaveTexture2DDebug(UTexture2D* PTexture, FString Filename)
{
	PTexture->UpdateResourceW();
	FTexture2DMipMap* MM = &PTexture->PlatformData->Mips[0];

	TArray<FColor> OutBMP;
	int w = MM->SizeX;
	int h = MM->SizeY;

	OutBMP.InsertZeroed(0, w*h);

	FByteBulkData* RawImageData = &MM->BulkData;

	FColor* FormatedImageData = static_cast<FColor*>(RawImageData->Lock(LOCK_READ_ONLY));

	for (int i = 0; i < (w*h); ++i)
	{
		OutBMP* = FormatedImageData*;
		OutBMP*.A = 255;
	}

	RawImageData->Unlock();
	FIntPoint DestSize(w, h);

	FString ResultPath;
	FHighResScreenshotConfig& HighResScreenshotConfig = GetHighResScreenshotConfig();
	bool bSaved = HighResScreenshotConfig.SaveImage(Filename, OutBMP, DestSize, &ResultPath);
	/*
	FTexture2DResource* PR = (FTexture2DResource*)PTexture->Resource;

	if (PR)
	{
		uint32 Stride;
		void* buf = RHILockTexture2D(PR->GetTexture2DRHI(), 0, RLM_ReadOnly, Stride, false);

	
	}*/



	UE_LOG(LogHTML5UI, Warning, TEXT("UHTML5UIWidget::SaveTexture2DDebug: %d %d"), w,h);
	UE_LOG(LogHTML5UI, Warning, TEXT("UHTML5UIWidget::SaveTexture2DDebug: %s %d"),*ResultPath,bSaved==true ? 1 : 0);

}

void SaveTexture2DDebug(const uint8* PPixelData, int width, int height, FString Filename)
{
	TArray<FColor> OutBMP;
	int w = width;
	int h = height;

	OutBMP.InsertZeroed(0, w*h);

	for (int i = 0; i < (w*h); ++i)
	{
		uint8 R = PPixelData[i * 4 + 2];
		uint8 G = PPixelData[i * 4 + 1];
		uint8 B = PPixelData[i * 4 + 0];
		uint8 A = PPixelData[i * 4 + 3];

		OutBMP*.R = R;
		OutBMP*.G = G;
		OutBMP*.B = B;
		OutBMP*.A = A;
	}

	FIntPoint DestSize(w, h);

	FString ResultPath;
	FHighResScreenshotConfig& HighResScreenshotConfig = GetHighResScreenshotConfig();
	bool bSaved = HighResScreenshotConfig.SaveImage(Filename, OutBMP, DestSize, &ResultPath);


	UE_LOG(LogHTML5UI, Warning, TEXT("UHTML5UIWidget::SaveTexture2DDebug: %d %d"), w, h);
	UE_LOG(LogHTML5UI, Warning, TEXT("UHTML5UIWidget::SaveTexture2DDebug: %s %d"), *ResultPath, bSaved == true ? 1 : 0);

}

It’s very useful!

Thank you EddyTheTank.

Hi, I want to realize the reverse function: generate texture2D from a given picture(like PNG) using C++ code.

Hoping you can offer me some aid.

Hi jiangjiashi

UTexture2D* tmpTex = UTexture2D::CreateTransient(size, size);
tmpTex->Source.Init(…)

To save you reinventing the wheel, check out the C++ source for Rama’s Extra Blueprint nodes.
It includes saving/loading textures, including textures from scene capture components.

哥们你下面这句语法都有问题 ,哪来的SOURCE对象:confused:

Hi Kris

The function isn´t saving the file, maybe I´m doing something wrong with the path?

thanks

Hi

Sorry, please nevermind, the files wasn´t being saved because I used the wrong format :slight_smile:
working fine now, thanks a lot!

I modified the function a bit.
The issue is that the texture settings must be set properly for the export.
-No Compression
-No Mipmaps

The function changes the settings of the texture temporarly.


void SaveTextureToDisk(UTexture2D* texture, const FString& file)
{
    // Here I tried to work with a temporary texture, but that did not work. Changing the settings
    // of the texture after copy did not have effect.
    //UTexture2D* tempTex = texture->CreateTransient(texture->GetSizeX(), texture->GetSizeY());
    //void* dest = tempTex->PlatformData->Mips[0].BulkData.Lock(LOCK_READ_WRITE);
    //texture->PlatformData->Mips[0].BulkData.GetCopy(&dest, false);
    //tempTex->PlatformData->Mips[0].BulkData.Unlock();
    //tempTex->CompressionSettings = TextureCompressionSettings::TC_VectorDisplacementmap;
    //tempTex->MipGenSettings = TextureMipGenSettings::TMGS_NoMipmaps;
    //tempTex->UpdateResource();

    TextureCompressionSettings prevCompression = texture->CompressionSettings;
    TextureMipGenSettings prevMipSettings = texture->MipGenSettings;
    texture->CompressionSettings = TextureCompressionSettings::TC_VectorDisplacementmap;
    texture->MipGenSettings = TextureMipGenSettings::TMGS_NoMipmaps;
    texture->UpdateResource();
    FTexture2DMipMap* MM = &texture->PlatformData->Mips[0];

    TArray<FColor> OutBMP;
    int w = MM->SizeX;
    int h = MM->SizeY;

    OutBMP.SetNumUninitialized(w*h);

    FByteBulkData* RawImageData = &MM->BulkData;

    FColor* FormatedImageData = static_cast<FColor*>(RawImageData->Lock(LOCK_READ_ONLY));
    if (FormatedImageData)
    {
        for (int i = 0; i < (w*h); ++i)
        {
            OutBMP* = FormatedImageData*;
            OutBMP*.A = 255;
        }

        RawImageData->Unlock();
        FIntPoint DestSize(w, h);

        FString ResultPath;
        FHighResScreenshotConfig& HighResScreenshotConfig = GetHighResScreenshotConfig();
        HighResScreenshotConfig.SaveImage(file, OutBMP, DestSize, nullptr);
    }
    else
    {
        UE_LOG(LogTemp, Error, TEXT("SaveTextureToDisk: could not access bulk data of texture! Texture: %s"), *texture->GetFullName());
    }

    texture->CompressionSettings = prevCompression;
    texture->MipGenSettings = prevMipSettings;
}

1 Like

@Rumbleball, faced with difficulties with HighResScreenshotConfig.SaveImage (I can`t use it in 4.20 version). How I can replace it?Thanks in advance

what is not working? We are still on 4.19.

Rumbleball, I cant use SaveImage function.And I cant find this function at FHighResScreenshotConfig.h
https://api.unrealengine.com/INT/API/Runtime/Engine/FHighResScreenshotConfig/index.html
Maybe I make something wrong?

Seems they changed it.
ImageWriteQueue in FHighResScreenshotConfig looks promising

I think the old system has been replaced by UImageWriteBlueprintLibrary::ExportToDisk(). Here an example of usage.

This was one of the threads that I stumbled across while trying to figure out how to get screenshots to save to a completely outside-the-engine location. It’s not directly related to saving UTexture2D, but I did come up with a way to save a TArray<FColor>: quick code tutorial, how to get a screenshot and write the texture data to a file - C++ Gameplay Programming - Unreal Engine Forums

Hi! Rumbleball solution does not work in packaged game because UTexture::MipGenSettings is editor-only data.
Besides, BulkData size is different between cooked and non-cooked data…
How can I extract texture pixel array for cooked UTexture?
Thank you!

I’m pretty sure that worked for us in 4.16/4.19. Haven’t been packing for long time now, but maybe will run into this then.

This API is not working can you please share the example usage code here, because the links also not working

Links are working correctly. You must be logged into GitHub, and your GitHub account must be linked with your Epic Games account. Follow instruction here: Unreal Engine on GitHub - Unreal Engine