Source: parsers/parsers.nrrd.js

/** * Imports ***/
import ParsersVolume from './parsers.volume';
import { Vector3 } from 'three/src/math/Vector3';

let pako = require('pako');
let NrrdReader = require('nrrd-js');
/**
 * @module parsers/nifti
 */
export default class ParsersNifti extends ParsersVolume {
  /**
   * Constructor
   *
   * @param {*} data
   * @param {*} id
   */
  constructor(data, id) {
    super();

    /**
     * @member
     * @type {arraybuffer}
     */
    this._id = id;
    this._arrayBuffer = data.buffer;
    this._url = data.url;
    this._dataSet = null;
    this._unpackedData = null;

    try {
      this._dataSet = NrrdReader.parse(this._arrayBuffer);
    } catch (error) {
      window.console.log('ooops... :(');
    }
  }

  /**
   * Is the data right-handed
   *
   * @return {*}
   */
  rightHanded() {
    if (
      this._dataSet.space.match(/^right-anterior-superior/) ||
      this._dataSet.space.match(/^left-posterior-superior/)
    ) {
      this._rightHanded = true;
    } else {
      this._rightHanded = false;
    }

    return this._rightHanded;
  }

  /**
   * Series instance UID
   *
   * @return {*}
   */
  seriesInstanceUID() {
    // use filename + timestamp..?
    return this._url;
  }

  /**
   * Number of frames
   *
   * @return {*}
   */
  numberOfFrames() {
    return this._dataSet.sizes[2];
  }

  /**
   * Number of channels
   *
   * @return {*}
   */
  numberOfChannels() {
    return 1;
  }

  /**
   * SOP instance UID
   *
   * @param {*} frameIndex
   *
   * @return {*}
   */
  sopInstanceUID(frameIndex = 0) {
    return frameIndex;
  }

  /**
   * Rows
   *
   * @param {*} frameIndex
   *
   * @return {*}
   */
  rows(frameIndex = 0) {
    return this._dataSet.sizes[1];
  }

  /**
   * Columns
   *
   * @param {*} frameIndex
   *
   * @return {*}
   */
  columns(frameIndex = 0) {
    return this._dataSet.sizes[0];
  }

  /**
   * Pixel type
   *
   * @param {*} frameIndex
   *
   * @return {*}
   */
  pixelType(frameIndex = 0) {
    // 0 - int
    // 1 - float
    let pixelType = 0;
    if (this._dataSet.type === 'float') {
      pixelType = 1;
    }
    return pixelType;
  }

  /**
   * Bits allocated
   *
   * @param {*} frameIndex
   *
   * @return {*}
   */
  bitsAllocated(frameIndex = 0) {
    let bitsAllocated = 1;

    if (
      this._dataSet.type === 'int8' ||
      this._dataSet.type === 'uint8' ||
      this._dataSet.type === 'char'
    ) {
      bitsAllocated = 8;
    } else if (
      this._dataSet.type === 'int16' ||
      this._dataSet.type === 'uint16' ||
      this._dataSet.type === 'short'
    ) {
      bitsAllocated = 16;
    } else if (
      this._dataSet.type === 'int32' ||
      this._dataSet.type === 'uint32' ||
      this._dataSet.type === 'float'
    ) {
      bitsAllocated = 32;
    }

    return bitsAllocated;
  }

  /**
   * Pixel spacing
   *
   * @param {*} frameIndex
   *
   * @return {*}
   */
  pixelSpacing(frameIndex = 0) {
    const x = new Vector3(
      this._dataSet.spaceDirections[0][0],
      this._dataSet.spaceDirections[0][1],
      this._dataSet.spaceDirections[0][2]
    );

    const y = new Vector3(
      this._dataSet.spaceDirections[1][0],
      this._dataSet.spaceDirections[1][1],
      this._dataSet.spaceDirections[1][2]
    );

    const z = new Vector3(
      this._dataSet.spaceDirections[2][0],
      this._dataSet.spaceDirections[2][1],
      this._dataSet.spaceDirections[2][2]
    );

    return [x.length(), y.length(), z.length()];
  }

  /**
   * Image orientation
   *
   * @param {*} frameIndex
   *
   * @return {*}
   */
  imageOrientation(frameIndex = 0) {
    let invertX = this._dataSet.space.match(/right/) ? -1 : 1;
    let invertY = this._dataSet.space.match(/anterior/) ? -1 : 1;

    let x = new Vector3(
      this._dataSet.spaceDirections[0][0] * invertX,
      this._dataSet.spaceDirections[0][1] * invertY,
      this._dataSet.spaceDirections[0][2]
    );
    x.normalize();

    let y = new Vector3(
      this._dataSet.spaceDirections[1][0] * invertX,
      this._dataSet.spaceDirections[1][1] * invertY,
      this._dataSet.spaceDirections[1][2]
    );
    y.normalize();

    return [x.x, x.y, x.z, y.x, y.y, y.z];
  }

  /**
   * Image position
   *
   * @param {*} frameIndex
   *
   * @return {*}
   */
  imagePosition(frameIndex = 0) {
    return [
      this._dataSet.spaceOrigin[0],
      this._dataSet.spaceOrigin[1],
      this._dataSet.spaceOrigin[2],
    ];
  }

  /**
   * Extract pixel data ffrom array buffer
   *
   * @param {*} frameIndex
   *
   * @return {*}
   */
  extractPixelData(frameIndex = 0) {
    return this._decompressUncompressed(frameIndex);
  }

  /**
   * Decompress data from uncompressed array buffer
   *
   * @param {*} frameIndex
   *
   * @return {*}
   */
  _decompressUncompressed(frameIndex = 0) {
    let buffer = this._dataSet.buffer;
    const numberOfChannels = this.numberOfChannels();
    const numPixels = this.rows(frameIndex) * this.columns(frameIndex) * numberOfChannels;
    if (!this.rightHanded()) {
      frameIndex = this.numberOfFrames() - 1 - frameIndex;
    }
    let frameOffset = frameIndex * numPixels;

    // unpack data if needed
    if (this._unpackedData === null && this._dataSet.encoding === 'gzip') {
      let unpackedData = pako.inflate(this._dataSet.buffer);
      this._unpackedData = unpackedData.buffer;
      buffer = this._unpackedData;
    } else if (this._dataSet.encoding === 'gzip') {
      buffer = this._unpackedData;
    }

    if (this._dataSet.type === 'int8' || this._dataSet.type === 'char') {
      return new Int8Array(buffer, frameOffset, numPixels);
    } else if (this._dataSet.type === 'uint8') {
      return new Uint8Array(buffer, frameOffset, numPixels);
    } else if (this._dataSet.type === 'int16' || this._dataSet.type === 'short') {
      frameOffset = frameOffset * 2;
      return new Int16Array(buffer, frameOffset, numPixels);
    } else if (this._dataSet.type === 'uint16') {
      frameOffset = frameOffset * 2;
      return new Uint16Array(buffer, frameOffset, numPixels);
    } else if (this._dataSet.type === 'int32') {
      frameOffset = frameOffset * 4;
      return new Int32Array(buffer, frameOffset, numPixels);
    } else if (this._dataSet.type === 'uint32') {
      frameOffset = frameOffset * 4;
      return new Uint32Array(buffer, frameOffset, numPixels);
    } else if (this._dataSet.type === 'float') {
      frameOffset = frameOffset * 4;
      return new Float32Array(buffer, frameOffset, numPixels);
    }
  }
}