I am trying to create a 16bit heightmap png from a 32bit Rgb encoded height value png.
16 bit heightmap png. You have to zoom in to see the image changes
Update:
Thanks to traktor for the suggestion. I wanted to add some information to my question.
I don't necessarily need to use image-js. My main goal is to get a 16 bit heightmap from a 32 bit RGB. So any other browser side javscript method would be fine. I also am using browser side createWritable(); stream to write file to disk.
I have a method used from this nice module https://github.com/colkassad/terrain-rgb-height however I cannot get the browser side version of pngjs to work correctly. I think there is a difference between browser side stream reader/writers and node reader/writers that make it not work.
Thanks!
CodePudding user response:
Looking through the source code for Image-js
package on GitHub turns up that the options
object used in calls to the library is verified in source file kind.js
which enumerates supported options properties in the assignment statement:
const { components, alpha, bitDepth, colorModel } = definition;
However, many options are defaulted using kind
option property, which itself defaults to "RGBA".
Knowing more about option properties allows using them (I couldn't find options documentation outside of the code).
I would suggest
Create an Image-js image from the 32bit encoded height png. Omit a
kind
property to use the default 32bit PNG pixel model of 3 color channels plus one alpha channel.Convert the image data (held as a typed array in the image object's
data
property) to a single dimensional array of height values using the MapBox conversion algorithm. The layout of the (image.data
) typed array appears to be the same as that used for ImageDataCreate a new image-js image using
new Image(width, height, decodedHeightArray, {kind="GREY", bitDepth:16})
where
decodedHeightArray
is the array prepared in the previous step.
Just adding my code to what tracktor's answer provided Thank you very much traktor
This worked perfectly. For anyone who wants the code
I am using image-js to encode and decode the image
let file_handleSixteen = await dir_handle.getFileHandle(sixteen_file_name, {create: true})
let writableSixteen = await file_handleSixteen.createWritable();
async function convert16(arrayBuff) {
let image = await Image.load(arrayBuff);
let width = image.width
let height = image.height
let decodedHeightArray = []
let pixelsArray = image.getPixelsArray()
for (const pixel of pixelsArray) {
let r = pixel[0]
let g = pixel[1]
let b = pixel[2]
let height = getHeightFromRgb(r, g, b);
decodedHeightArray.push(height)
}
let newImage = new Image(width, height, decodedHeightArray, {kind: "GREY", bitDepth: 16})
return newImage.toBlob()
}
function getHeightFromRgb(r, g, b) {
return -10000 ((r * 256 * 256 g * 256 b) * 0.1);
}
const file = await file_handleRgb.getFile();
let imageBuffer = await file.arrayBuffer()
let convertedArray = await convert16(imageBuffer)
await writableSixteen.write(convertedArray)
await writableSixteen.close();
I am also using the browser streams api to write the file to disk. Note the filestreams writable.write only accepts certain values one of them being a Blob that is why converted it to Blob before passing it to the write method