# [ACCEPTED]-Looking to access 16-bit image data in Javascript/WebGL-webgl

Accepted answer
Score: 10

In case of combining two PNG images, one 28 with the top 8 bits and the second with 27 the low 8 bits, I think it should be:

``````highp vec4 texCol = texture2D(tex_low, vec2(vTexCoord.s, vTexCoord.t)) * (1.0 / 257.0);
texCol += texture2D(tex_up, vec2(vTexCoord.s, vTexCoord.t)) * (256.0 / 257.0);
``````

In 26 8 bits per channel RGB colors will range 25 from 0 to 255 = 2^8 - 1.
In 16 bits per 24 channel RGB colors will range from 0 to 23 65535 = 2^16 - 1 = 255*257.

## Explanation

WebGL works using 22 colour values from 0 to 1 and makes it by 21 dividing 8 bit color value by 255. So the 20 divided value belongs to the range <0,1>.
In 19 case of 16 bit per channel we would like 18 to divide it by 65535 to get the proper 17 number from range <0,1>.

What we want 16 is 16 bit color value reduced to range <0,1>.
Let 15 `low` and `up` be color value from range 0..255. `up` is 14 top 8 bits and `low` is low 8 bits.
To get 16 13 bit value we can compute: `low + up*256`. Now we have 12 number in range 0..65535. To get value from 11 range <0,1> we divide it by 65535. Note 10 that WebGL works using color values from 9 range <0,1> , it is `Lw=low/255` and `Uw=up/255`. So, we 8 don't have to multiply it by 255 and divide 7 it by 65535 because 65535 = 255*257. Instead 6 we just divide by 257.

Also I could not find 5 any software to split 16 bit / channel image 4 into two 8 bit/channel image, so here is 3 my code, feel free to use it, it splits 2 16 bit / channel Tiff into two 8 bit/channel 1 PNGs:

https://github.com/czero69/ImageSplitter

Score: 5

PNGToy is a pretty featured library for extracting 6 PNG chunks of almost all depths and channel 5 modes with javascript (really client-side 4 / without node.js, just Promise.js dependencies). The 3 decode method will return the desired buffer. Here 2 is an example for 16 bits grayscale PNG 1 (16 bits RGB should work as well) :

``````var dataObj;
var img = new PngImage();
var buffer;

img.onload = function() {

var pngtoy = this.pngtoy;

dataObj = pngtoy.decode().then(function(results) {

buffer = new Uint16Array(results.bitmap);

for(var i = 0, j; i < buffer.length; i++) {

j = buffer[i];
buffer[i] = ((j & 0xff) << 8) | ((j & 0xff00) >>> 8); // needed to swap bytes for correct unsigned integer values
}

console.log(buffer);
});
};

img.onerror = function(e) {
console.log(e.message);
};

img.src = "image.png";
``````
Score: 4

I don't think the main browsers natively 16 support any 16-bit/channel image format 15 at the moment.

One way to achieve the same 14 effect would be to create two PNG images, one 13 with the top 8 bits of each colour channel 12 in the image and one with the bottom 8 bits. Then 11 bind the images as two textures and combine 10 the values in your shader, e.g.

``````highp float val = texture2d(samplerTop8bits, tex_coord) * (256.0 / 257.0);
val += texture2d(samplerBottom8bits, tex_coord) * (1.0 / 257.0);
``````

(Note: you 9 need highp precision to represent your data 8 correctly in a 16-bit range)

Another method 7 is only possible if floating point textures 6 are supported in your target browser(s). You 5 would, in the browser, combine the two PNG 4 images into a floating point texture then 3 access that normally. This may not be any 2 faster and will probably use twice the amount 1 of texture memory.

More Related questions