Home > OS >  How do you convert a 32bit RGB png with encoded height values to 16 bit png using browser side javas
How do you convert a 32bit RGB png with encoded height values to 16 bit png using browser side javas

Time:10-01

I am trying to create a 16bit heightmap png from a 32bit Rgb encoded height value png.

According to enter image description here

16 bit heightmap png. You have to zoom in to see the image changes enter image description here

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

  1. 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.

  2. 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 ImageData

  3. Create 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


  • Related