Adding texture assets permanently to game content folder

I’m working on an editor plugin that should automatically import multiple textures into game content folder. I use a function to import the texture. It seems to work at first, and the texture pops up in the content browser, however, it doesn’t seem to work properly. When mouse-hovering over it, it shows 0x0 dimensions. Also, making adjustments to the texture, such as altering brightness, doesn’t seem to work. When the project is restarted the texture is just black and trying to open, delete or rename it will make the project crash immediately. Any help is much appreciated. Here is the code I’m using:

UTexture2D* FVolumeRendererModule::LoadTexture2D_FromFile_ToPackage(const FString& FullFilePath, const FString& PackageName, EJoyImageFormats ImageFormat, bool& IsValid, int32& Width, int32& Height)
{


	IsValid = false;
	UTexture2D* NewTextureAsset = NULL;
	UPackage* Package = CreatePackage(NULL, *PackageName);
	//Package = NewObject<UPackage>(NULL, FName(*PackageName), RF_Standalone | RF_Public  | RF_MarkAsRootSet);

	IImageWrapperModule& ImageWrapperModule = FModuleManager::LoadModuleChecked<IImageWrapperModule>(FName("ImageWrapper"));
	IImageWrapperPtr ImageWrapper = ImageWrapperModule.CreateImageWrapper(GetJoyImageFormat(ImageFormat));

	//Load From File
	TArray<uint8> RawFileData;
	if (!FFileHelper::LoadFileToArray(RawFileData, *FullFilePath)) return NULL;
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	//Create T2D!
	if (ImageWrapper.IsValid() && ImageWrapper->SetCompressed(RawFileData.GetData(), RawFileData.Num()))
	{
		const TArray<uint8>* UncompressedBGRA = NULL;
		if (ImageWrapper->GetRaw(ERGBFormat::BGRA, 8, UncompressedBGRA))
		{
			Width = ImageWrapper->GetWidth();
			Height = ImageWrapper->GetHeight();

			//UTexture2D* LoadedT2D2 = NewObject<UTexture2D>(Package, FName("MyAsset"), RF_Public | RF_Standalone | RF_MarkAsRootSet, NULL, false);
			NewTextureAsset = NewObject<UTexture2D>(Package, FName("NewTextureAsset"), RF_Public | RF_Standalone | RF_MarkAsRootSet, NULL, false);
			//LoadedT2D2->Source.Init(Width, Height, 1, 1, TSF_BGRA8, RawFileData);
			//LoadedT2D2->Source.SetId(FGuid::NewGuid(), true);
			NewTextureAsset->PlatformData = new FTexturePlatformData();
			NewTextureAsset->PlatformData->SizeX = Width;
			NewTextureAsset->PlatformData->SizeY = Height;
			NewTextureAsset->PlatformData->PixelFormat = EPixelFormat::PF_B8G8R8A8;

			//LoadedT2D2->PlatformData->
			// Allocate first mipmap.
			int32 NumBlocksX = Width / GPixelFormats[EPixelFormat::PF_B8G8R8A8].BlockSizeX;
			int32 NumBlocksY = Height / GPixelFormats[EPixelFormat::PF_B8G8R8A8].BlockSizeY;
			FTexture2DMipMap* Mip = new(NewTextureAsset->PlatformData->Mips) FTexture2DMipMap();
			Mip->SizeX = Width;
			Mip->SizeY = Height;

			Mip->BulkData.Lock(LOCK_READ_WRITE);
			//void* TextureData = LoadedT2D2->PlatformData->Mips[0].BulkData.Lock(LOCK_READ_WRITE);
			Mip->BulkData.Realloc(NumBlocksX * NumBlocksY * GPixelFormats[EPixelFormat::PF_B8G8R8A8].BlockBytes);
			Mip->BulkData.Unlock();

			//void* TextureData = Mip->BulkData.Lock(LOCK_READ_WRITE);
			//FMemory::Memcpy(TextureData, UncompressedBGRA->GetData(), UncompressedBGRA->Num());
			//LoadedT2D->PlatformData->Mips[0].BulkData.GetCopy(Mip->BulkData);
			//Mip->BulkData.Unlock();

			NewTextureAsset->CreateResource();

			FAssetRegistryModule::AssetCreated(NewTextureAsset);
			NewTextureAsset->MarkPackageDirty();
			Package->SetDirtyFlag(true); //Mark the asset with a small astrisk indicating that it still hasn't been saved in the content folder permenantly
			NewTextureAsset->PreSave();
			NewTextureAsset->AddToRoot();
			NewTextureAsset->PostEditChange();
			NewTextureAsset->UpdateResource();

			GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Blue, FString::Printf(TEXT("All Done Well")));
			Package->PreSave();
			GEditor->SavePackage(Package, NewTextureAsset, EObjectFlags::RF_NoFlags, *PackageName, GWarn, nullptr, true, true, NULL);
			Package->PostSaveRoot(true);

		}

	}

	return NewTextureAsset;
}

