@kitware/vtk.js
Version:
Visualization Toolkit for the Web
162 lines (129 loc) • 6.42 kB
JavaScript
import { create } from 'xmlbuilder2';
import { zlibSync } from 'fflate';
import macro from '../../macros.js';
import { fromArrayBuffer } from '../../Common/Core/Base64.js';
import { FormatTypes, TYPED_ARRAY } from './XMLWriter/Constants.js';
// Global methods
// ----------------------------------------------------------------------------
function compressBlock(uncompressed) {
return zlibSync(uncompressed);
}
function processDataArray(dataArray, format, blockSize) {
var compressor = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 'vtkZLibDataCompressor';
if (format === FormatTypes.ASCII) {
return dataArray.getData().join(' ');
}
if (format === FormatTypes.BINARY) {
if (compressor === 'vtkZLibDataCompressor') {
// ----------------------------------------------------------------------
// Layout of the data
// header[N, s1, s1, blockSize1, ..., blockSizeN], [padding???], block[compressedData], ..., block[compressedData]
// [header] N, s1 and s2 are uint 32 or 64 (defined by header_type="UInt64" attribute on the root node)
// [header] s1: uncompress size of each block except the last one
// [header] s2: uncompress size of the last blocks
// [header] blockSize: size of the block in compressed space that represent to bloc to inflate in zlib. (This also give the offset to the next block)
// ----------------------------------------------------------------------
var componentUint8Size = dataArray.getElementComponentSize();
var uncompressedUint8Size = dataArray.getNumberOfValues() * componentUint8Size;
var blockUint8Size = blockSize;
var nbFullBlocks = Math.trunc(uncompressedUint8Size / blockUint8Size);
var lastBlockUint8Size = uncompressedUint8Size % blockUint8Size;
var nbBlocks = nbFullBlocks + (lastBlockUint8Size ? 1 : 0);
var header = new Uint32Array(3 + nbBlocks);
header[0] = nbBlocks; // N
header[1] = blockUint8Size; // s1
header[2] = lastBlockUint8Size; // s2
var totalUint8Length = 0;
var blocks = [];
var dataOffset = 0;
var lastBlockId = nbBlocks - 1;
for (var blockId = 0; blockId < nbBlocks; ++blockId) {
var currentBlockUint8Size = lastBlockUint8Size === 0 || blockId < lastBlockId ? blockUint8Size : header[2];
var uncompressedBlock = new Uint8Array(dataArray.getData().buffer, dataOffset, currentBlockUint8Size);
dataOffset += blockUint8Size;
var compressedUint8Block = compressBlock(uncompressedBlock);
blocks.push(compressedUint8Block);
header[3 + blockId] = compressedUint8Block.length;
totalUint8Length += compressedUint8Block.length;
}
var uint8 = new Uint8Array(totalUint8Length);
var uint8Offset = 0;
var headerUint8 = new Uint8Array(header.buffer);
for (var _blockId = 0; _blockId < nbBlocks; ++_blockId) {
uint8.set(blocks[_blockId], uint8Offset);
uint8Offset += header[3 + _blockId];
}
return fromArrayBuffer(headerUint8.buffer) + fromArrayBuffer(uint8.buffer);
}
throw new Error('Only vtkZLibDataCompressor is supported');
}
if (format === FormatTypes.APPENDED) {
throw new Error('Appended format is not supported');
}
throw new Error('Format is not supported');
} // ----------------------------------------------------------------------------
// vtkXMLWriter methods
// ----------------------------------------------------------------------------
function vtkXMLWriter(publicAPI, model) {
// Set our className
model.classHierarchy.push('vtkXMLWriter'); // Can be overridden in subclass
publicAPI.create = function (dataObject) {
return create().ele('VTKFile').att('type', model.dataType).att('version', '0.1').att('byte_order', 'LittleEndian').att('header_type', 'UInt32').att('compressor', model.format === FormatTypes.ASCII ? '' : 'vtkZLibDataCompressor');
};
publicAPI.write = function (object) {
return publicAPI.create(object).end({
pretty: true
});
};
publicAPI.processDataSetAttributes = function (parentElement, name, datasetAttributes) {
var activeAttributes = {};
var attrTypes = ['Scalars', 'Vectors', 'Normals', 'TCoords', 'Tensors', 'GlobalIds', 'PedigreeIds'];
attrTypes.forEach(function (attrType) {
var activeAttribute = datasetAttributes.getActiveAttribute(attrType);
if (activeAttribute) {
activeAttributes[attrType] = activeAttribute.getName();
}
});
var datasetAttributesEle = parentElement.ele(name, activeAttributes);
for (var i = 0; i < datasetAttributes.getNumberOfArrays(); ++i) {
publicAPI.processDataArray(datasetAttributesEle, datasetAttributes.getArrayByIndex(i));
}
return datasetAttributesEle;
};
publicAPI.processDataArray = function (parentEle, scalars) {
return parentEle.ele('DataArray', {
type: TYPED_ARRAY[scalars.getDataType()],
Name: scalars.getName(),
format: publicAPI.getFormat(),
RangeMin: scalars.getRange()[0],
RangeMax: scalars.getRange()[1],
NumberOfComponents: scalars.getNumberOfComponents()
}).txt(processDataArray(scalars, publicAPI.getFormat(), publicAPI.getBlockSize()));
};
publicAPI.requestData = function (inData, outData) {
model.file = publicAPI.write(inData);
};
} // ----------------------------------------------------------------------------
// Object factory
// ----------------------------------------------------------------------------
var DEFAULT_VALUES = {
blockSize: 1024,
// file: null,
format: FormatTypes.BINARY
}; // ----------------------------------------------------------------------------
function extend(publicAPI, model) {
var initialValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
Object.assign(model, DEFAULT_VALUES, initialValues); // Build VTK API
macro.obj(publicAPI, model);
macro.setGet(publicAPI, model, ['blockSize', 'format']);
macro.get(publicAPI, model, ['file']);
macro.algo(publicAPI, model, 1, 0); // vtkXMLWriter methods
vtkXMLWriter(publicAPI, model);
} // ----------------------------------------------------------------------------
var vtkXMLWriter$1 = {
extend: extend,
compressBlock: compressBlock,
processDataArray: processDataArray,
FormatTypes: FormatTypes
};
export { vtkXMLWriter$1 as default, extend };