记个笔记:UE截图工具

​ 最近工作中使用UE截图的需求,就寻找并学习了下,将实现记录一下,记个笔记!!!

工具版本

UE: 5.2.1
Rider: 2023.3.6
VS2022: 17.4.0

ScreenShotSubsystem.h

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "Subsystems/GameInstanceSubsystem.h"
#include "ScreenShotSubsystem.generated.h"

class UTexture2D;

UENUM(BlueprintType)
enum class EScreenShotType : uint8
{
	ESST_Normal UMETA(DisplayName = "普通截图(不带UI)"),
	ESST_NormalWithUI UMETA(DisplayName = "普通截图(带UI)"),
	ESST_HighResShot UMETA(DisplayName = "高精度截图(不带UI)")
};

UENUM(BlueprintType)
enum class EScreenShotSuffix : uint8
{
	ESSS_PNG UMETA(DisplayName = "PNG"),
	ESSS_JPG UMETA(DisplayName = "JPG")
};

UENUM(BlueprintType)
enum class EFixType : uint8
{
	EFT_Prefix UMETA(DisplayName = "前缀"),
	EFT_Suffix UMETA(DisplayName = "后缀")
};

USTRUCT(BlueprintType)
struct FResolution
{
	GENERATED_BODY()
	UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "ScreenSize")
	int32 Width{0};
	UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "ScreenSize")
	int32 Height{0};
};

USTRUCT(BlueprintType)
struct FScreenShotParams
{
	GENERATED_BODY()
	UPROPERTY(BlueprintReadWrite, Category = "SSParams")
	EScreenShotType ScreenShotType {EScreenShotType::ESST_Normal};
	UPROPERTY(BlueprintReadWrite, Category = "SSParams")
	EScreenShotSuffix SSSuffix {EScreenShotSuffix::ESSS_PNG};
	UPROPERTY(BlueprintReadWrite, Category = "SSParams")
	FString Filename {FString()};
	UPROPERTY(BlueprintReadWrite, Category = "SSParams")
	FString SavedFilePath {FString()};
	UPROPERTY(BlueprintReadWrite, Category = "SSParams", meta=(EditConditionHides = "ScreenShotType=EScreenShotType::ESST_HighResShot"))
	FResolution Resolution {FResolution()};
	
	FString ReturnFilePath {FString()};
};

/**
 * 
 */
UCLASS()
class SCREENSHOT_API UScreenShotSubsystem : public UGameInstanceSubsystem
{
	GENERATED_BODY()
public:
	virtual void Initialize(FSubsystemCollectionBase& Collection) override;
	virtual void Deinitialize() override;
	virtual bool ShouldCreateSubsystem(UObject* Outer) const override;
	
	static FDelegateHandle DelegateHandle;
	
	// 从本地路径导入图片并转换为Texture2D格式
	UFUNCTION(BlueprintCallable, Category = "LoadAssets")
	UTexture2D* LoadTexture2DFromLocal(UPARAM(ref) FString& ImagePath) const;
	// 实现截图
	UFUNCTION(BlueprintCallable, Category = "ScreenShot")
	FString CaptureImage(UPARAM(ref) FScreenShotParams& SSParams);
	// 获取同意文件夹下的某前缀或后缀的文件
	UFUNCTION(BlueprintCallable, Category = "Tools")
	TArray<FString> GetLocalAllFiles(UPARAM(ref) FString& FilePath, const FString FileFix, const EFixType FixType = EFixType::EFT_Suffix);
private:
	static void OnScreenshotCompleteImage(int32 InWidth, int32 InHeight, const TArray<FColor>& InColors, const FScreenShotParams SSParams);
};

ScreenShotSubsystem.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "ScreenShot/Subsystems/ScreenShotSubsystem.h"
#include "IImageWrapper.h"
#include "IImageWrapperModule.h"

FDelegateHandle UScreenShotSubsystem::DelegateHandle = {};

void UScreenShotSubsystem::Initialize(FSubsystemCollectionBase& Collection)
{
	Super::Initialize(Collection);
}

void UScreenShotSubsystem::Deinitialize()
{
	Super::Deinitialize();
}

bool UScreenShotSubsystem::ShouldCreateSubsystem(UObject* Outer) const
{
	TArray<UClass*> ChildClasses;
	GetDerivedClasses(GetClass(), ChildClasses, false);
	return ChildClasses.Num() == 0;
}

