s2-tools
Version:
A collection of geospatial tools primarily designed for WGS84, Web Mercator, and S2.
202 lines • 6.95 kB
JavaScript
import { EXTRA_SAMPLES_VALUES, PHOTOMETRIC_INTERPRETATIONS } from './constants';
/**
* Converts photometric interpretation to samples
* @param pi - photometric interpretation
* @param bitsPerSample - bits per sample
* @param extraSamples - extra samples
* @returns - sample output
*/
export function buildSamples(pi, bitsPerSample = [], extraSamples = 0) {
let samples;
if (pi === PHOTOMETRIC_INTERPRETATIONS.RGB) {
samples = [0, 1, 2, 3];
// support alpha if it exists
if (!(extraSamples === EXTRA_SAMPLES_VALUES.Unspecified)) {
samples = [];
for (let i = 0; i < bitsPerSample.length; i += 1) {
samples.push(i);
}
}
}
else {
switch (pi) {
case PHOTOMETRIC_INTERPRETATIONS.WhiteIsZero:
case PHOTOMETRIC_INTERPRETATIONS.BlackIsZero:
case PHOTOMETRIC_INTERPRETATIONS.Palette:
samples = [0];
break;
case PHOTOMETRIC_INTERPRETATIONS.CMYK:
samples = [0, 1, 2, 3];
break;
case PHOTOMETRIC_INTERPRETATIONS.YCbCr:
case PHOTOMETRIC_INTERPRETATIONS.CIELab:
case PHOTOMETRIC_INTERPRETATIONS.ICCLab:
samples = [0, 1, 2];
break;
default:
throw new Error('Invalid or unsupported photometric interpretation.');
}
}
return samples;
}
/**
* Convert color space raster to RGB
* TODO: ICCLAB, ITULAB
* @param pi - photometric interpretation
* @param rasterData - raster data
* @param max - maximum value if needed
* @param colorMap - color map if needed
*/
export function convertColorSpace(pi, rasterData, max, colorMap = []) {
if (pi === PHOTOMETRIC_INTERPRETATIONS.RGB) {
return;
}
else if (pi === PHOTOMETRIC_INTERPRETATIONS.WhiteIsZero) {
fromWhiteIsZero(rasterData, max);
}
else if (pi === PHOTOMETRIC_INTERPRETATIONS.BlackIsZero) {
fromBlackIsZero(rasterData, max);
}
else if (pi === PHOTOMETRIC_INTERPRETATIONS.Palette) {
fromPalette(rasterData, colorMap);
}
else if (pi === PHOTOMETRIC_INTERPRETATIONS.CMYK) {
fromCMYK(rasterData);
}
else if (pi === PHOTOMETRIC_INTERPRETATIONS.YCbCr) {
fromYCbCr(rasterData);
}
else if (pi === PHOTOMETRIC_INTERPRETATIONS.CIELab) {
fromCIELab(rasterData);
}
else {
throw new Error(`Unsupported photometric interpretation ${pi}.`);
}
}
/**
* Converts raster with white is zero and max is one to RGB
* @param raster - raster
* @param max - maximum value
*/
export function fromWhiteIsZero(raster, max) {
const { width, height, data } = raster;
const rbgdata = new Uint8Array(width * height * 3);
let value;
for (let i = 0, j = 0; i < data.length; ++i, j += 3) {
value = 256 - (data[i] / max) * 256;
rbgdata[j] = value;
rbgdata[j + 1] = value;
rbgdata[j + 2] = value;
}
raster.data = rbgdata;
}
/**
* Converts raster with black is zero and max is one to RGB
* @param raster - raster
* @param max - maximum value
*/
export function fromBlackIsZero(raster, max) {
const { width, height, data } = raster;
const rbgdata = new Uint8Array(width * height * 3);
let value;
for (let i = 0, j = 0; i < data.length; ++i, j += 3) {
value = (data[i] / max) * 256;
rbgdata[j] = value;
rbgdata[j + 1] = value;
rbgdata[j + 2] = value;
}
raster.data = rbgdata;
}
/**
* Converts raster with a color map to RGB
* @param raster - raster
* @param colorMap - color map
*/
export function fromPalette(raster, colorMap) {
const { width, height, data } = raster;
const rbgdata = new Uint8Array(width * height * 3);
const greenOffset = colorMap.length / 3;
const blueOffset = (colorMap.length / 3) * 2;
let mapIndex;
for (let i = 0, j = 0; i < data.length; ++i, j += 3) {
mapIndex = data[i];
rbgdata[j] = (colorMap[mapIndex] / 65536) * 256;
rbgdata[j + 1] = (colorMap[mapIndex + greenOffset] / 65536) * 256;
rbgdata[j + 2] = (colorMap[mapIndex + blueOffset] / 65536) * 256;
}
raster.data = rbgdata;
}
/**
* Converts CMYK to RGB
* @param raster - CMYK raster
*/
export function fromCMYK(raster) {
const { width, height, data } = raster;
const rbgdata = new Uint8Array(width * height * 3);
let c, m, y, k;
for (let i = 0, j = 0; i < data.length; i += 4, j += 3) {
c = data[i];
m = data[i + 1];
y = data[i + 2];
k = data[i + 3];
rbgdata[j] = 255 * ((255 - c) / 256) * ((255 - k) / 256);
rbgdata[j + 1] = 255 * ((255 - m) / 256) * ((255 - k) / 256);
rbgdata[j + 2] = 255 * ((255 - y) / 256) * ((255 - k) / 256);
}
raster.data = rbgdata;
}
/**
* Converts YCbCr to RGB
* @param raster - YCbCr raster
*/
export function fromYCbCr(raster) {
const { width, height, data } = raster;
const rbgdata = new Uint8ClampedArray(width * height * 3);
let y, cb, cr;
for (let i = 0, j = 0; i < data.length; i += 3, j += 3) {
y = data[i];
cb = data[i + 1];
cr = data[i + 2];
rbgdata[j] = y + 1.402 * (cr - 0x80);
rbgdata[j + 1] = y - 0.34414 * (cb - 0x80) - 0.71414 * (cr - 0x80);
rbgdata[j + 2] = y + 1.772 * (cb - 0x80);
}
raster.data = rbgdata;
}
const Xn = 0.95047;
const Yn = 1.0;
const Zn = 1.08883;
/**
* Converts CIELab to RGB
* https://github.com/antimatter15/rgb-lab/blob/master/color.js
* @param raster - CIELab raster
*/
export function fromCIELab(raster) {
const { width, height, data } = raster;
const rbgdata = new Uint8Array(width * height * 3);
let L, a_, b_;
let x, y, z;
let r, g, b;
for (let i = 0, j = 0; i < data.length; i += 3, j += 3) {
L = data[i + 0];
a_ = (data[i + 1] << 24) >> 24; // conversion from uint8 to int8
b_ = (data[i + 2] << 24) >> 24; // same
y = (L + 16) / 116;
x = a_ / 500 + y;
z = y - b_ / 200;
x = Xn * (x * x * x > 0.008856 ? x * x * x : (x - 16 / 116) / 7.787);
y = Yn * (y * y * y > 0.008856 ? y * y * y : (y - 16 / 116) / 7.787);
z = Zn * (z * z * z > 0.008856 ? z * z * z : (z - 16 / 116) / 7.787);
r = x * 3.2406 + y * -1.5372 + z * -0.4986;
g = x * -0.9689 + y * 1.8758 + z * 0.0415;
b = x * 0.0557 + y * -0.204 + z * 1.057;
r = r > 0.0031308 ? 1.055 * r ** (1 / 2.4) - 0.055 : 12.92 * r;
g = g > 0.0031308 ? 1.055 * g ** (1 / 2.4) - 0.055 : 12.92 * g;
b = b > 0.0031308 ? 1.055 * b ** (1 / 2.4) - 0.055 : 12.92 * b;
rbgdata[j] = Math.max(0, Math.min(1, r)) * 255;
rbgdata[j + 1] = Math.max(0, Math.min(1, g)) * 255;
rbgdata[j + 2] = Math.max(0, Math.min(1, b)) * 255;
}
raster.data = rbgdata;
}
//# sourceMappingURL=color.js.map