geotiff.js icon indicating copy to clipboard operation
geotiff.js copied to clipboard

Feature write float32array

Open m0ose opened this issue 6 years ago • 10 comments

Added support for float32Array writing. I only tested it on one float32Array but it should work on other typed arrays. Addresses This issue #103.

I tested it with this code.

async function raster_to_tiff(raster) {
  const metadata = {
    height: 32,
    width: 32
  };
  const arrayBuffer = await GeoTIFF.writeArrayBuffer(raster, metadata);
  let blob = new Blob([arrayBuffer], { type: "application/octet-stream;charset=utf-8" });
  var url = (URL.createObjectURL(blob)); // fake_download is just a trick that simulates... you get it.

  return {blob, url}
};
await raster_to_tiff(new Float32Array(32*32))

m0ose avatar Oct 01 '19 16:10 m0ose

Thanks @m0ose for the effort!

Please keep in mind, that apart from writing the array-data several metadata tags have to be set in accordance to the metadata. For example the SampleFormat tag, that tells readers how to interpret the array data.

constantinius avatar Oct 08 '19 08:10 constantinius

It now writes metadata. There may be a problem 'though. If the metadata(bitsPerSample and sampleFormat) and the typed array do not match, should it go by whats in the metadata or the typed array? Right now if they don't match I don't know what will happen. This is related to what @DanielJDufour said up here, https://github.com/geotiffjs/geotiff.js/pull/106#discussion_r332979454.

m0ose avatar Oct 10 '19 05:10 m0ose

I think this should be solved using a layered architecture.

The high level one should be as easy and uncomplicated as the readRasters and readRGB. The users should not be hassled with the sometimes ugly internals of the TIFF format and the best defaults should used unless understandable options are set. This API will need to be designed, but will not make the cut for v1.0.

The low level API should allow the setting of the various TIFF tags and raster data. Here it could be possible to set conflicting options, but users should usually not access that API directly. I consider the current write API as the lower level one, so you could pick where you get the metadata from and what to do when they are conflicting.

constantinius avatar Oct 10 '19 09:10 constantinius

Hi, @m0ose . Let me know when you want me to take another look at your PR! Thanks for your awesome work :-)

DanielJDufour avatar Oct 16 '19 03:10 DanielJDufour

Ok. I think there are just some small things. I will try to get to them soon.

Cody Smith

On Tue, Oct 15, 2019 at 9:21 PM Daniel J. Dufour [email protected] wrote:

Hi, @m0ose https://github.com/m0ose . Let me know when you want me to take another look at your PR! Thanks for your awesome work :-)

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/geotiffjs/geotiff.js/pull/106?email_source=notifications&email_token=AADADQXHV3L4BLDAKLJ6GVTQO2CCNA5CNFSM4I4MDQT2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEBK4TGI#issuecomment-542493081, or unsubscribe https://github.com/notifications/unsubscribe-auth/AADADQQOZ65YZUOJMAE4THLQO2CCNANCNFSM4I4MDQTQ .

m0ose avatar Oct 17 '19 02:10 m0ose

Hey, this might be a unique problem to me? But When I tried your code it didn't work until I enforced big-endian encoding.

So I changed the code like this (SUPER SUPER UGLY, just proof of working):

const data = new Uint8Array(numBytesInIfd + (values.length * 4 * samplesPerPixel));
  times(prfx.length, (i) => { data[i] = prfx[i]; });
  // forEach(img, (value, i) => {
  //   data[numBytesInIfd + i] = value;
  // });

  // store data
  for (let i = 0, vl = values.length; i < vl; i++) {
    const value = values[i]
    const buffer = new ArrayBuffer(4)
    const view = new DataView(buffer)
    view.setFloat32(0, value, false)
    const uint8 = new Uint8Array(view.buffer)
    const idx = numBytesInIfd + i * 4
    data[idx] = uint8[0]
    data[idx + 1] = uint8[1]
    data[idx + 2] = uint8[2]
    data[idx + 3] = uint8[3]
  }

CraigglesO avatar Jan 22 '21 02:01 CraigglesO

After trying the above code, I am getting "RangeError: Offset is outside the bounds of the DataView" while parsing the arraybuffer returned.

manivannan23k avatar Jul 15 '22 18:07 manivannan23k

Resolved by adding correct "StripByteCounts" value along with "SampleFormat" and "BitsPerSample"

manivannan23k avatar Jul 18 '22 14:07 manivannan23k

image

trying to write float32bit the file is corrupted @manivannan23k can you help me.


const len = this.width * this.height;
    const newdata = new Float32Array(len);
    for (var i = 0; i < len; i++) {
      newdata[i] = this.data[i] + this.WhatIfLayers[0]?.data[i];
    }

    const image = await this.originalTiff.getImage();
    const origin = image.getOrigin();
    const resolution = image.getResolution();

    const metadata = {
      height: this.height,
      width: this.width,
      ModelPixelScale: resolution,
      GeographicTypeGeoKey: 3857,
      GeogCitationGeoKey: 'WGS 84',
      GTModelTypeGeoKey: 2,
      ModelTiepoint: [0, 0, 0, ...origin]
    };
    const arrayBuffer = await writeArrayBuffer(newdata, metadata);
    var blob = new Blob([arrayBuffer], { type: 'image/tiff' });
    //uplaodEditedDSM(this.reportid, blob, `dsm_${this.reportid}`)
    var link = document.createElement("a");
    link.href = window.URL.createObjectURL(blob);
    var fileName = 'dsm_edited';
    link.download = fileName;
    link.click();

aboss-developer avatar Jul 25 '22 17:07 aboss-developer

This would be a fantastic addition. These tricky problems are above my ability but how can I best encourage progress? Is sponsoring the feature an option? It seems like a few people have been interested in this over time.

benboughton1 avatar Mar 21 '23 11:03 benboughton1