@babylonjs/core
Version:
Getting started? Play directly with the Babylon.js API using our [playground](https://playground.babylonjs.com/). It also contains a lot of samples to learn how to use it.
147 lines • 6.17 kB
JavaScript
import { ApplyLut, HufUncompress, ReverseLutFromBitmap, Wav2Decode } from "./exrLoader.compression.huf.js";
import { DecodeRunLength } from "./exrLoader.compression.rle.js";
import { InterleaveScalar, ParseUint16, ParseUint32, ParseUint8, Predictor } from "./exrLoader.core.js";
import { BITMAP_SIZE, INT16_SIZE, USHORT_RANGE } from "./exrLoader.interfaces.js";
/**
* No compression
* @param decoder defines the decoder to use
* @returns a decompressed data view
*/
export function UncompressRAW(decoder) {
return new DataView(decoder.array.buffer, decoder.offset.value, decoder.size);
}
/**
* RLE compression
* @param decoder defines the decoder to use
* @returns a decompressed data view
*/
export function UncompressRLE(decoder) {
const compressed = decoder.viewer.buffer.slice(decoder.offset.value, decoder.offset.value + decoder.size);
const rawBuffer = new Uint8Array(DecodeRunLength(compressed));
const tmpBuffer = new Uint8Array(rawBuffer.length);
Predictor(rawBuffer);
InterleaveScalar(rawBuffer, tmpBuffer);
return new DataView(tmpBuffer.buffer);
}
/**
* Zip compression
* @param decoder defines the decoder to use
* @returns a decompressed data view
*/
export function UncompressZIP(decoder) {
const compressed = decoder.array.slice(decoder.offset.value, decoder.offset.value + decoder.size);
const rawBuffer = fflate.unzlibSync(compressed);
const tmpBuffer = new Uint8Array(rawBuffer.length);
Predictor(rawBuffer);
InterleaveScalar(rawBuffer, tmpBuffer);
return new DataView(tmpBuffer.buffer);
}
/**
* PXR compression
* @param decoder defines the decoder to use
* @returns a decompressed data view
*/
export function UncompressPXR(decoder) {
const compressed = decoder.array.slice(decoder.offset.value, decoder.offset.value + decoder.size);
const rawBuffer = fflate.unzlibSync(compressed);
const sz = decoder.lines * decoder.channels * decoder.width;
const tmpBuffer = decoder.type == 1 ? new Uint16Array(sz) : new Uint32Array(sz);
let tmpBufferEnd = 0;
let writePtr = 0;
const ptr = new Array(4);
for (let y = 0; y < decoder.lines; y++) {
for (let c = 0; c < decoder.channels; c++) {
let pixel = 0;
switch (decoder.type) {
case 1:
ptr[0] = tmpBufferEnd;
ptr[1] = ptr[0] + decoder.width;
tmpBufferEnd = ptr[1] + decoder.width;
for (let j = 0; j < decoder.width; ++j) {
const diff = (rawBuffer[ptr[0]++] << 8) | rawBuffer[ptr[1]++];
pixel += diff;
tmpBuffer[writePtr] = pixel;
writePtr++;
}
break;
case 2:
ptr[0] = tmpBufferEnd;
ptr[1] = ptr[0] + decoder.width;
ptr[2] = ptr[1] + decoder.width;
tmpBufferEnd = ptr[2] + decoder.width;
for (let j = 0; j < decoder.width; ++j) {
const diff = (rawBuffer[ptr[0]++] << 24) | (rawBuffer[ptr[1]++] << 16) | (rawBuffer[ptr[2]++] << 8);
pixel += diff;
tmpBuffer[writePtr] = pixel;
writePtr++;
}
break;
}
}
}
return new DataView(tmpBuffer.buffer);
}
/**
* PIZ compression
* @param decoder defines the decoder to use
* @returns a decompressed data view
*/
export function UncompressPIZ(decoder) {
const inDataView = decoder.viewer;
const inOffset = { value: decoder.offset.value };
const outBuffer = new Uint16Array(decoder.width * decoder.scanlineBlockSize * (decoder.channels * decoder.type));
const bitmap = new Uint8Array(BITMAP_SIZE);
// Setup channel info
let outBufferEnd = 0;
const pizChannelData = new Array(decoder.channels);
for (let i = 0; i < decoder.channels; i++) {
pizChannelData[i] = {};
pizChannelData[i]["start"] = outBufferEnd;
pizChannelData[i]["end"] = pizChannelData[i]["start"];
pizChannelData[i]["nx"] = decoder.width;
pizChannelData[i]["ny"] = decoder.lines;
pizChannelData[i]["size"] = decoder.type;
outBufferEnd += pizChannelData[i].nx * pizChannelData[i].ny * pizChannelData[i].size;
}
// Read range compression data
const minNonZero = ParseUint16(inDataView, inOffset);
const maxNonZero = ParseUint16(inDataView, inOffset);
if (maxNonZero >= BITMAP_SIZE) {
throw new Error("Wrong PIZ_COMPRESSION BITMAP_SIZE");
}
if (minNonZero <= maxNonZero) {
for (let i = 0; i < maxNonZero - minNonZero + 1; i++) {
bitmap[i + minNonZero] = ParseUint8(inDataView, inOffset);
}
}
// Reverse LUT
const lut = new Uint16Array(USHORT_RANGE);
const maxValue = ReverseLutFromBitmap(bitmap, lut);
const length = ParseUint32(inDataView, inOffset);
// Huffman decoding
HufUncompress(decoder.array, inDataView, inOffset, length, outBuffer, outBufferEnd);
// Wavelet decoding
for (let i = 0; i < decoder.channels; ++i) {
const cd = pizChannelData[i];
for (let j = 0; j < pizChannelData[i].size; ++j) {
Wav2Decode(outBuffer, cd.start + j, cd.nx, cd.size, cd.ny, cd.nx * cd.size, maxValue);
}
}
// Expand the pixel data to their original range
ApplyLut(lut, outBuffer, outBufferEnd);
// Rearrange the pixel data into the format expected by the caller.
let tmpOffset = 0;
const tmpBuffer = new Uint8Array(outBuffer.buffer.byteLength);
for (let y = 0; y < decoder.lines; y++) {
for (let c = 0; c < decoder.channels; c++) {
const cd = pizChannelData[c];
const n = cd.nx * cd.size;
const cp = new Uint8Array(outBuffer.buffer, cd.end * INT16_SIZE, n * INT16_SIZE);
tmpBuffer.set(cp, tmpOffset);
tmpOffset += n * INT16_SIZE;
cd.end += n;
}
}
return new DataView(tmpBuffer.buffer);
}
//# sourceMappingURL=exrLoader.compression.js.map