Copy asset Thumbnail to new Texture2d?

Is it possible to write a python script to load an asset Thumbnail image into a new Texture2d asset that I can use at runtime in my UI?

Hello, did you find a solution?

I think if you want to export the thumbnail and import it as a texture assets in python or bp, you need do a little c++ work: export a Blueprint callable function which export the thumbnail as a image, then import it as texture2D assets with python script or bp.

The source of the export function from JoeRadak:
Exporting Thumbnails to PNGs - Pipeline & Plugins / Editor Scripting - Unreal Engine Forums

	/** .h
	 * Save the Thumbnail of assets to disc.
	 *
	 * @param   ObjectPath					The specified path of asset
	 * @param	OutputPath					Thumbnail output path
	 */
	UFUNCTION(BlueprintCallable, meta = (Keywords = "Python Editor"), Category = "PythonEditor")
	static void SaveThumbnail(FString ObjectPath, FString OutputPath);

and the implementation in .cpp

/** .cpp */
void UPythonBPLib::SaveThumbnail(FString ObjectPath, FString OutputPath)
{
	FAssetRegistryModule& AssetRegistryModule = FModuleManager::Get().LoadModuleChecked<FAssetRegistryModule>(TEXT("AssetRegistry"));
	FAssetData AssetData = AssetRegistryModule.Get().GetAssetByObjectPath(*ObjectPath);
	UObject* MyObject = AssetData.GetAsset();
	if (MyObject)
	{
		FObjectThumbnail* ObjectThumbnail = ThumbnailTools::GenerateThumbnailForObjectToSaveToDisk(MyObject);
		if (ObjectThumbnail)
		{
			IImageWrapperModule& ImageWrapperModule = FModuleManager::Get().LoadModuleChecked<IImageWrapperModule>(TEXT("ImageWrapper"));
			TSharedPtr<IImageWrapper> ImageWrapper = ImageWrapperModule.CreateImageWrapper(EImageFormat::PNG);

			ImageWrapper->SetRaw(ObjectThumbnail->GetUncompressedImageData().GetData(), ObjectThumbnail->GetUncompressedImageData().Num(), ObjectThumbnail->GetImageWidth(), ObjectThumbnail->GetImageHeight(), ERGBFormat::BGRA, 8);
			if (ImageWrapper)
			{
				const TArray64<uint8>& CompressedByteArray = ImageWrapper->GetCompressed();
				FFileHelper::SaveArrayToFile(CompressedByteArray, *OutputPath);
			}
		}
	}
}

Then, we can export the thumbnail with python like this:


    def on_button_ExportThumbnail_click(self):
        print('on_button_ExportThumbnail_click')
        folder = "/Game/YourAssetsFolder"
        asset_paths = unreal.EditorAssetLibrary.list_assets(folder, recursive=True)
        target_folder = r"D:\YouArtSourceFolder"

        for i, asset_path in enumerate(asset_paths):
            asset = unreal.load_asset(asset_path)
            if type(asset) is not unreal.StaticMesh:  # change the types
                continue

            name_with_folder = asset_path[len(folder)+1:].split(".")[0]
            target_file_path = os.path.join(target_folder, f"{name_with_folder.replace('/', '_')}.png")
            
            unreal.PythonBPLib.save_thumbnail(asset_path, target_file_path)

After that, import the exported thumbnail as texture

    import_task = unreal.AssetImportTask()
    # set the import_task.filename, destination_path, options and so on
    import_task.filename = texture_path
    # ...
    unreal.AssetToolsHelpers.get_asset_tools().import_asset_tasks([import_task])

Hope, that helps.

1 Like

For posterity, here’s a way to generate a UTexture2D asset from an Asset’s thumbnail, using only C++. Thanks to @chpsemail and IsaraTech from UE4 - Save a procedurally generated texture as a new asset - Isara Tech.


UTexture2D* SaveThumbnailAsTexture2d(UObject* obj, FString TextureName, FString GamePath) {
	int32 pathSeparatorIdx;
	if (TextureName.FindChar('/', pathSeparatorIdx)) {
		// TextureName should not have any path separators in it
		return nullptr;
	}

	FObjectThumbnail* thumb = ThumbnailTools::GenerateThumbnailForObjectToSaveToDisk(obj);
	if (!thumb) {
		return nullptr;
	}

	FString PackageName = GamePath;
	if (!PackageName.EndsWith("/")) {
		PackageName += "/";
	}
	PackageName += TextureName;

	UPackage* Package = CreatePackage(*PackageName);
	Package->FullyLoad();

	UTexture2D* NewTexture = NewObject<UTexture2D>(Package, *TextureName, RF_Public | RF_Standalone | RF_MarkAsRootSet);
	NewTexture->AddToRoot();
	FTexturePlatformData* platformData = new FTexturePlatformData();
	platformData->SizeX = thumb->GetImageWidth();
	platformData->SizeY = thumb->GetImageHeight();
	//platformData->NumSlices = 1;
	platformData->PixelFormat = EPixelFormat::PF_B8G8R8A8;
	NewTexture->SetPlatformData(platformData);

	FTexture2DMipMap* Mip = new FTexture2DMipMap();
	platformData->Mips.Add(Mip);
	Mip->SizeX = thumb->GetImageWidth();
	Mip->SizeY = thumb->GetImageHeight();

	Mip->BulkData.Lock(LOCK_READ_WRITE);
	uint8* TextureData = (uint8*)Mip->BulkData.Realloc(thumb->GetUncompressedImageData().Num() * 4);
	FMemory::Memcpy(TextureData, thumb->GetUncompressedImageData().GetData(), thumb->GetUncompressedImageData().Num());
	Mip->BulkData.Unlock();

	NewTexture->Source.Init(thumb->GetImageWidth(), thumb->GetImageHeight(), 1, 1, ETextureSourceFormat::TSF_BGRA8, thumb->GetUncompressedImageData().GetData());

	NewTexture->UpdateResource();
	Package->MarkPackageDirty();
	FAssetRegistryModule::AssetCreated(NewTexture);

	FSavePackageArgs SaveArgs;
	SaveArgs.TopLevelFlags = EObjectFlags::RF_Public | EObjectFlags::RF_Standalone;
	SaveArgs.SaveFlags = SAVE_NoError;
	SaveArgs.bForceByteSwapping = true;
	FString PackageFileName = FPackageName::LongPackageNameToFilename(PackageName, FPackageName::GetAssetPackageExtension());
	bool bSaved = UPackage::SavePackage(Package, NewTexture, *PackageFileName, SaveArgs);

	return NewTexture;
}

UTexture2D* SaveThumbnailAsTexture2d(UObject* obj) {
	FString GamePath = obj->GetPathName();
	FString AssetName;
	int32 pathEnd;
	if (GamePath.FindLastChar('/', pathEnd)) {
		++pathEnd;

		AssetName = GamePath;
		AssetName.RightChopInline(pathEnd);
		int32 extensionIdx;
		if (AssetName.FindChar('.', extensionIdx)) {
			AssetName.LeftInline(extensionIdx);
		}
		AssetName += "_Thumbnail";

		GamePath.LeftInline(pathEnd);
	}
	else {
		AssetName = "Thumbnail";
	}
	return SaveThumbnailAsTexture2d(obj, AssetName, GamePath);
}

2 Likes

ue 5.0 not work

It works for me in UE 5.3.

Is there a way to save this with a transparent background instead of the checkered background?