user3576026
user3576026

Reputation:

Convert Float32Array to Buffer

I am trying to return a binary array of floating points. I get a Float32Array from a geotiff library, however the http can only return a string or buffer so I have to 'convert' it to a buffer.

const tiff  = await geotiff.fromUrl(ahnUrl);
const image = await tiff.getImage();
const data  = await image.readRasters(); <-- Is Float32Array
res.writeHead(200, {'Content-Type': 'application/octet-stream'});
var buf = Buffer.allocUnsafe( data.width * data.height );
for ( var y = 0; y < data.height; y++ )
{
  for ( var x = 0; x < data.width; x++ )
  {
    buf.writeFloatLE(data[y*data.width+x]);
  }
}
// buf = Buffer.from(data); <-- does not work
// buf = Buffer.from(data.buffer); neither
res.end(buf);

The problem is the double for loop, I do not want this. Ideally, there is no additional data copy and definitely not this very slow double for loop. Speed is pretty critical.

I am new to javascript/nodejs, but it appears that the Float32Array is multidimensional as its length returns 1, but its width and height are 1024x1024 (as expected).

The result of 'const buf = Buffer.from(data)' is a buffer with a single byte length.

Upvotes: 1

Views: 2259

Answers (2)

Bart Knuiman
Bart Knuiman

Reputation: 11

A thanks, this does help. However, doing Buffer.from( Float32Array ) results in a 1byte per float buffer plus it copies the data. To get it working you also have to use this package:

let toBuffer = require("typedarray-to-buffer")
function()
{
  const data  = await image.readRasters({interleave:true});
  const buf   = toBuffer(data); <-- Now if contains 1 float, this is 4 bytes long.
}

Upvotes: 1

benbotto
benbotto

Reputation: 2439

I think you've misunderstood the return type of readRasters. As far as I can tell from the docs, it's not by default a Float32Array, but an array of arrays (one for each channel, e.g. R, G, and B).

By default, the raster is split to a separate array for each component. For an RGB image for example, we'd get three arrays, one for red, green and blue.

Try passing {interleave: true} to readRasters.

If we want instead all the bands interleaved in one big array, we have to pass the interleave: true option:

After that Buffer.from aught to do the trick.

Upvotes: 0

Related Questions