# Using Unity Jobs to encode file to PNG and then save it on Main Thread

I have a following code , and i can not retrive encoded Output from Job.

If I Use JOB : The result is not a valid png file. What I get is a 67,2 MB file which can not be opened with any image editor I tried. When I open it with a text editor, it seems to contain only whitespaces.

else i got normal valid png file saved on my disc .

Can we use this approach for encoding inside Unity ?

public class Loger : MonoBehaviour
{
[SerializeField]

[SerializeField]
private RenderTexture _rt;
private NativeArray<byte> _data;

public bool useJob;

private void Start()
{
CreateBuffer(ref _data, ref _rt);

}

System.Collections.IEnumerator StartEncoding(RenderTexture oRTs, bool active)
{
int i = 0;
while (active)
{
if(_request.hasError)
{
Debug.Log("Error in GPU request "); break;
}

yield return new WaitUntil(() => _request.done);

if(useJob)
{
Debug.Log("creating  Job");
EncodeJob job = new EncodeJob
{
input = new NativeArray<byte>(_data, Allocator.TempJob),
output = new NativeArray<byte>(_data.Length, Allocator.TempJob),
graphicsFormat = oRTs.graphicsFormat,
width = oRTs.width,
height = oRTs.height,
result = new NativeArray<int>(1, Allocator.TempJob)
};

Debug.Log("result from job is " + " " + job.result[0]);
var data = job.output;
Debug.Log("created PNG file ");
string pathName = "Logs/" + "FLCW" + "/" + i++ + "JOB" + ".png";
System.IO.File.WriteAllBytes(pathName, data.ToArray());
yield return new WaitUntil(() => _request.done);
}

else if(!useJob)
{
var fileData =ImageConversion.EncodeNativeArrayToPNG(_data, oRTs.graphicsFormat, (uint)oRTs.width, (uint)oRTs.height);
Debug.Log("created PNG file ");
string pathName = "Logs/" + "FLCW" + "/" + i++ + "MAIN" +".png" ;
System.IO.File.WriteAllBytes(pathName, fileData.ToArray());
yield return new WaitUntil(() => _request.done);
}

yield return new WaitUntil(() => _request.done);
}
}

void CreateBuffer(ref NativeArray<byte> buffer, ref RenderTexture oRTS)
{
buffer = new NativeArray<byte>(oRTS.height * oRTS.width * 4, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
}

private void OnApplicationQuit()
{
_data.Dispose();
}

struct EncodeJob : IJob
{
public NativeArray<byte> input;
public NativeArray<byte>  output;
public GraphicsFormat graphicsFormat;
public NativeArray<int> result;
public int width;
public int height;
public void Execute()
{
output = ImageConversion.EncodeNativeArrayToPNG(input,graphicsFormat,(uint)width,(uint)height);
result[0] = width + height;
}

}

}

• In what way exactly is the returned PNG data "invalid"? Is there any data at all? Is it a valid PNG file? If not what about it is broken specifically? And does the code for PNG encoding work when you run it regularly and not as part of a job? May 11 at 10:54
• @Philipp file i have is not PNG valid , i can not open it after saving as a png . EncodeJob i have it there on the end of the script i have attached . May 11 at 10:57
• Did you look at the file in a hex editor to confirm if it has a PNG header? May 11 at 10:57
• @Philipp no .if i open with Notpad its just blanc , empty file ....huge empty white space file . No PNG header as in other .png files i have . May 11 at 11:06
• When you open a valid PNG file in a text editor, then it should begin with the line ‰PNG followed by binary gibberish. What's the file size? Is it a 0 byte file or does it contain lots of whitespaces? May 11 at 11:53

After testing I found a few problems.

1. The png format does not save the color information of each pixel. It is a compressed image format. The length of the btyes written to the file is obviously uncompressed.

2. According to 1, you can't know the size of the png before starting the job. The size allocated for the output can only be used as the buffer size.

3. Assignment to member variables during job execution is invalid, that's why you use NativeArray to hold the resulting value. So the assignment to output is also invalid:

public void Execute()
{
output = ...
}


Fix:

1. Use NativeArray to pass out the length of the resulting array.
2. Use the length value to slice the output and save it to a file.

Code:

EncodeJob job = new EncodeJob
{
...
result = new NativeArray<int>(2, Allocator.TempJob)
};

Debug.Log("result from job is " + " " + job.result[0]);
var data = new byte[job.result[1]];
NativeArray<byte>.Copy(job.output, data, job.result[1]);
Debug.Log("created PNG file ");
string pathName = "Logs/" + "FLCW" + "/" + i++ + "JOB" + ".png";
System.IO.File.WriteAllBytes(pathName, data);


And:

public void Execute()
{
var o = ImageConversion.EncodeArrayToPNG(input.ToArray(), graphicsFormat,
(uint)width, (uint)height);
NativeArray<byte>.Copy(o, output, o.Length);
result[0] = width + height;
result[1] = o.Length;
}

• yes , thank you . its a correct answer .I was going around it but was not sure how to make it thats way i have that result of int inside our code at first place :) May 11 at 14:24
• When you've verified an answer is correct, you should click the checkmark icon in the top-left to mark the answer as Accepted. May 11 at 14:29