prepareImageForRender()

in src/engine/Graphics2d.js [123:487]


  prepareImageForRender(volIndexArg) {
    //TODO: center the image by click
    const objCanvas = this.m_mount.current; // Canvas HTML element reference
    if (objCanvas === null) {
      return;
    }
    // resetting canvas max sizes, by checking its wrapper's size
    const canvasWrapper = objCanvas.parentNode;
    const w = canvasWrapper.clientWidth;
    const h = canvasWrapper.clientHeight;
    if (w * h === 0) {
      return;
    }

    const ctx = objCanvas.getContext('2d');
    ctx.fillStyle = 'rgb(64, 64, 64)';
    ctx.fillRect(0, 0, w, h);

    const store = this.props;
    const volSet = store.volumeSet;
    const dicom = store.loaderDicom;
    if (dicom != null && !this.props.is16bit) {
      this.m_winRight = dicom.m_winRight;
      this.m_winLeft = dicom.m_winLeft;
    }
    // const volIndex = this.m_volumeIndex;
    const volIndex = volIndexArg !== undefined ? volIndexArg : store.volumeIndex;

    const vol = volSet.getVolume(volIndex);
    const mode2d = this.m_mode2d;
    const sliceRatio = store.sliceRatio;

    if (vol === null) return;

    if (vol.m_dataArray === null) {
      console.log('Graphics2d. Volume has no data array');
      return;
    }
    const xDim = vol.m_xDim;
    const yDim = vol.m_yDim;
    const zDim = vol.m_zDim;
    const xyDim = xDim * yDim;
    let dataSrc = vol.m_dataArray; // 1 or 4 bytes array of pixels
    if (dicom != null && this.props.is16bit) {
      dataSrc = vol.m_dataArray16; // 2 bytes array of pixels
    }
    if (dataSrc.length !== xDim * yDim * zDim * vol.m_bytesPerVoxel) {
      console.log(`Bad src data len = ${dataSrc.length}, but expect ${xDim}*${yDim}*${zDim}`);
    }

    // console.log(`Graphics2d. prepareImageForRender. mode= ${mode2d}`);

    const ONE = 1;
    const FOUR = 4;
    const OFF_3 = 3;

    let imgData = null;
    let dataDst = null;

    const roiPal256 = getPalette256();

    // determine actual render square (not w * h - viewport)
    // calculate area using physical volume dimension
    const TOO_SMALL = 1.0e-5;
    const pbox = vol.m_boxSize;
    if (pbox.x * pbox.y * pbox.z < TOO_SMALL) {
      console.log(`Bad physical dimensions for rendered volume = ${pbox.x}*${pbox.y}*${pbox.z} `);
    }
    let wScreen = 0,
      hScreen = 0;

    if (mode2d === Modes2d.TRANSVERSE) {
      // calc screen rect based on physics volume slice size (z slice)
      const xyRratio = pbox.x / pbox.y;
      wScreen = w;
      hScreen = Math.floor(w / xyRratio);
      if (hScreen > h) {
        hScreen = h;
        wScreen = Math.floor(h * xyRratio);
        if (wScreen > w) {
          console.log(`logic error! wScreen * hScreen = ${wScreen} * ${hScreen}`);
        }
      }
      hScreen = hScreen > 0 ? hScreen : 1;

      // console.log(`gra2d. render: wScreen*hScreen = ${wScreen} * ${hScreen}, but w*h=${w}*${h} `);

      this.m_toolPick.setScreenDim(wScreen, hScreen);
      this.m_toolPaint.setScreenDim(wScreen, hScreen);
      this.m_toolDistance.setScreenDim(wScreen, hScreen);
      this.m_toolAngle.setScreenDim(wScreen, hScreen);
      this.m_toolArea.setScreenDim(wScreen, hScreen);
      this.m_toolRect.setScreenDim(wScreen, hScreen);
      this.m_toolText.setScreenDim(wScreen, hScreen);
      this.m_toolEdit.setScreenDim(wScreen, hScreen);
      this.m_toolDelete.setScreenDim(wScreen, hScreen);

      // setup pixel size for 2d tools
      const xPixelSize = vol.m_boxSize.x / xDim;
      const yPixelSize = vol.m_boxSize.y / yDim;
      // console.log(`xyPixelSize = ${xPixelSize} * ${yPixelSize}`);
      this.m_toolDistance.setPixelSize(xPixelSize, yPixelSize);
      this.m_toolAngle.setPixelSize(xPixelSize, yPixelSize);
      this.m_toolArea.setPixelSize(xPixelSize, yPixelSize);
      this.m_toolRect.setPixelSize(xPixelSize, yPixelSize);
      this.m_toolText.setPixelSize(xPixelSize, yPixelSize);
      this.m_toolEdit.setPixelSize(xPixelSize, yPixelSize);
      this.m_toolDelete.setPixelSize(xPixelSize, yPixelSize);

      // create image data
      imgData = ctx.createImageData(wScreen, hScreen);
      dataDst = imgData.data;
      if (dataDst.length !== wScreen * hScreen * 4) {
        console.log(`Bad dst data len = ${dataDst.length}, but expect ${wScreen}*${hScreen}*4`);
      }

      // z slice
      let zSlice = Math.floor(zDim * sliceRatio);
      zSlice = zSlice < zDim ? zSlice : zDim - 1;
      const zOff = zSlice * xyDim;
      const xStep = xDim / wScreen;
      const yStep = yDim / hScreen;
      let j = 0;
      if (vol.m_bytesPerVoxel === ONE) {
        for (let y = 0; y < hScreen; y++) {
          const ySrc = Math.floor(y * yStep);
          const yOff = ySrc * xDim;
          for (let x = 0; x < wScreen; x++) {
            const xSrc = Math.floor(x * xStep);
            const val = dataSrc[zOff + yOff + xSrc];
            let newVal = val;
            if (dicom != null && this.props.is16bit) {
              const scale = 255 / ((this.m_winRight - this.m_winLeft) * (dicom.m_maxVal - dicom.m_minVal));
              newVal = Math.floor((val - this.m_winLeft * (dicom.m_maxVal - dicom.m_minVal)) * scale);
            }
            if (newVal < 0) newVal = 0;
            if (newVal > 255) newVal = 255;
            dataDst[j + 0] = newVal;
            dataDst[j + 1] = newVal;
            dataDst[j + 2] = newVal;
            dataDst[j + 3] = 255; // opacity
            j += 4;
          } // for (x)
        } // for (y)
      } else if (vol.m_bytesPerVoxel === FOUR) {
        for (let y = 0; y < hScreen; y++) {
          const ySrc = Math.floor(y * yStep);
          const yOff = ySrc * xDim;
          for (let x = 0; x < wScreen; x++) {
            const xSrc = Math.floor(x * xStep);
            const val = dataSrc[(zOff + yOff + xSrc) * FOUR + OFF_3];
            const val4 = val * FOUR;
            const rCol = roiPal256[val4 + 0];
            const gCol = roiPal256[val4 + 1];
            const bCol = roiPal256[val4 + 2];

            dataDst[j + 0] = bCol;
            dataDst[j + 1] = gCol;
            dataDst[j + 2] = rCol;
            dataDst[j + 3] = 255;
            j += 4;
          } // for (x)
        } // for (y)
      } // if 4 bpp
    } else if (mode2d === Modes2d.SAGGITAL) {
      // calc screen rect based on physics volume slice size (x slice)
      const yzRatio = pbox.y / pbox.z;
      wScreen = w;
      hScreen = Math.floor(w / yzRatio);
      if (hScreen > h) {
        hScreen = h;
        wScreen = Math.floor(h * yzRatio);
        if (wScreen > w) {
          console.log(`logic error! wScreen * hScreen = ${wScreen} * ${hScreen}`);
        }
      }
      hScreen = hScreen > 0 ? hScreen : 1;
      // console.log(`gra2d. render: wScreen*hScreen = ${wScreen} * ${hScreen}, but w*h=${w}*${h} `);

      this.m_toolPick.setScreenDim(wScreen, hScreen);
      this.m_toolPaint.setScreenDim(wScreen, hScreen);
      this.m_toolDistance.setScreenDim(wScreen, hScreen);
      this.m_toolAngle.setScreenDim(wScreen, hScreen);
      this.m_toolArea.setScreenDim(wScreen, hScreen);
      this.m_toolRect.setScreenDim(wScreen, hScreen);
      this.m_toolText.setScreenDim(wScreen, hScreen);
      this.m_toolEdit.setScreenDim(wScreen, hScreen);
      this.m_toolDelete.setScreenDim(wScreen, hScreen);

      // setup pixel size for 2d tools
      const xPixelSize = vol.m_boxSize.y / yDim;
      const yPixelSize = vol.m_boxSize.z / zDim;
      // console.log(`xyPixelSize = ${xPixelSize} * ${yPixelSize}`);
      this.m_toolDistance.setPixelSize(xPixelSize, yPixelSize);
      this.m_toolAngle.setPixelSize(xPixelSize, yPixelSize);
      this.m_toolArea.setPixelSize(xPixelSize, yPixelSize);
      this.m_toolRect.setPixelSize(xPixelSize, yPixelSize);
      this.m_toolText.setPixelSize(xPixelSize, yPixelSize);
      this.m_toolEdit.setPixelSize(xPixelSize, yPixelSize);
      this.m_toolDelete.setPixelSize(xPixelSize, yPixelSize);

      // create image data
      imgData = ctx.createImageData(wScreen, hScreen);
      dataDst = imgData.data;
      if (dataDst.length !== wScreen * hScreen * 4) {
        console.log(`Bad dst data len = ${dataDst.length}, but expect ${wScreen}*${hScreen}*4`);
      }

      // x slice
      let xSlice = Math.floor(xDim * sliceRatio);
      xSlice = xSlice < xDim ? xSlice : xDim - 1;

      const yStep = yDim / wScreen;
      const zStep = zDim / hScreen;
      let j = 0;
      if (vol.m_bytesPerVoxel === ONE) {
        for (let y = 0; y < hScreen; y++) {
          const zSrc = Math.floor(y * zStep);
          const zOff = zSrc * xDim * yDim;
          for (let x = 0; x < wScreen; x++) {
            const ySrc = Math.floor(x * yStep);
            const yOff = ySrc * xDim;
            const val = dataSrc[zOff + yOff + xSlice];
            let newVal = val;
            if (dicom != null) {
              const scale = 255 / ((this.m_winRight - this.m_winLeft) * (dicom.m_maxVal - dicom.m_minVal));
              newVal = Math.floor((val - this.m_winLeft * (dicom.m_maxVal - dicom.m_minVal)) * scale);
            }
            if (newVal < 0) newVal = 0;
            if (newVal > 255) newVal = 255;
            dataDst[j + 0] = newVal;
            dataDst[j + 1] = newVal;
            dataDst[j + 2] = newVal;
            dataDst[j + 3] = 255; // opacity
            j += 4;
          } // for (x)
        } // for (y)
      } else if (vol.m_bytesPerVoxel === FOUR) {
        for (let y = 0; y < hScreen; y++) {
          const zSrc = Math.floor(y * zStep);
          const zOff = zSrc * xDim * yDim;
          for (let x = 0; x < wScreen; x++) {
            const ySrc = Math.floor(x * yStep);
            const yOff = ySrc * xDim;
            const val = dataSrc[(zOff + yOff + xSlice) * FOUR + OFF_3];
            const val4 = val * FOUR;
            const rCol = roiPal256[val4 + 0];
            const gCol = roiPal256[val4 + 1];
            const bCol = roiPal256[val4 + 2];

            dataDst[j + 0] = bCol;
            dataDst[j + 1] = gCol;
            dataDst[j + 2] = rCol;
            dataDst[j + 3] = 255; // opacity

            j += 4;
          } // for (x)
        } // for (y)
      } // if 4 bppp
    } else if (mode2d === Modes2d.CORONAL) {
      // calc screen rect based on physics volume slice size (y slice)
      const xzRatio = pbox.x / pbox.z;
      wScreen = w;
      hScreen = Math.floor(w / xzRatio);
      if (hScreen > h) {
        hScreen = h;
        wScreen = Math.floor(h * xzRatio);
        if (wScreen > w) {
          console.log(`logic error! wScreen * hScreen = ${wScreen} * ${hScreen}`);
        }
      }
      hScreen = hScreen > 0 ? hScreen : 1;
      // console.log(`gra2d. render: wScreen*hScreen = ${wScreen} * ${hScreen}, but w*h=${w}*${h} `);

      this.m_toolPick.setScreenDim(wScreen, hScreen);
      this.m_toolPaint.setScreenDim(wScreen, hScreen);
      this.m_toolDistance.setScreenDim(wScreen, hScreen);
      this.m_toolAngle.setScreenDim(wScreen, hScreen);
      this.m_toolArea.setScreenDim(wScreen, hScreen);
      this.m_toolRect.setScreenDim(wScreen, hScreen);
      this.m_toolText.setScreenDim(wScreen, hScreen);
      this.m_toolEdit.setScreenDim(wScreen, hScreen);
      this.m_toolDelete.setScreenDim(wScreen, hScreen);

      // setup pixel size for 2d tools
      const xPixelSize = vol.m_boxSize.x / xDim;
      const yPixelSize = vol.m_boxSize.z / zDim;
      // console.log(`xyPixelSize = ${xPixelSize} * ${yPixelSize}`);
      this.m_toolDistance.setPixelSize(xPixelSize, yPixelSize);
      this.m_toolAngle.setPixelSize(xPixelSize, yPixelSize);
      this.m_toolArea.setPixelSize(xPixelSize, yPixelSize);
      this.m_toolRect.setPixelSize(xPixelSize, yPixelSize);
      this.m_toolText.setPixelSize(xPixelSize, yPixelSize);
      this.m_toolEdit.setPixelSize(xPixelSize, yPixelSize);
      this.m_toolDelete.setPixelSize(xPixelSize, yPixelSize);

      // create image data
      imgData = ctx.createImageData(wScreen, hScreen);
      dataDst = imgData.data;
      if (dataDst.length !== wScreen * hScreen * 4) {
        console.log(`Bad dst data len = ${dataDst.length}, but expect ${wScreen}*${hScreen}*4`);
      }

      // y slice
      let ySlice = Math.floor(yDim * sliceRatio);
      ySlice = ySlice < yDim ? ySlice : yDim - 1;
      const yOff = ySlice * xDim;

      const xStep = xDim / wScreen;
      const zStep = zDim / hScreen;
      let j = 0;
      if (vol.m_bytesPerVoxel === ONE) {
        for (let y = 0; y < hScreen; y++) {
          const zSrc = Math.floor(y * zStep);
          const zOff = zSrc * xDim * yDim;
          for (let x = 0; x < wScreen; x++) {
            const xSrc = Math.floor(x * xStep);
            const val = dataSrc[zOff + yOff + xSrc];
            let newVal = val;
            if (dicom != null) {
              const scale = 255 / ((this.m_winRight - this.m_winLeft) * (dicom.m_maxVal - dicom.m_minVal));
              newVal = Math.floor((val - this.m_winLeft * (dicom.m_maxVal - dicom.m_minVal)) * scale);
            }
            if (newVal < 0) newVal = 0;
            if (newVal > 255) newVal = 255;
            dataDst[j + 0] = newVal;
            dataDst[j + 1] = newVal;
            dataDst[j + 2] = newVal;
            dataDst[j + 3] = 255; // opacity
            j += 4;
          } // for (x)
        } // for (y)
      } else if (vol.m_bytesPerVoxel === FOUR) {
        for (let y = 0; y < hScreen; y++) {
          const zSrc = Math.floor(y * zStep);
          const zOff = zSrc * xDim * yDim;
          for (let x = 0; x < wScreen; x++) {
            const xSrc = Math.floor(x * xStep);
            const val = dataSrc[(zOff + yOff + xSrc) * FOUR + OFF_3];
            const val4 = val * FOUR;
            const rCol = roiPal256[val4 + 0];
            const gCol = roiPal256[val4 + 1];
            const bCol = roiPal256[val4 + 2];

            dataDst[j + 0] = bCol;
            dataDst[j + 1] = gCol;
            dataDst[j + 2] = rCol;
            dataDst[j + 3] = 255; // opacity

            j += 4;
          } // for (x)
        } // for (y)
      } // end if 4 bpp
    }

    // centering: setting canvas image size, to match its HTML element's size
    objCanvas.width = this.m_mount.current.clientWidth;
    objCanvas.height = this.m_mount.current.clientHeight;
    // check is segmentation 2d mode is active
    // const isSegm = store.graphics2dModeSegmentation;
    // console.log("Segm2d mode = " + isSegm);

    this.imgData = imgData;
    this.segm2d.setImageData(imgData);
  } // prepareImageForRender