Float to PoolByteArray

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By QuantumMartin

Hi, I try to create an image with float data in it (32bit Format.RF).

I have an array of float, I need to transform it in an array of bytes (PoolByteArray) to pass it as parameter of create_from_data() so I can create the image.

Here is what I did :

	var byte_array:PoolByteArray
for i in range(layer_count):
	var arr = []
	for j in range(neuron_max):
		if(j<weights[i].size()):
			arr.append(weights[i][j]*255)
		else:
			arr.append(0)
	byte_array.append_array(PoolByteArray(arr))

var wimg = Image.new()
wimg.create_from_data(neuron_max,layer_count,false, Image.FORMAT_RF, weights)

Error :

E 0:00:02.567   create: Expected data size of 108 bytes in Image::create(), got instead 3 bytes.

Thank you for your precious help !

:bust_in_silhouette: Reply From: AlexTheRegent

You created byte_array, but passed weights to create_from_data method. Shouldn’t it be wimg.create_from_data(neuron_max,layer_count,false, Image.FORMAT_RF, byte_array)?

:bust_in_silhouette: Reply From: DavidPgl

Not sure if you still need an answer but I had to do something similar and couldn’t find anything helpful. Ended up with this:

var imageData: PoolByteArray

# Resize to required image size (* 4 as each float has 4 bytes)
imageData.resize(image_width * image_height * 4)

# Wrap 64-bit float into Vector2 to cast it to 32-bit
var valueVector: Vector2 = Vector2(value, 0.0)

# Convert Vector2 to bytes
var bytes: PoolByteArray = var2bytes(valueVector)

# Calculate position in image (* 4 as each float has 4 bytes)
var position: int = (y * image_width + x) * 4

# Read Vector.x float bytes (byte 4 to 7)
for i in range(4):
	imageData[position + i] = bytes[i + 4]

var image: Image = Image.new()
image.create_from_data(image_width, image_height, false, Image.FORMAT_RF, imageData)

If you just append to the PoolByteArray this should work:

var valueVector: Vector2 = Vector2(value, 0.0)
var bytes: PoolByteArray = var2bytes(valueVector)
for i in range(4):
	imageData.append(bytes[i + 4])

var image: Image = Image.new()
image.create_from_data(image_width, image_height, false, Image.FORMAT_RF, imageData)

Took me a while until I noticed that Godot uses 64-bit floats but the Images only support 32-bit floats.

:bust_in_silhouette: Reply From: zaflick

There’s a useful class meant for building buffers to send over the network called StreamPeerBuffer, which can be used for this purpose.

var input = [ 0.1, 1.0, ... ]
var buffer := StreamPeerBuffer.new()
for value in input:
    data.put_float(value)  # Correctly serializes as 32-bit

var image := Image.new()
image.create_from_data(len(input), 1, false, Image.FORMAT_RF, buffer.data_array)