I am mostly just using UE4 API functions for , so I am not sure what the cause of the is.
Here is the relevant portion of the source code for node:
bool UVictoryBPFunctionLibrary::Victory_SavePixels(const FString& FullFilePath,int32 Width, int32 Height, const TArray<FLinearColor>& ImagePixels, FString& ErrorString)
{
//Create FColor version
TArray<FColor> ColorArray;
for(const FLinearColor& Each : ImagePixels)
{
ColorArray.Add(Each.ToFColor(true));
}
if(ColorArray.Num() != Width * Height)
{
ErrorString = "Error ~ height x width is not equal to the total pixel array length!";
return false;
}
TArray<uint8> CompressedPNG;
FImageUtils::CompressImageArray(
Width,
Height,
ColorArray,
CompressedPNG
);
return FFileHelper::SaveArrayToFile(CompressedPNG, *FinalFilename);
There’s not much room here for me to make mistakes of my own, its really just API calls.
But clearly something is amiss, I tested saving as a bmp and got the same unusual results as with compressed png:
I did a test with 0.25 and got 137 as well, instead of what you’d expect, 63.75 (255 * 0.25).
I tested 0.715 and got 220 instead of 182.325
The culprit appears to be the ToFColor function:
//Create FColor version
TArray<FColor> ColorArray;
for(const FLinearColor& Each : ImagePixels)
{
ColorArray.Add(Each.ToFColor(true));
UE_LOG(LogTemp,Error,TEXT("float is %f, byte added as %d"), Each.R, ColorArray.Last().R);
}
yields :
LogTemp:Error: float is 0.000000, byte added as 0
LogTemp:Error: float is 0.250000, byte added as 137
LogTemp:Error: float is 0.000000, byte added as 0
LogTemp:Error: float is 0.000000, byte added as 0
LogTemp:Error: float is 1.000000, byte added as 255
LogTemp:Error: float is 0.000000, byte added as 0
LogTemp:Error: float is 0.000000, byte added as 0
LogTemp:Error: float is 0.715000, byte added as 220
LogTemp:Error: float is 0.000000, byte added as 0
So the conversion you are not enjoying is being by FLinearColor::ToFColor
ToFColor has sRGB option:
/** Quantizes the linear color and returns the result as a FColor with optional sRGB conversion and quality as goal. */
FColor FLinearColor::ToFColor(const bool bSRGB) const
{
The sRGB conversion algorithm can be found in Color.cpp if you want to see it for yourself!
When I set that to false then the values you’d expect are returned:
LogTemp:Error: float is 0.000000, byte added as 0
LogTemp:Error: float is 0.250000, byte added as 63
LogTemp:Error: float is 0.000000, byte added as 0
LogTemp:Error: float is 0.000000, byte added as 0
LogTemp:Error: float is 1.000000, byte added as 255
LogTemp:Error: float is 0.000000, byte added as 0
LogTemp:Error: float is 0.000000, byte added as 0
LogTemp:Error: float is 0.715000, byte added as 183
LogTemp:Error: float is 0.000000, byte added as 0
You can read about sRGB here:
I’ve now made sRGB conversion optional, and off by default
The update will be in my next plugin release