122092-a.jpg

122093-b.jpg

have you tried UTextureFactory::FactoryCreateBinary for writing the files, instead of GEditor?

you can check how epic is creating/writing textures from fbx files from UnFbx::FFbxImporter::ImportTexture and maybe replicate the results in your plugin.

That was a great pointer, man. Thanks for saving me hours of trouble looking elsewhere inside UE4 code. You’re a life saver.

Got it working thanks to emrahgunduz’s excellent advice. I’m posting some working code (which might need sme cleanup, btw) here in hope it’ll help someone who runs into the same trouble in the future.

UTexture2D* FVolumeRendererModule::LoadTexture2D_FromFile_ToPackage(const FString& FullFilePath, const FString& PackageName, EJoyImageFormats ImageFormat, bool& IsValid, int32& Width, int32& Height)
{


	IsValid = false;
	UTexture2D* NewTextureAsset = NULL;
	UPackage* Package = CreatePackage(NULL, *PackageName);
	//Package = NewObject<UPackage>(NULL, FName(*PackageName), RF_Standalone | RF_Public  | RF_MarkAsRootSet);

	IImageWrapperModule& ImageWrapperModule = FModuleManager::LoadModuleChecked<IImageWrapperModule>(FName("ImageWrapper"));
	IImageWrapperPtr ImageWrapper = ImageWrapperModule.CreateImageWrapper(GetJoyImageFormat(ImageFormat));

	//Load From File
	TArray<uint8> RawFileData;
	if (!FFileHelper::LoadFileToArray(RawFileData, *FullFilePath)) return NULL;
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	//Create T2D!
	if (ImageWrapper.IsValid() && ImageWrapper->SetCompressed(RawFileData.GetData(), RawFileData.Num()))
	{
		const TArray<uint8>* UncompressedBGRA = NULL;
		ImageWrapper->GetRaw(ERGBFormat::BGRA, 8, UncompressedBGRA);
	}

	UTexture* UnrealTexture = NULL;
	const uint8* PtrTexture = RawFileData.GetData();
	auto TextureFact = NewObject<UTextureFactory>();
	TextureFact->AddToRoot();
	// save texture settings if texture exist
	TextureFact->SuppressImportOverwriteDialog();
	UnrealTexture = (UTexture*)TextureFact->FactoryCreateBinary(
		UTexture2D::StaticClass(), Package, TEXT("NewTexture"),//*FullFilePath,
		RF_Standalone | RF_Public, NULL, TEXT("jpg"),
		PtrTexture, PtrTexture + RawFileData.Num(), GWarn);

	if (UnrealTexture != NULL)
	{
		//Make sure the AssetImportData point on the texture file and not on the fbx files since the factory point on the fbx file
		UnrealTexture->AssetImportData->Update(IFileManager::Get().ConvertToAbsolutePathForExternalAppForRead(TEXT("NewTexture")));

		// Notify the asset registry
		FAssetRegistryModule::AssetCreated(UnrealTexture);

		// Set the dirty flag so this package will get saved later
		Package->SetDirtyFlag(true);
	}
	TextureFact->RemoveFromRoot();

	return NewTextureAsset;
}

I am from the future and it helped me. thank you