Creating ohif:metadata package with metadata classes and adding it to the viewers

This commit is contained in:
Eloízio Salgado 2017-01-16 19:29:49 -02:00 committed by Emanuel F. Oliveira
parent 30a50c7ade
commit 660b828f4b
24 changed files with 242 additions and 28 deletions

View File

@ -35,6 +35,7 @@ ohif:dicom-services
ohif:hanging-protocols
ohif:user-management
ohif:lesiontracker
ohif:metadata
accounts-base@1.2.14
accounts-password@1.3.3

View File

@ -95,6 +95,7 @@ ohif:hanging-protocols@0.0.1
ohif:lesiontracker@0.0.1
ohif:log@0.0.1
ohif:measurements@0.0.1
ohif:metadata@0.0.1
ohif:study-list@0.0.1
ohif:user-management@0.0.1
ohif:viewerbase@0.0.1

View File

@ -13,6 +13,7 @@ ohif:study-list
ohif:dicom-services
ohif:hanging-protocols
# ohif:user-management
ohif:metadata
twbs:bootstrap
http@1.2.10

View File

@ -20,10 +20,6 @@ caching-compiler@1.1.9
caching-html-compiler@1.0.7
callback-hook@1.0.10
check@1.2.4
clinical:router@2.0.17
clinical:router-location@2.0.14
clinical:router-middleware-stack@2.0.13
clinical:router-url@2.0.15
coffeescript@1.11.1_4
ddp@1.2.5
ddp-client@1.3.2
@ -81,6 +77,7 @@ ohif:design@0.0.1
ohif:dicom-services@0.0.1
ohif:hanging-protocols@0.0.1
ohif:log@0.0.1
ohif:metadata@0.0.1
ohif:study-list@0.0.1
ohif:viewerbase@0.0.1
ohif:wadoproxy@0.0.1

View File

