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