Skip to content

Instantly share code, notes, and snippets.

@dannyrb
Forked from jdnarvaez/GraphicOverlays.js
Created January 30, 2019 17:41
Show Gist options
  • Save dannyrb/ed33fbc3e5238eee1160872da2fd6eaa to your computer and use it in GitHub Desktop.
Save dannyrb/ed33fbc3e5238eee1160872da2fd6eaa to your computer and use it in GitHub Desktop.
DICOM Overlays
const overlayGroupTags = [];
for (var i = 0; i <= (0x00ee0000); i += (0x00020000)) {
overlayGroupTags.push((0x60000000 + i));
}
imageRendered(e) {
const eventData = e.detail;
if (eventData && eventData.image && eventData.image.$presentationStateDataSet) {
const context = eventData.canvasContext.canvas.getContext('2d');
context.save();
const imageWidth = Math.abs(eventData.viewport.displayedArea.brhc.x - eventData.viewport.displayedArea.tlhc.x) * eventData.viewport.displayedArea.columnPixelSpacing;
const imageHeight = Math.abs(eventData.viewport.displayedArea.brhc.y - eventData.viewport.displayedArea.tlhc.y) * eventData.viewport.displayedArea.rowPixelSpacing;
const presentationState = eventData.image.$presentationStateDataSet;
if (!presentationState) {
return;
}
_.each(overlayGroupTags, function(overlayGroupNumber) {
const activationLayer = Overlays.getOverlayActivationLayer(presentationState, overlayGroupNumber) || Overlays.getOverlayActivationLayer(eventData.image.dataSet, overlayGroupNumber);
if (!activationLayer) {
return;
}
const overlay = Overlays.extractOverlay(presentationState, overlayGroupNumber) || Overlays.extractOverlay(eventData.image.dataSet, overlayGroupNumber, eventData.image);
if (overlay) {
const layerCanvas = document.createElement('canvas');
layerCanvas.width = imageWidth;
layerCanvas.height = imageHeight;
const layerContext = layerCanvas.getContext('2d');
const transform = cornerstone.internal.getTransform(eventData.enabledElement);
layerContext.setTransform(transform.m[0], transform.m[1], transform.m[2], transform.m[3], transform.m[4], transform.m[5]);
layerContext.save();
layerContext.setTransform(1, 0, 0, 1, 0, 0);
layerContext.fillStyle = Theme.getProperty(Theme.VIEWPORT_TEXT);
if (overlay) {
if (overlay.type === 'R') {
layerContext.fillRect(0, 0, layerCanvas.width, layerCanvas.height);
layerContext.globalCompositeOperation = 'xor';
}
let i = 0;
for (var y = 0; y < overlay.height; y++) {
for (var x = 0; x < overlay.width; x++) {
const pixel = overlay.data[i++];
if (pixel > 0) {
layerContext.fillRect(x, y, 1, 1);
}
}
}
}
layerContext.restore();
context.drawImage(layerCanvas, 0, 0);
}
});
context.restore();
}
}
//import Tag from './Tag'; DICOM Tag dictionary
class Overlays {
constructor() {
const overlayGroupTags = [];
for (var i = 0; i <= (0x00ee0000); i += (0x00020000)) {
overlayGroupTags.push((0x60000000 + i));
}
this.OVERLAY_GROUP_TAGS = overlayGroupTags;
//AutoBind(this); This is a utility for injecting the 'this' keyword into every method
}
getOverlayWidth(dataSet, overlayNumber) {
return dataSet.uint16(Tag.toHexString(Tag.OverlayColumns | (overlayNumber &= 0x60FF0000)));
}
getOverlayHeight(dataSet, overlayNumber) {
return dataSet.uint16(Tag.toHexString(Tag.OverlayRows | (overlayNumber &= 0x60FF0000)));
}
getOverlayActivationLayer(dataSet, overlayNumber) {
return dataSet.string(Tag.toHexString(Tag.OverlayActivationLayer | (overlayNumber &= 0x60FF0000)));
}
isOverlay(imageIndex) {
return ((imageIndex & 0x60000000) === 0x60000000) && (imageIndex & 0x9F010000) === 0;
}
extractFrameNumber(imageIndex) {
const {isOverlay} = this;
if (isOverlay(imageIndex)) {
return imageIndex & 0xFFFF;
}
return 0;
}
extractOverlay(dataSet, overlayNumber, image) {
const {isOverlay, extractFrameNumber, getOverlayHeight, getOverlayWidth, getOverlayActivationLayer} = this;
if (!isOverlay(overlayNumber)) {
return undefined;
}
const frameNumber = extractFrameNumber(overlayNumber);
overlayNumber = overlayNumber & 0x60FE0000;
const rows = getOverlayHeight(dataSet, overlayNumber);
const columns = getOverlayWidth(dataSet, overlayNumber);
const bitPosition = dataSet.uint16(Tag.toHexString(overlayNumber | Tag.OverlayBitPosition));
let data;
if (bitPosition === 0) {
const overlayData = dataSet.elements[Tag.toHexString(overlayNumber | Tag.OverlayData)];
if (overlayData) {
const length = rows * columns * 8;
data = [];
for (var i = 0; i < overlayData.length; i++) {
for (var k = 0; k < 8; k++) {
const byte_as_int = dataSet.byteArray[overlayData.dataOffset + i];
data[i * 8 + k] = (byte_as_int >> k) & 0b1;
}
}
}
} else if (image) {
const bitsAllocated = dataSet.int16(Tag.toHexString(overlayNumber | Tag.OverlayBitsAllocated));
const pixelData = image.getPixelData();
data = [];
const bit = (1 << bitPosition);
var j = 0;
for (var y = 0; y < rows; y++) {
for (var x = 0; x < columns; x++) {
const pixel = pixelData[j];
if ((pixel & bit) != 0) {
data[j] = 1;
} else {
data[j] = 0;
}
j++;
}
}
}
if (data) {
return {
x : dataSet.int16(Tag.toHexString(overlayNumber | Tag.OverlayOrigin), 1) - 1,
y : dataSet.int16(Tag.toHexString(overlayNumber | Tag.OverlayOrigin), 0) - 1,
width : columns,
height : rows,
data : data,
type : dataSet.string(Tag.toHexString(overlayNumber | Tag.OverlayType)),
layer : getOverlayActivationLayer(dataSet, overlayNumber)
};
}
}
}
export default new Overlays();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment