src_image_modalityLut.js

// doc imports
/* eslint-disable no-unused-vars */
import {RescaleSlopeAndIntercept} from './rsi';
/* eslint-enable no-unused-vars */

/**
 * Modality LUT class: compensates for any modality-specific presentation.
 * Typically consists of a rescale slope and intercept to
 * rescale the data range.
 *
 * Ref: {@link https://dicom.nema.org/medical/dicom/2022a/output/chtml/part03/sect_C.11.html}.
 */
export class ModalityLut {

  /**
   * The rescale slope.
   *
   * @type {RescaleSlopeAndIntercept}
   */
  #rsi;

  /**
   * Is the RSI an identity one.
   *
   * @type {boolean}
   */
  #isIdRsi;

  /**
   * The size of the LUT array.
   *
   * @type {number}
   */
  #length;

  /**
   * The internal LUT array.
   *
   * @type {Float32Array}
   */
  #lut;

  /**
   * @param {RescaleSlopeAndIntercept} rsi The rescale slope and intercept.
   * @param {number} bitsStored The number of bits used to store the data.
   */
  constructor(rsi, bitsStored) {
    this.#rsi = rsi;
    this.#isIdRsi = rsi.isID();

    this.#length = Math.pow(2, bitsStored);

    // create lut if not identity RSI
    if (!this.#isIdRsi) {
      this.#lut = new Float32Array(this.#length);
      for (let i = 0; i < this.#length; ++i) {
        this.#lut[i] = this.#rsi.apply(i);
      }
    }
  }

  /**
   * Get the Rescale Slope and Intercept (RSI).
   *
   * @returns {RescaleSlopeAndIntercept} The rescale slope and intercept object.
   */
  getRSI() {
    return this.#rsi;
  }

  /**
   * Get the length of the LUT array.
   *
   * @returns {number} The length of the LUT array.
   */
  getLength() {
    return this.#length;
  }

  /**
   * Get the value of the LUT at the given offset.
   *
   * @param {number} offset The input offset in [0,2^bitsStored] range
   *   or full range for ID rescale.
   * @returns {number} The float32 value of the LUT at the given offset.
   */
  getValue(offset) {
    return this.#isIdRsi ? offset : this.#lut[offset];
  }

} // class ModalityLut