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

Write raw values bigger than 255 (Uint8), or: how to write Uint32, Float32 etc?

Open daumann opened this issue 2 years ago • 7 comments

Here is a snippet of the code I am testing with:

        const values = [1, 2, 3, 4, 5, 6, 7, 8, 4020];

	const metadata = {
		ImageLength: 3,
		ImageWidth: 3,
	};

	const arrayBuffer = await GeoTIFF.writeArrayBuffer( new Uint32Array(values), metadata);

	var blob = new Blob([arrayBuffer], {type: "image/tiff"});
	var link = document.createElement('a');
	link.href = window.URL.createObjectURL(blob);
	link.download = "test.tiff";

Unfortunately this won't work because when inspecting the resulting tiff with gdalinfo -stats test.tiff -mm The values have been corrupted:

Band 1 Block=3x3 Type=Byte, ColorInterp=Gray Min=1.000 Max=180.000 Computed Min/Max=1.000,180.000 Minimum=1.000, Maximum=180.000, Mean=24.000, StdDev=55.197

while the Minimum is correct, the Maximum is off (because it exceeds the Uint8 limit).

I tried to change my code by adding

SamplesPerPixel: 1, 
BitsPerSample: [32],

to the metadata but this gives me the following issue when inspecting the result:

Band 1 Block=3x3 Type=UInt32, ColorInterp=Gray ERROR 1: TIFFReadEncodedStrip:Read error at scanline 4294967295; got 9 bytes, expected 36 ERROR 1: TIFFReadEncodedStrip() failed. ERROR 1: r2.tiff, band 1: IReadBlock failed at X offset 0, Y offset 0: TIFFReadEncodedStrip() failed.

Notice that the Type has now changed from Byte to UInt32, but the data does not seem to have been encoded correctly.

Any pointers are very welcome!

daumann avatar Jun 01 '23 21:06 daumann

Hello, thank you for posting this important issue. It helps gauge community interest in different features. Unfortunately, it's a current limitation of the writer that it can only write Uint8 values. However, updating the code to support other data types is very achievable. Please let me know if you have the time to write a PR and I can provide some more background. Hope you have a nice rest of your day.

DanielJDufour avatar Jun 02 '23 00:06 DanielJDufour

Thanks Daniel for the quick response! Yes I can look into adding that feature. If you could give me some starting points, that would be great!

daumann avatar Jun 02 '23 04:06 daumann

Hey, great to hear. Here's a few links to the relevant parts:

The main file that does the writing: https://github.com/geotiffjs/geotiff.js/blob/master/src/geotiffwriter.js. I tried to put all the writing functionality in one file to keep things modular (and separate from the reading functionality). It does however use globals.js and utils.js.

This line is currently assuming uint8 data type, but will need to be dynamic depending on nbit value I assume: https://github.com/geotiffjs/geotiff.js/blob/master/src/geotiffwriter.js#L255. I think the other lines in encodeImage will have be refactored as well.

Hopefully this helps a little, but it already seems like you have a good sense of it.

Happy to answer any more questions or help with code review later on.

Best of luck!

DanielJDufour avatar Jun 05 '23 03:06 DanielJDufour

Hi, @daumann . I'm sorry. I totally forgot about this old PR until I came across it today: https://github.com/geotiffjs/geotiff.js/pull/106. I think you could definitely build off of it or consult the comments. Let me know if you have any more questions.

DanielJDufour avatar Jun 06 '23 17:06 DanielJDufour

@DanielJDufour Here is the PR that adds support for writing uint8, uint16, uint32 and float32: https://github.com/geotiffjs/geotiff.js/pull/366

I also added tests for each new data type (which all pass)

daumann avatar Jun 13 '23 10:06 daumann

That's awesome! I'll try to review it as soon as I can. Thank you!

DanielJDufour avatar Jun 13 '23 10:06 DanielJDufour

@DanielJDufour Quick reminder, so this PR isn't forgotten...

daumann avatar Jul 07 '23 09:07 daumann