UE4 FColor数据保存成图片
1、TArray<FColor>或是FColor*可通过ImageWrapper直接保存成图片
1 void URenderCineCameraLibrary::SaveColorToFile(FColor* SourceColor, uint32 Width, uint32 Height) 2 { 3 check(SourceColor != nullptr); 4 5 /*// FColor* SurfaceColor ...png 6 for (FColor& Color : SurfaceColor) 7 { 8 Color.A = 255; 9 } 10 11 TArray<uint8> TextureData; 12 TextureData.AddUninitialized(Width * Height * sizeof(FColor)); 13 FMemory::Memcpy(TextureData.GetData(), (uint8*)SourceColor, Width * Height * sizeof(FColor)); 14 if (TextureData.Num() <= 0) 15 { 16 UE_LOG(LogTemp, Error, TEXT("TextureData is empty ...")); 17 return; 18 }*/ 19 20 // save png 21 IImageWrapperModule& ImageWrapperModule = FModuleManager::LoadModuleChecked<IImageWrapperModule>(FName("ImageWrapper")); 22 TSharedPtr<IImageWrapper> ImageWrapper = ImageWrapperModule.CreateImageWrapper(EImageFormat::JPEG); 23 ImageWrapper->SetRaw(SourceColor, Width * Height * sizeof(FColor), Width, Height, ERGBFormat::BGRA, 8); 24 25 26 const TArray64<uint8>& PNGData = ImageWrapper->GetCompressed(100); 27 28 FString FileName = TEXT("D:\\CineCapture1.jpg"); 29 FFileHelper::SaveArrayToFile(PNGData, *FileName); 30 ImageWrapper.Reset(); 31 }
2、将UTexture2D保存成图片
1 void URenderCineCameraLibrary::SaveTextureToFile(UTexture2D* SourceTex) 2 { 3 check(SourceTex); 4 int32 Width = SourceTex->GetSizeX(); 5 int32 Height = SourceTex->GetSizeY(); 6 7 FTexture2DMipMap& MipMap = SourceTex->GetPlatformData()->Mips[0]; 8 void* Data = MipMap.BulkData.Lock(LOCK_READ_ONLY); 9 10 TArray<uint8> TextureData; 11 TextureData.AddUninitialized(Width * Height * sizeof(FColor)); 12 FMemory::Memcpy(TextureData.GetData(), (uint8*)Data, Width * Height * sizeof(FColor)); 13 if (TextureData.Num() <= 0) 14 { 15 UE_LOG(LogTemp, Error, TEXT("TextureData is empty ...")); 16 return; 17 } 18 19 // save png 20 IImageWrapperModule& ImageWrapperModule = FModuleManager::LoadModuleChecked<IImageWrapperModule>(FName("ImageWrapper")); 21 TSharedPtr<IImageWrapper> ImageWrapper = ImageWrapperModule.CreateImageWrapper(EImageFormat::JPEG); 22 ImageWrapper->SetRaw(TextureData.GetData(), Width * Height * sizeof(FColor), Width, Height, ERGBFormat::BGRA, 8); 23 24 25 const TArray64<uint8>& PNGData = ImageWrapper->GetCompressed(100); 26 27 FString FileName = TEXT("D:\\CineTexture.jpg"); 28 FFileHelper::SaveArrayToFile(PNGData, *FileName); 29 ImageWrapper.Reset(); 30 31 32 MipMap.BulkData.Unlock(); 33 }
3、创建UTextureRenderTarget2D、设置及保存为图片
1 void URenderCineCameraLibrary::ConstructRT2D() 2 { 3 if (m_CineTexRT2D == nullptr) 4 { 5 m_CineTexRT2D = NewObject<UTextureRenderTarget2D>(); 6 m_CineTexRT2D->AddToRoot(); 7 m_CineTexRT2D->ClearColor = FLinearColor::Transparent; 8 m_CineTexRT2D->TargetGamma = 0.f; 9 m_CineTexRT2D->InitCustomFormat(/*m_CaptureViewport->m_ViewportX*/1920, /*m_CaptureViewport->m_ViewportY*/1080, PF_B8G8R8A8, false); 10 } 11 12 check(GCineWorld != nullptr); 13 check(m_CineCamTex != nullptr); 14 CopyTextureToRenderTargetTexture(m_CineCamTex, m_CineTexRT2D, GCineWorld->FeatureLevel); 15 16 // save 17 //SaveRenderTargetToFile(m_CineTexRT2D, TEXT("D:\\RT_Cine.jpg")); 18 } 19 20 // 21 22 void URenderCineCameraLibrary::CopyTextureToRenderTargetTexture(UTexture* SourceTexture, UTextureRenderTarget2D* RenderTargetTexture, ERHIFeatureLevel::Type FeatureLevel) 23 { 24 check(SourceTexture != nullptr); 25 check(RenderTargetTexture != nullptr); 26 27 // Grab the actual render target resource from the texture. Note that we're absolutely NOT ALLOWED to 28 // dereference this pointer. We're just passing it along to other functions that will use it on the render 29 // thread. The only thing we're allowed to do is check to see if it's nullptr or not. 30 FTextureRenderTargetResource* RenderTargetResource = RenderTargetTexture->GameThread_GetRenderTargetResource(); 31 check(RenderTargetResource != nullptr); 32 33 // Create a canvas for the render target and clear it to black 34 FCanvas Canvas(RenderTargetResource, nullptr, FGameTime(), FeatureLevel); 35 36 const uint32 Width = RenderTargetTexture->GetSurfaceWidth(); 37 const uint32 Height = RenderTargetTexture->GetSurfaceHeight(); 38 39 // @todo MeshPaint: Need full color/alpha writes enabled to get alpha 40 // @todo MeshPaint: Texels need to line up perfectly to avoid bilinear artifacts 41 // @todo MeshPaint: Potential gamma issues here 42 // @todo MeshPaint: Probably using CLAMP address mode when reading from source (if texels line up, shouldn't matter though.) 43 44 // @todo MeshPaint: Should use scratch texture built from original source art (when possible!) 45 // -> Current method will have compression artifacts! 46 47 // Grab the texture resource. We only support 2D textures and render target textures here. 48 FTexture* TextureResource = nullptr; 49 UTexture2D* Texture2D = Cast<UTexture2D>(SourceTexture); 50 if (Texture2D != nullptr) 51 { 52 TextureResource = Texture2D->GetResource(); 53 } 54 else 55 { 56 UTextureRenderTarget2D* TextureRenderTarget2D = Cast<UTextureRenderTarget2D>(SourceTexture); 57 TextureResource = TextureRenderTarget2D->GameThread_GetRenderTargetResource(); 58 } 59 check(TextureResource != nullptr); 60 61 // Draw a quad to copy the texture over to the render target 62 { 63 const float MinU = 0.0f; 64 const float MinV = 0.0f; 65 const float MaxU = 1.0f; 66 const float MaxV = 1.0f; 67 const float MinX = 0.0f; 68 const float MinY = 0.0f; 69 const float MaxX = Width; 70 const float MaxY = Height; 71 72 FCanvasUVTri Tri1; 73 FCanvasUVTri Tri2; 74 Tri1.V0_Pos = FVector2D(MinX, MinY); 75 Tri1.V0_UV = FVector2D(MinU, MinV); 76 Tri1.V1_Pos = FVector2D(MaxX, MinY); 77 Tri1.V1_UV = FVector2D(MaxU, MinV); 78 Tri1.V2_Pos = FVector2D(MaxX, MaxY); 79 Tri1.V2_UV = FVector2D(MaxU, MaxV); 80 81 Tri2.V0_Pos = FVector2D(MaxX, MaxY); 82 Tri2.V0_UV = FVector2D(MaxU, MaxV); 83 Tri2.V1_Pos = FVector2D(MinX, MaxY); 84 Tri2.V1_UV = FVector2D(MinU, MaxV); 85 Tri2.V2_Pos = FVector2D(MinX, MinY); 86 Tri2.V2_UV = FVector2D(MinU, MinV); 87 Tri1.V0_Color = Tri1.V1_Color = Tri1.V2_Color = Tri2.V0_Color = Tri2.V1_Color = Tri2.V2_Color = FLinearColor::White; 88 TArray< FCanvasUVTri > List; 89 List.Add(Tri1); 90 List.Add(Tri2); 91 FCanvasTriangleItem TriItem(List, TextureResource); 92 TriItem.BlendMode = SE_BLEND_Opaque; 93 Canvas.DrawItem(TriItem); 94 } 95 96 // Tell the rendering thread to draw any remaining batched elements 97 Canvas.Flush_GameThread(true); 98 99 ENQUEUE_RENDER_COMMAND(UpdateMeshPaintRTCommand)( 100 [RenderTargetResource](FRHICommandListImmediate& RHICmdList) 101 { 102 // Copy (resolve) the rendered image from the frame buffer to its render target texture 103 RHICmdList.CopyToResolveTarget( 104 RenderTargetResource->GetRenderTargetTexture(), // Source texture 105 RenderTargetResource->TextureRHI, // Dest texture 106 FResolveParams()); // Resolve parameters 107 }); 108 } 109 110 // 111 bool URenderCineCameraLibrary::SaveRenderTargetToFile(UTextureRenderTarget2D* rt, const FString& fileDestination) 112 { 113 FTextureRenderTargetResource* rtResource = rt->GameThread_GetRenderTargetResource(); 114 FReadSurfaceDataFlags readPixelFlags(RCM_UNorm); 115 116 TArray<FColor> outBMP; 117 outBMP.AddUninitialized(rt->GetSurfaceWidth() * rt->GetSurfaceHeight()); 118 rtResource->ReadPixels(outBMP, readPixelFlags); 119 120 121 IImageWrapperModule& ImageWrapperModule = FModuleManager::LoadModuleChecked<IImageWrapperModule>(FName("ImageWrapper")); 122 TSharedPtr<IImageWrapper> ImageWrapper = ImageWrapperModule.CreateImageWrapper(EImageFormat::JPEG); 123 ImageWrapper->SetRaw(outBMP.GetData(), outBMP.GetAllocatedSize(), rt->GetSurfaceWidth(), rt->GetSurfaceHeight(), ERGBFormat::BGRA, 8); 124 125 const TArray64<uint8>& PNGData = ImageWrapper->GetCompressed(100); 126 bool imageSavedOk = FFileHelper::SaveArrayToFile(PNGData, *fileDestination); 127 ImageWrapper.Reset(); 128 129 130 /*FIntPoint destSize(rt->GetSurfaceWidth(), rt->GetSurfaceHeight()); 131 TArray<uint8> CompressedBitmap; 132 FImageUtils::CompressImageArray(destSize.X, destSize.Y, outBMP, CompressedBitmap); 133 bool imageSavedOk = FFileHelper::SaveArrayToFile(CompressedBitmap, *fileDestination);*/ 134 135 return imageSavedOk; 136 }