All files / dicomImageLoader/src/imageLoader/colorSpaceConverters convertPALETTECOLOR.ts

59.61% Statements 31/52
37.03% Branches 10/27
80% Functions 4/5
59.18% Lines 29/49

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110        24x 24x   24x 6144x     24x       24x 24x 24x                                                       8x 8x   8x         8x           8x 8x 8x   8x   8x   8x 8x 8x   8x                                         8x 2048000x   2048000x   2048000x     2048000x     2048000x 2048000x 2048000x        
import type { ByteArray } from 'dicom-parser';
import { metaData, type Types } from '@cornerstonejs/core';
 
function convertLUTto8Bit(lut: number[], shift: number) {
  const numEntries = lut.length;
  const cleanedLUT = new Uint8ClampedArray(numEntries);
 
  for (let i = 0; i < numEntries; ++i) {
    cleanedLUT[i] = lut[i] >> shift;
  }
 
  return cleanedLUT;
}
 
function fetchPaletteData(imageFrame, color, fallback) {
  const data = imageFrame[`${color}PaletteColorLookupTableData`];
  Eif (data) {
    return Promise.resolve(data);
  }
 
  const result = metaData.get('imagePixelModule', imageFrame.imageId);
 
  if (result && typeof result.then === 'function') {
    return result.then((module) =>
      module ? module[`${color}PaletteColorLookupTableData`] : fallback
    );
  } else {
    return Promise.resolve(
      result ? result[`${color}PaletteColorLookupTableData`] : fallback
    );
  }
}
 
/**
 * Convert pixel data with PALETTE COLOR Photometric Interpretation to RGBA
 *
 * @param imageFrame - The ImageFrame to convert
 * @param colorBuffer - The buffer to write the converted pixel data to
 * @returns
 */
export default function (
  imageFrame: Types.IImageFrame,
  colorBuffer: ByteArray,
  useRGBA: boolean
): void {
  const numPixels = imageFrame.columns * imageFrame.rows;
  const pixelData = imageFrame.pixelData;
 
  Promise.all([
    fetchPaletteData(imageFrame, 'red', null),
    fetchPaletteData(imageFrame, 'green', null),
    fetchPaletteData(imageFrame, 'blue', null),
  ]).then(([rData, gData, bData]) => {
    Iif (!rData || !gData || !bData) {
      throw new Error(
        'The image does not have a complete color palette. R, G, and B palette data are required.'
      );
    }
 
    const len = rData.length;
    let palIndex = 0;
    let bufferIndex = 0;
 
    const start = imageFrame.redPaletteColorLookupTableDescriptor[1];
    const shift =
      imageFrame.redPaletteColorLookupTableDescriptor[2] === 8 ? 0 : 8;
 
    const rDataCleaned = convertLUTto8Bit(rData, shift);
    const gDataCleaned = convertLUTto8Bit(gData, shift);
    const bDataCleaned = convertLUTto8Bit(bData, shift);
 
    Iif (useRGBA) {
      for (let i = 0; i < numPixels; ++i) {
        let value = pixelData[palIndex++];
 
        if (value < start) {
          value = 0;
        } else if (value > start + len - 1) {
          value = len - 1;
        } else {
          value -= start;
        }
 
        colorBuffer[bufferIndex++] = rDataCleaned[value];
        colorBuffer[bufferIndex++] = gDataCleaned[value];
        colorBuffer[bufferIndex++] = bDataCleaned[value];
        colorBuffer[bufferIndex++] = 255;
      }
 
      return;
    }
 
    for (let i = 0; i < numPixels; ++i) {
      let value = pixelData[palIndex++];
 
      Iif (value < start) {
        value = 0;
      } else Iif (value > start + len - 1) {
        value = len - 1;
      } else {
        value -= start;
      }
 
      colorBuffer[bufferIndex++] = rDataCleaned[value];
      colorBuffer[bufferIndex++] = gDataCleaned[value];
      colorBuffer[bufferIndex++] = bDataCleaned[value];
    }
  });
}