UNPKG

@kitware/vtk.js

Version:

Visualization Toolkit for the Web

162 lines (129 loc) 6.42 kB
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 };