UTexture2D* UScreenShotSubsystem::LoadTexture2DFromLocal(FString& ImagePath) const
{
	TArray<FString> ImageFiles;
	FPaths::NormalizeDirectoryName(ImagePath);
	FString FinalPath = FPaths::ProjectContentDir() + ImagePath;
	IFileManager& FileManager = IFileManager::Get();
	FileManager.FindFiles(ImageFiles, *FinalPath, true, true);
	if (ImageFiles.Num() > 0)
	{
		FString ImgPath = ImageFiles[0];
		TArray<uint8> CompressedData;
		if (FFileHelper::LoadFileToArray(CompressedData, *FinalPath))
		{
			EImageFormat ImageFormat = EImageFormat::Invalid;
			if (ImgPath.EndsWith(".png"))
			{
				ImageFormat = EImageFormat::PNG;
			}
			else if (ImgPath.EndsWith(".jpg") || ImgPath.EndsWith(".jpeg") || ImgPath.EndsWith(".PNG") || ImgPath.
				EndsWith(".JPEG"))
			{
				ImageFormat = EImageFormat::JPEG;
			}
			IImageWrapperModule& ImageWrapperModule = FModuleManager::LoadModuleChecked<IImageWrapperModule>(
				FName("ImageWrapper"));
			TSharedPtr<IImageWrapper> ImageWrapper = ImageWrapperModule.CreateImageWrapper(ImageFormat);
			if (ImageWrapper->SetCompressed(CompressedData.GetData(), CompressedData.Num()))
			{
				TArray<uint8> UncompressedRGBA;
				if (ImageWrapper->GetRaw(ERGBFormat::RGBA, 8, UncompressedRGBA))
				{
					TObjectPtr<UTexture2D> Texture2D = UTexture2D::CreateTransient(
						ImageWrapper->GetWidth(), ImageWrapper->GetHeight(), PF_R8G8B8A8);
					void* TextureData = Texture2D->PlatformData->Mips[0].BulkData.Lock(LOCK_READ_WRITE);
					FMemory::Memcpy(TextureData, UncompressedRGBA.GetData(), UncompressedRGBA.Num());
					Texture2D->PlatformData->Mips[0].BulkData.Unlock();
					Texture2D->UpdateResource();
					return Texture2D.Get();
				}
			}
		}
	}
	return nullptr;
}

FString UScreenShotSubsystem::CaptureImage(FScreenShotParams& SSParams)
{
	if (!GEngine || !GEngine->GameViewport)
	{
		return FString();
	}
	const FString SavedFilePath = !SSParams.SavedFilePath.IsEmpty()
		                              ? SSParams.SavedFilePath
		                              : FString::Printf(TEXT("%s/Screenshots/"), *FPaths::ProjectContentDir());
	FString ReturnFilePath = FString::Printf(TEXT("%s/%s"), *SavedFilePath, *SSParams.Filename);
	if (SSParams.SSSuffix == EScreenShotSuffix::ESSS_JPG)
	{
		ReturnFilePath = FString::Printf(TEXT("%s%s"), *ReturnFilePath, *FString(".jpg"));
	}
	else if (SSParams.SSSuffix == EScreenShotSuffix::ESSS_PNG)
	{
		ReturnFilePath = FString::Printf(TEXT("%s%s"), *ReturnFilePath, *FString(".png"));
	}
	SSParams.ReturnFilePath = ReturnFilePath;
	DelegateHandle = UGameViewportClient::OnScreenshotCaptured().AddStatic(&OnScreenshotCompleteImage, SSParams);

	if (SSParams.ScreenShotType == EScreenShotType::ESST_Normal)
	{
		if (GEngine->GameViewport->Exec(nullptr, TEXT("Shot"), *GLog))
		{
			return ReturnFilePath;
		}
	}
	else if (SSParams.ScreenShotType == EScreenShotType::ESST_NormalWithUI)
	{
		if (GEngine->GameViewport->Exec(nullptr, TEXT("Shot showui"), *GLog))
		{
			return ReturnFilePath;
		}
	}
	else if (SSParams.ScreenShotType == EScreenShotType::ESST_HighResShot)
	{
		const FString Command = FString::Printf(
			TEXT("HighResShot %dx%d"), SSParams.Resolution.Width, SSParams.Resolution.Height);
		if (GEngine->GameViewport->Exec(nullptr, *Command, *GLog))
		{
			return ReturnFilePath;
		}
	}
	return FString();
}

void UScreenShotSubsystem::OnScreenshotCompleteImage(int32 InWidth, int32 InHeight, const TArray<FColor>& InColors,
                                                     const FScreenShotParams SSParams)
{
	IImageWrapperModule& ImageWrapperModule = FModuleManager::Get().LoadModuleChecked<IImageWrapperModule>(
		FName("ImageWrapper"));
	TSharedPtr<IImageWrapper> ImageWrapper = nullptr;
	if (SSParams.SSSuffix == EScreenShotSuffix::ESSS_JPG)
	{
		ImageWrapper = ImageWrapperModule.CreateImageWrapper(EImageFormat::JPEG);
	}
	else if (SSParams.SSSuffix == EScreenShotSuffix::ESSS_PNG)
	{
		ImageWrapper = ImageWrapperModule.CreateImageWrapper(EImageFormat::PNG);
	}
	if (ImageWrapper->SetRaw(InColors.GetData(), InColors.Num() * sizeof(FColor),
	                         InWidth, InHeight, ERGBFormat::BGRA, 8))
	{
		FFileHelper::SaveArrayToFile(ImageWrapper->GetCompressed(), *SSParams.ReturnFilePath);
	}
	UGameViewportClient::OnScreenshotCaptured().Remove(DelegateHandle);
}

TArray<FString> UScreenShotSubsystem::GetLocalAllFiles(FString& FilePath, const FString FileFix,
                                                       const EFixType FixType)
{
	TArray<FString> Files = TArray<FString>();
	FPaths::NormalizeDirectoryName(FilePath);
	IFileManager& FileManager = IFileManager::Get();
	const FString FinalPath = FilePath / TEXT("*");
	FileManager.FindFiles(Files, *FinalPath, true, true);
	TArray<FString> ReturnFiles = TArray<FString>();
	if (FixType == EFixType::EFT_Prefix)
	{
		for (const FString File : Files)
		{
			if(File.StartsWith(*FileFix))
			{
				ReturnFiles.Add(File);
			}
		}
	}
	else if (FixType == EFixType::EFT_Suffix)
	{
		for (const FString File : Files)
		{
			if(File.EndsWith(*FileFix))
			{
				ReturnFiles.Add(File);
			}
		}
	}
	return ReturnFiles;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值