@ -1,7 +1,8 @@
import { OHIF } from 'meteor/ohif:core';
import { Template } from 'meteor/templating';
import { $ } from 'meteor/jquery';
import { Viewerbase } from 'meteor/ohif:viewerbase';
import { OHIF } from 'meteor/ohif:core';
import 'meteor/ohif:viewerbase';
Template.toolbarSection.onCreated(() => {
const instance = Template.instance();
@ -182,7 +183,7 @@ Template.toolbarSection.helpers({
title: 'CINE',
classes: 'imageViewerCommand',
iconClasses: 'fa fa-youtube-play',
disableFunction: Viewerbase.viewportUtils.hasMultipleFrames
disableFunction: OHIF.viewerbase.viewportUtils.hasMultipleFrames
});
}
@ -232,11 +233,11 @@ Template.toolbarSection.onRendered(function() {
instance.$('#layout').dropdown();
if (OHIF.uiSettings.displayEchoUltrasoundWorkflow) {
Viewerbase.viewportUtils.toggleCineDialog();
toggleCineDialog();
}
// Set disabled/enabled tool buttons that are set in toolManager
const states = Viewerbase.toolManager.getToolDefaultStates();
const states = OHIF.viewerbase.toolManager.getToolDefaultStates();
const disabledToolButtons = states.disabledToolButtons;
const allToolbarButtons = $('#toolbar').find('button');
if (disabledToolButtons && disabledToolButtons.length > 0) {

View File

@ -1,5 +1,6 @@
import { OHIF } from 'meteor/ohif:core';
import { Viewerbase } from 'meteor/ohif:viewerbase';
import 'meteor/ohif:viewerbase';
import 'meteor/ohif:metadata';
OHIF.viewer = OHIF.viewer || {};
OHIF.viewer.defaultTool = 'wwwc';
@ -54,6 +55,8 @@ Template.viewer.onCreated(() => {
instance.data.studies.forEach(study => {
study.selected = true;
study.displaySets = Viewerbase.createStacks(study);
// const studyMetadata = new OHIF.metadata.StudyMetadata(study);
// study.displaySets = OHIF.viewerbase.sortingManager.getDisplaySets(studyMetadata);
ViewerStudies.insert(study);
ViewerData[contentId].studyInstanceUids.push(study.studyInstanceUid);
});

View File

@ -26,7 +26,6 @@ Package.onUse(function(api) {
// Both client & server
api.addFiles('both/namespace.js');
api.addFiles('both/collections.js');
//api.addFiles('both/dicomTagDescriptions.js');
api.addFiles('both/schema.js');
api.addFiles('both/hardcodedData.js');
api.addFiles('both/testData.js');

View File

@ -0,0 +1,58 @@
import { Viewerbase } from 'meteor/ohif:viewerbase';
const InstanceMetadata = Viewerbase.metadata.InstanceMetadata;
export class OHIFInstanceMetadata extends InstanceMetadata {
/**
* @param {Object} Instance object.
*/
constructor(data) {
super(data);
this.init();
}
init() {
const data = this.getData();
// set protected property...
this._sopInstanceUID = data.sopInstanceUid;
}
// Override
getRawValue(tagOrProperty, defaultValue) {
const propertyName = OHIFInstanceMetadata.getPropertyName(tagOrProperty);
const data = this.getData();
const rawValue = data[propertyName];
return rawValue !== void 0 ? rawValue : defaultValue;
}
// Override
tagExists(tagOrProperty) {
const propertyName = OHIFInstanceMetadata.getPropertyName(tagOrProperty);
const data = this.getData();
return (propertyName in data);
}
/**
* Static methods
*/
static getPropertyName(tagOrProperty) {
const tagInfo = InstanceMetadata.getTagInfo(tagOrProperty);
if(tagInfo.propertyName === null) {
return;
}
let propertyName = tagInfo.propertyName.charAt(0).toLowerCase() + tagInfo.propertyName.substr(1);
// TODO: Improve this: change retriveMetadata to use dicom standard names (see dicomTagDescriptions.js)
propertyName = propertyName.replace(/^sop/, 'SOP');
propertyName = propertyName.replace(/uid$/i, 'UID');
return propertyName;
}
}

View File

@ -0,0 +1,26 @@
import { Viewerbase } from 'meteor/ohif:viewerbase';
import { OHIFInstanceMetadata } from './OHIFInstanceMetadata';
export class OHIFSeriesMetadata extends Viewerbase.metadata.SeriesMetadata {
/**
* @param {Object} Series object.
*/
constructor(data) {
super(data);
this.init();
}
init() {
const data = this.getData();
// set protected property...
this._seriesInstanceUID = data.seriesInstanceUid;
// populate internal list of instances...
data.instances.forEach(instance => {
this.addInstance(new OHIFInstanceMetadata(instance));
});
}
}

View File

@ -0,0 +1,25 @@
import { Viewerbase } from 'meteor/ohif:viewerbase';
import { OHIFSeriesMetadata } from './OHIFSeriesMetadata';
export class OHIFStudyMetadata extends Viewerbase.metadata.StudyMetadata {
/**
* @param {Object} Study object.
*/
constructor(data) {
super(data);
this.init();
}
init() {
const data = this.getData();
// set protected property...
this._studyInstanceUID = data.studyInstanceUid;
// populate internal list of series...
data.seriesList.forEach(series => {
this.addSeries(new OHIFSeriesMetadata(series));
});
}
}

View File

@ -0,0 +1,10 @@
import { Metadata } from '../namespace';
// OHIFStudyMetadata, OHIFSeriesMetadata, OHIFInstanceMetadata
import { OHIFStudyMetadata } from './OHIFStudyMetadata';
import { OHIFSeriesMetadata } from './OHIFSeriesMetadata';
import { OHIFInstanceMetadata } from './OHIFInstanceMetadata';
Metadata.StudyMetadata = OHIFStudyMetadata;
Metadata.SeriesMetadata = OHIFSeriesMetadata;
Metadata.InstanceMetadata = OHIFInstanceMetadata;

View File

@ -0,0 +1,39 @@
/**
* Import namespace...
*/
import { OHIF, Metadata } from './namespace.js';
/**
* Import scripts that will populate the Metadata namespace as a side effect only import. This is effectively the public API...
*/
import './client/'; // which is actually: import './client/index.js';
/**
* Export relevant objects...
*
* With the following export it becomes possible to import "OHIF" from "ohif:core" and "Metadata"
* from "ohif:metadata" using a single import (a shorthand), like this:
*
* import { OHIF } from 'meteor/ohif:metadata';
*
* Which is equivalent to:
*
* import { OHIF } from 'meteor/ohif:core';
* import 'meteor/ohif:metadata';
*
* The second (extended) format should be used when other OHIF packages are also to be used within
* the current module. This makes it explicit that the following imports will populate their
* respective namespaces within the to "OHIF" namespace. Example:
*
* import { OHIF } from 'meteor/ohif:core';
* import 'meteor/ohif:metadata';
* import 'meteor/ohif:hanging-protocols';
* [ ... ]
* OHIF.metadata.setActiveViewport(...);
* OHIF.hangingprotocols.doSomething(...);
*
*/
export { OHIF, Metadata };

View File

@ -0,0 +1,23 @@
/**
* Import main dependency...
*/
import { OHIF } from 'meteor/ohif:core';
/**
* Create Metadata namespace...
*/
const Metadata = {};
/**
* Append Metadata namespace to OHIF namespace...
*/
OHIF.metadata = Metadata;
/**
* Export relevant objects...
*/
export { OHIF, Metadata };

View File

@ -0,0 +1,16 @@
Package.describe({
name: 'ohif:metadata',
summary: 'OHIF Metadata classes',
version: '0.0.1'
});
Package.onUse(function(api) {
api.versionsFrom('1.4');
api.use('ecmascript');
api.use('ohif:core');
api.use('ohif:viewerbase');
api.mainModule('main.js', 'client');
});

View File

@ -1,5 +1,5 @@
import { OHIF } from 'meteor/ohif:core';
import { Viewerbase } from 'meteor/ohif:viewerbase';
import 'meteor/ohif:viewerbase';
// Define the StudyMetaData object. This is used as a cache
// to store study meta data information to prevent unnecessary
@ -56,7 +56,7 @@ getStudyMetadata = function(studyInstanceUid, doneCallback, failCallback) {
// Once we have retrieved the data, we sort the series' by series
// and instance number in ascending order
Viewerbase.sortStudy(study);
OHIF.viewerbase.sortStudy(study);
// Add additional metadata to our study from the studylist
var studylistStudy = StudyListStudies.findOne({

View File

@ -119,7 +119,7 @@ function resultDataToStudyMetadata(studyInstanceUid, resultData) {
laterality: instance[0x00200062],
viewPosition: instance[0x00185101],
acquisitionDatetime: instance[0x0008002A],
numFrames: parseFloat(instance[0x00280008]),
numberOfFrames: parseFloat(instance[0x00280008]),
frameIncrementPointer: getValue(instance[0x00280009]),
frameTime: parseFloat(instance[0x00181063]),
frameTimeVector: parseFloatArray(instance[0x00181065]),

View File

@ -97,7 +97,7 @@ function resultDataToStudyMetadata(server, studyInstanceUid, resultData) {
laterality: remoteGetValue(instance['0020,0062']),
viewPosition: remoteGetValue(instance['0018,5101']),
acquisitionDatetime: remoteGetValue(instance['0008,002A']),
numFrames: parseFloat(remoteGetValue(instance['0028,0008'])),
numberOfFrames: parseFloat(remoteGetValue(instance['0028,0008'])),
frameIncrementPointer: remoteGetValue(instance['0028,0009']),
frameTime: parseFloat(remoteGetValue(instance['0018,1063'])),
frameTimeVector: parseFloatArray(remoteGetValue(instance['0018,1065']))

View File

@ -109,7 +109,7 @@ function resultDataToStudyMetadata(server, studyInstanceUid, resultData) {
laterality: DICOMWeb.getString(instance['00200062']),
viewPosition: DICOMWeb.getString(instance['00185101']),
acquisitionDatetime: DICOMWeb.getString(instance['0008002A']),
numFrames: DICOMWeb.getNumber(instance['00280008']),
numberOfFrames: DICOMWeb.getNumber(instance['00280008']),
frameIncrementPointer: DICOMWeb.getAttribute(instance['00280009']),
frameTime: DICOMWeb.getNumber(instance['00181063']),
frameTimeVector: parseFloatArray(DICOMWeb.getString(instance['00181065'])),

View File

@ -163,6 +163,10 @@ Viewerbase.helpers = helpers;
import { sopClassDictionary } from './lib/sopClassDictionary';
Viewerbase.sopClassDictionary = sopClassDictionary;
// dicomTagDescriptions
import { dicomTagDescriptions } from './lib/dicomTagDescriptions';
Viewerbase.dicomTagDescriptions = dicomTagDescriptions;
/**
* Exported Classes
*/

View File

@ -30,10 +30,10 @@ function createAndAddStack(stackMap, study, displaySet) {
imageIndex: imageIndex + 1
};
const numFrames = image.numFrames;
if (numFrames > 1) {
const numberOfFrames = image.numberOfFrames;
if (numberOfFrames > 1) {
OHIF.log.info('Multiframe image detected');
for (let i = 0; i < numFrames; i++) {
for (let i = 0; i < numberOfFrames; i++) {
metaData.frame = i;
imageId = getImageId(image, i);
imageIds.push(imageId);

View File

@ -1,9 +1,10 @@
import { Metadata } from './Metadata';
import { dicomTagDescriptions } from '../../dicomTagDescriptions';
const UNDEFINED = 'undefined';
const NUMBER = 'number';
const STRING = 'string';
const REGEX_TAG = /^x[0-9a-f]{8}$/;
const REGEX_TAG = /^x[0-9a-fx]{8}$/;
export class InstanceMetadata extends Metadata {
@ -132,7 +133,17 @@ export class InstanceMetadata extends Metadata {
propertyName = tagOrProperty;
}
// @TODO: map tagName to propertyName and vice versa
// It's a property
if (tagName === null) {
for (let tag in dicomTagDescriptions) {
if (dicomTagDescriptions[tag] === propertyName) {
tagName = tag;
break;
}
}
} else if (propertyName === null) {
propertyName = dicomTagDescriptions[tagName] || null;
}
return { tagName, propertyName };
}

View File

@ -44,7 +44,7 @@ function createStacks(study) {
displaySet.setAttributes({
isClip: true,
studyInstanceUid: study.studyInstanceUid, // Include the study instance Uid for drag/drop purposes
numImageFrames: instance.numFrames, // Override the default value of instances.length
numImageFrames: instance.numberOfFrames, // Override the default value of instances.length
instanceNumber: instance.instanceNumber, // Include the instance number
acquisitionDatetime: instance.acquisitionDatetime // Include the acquisition datetime
});
@ -110,7 +110,7 @@ function isSingleImageModality(modality) {
}
function isMultiFrame(instance) {
return instance.numFrames > 1;
return instance.numberOfFrames > 1;
}
/**

View File

@ -1,4 +1,4 @@
HP.tagDescriptions = {
export const dicomTagDescriptions = {
x00020000: 'FileMetaInfoGroupLength',
x00020001: 'FileMetaInfoVersion',
x00020002: 'MediaStorageSOPClassUID',
@ -3145,4 +3145,4 @@ HP.tagDescriptions = {
xfffee000: 'StartOfItem',
xfffee00d: 'EndOfItems',
xfffee0dd: 'EndOfSequence'
};
};

View File

@ -126,7 +126,6 @@ const stackOfInstancesToDisplaySets = (sopInstances, seriesView) => {
const groups = _.groupBy(sopInstances, sopInstance => {
// Create an empty string to store our key
let result = '';
const instanceView = sopInstance.getData();
// For each rule, find out if the tag exists
seriesSplittingRules.forEach(rule => {
@ -134,8 +133,8 @@ const stackOfInstancesToDisplaySets = (sopInstances, seriesView) => {
result += ';'
// If the tag exists, concatenate its value to our key
if (instanceView.exists(rule.tag)) {
result += instanceView.raw(rule.tag);
if (sopInstance.tagExists(rule.tag)) {
result += sopInstance.getRawValue(rule.tag);
}
});