Skip to content

Commit

Permalink
Merge pull request fli-iam#2317 from pierrehenri-dauvergne/shanoir-is…
Browse files Browse the repository at this point in the history
…sue#2222-2

shanoir-issue#2222-2: OHIF viewer
  • Loading branch information
michaelkain authored Jul 25, 2024
2 parents a5b1f34 + e37569d commit 1c6ce73
Show file tree
Hide file tree
Showing 7 changed files with 70 additions and 155 deletions.
2 changes: 1 addition & 1 deletion docker-compose/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ CMD []

################ nginx #####################################################

FROM ohif/viewer:v4.12.32.19362 AS nginx-viewer
FROM ohif/app:v3.9.0-beta.64 AS nginx-viewer

FROM nginx as nginx

Expand Down
168 changes: 29 additions & 139 deletions docker-compose/nginx/viewer/app-config.js
Original file line number Diff line number Diff line change
@@ -1,35 +1,31 @@
window.config = {
// default: '/'
routerBasename: '/',
extensions: ['cornerstone', 'dicom-p10-downloader'],
showStudyList: true,
filterQueryParam: false,
disableServersCache: false,
studyPrefetcher: {
enabled: true,
order: 'closest',
displaySetCount: 3,
preventCache: false,
prefetchDisplaySetsTimeout: 300,
displayProgress: true,
includeActiveDisplaySet: true,
},
servers: {
dicomWeb: [
{
name: 'SHANOIR-NG',
wadoUriRoot: 'SHANOIR_VIEWER_OHIF_URL_SCHEME://SHANOIR_VIEWER_OHIF_URL_HOST/shanoir-ng/',
qidoRoot: 'SHANOIR_VIEWER_OHIF_URL_SCHEME://SHANOIR_VIEWER_OHIF_URL_HOST/dicomweb',
wadoRoot: 'SHANOIR_VIEWER_OHIF_URL_SCHEME://SHANOIR_VIEWER_OHIF_URL_HOST/dicomweb',
qidoSupportsIncludeField: true,
imageRendering: 'wadors',
thumbnailRendering: 'wadors',
enableStudyLazyLoad: true,
supportsFuzzyMatching: true,
},
],
},
oidc: [
window.config = {
routerBasename: '/',
extensions: [],
modes: [],
showStudyList: true,
dataSources: [
{
namespace: '@ohif/extension-default.dataSourcesModule.dicomweb',
sourceName: 'dicomweb',
configuration: {
friendlyName: 'SHANOIR-NG',
name: 'SHANOIR-NG',
wadoUriRoot: 'SHANOIR_VIEWER_OHIF_URL_SCHEME://SHANOIR_VIEWER_OHIF_URL_HOST/shanoir-ng/',
qidoRoot: 'SHANOIR_VIEWER_OHIF_URL_SCHEME://SHANOIR_VIEWER_OHIF_URL_HOST/dicomweb',
wadoRoot: 'SHANOIR_VIEWER_OHIF_URL_SCHEME://SHANOIR_VIEWER_OHIF_URL_HOST/dicomweb',
qidoSupportsIncludeField: true,
supportsReject: true,
imageRendering: 'wadors',
thumbnailRendering: 'wadors',
enableStudyLazyLoad: true,
supportsFuzzyMatching: true,
supportsWildcard: true,
omitQuotationForMultipartRequest: false,
},
},
],
defaultDataSourceName: 'dicomweb',
oidc: [
{
// ~ REQUIRED
// Authorization Server URL
Expand All @@ -43,111 +39,5 @@ window.config = {
// ~ OPTIONAL
post_logout_redirect_uri: 'SHANOIR_URL_SCHEME://SHANOIR_URL_HOST'
}
],
// Extensions should be able to suggest default values for these?
// Or we can require that these be explicitly set
hotkeys: [
// ~ Global
{
commandName: 'incrementActiveViewport',
label: 'Next Viewport',
keys: ['right'],
},
{
commandName: 'decrementActiveViewport',
label: 'Previous Viewport',
keys: ['left'],
},
// Supported Keys: https://craig.is/killing/mice
// ~ Cornerstone Extension
{ commandName: 'rotateViewportCW', label: 'Rotate Right', keys: ['r'] },
{ commandName: 'rotateViewportCCW', label: 'Rotate Left', keys: ['l'] },
{ commandName: 'invertViewport', label: 'Invert', keys: ['i'] },
{
commandName: 'flipViewportVertical',
label: 'Flip Horizontally',
keys: ['h'],
},
{
commandName: 'flipViewportHorizontal',
label: 'Flip Vertically',
keys: ['v'],
},
{ commandName: 'scaleUpViewport', label: 'Zoom In', keys: ['+'] },
{ commandName: 'scaleDownViewport', label: 'Zoom Out', keys: ['-'] },
{ commandName: 'fitViewportToWindow', label: 'Zoom to Fit', keys: ['='] },
{ commandName: 'resetViewport', label: 'Reset', keys: ['space'] },
// clearAnnotations
{ commandName: 'nextImage', label: 'Next Image', keys: ['down'] },
{ commandName: 'previousImage', label: 'Previous Image', keys: ['up'] },
// firstImage
// lastImage
{
commandName: 'previousViewportDisplaySet',
label: 'Previous Series',
keys: ['pagedown'],
},
{
commandName: 'nextViewportDisplaySet',
label: 'Next Series',
keys: ['pageup'],
},
// ~ Cornerstone Tools
{ commandName: 'setZoomTool', label: 'Zoom', keys: ['z'] },
// ~ Window level presets
{
commandName: 'windowLevelPreset1',
label: 'W/L Preset 1',
keys: ['1'],
},
{
commandName: 'windowLevelPreset2',
label: 'W/L Preset 2',
keys: ['2'],
},
{
commandName: 'windowLevelPreset3',
label: 'W/L Preset 3',
keys: ['3'],
},
{
commandName: 'windowLevelPreset4',
label: 'W/L Preset 4',
keys: ['4'],
},
{
commandName: 'windowLevelPreset5',
label: 'W/L Preset 5',
keys: ['5'],
},
{
commandName: 'windowLevelPreset6',
label: 'W/L Preset 6',
keys: ['6'],
},
{
commandName: 'windowLevelPreset7',
label: 'W/L Preset 7',
keys: ['7'],
},
{
commandName: 'windowLevelPreset8',
label: 'W/L Preset 8',
keys: ['8'],
},
{
commandName: 'windowLevelPreset9',
label: 'W/L Preset 9',
keys: ['9'],
},
],
cornerstoneExtensionConfig: {},
// Following property limits number of simultaneous series metadata requests.
// For http/1.x-only servers, set this to 5 or less to improve
// on first meaningful display in viewer
// If the server is particularly slow to respond to series metadata
// requests as it extracts the metadata from raw files everytime,
// try setting this to even lower value
// Leave it undefined for no limit, suitable for HTTP/2 enabled servers
// maxConcurrentMetadataRequests: 5,
]
};
1 change: 0 additions & 1 deletion docker-compose/nginx/viewer/ohif-viewer.template.conf
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ location /
try_files $uri $uri/ /index.html;

#more_set_headers 'X-Frame-Options: SAMEORIGIN';
add_header 'X-Frame-Options' 'SAMEORIGIN';
}

# Directly root to MS-Datasets, to avoid CORS-errors from OHIF Viewer
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package org.shanoir.ng.dicom.web;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.shanoir.ng.dicom.web.service.DICOMWebService;
import org.shanoir.ng.examination.model.Examination;
Expand All @@ -14,14 +14,19 @@
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;

import java.util.Iterator;
import java.util.Map;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

import jakarta.servlet.http.HttpServletRequest;

@Controller
public class DICOMWebApiController implements DICOMWebApi {
Expand All @@ -47,13 +52,34 @@ public ResponseEntity<String> findPatients() throws RestServiceException {

@Override
public ResponseEntity<String> findStudies(Map<String, String> allParams) throws RestServiceException, JsonMappingException, JsonProcessingException {
Page<Examination> examinations = null;
int offset = Integer.valueOf(allParams.get("offset"));
int limit = Integer.valueOf(allParams.get("limit"));
Pageable pageable = PageRequest.of(offset, limit);
// Search for studies with patient name (DICOM patientID does not make sense in case of Shanoir)
// 1. Search for studies with patient name
// (DICOM patientID does not make sense in case of Shanoir)
String patientName = allParams.get("PatientName");
Page<Examination> examinations = examinationService.findPage(pageable, patientName);
if (examinations.getContent().isEmpty()) {
if (patientName != null) {
examinations = examinationService.findPage(pageable, patientName);
} else {
// 2. Try StudyInstanceUIDs, in case no patient name
// Manage already multiple study instance UIDs
String studyInstanceUIDs = allParams.get("StudyInstanceUIDs");
if (studyInstanceUIDs != null) {
List<Examination> examinationList = new ArrayList<>();
String[] studyInstanceUIDArray = studyInstanceUIDs.split(",");
for(String studyInstanceUID : studyInstanceUIDArray) {
String examinationIdString = studyInstanceUID.substring(studyInstanceUID.lastIndexOf(".") + 1, studyInstanceUID.length());
Examination examination = examinationService.findById(Long.valueOf(examinationIdString));
examinationList.add(examination);
}
examinations = new PageImpl<>(examinationList);
// 3. No param, return page of examinations in db
} else {
examinations = examinationService.findPage(pageable, null);
}
}
if (examinations == null || examinations.getContent().isEmpty()) {
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
StringBuffer studies = new StringBuffer();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,8 +154,8 @@ public Page<Examination> findPage(final Pageable pageable, boolean preclinical,

@Override
public Page<Examination> findPage(final Pageable pageable, String patientName) {
if (patientName.length() > 64) {
throw new IllegalArgumentException("A patient name cannot be longer than 64 chars, it exceed the data representation limit");
if (patientName != null && patientName.length() > 64) {
throw new IllegalArgumentException("A patient name cannot be longer than 64 chars, it exceed the data representation limit.");
}
if (KeycloakUtil.getTokenRoles().contains("ROLE_ADMIN")) {
if (StringUtils.isNotEmpty(patientName)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ export class ExaminationComponent extends EntityComponent<Examination> {
}

openViewer() {
window.open(environment.viewerUrl + '/viewer/1.4.9.12.34.1.8527.' + this.entity.id, '_blank');
window.open(environment.viewerUrl + '/viewer?StudyInstanceUIDs=1.4.9.12.34.1.8527.' + this.entity.id, '_blank');
}

getCenters(): void {
Expand Down
2 changes: 1 addition & 1 deletion shanoir-ng-front/src/app/solr/solr.search.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -459,7 +459,7 @@ export class SolrSearchComponent implements AfterViewChecked, AfterContentInit {
{headerName: "OHIF Viewer", type: "button", awesome: "fa-solid fa-up-right-from-square",
condition: item => (item.datasetType.includes("MR") || item.datasetType.includes("Pet") || item.datasetType.includes("Ct")),
action: item => {
window.open(environment.viewerUrl + '/viewer/1.4.9.12.34.1.8527.' + item.examinationId, '_blank');
window.open(environment.viewerUrl + '/viewer?StudyInstanceUIDs=1.4.9.12.34.1.8527.' + item.examinationId, '_blank');
}
}
];
Expand Down

0 comments on commit 1c6ce73

Please sign in to comment.