【UE4 C++】 外部图片读取、Texture 保存 png
蓝图版
导入外部图片
file://E:/UE___Projects_Test/MyProjectAAA/Plugins/WXimage.jpg
导出图图片
- 一般导出 .hdr 文件
- 导出 png 设置一些格式
C++ 版
读取外部图片
-
build.cs 添加 ImageWrapper 模块,使用时注意添加相关头文件
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "ImageWrapper" });
-
支持图片类型
- png
- jpg
- bmp
- ico
- exr
- icns
-
注意 jpg 读取后 R 和 B 的通道位置
- ERGBFormat::RGBA、PF_R8G8B8A8 → ERGBFormat::BGR、PF_B8G8R8A8
-
代码实现(4.26)
UENUM(BlueprintType) enum class EImgFormat : uint8 { /** Portable Network Graphics. */ PNG = 0, /** Joint Photographic Experts Group. */ JPEG, /** Single channel JPEG. */ GrayscaleJPEG, /** Windows Bitmap. */ BMP, /** Windows Icon resource. */ ICO, /** OpenEXR (HDR) image file format. */ EXR, /** Mac icon. */ ICNS }; UTexture2D* ADataDriveActor::ImportImage(const FString& path, EImgFormat Type, bool& IsValid, int32& OutWidth, int32& OutHeight) { UTexture2D* Texture = nullptr; IsValid = false; // 文件是否存在 if (!FPlatformFileManager::Get().GetPlatformFile().FileExists(*path)) { return nullptr; } // 图片是否加载 TArray<uint8> RawFileData; if (!FFileHelper::LoadFileToArray(RawFileData, *path)) { return nullptr; } IImageWrapperModule& ImageWrapperModule = FModuleManager::LoadModuleChecked<IImageWrapperModule>(FName("ImageWrapper")); // 自定义枚举转换 EImageFormat // IImageWrapperPtr 变更为 TSharedPtr<IImageWrapper> TSharedPtr<IImageWrapper> ImageWrapper = ImageWrapperModule.CreateImageWrapper(static_cast<EImageFormat>((int8)Type)); if (ImageWrapper.IsValid() && ImageWrapper->SetCompressed(RawFileData.GetData(), RawFileData.Num())) { // 此处有所变动 低版本为 const TArray<uint8>* UncompressedRGBA = nullptr; TArray<uint8> UncompressedRGBA ; if (ImageWrapper->GetRaw(ERGBFormat::RGBA, 8, UncompressedRGBA)) { Texture = UTexture2D::CreateTransient(ImageWrapper->GetWidth(), ImageWrapper->GetHeight(), PF_R8G8B8A8); if (Texture != nullptr) { IsValid = true; OutWidth = ImageWrapper->GetWidth(); OutHeight = ImageWrapper->GetHeight(); void* TextureData = Texture->PlatformData->Mips[0].BulkData.Lock(LOCK_READ_WRITE); FMemory::Memcpy(TextureData, UncompressedRGBA.GetData(), UncompressedRGBA.Num()); Texture->PlatformData->Mips[0].BulkData.Unlock(); Texture->UpdateResource(); } } } return Texture; }
Texture 导出 图片
-
使用 mip.BulkData.Lock(LOCK_READ_WRITE) 前需要对Texture 设置一些参数,否则会返回 nullptr
- CompressionSettings set to VectorDisplacementmap
- MipGenSettings to NoMipmaps
- SRGB to false
-
代码实现
bool ADataDriveActor::ExportImage(UTexture2D* Texture2D, const FString& Path) { // setup required parameters TextureCompressionSettings OldCompressionSettings = Texture2D->CompressionSettings; TextureMipGenSettings OldMipGenSettings = Texture2D->MipGenSettings; bool OldSRGB = Texture2D->SRGB; Texture2D->CompressionSettings = TextureCompressionSettings::TC_VectorDisplacementmap; Texture2D->MipGenSettings = TextureMipGenSettings::TMGS_NoMipmaps; Texture2D->SRGB = false; Texture2D->UpdateResource(); FTexture2DMipMap& mipmap = Texture2D->PlatformData->Mips[0]; uint8* Data = (uint8*)mipmap.BulkData.Lock(LOCK_READ_WRITE); //FColor* FormatedImageData = static_cast<FColor*>(mipmap.BulkData.Lock(LOCK_READ_WRITE)); if (Data == nullptr) { mipmap.BulkData.Unlock(); // 不释放,会卡住 Texture2D->UpdateResource(); return false; } int width = Texture2D->PlatformData->SizeX; int height = Texture2D->PlatformData->SizeY; TArray<FColor> nColors; for (int32 y = 0; y < height; y++) { for (int32 x = 0; x < width; x++) { FColor bColor; bColor.B = Data[(y * width + x) * 4 + 0];//B 0 - 255 bColor.G = Data[(y * width + x) * 4 + 1];//G bColor.R = Data[(y * width + x) * 4 + 2];//R bColor.A = Data[(y * width + x) * 4 + 3];//A nColors.Add(bColor); } } mipmap.BulkData.Unlock(); // return old parameters Texture2D->CompressionSettings = OldCompressionSettings; Texture2D->MipGenSettings = OldMipGenSettings; Texture2D->SRGB = OldSRGB; Texture2D->UpdateResource(); //获取 uint8 数据,保存 TArray<uint8> ImgData; FImageUtils::CompressImageArray(width, height, nColors, ImgData); return FFileHelper::SaveArrayToFile(ImgData, *Path); }
作者:砥才人
出处:https://www.cnblogs.com/shiroe
本系列文章为笔者整理原创,只发表在博客园上,欢迎分享本文链接,如需转载,请注明出处!