diff --git a/api/controller.class.js b/api/controller.class.js index 2120533b..bd83a03e 100644 --- a/api/controller.class.js +++ b/api/controller.class.js @@ -53,6 +53,19 @@ class Controller { this.postProcess(); } + + /** + * @return {string} + */ + paramsToString() { + let strArr = []; + let keys = Object.keys(this.request.params); + for(let i = 0 ; i < keys.length; i++) { + let key = keys[i]; + strArr.push(`${key}: ${this.request.params[key]}`); + } + return strArr.join(" "); + } } module.exports.Controller = Controller; \ No newline at end of file diff --git a/api/dicom-web/controller/STOW-RS/service/dicom-jpeg-generator.js b/api/dicom-web/controller/STOW-RS/service/dicom-jpeg-generator.js index 16929e9b..95fd4c5c 100644 --- a/api/dicom-web/controller/STOW-RS/service/dicom-jpeg-generator.js +++ b/api/dicom-web/controller/STOW-RS/service/dicom-jpeg-generator.js @@ -1,6 +1,7 @@ const fs = require("fs"); const { Dcm2JpgExecutor } = require("../../../../../models/DICOM/dcm4che/wrapper/org/github/chinlinlee/dcm2jpg/Dcm2JpgExecutor"); const { Dcm2JpgExecutor$Dcm2JpgOptions } = require("../../../../../models/DICOM/dcm4che/wrapper/org/github/chinlinlee/dcm2jpg/Dcm2JpgExecutor$Dcm2JpgOptions"); +const notImageSOPClass = require("../../../../../models/DICOM/dicomWEB/notImageSOPClass"); const { logger } = require("../../../../../utils/logs/log"); const dicomToJpegTask = require("../../../../../models/mongodb/models/dicomToJpegTask"); const colorette = require("colorette"); @@ -28,6 +29,10 @@ class DicomJpegGenerator { async generateAllFrames() { try { + + if (notImageSOPClass.includes(this.dicomJsonModel.getSopClassUid())) { + return; + } await this.insertStartTask_(); diff --git a/api/dicom-web/controller/WADO-RS/rendered/instanceFrames.js b/api/dicom-web/controller/WADO-RS/rendered/instanceFrames.js index 96acbc06..6baa8a39 100644 --- a/api/dicom-web/controller/WADO-RS/rendered/instanceFrames.js +++ b/api/dicom-web/controller/WADO-RS/rendered/instanceFrames.js @@ -1,5 +1,6 @@ const _ = require("lodash"); const renderedService = require("../service/rendered.service"); +const dicomModel = require("../../../../../models/mongodb/models/dicom"); const { MultipartWriter } = require("../../../../../utils/multipartWriter"); const errorResponse = require("../../../../../utils/errorResponse/errorResponseMessage"); const { ApiLogger } = require("../../../../../utils/logs/api-logger"); @@ -11,8 +12,8 @@ class RetrieveRenderedInstanceFramesController extends Controller { } async mainProcess() { - let apiLogger = new ApiLogger(this.request, "WADO-RS"); - apiLogger.addTokenValue(); + this.apiLogger = new ApiLogger(this.request, "WADO-RS"); + this.apiLogger.addTokenValue(); let { studyUID, @@ -21,7 +22,7 @@ class RetrieveRenderedInstanceFramesController extends Controller { frameNumber } = this.request.params; - apiLogger.logger.info(`Get study's series' rendered instances' frames, study UID: ${studyUID}, series UID: ${seriesUID}, instance UID: ${instanceUID}, frame: ${frameNumber}`); + this.apiLogger.logger.info(`Get study's series' rendered instances' frames, study UID: ${studyUID}, series UID: ${seriesUID}, instance UID: ${instanceUID}, frame: ${frameNumber}`); let headerAccept = _.get(this.request.headers, "accept", ""); if (!headerAccept.includes("*/*") && !headerAccept.includes("image/jpeg")) { @@ -33,25 +34,19 @@ class RetrieveRenderedInstanceFramesController extends Controller { } try { + let imagePathObj = await dicomModel.getPathOfInstance(this.request.params); + + if(!imagePathObj) { + return this.responseNotFound(); + } + let instanceFramesObj = await renderedService.getInstanceFrameObj(this.request.params); - if (!instanceFramesObj) { - this.response.writeHead(404, { - "Content-Type": "application/dicom+json" - }); - let notFoundMessage = errorResponse.getNotFoundErrorMessage(`Not Found Instance, Instance UID: ${ - instanceUID - }, Series UID: ${ - seriesUID - }, Study UID: ${ - studyUID - }`); - - let notFoundMessageStr = JSON.stringify(notFoundMessage); - - apiLogger.logger.warn(`[${notFoundMessageStr}]`); - - return this.response.end(notFoundMessageStr); + if (_.isUndefined(instanceFramesObj)) { + return this.response.status(400).json( + errorResponse.getBadRequestErrorMessage(`instance: ${this.request.params.instanceUID} doesn't have pixel data`) + ); } + let dicomNumberOfFrames = _.get(instanceFramesObj, "00280008.Value.0", 1); dicomNumberOfFrames = parseInt(dicomNumberOfFrames); @@ -65,7 +60,7 @@ class RetrieveRenderedInstanceFramesController extends Controller { let badRequestMessageStr = JSON.stringify(badRequestMessage); - apiLogger.logger.warn(badRequestMessageStr); + this.apiLogger.logger.warn(badRequestMessageStr); return this.response.end(JSON.stringify(badRequestMessageStr)); } @@ -78,7 +73,7 @@ class RetrieveRenderedInstanceFramesController extends Controller { this.response.writeHead(200, { "Content-Type": "image/jpeg" }); - apiLogger.logger.info(`Get instance's frame successfully, instance UID: ${instanceUID}, frame number: ${frameNumber[0]}`); + this.apiLogger.logger.info(`Get instance's frame successfully, instance UID: ${instanceUID}, frame number: ${frameNumber[0]}`); return this.response.end(postProcessResult.magick.toBuffer(), "binary"); } throw new Error(`Can not process this image, instanceUID: ${instanceFramesObj.instanceUID}, frameNumber: ${this.request.frameNumber[0]}`); @@ -87,7 +82,7 @@ class RetrieveRenderedInstanceFramesController extends Controller { await renderedService.writeSpecificFramesRenderedImages(this.request, frameNumber, instanceFramesObj, multipartWriter); multipartWriter.writeFinalBoundary(); - apiLogger.logger.info(`Get instance's frame successfully, instance UID: ${instanceUID}, frame numbers: ${frameNumber}`); + this.apiLogger.logger.info(`Get instance's frame successfully, instance UID: ${instanceUID}, frame numbers: ${frameNumber}`); return this.response.end(); } @@ -99,6 +94,18 @@ class RetrieveRenderedInstanceFramesController extends Controller { this.response.end(JSON.stringify(e, Object.getOwnPropertyNames(e), 4), "utf8"); } } + + responseNotFound() { + let notFoundStr = `Not Found Instance, ${this.paramsToString()}`; + + this.apiLogger.logger.warn(notFoundStr); + + let notFoundMessage = errorResponse.getNotFoundErrorMessage( + notFoundStr + ); + + return this.response.status(404).json(notFoundMessage); + } } /** * diff --git a/api/dicom-web/controller/WADO-RS/rendered/instances.js b/api/dicom-web/controller/WADO-RS/rendered/instances.js index 57f02a44..7a4b6401 100644 --- a/api/dicom-web/controller/WADO-RS/rendered/instances.js +++ b/api/dicom-web/controller/WADO-RS/rendered/instances.js @@ -34,6 +34,11 @@ class RetrieveRenderedInstancesController extends Controller { if (imagePathObj) { let multipartWriter = new MultipartWriter([], this.request, this.response); let instanceFramesObj = await renderedService.getInstanceFrameObj(imagePathObj); + if (_.isUndefined(instanceFramesObj)) { + return this.response.status(400).json( + errorResponse.getBadRequestErrorMessage(`instance: ${this.request.params.instanceUID} doesn't have pixel data`) + ); + } let dicomNumberOfFrames = _.get(instanceFramesObj, "00280008.Value.0", 1); dicomNumberOfFrames = parseInt(dicomNumberOfFrames); await renderedService.writeRenderedImages(this.request, dicomNumberOfFrames, instanceFramesObj, multipartWriter); diff --git a/api/dicom-web/controller/WADO-RS/rendered/series.js b/api/dicom-web/controller/WADO-RS/rendered/series.js index 4d3a7be4..d3e35e70 100644 --- a/api/dicom-web/controller/WADO-RS/rendered/series.js +++ b/api/dicom-web/controller/WADO-RS/rendered/series.js @@ -30,6 +30,7 @@ class RetrieveRenderedSeriesController extends Controller { for(let imagePathObj of instancesInSeries) { let instanceFramesObj = await renderedService.getInstanceFrameObj(imagePathObj); + if (_.isUndefined(instanceFramesObj)) continue; let dicomNumberOfFrames = _.get(instanceFramesObj, "00280008.Value.0", 1); dicomNumberOfFrames = parseInt(dicomNumberOfFrames); await renderedService.writeRenderedImages(this.request, dicomNumberOfFrames, instanceFramesObj, multipartWriter); diff --git a/api/dicom-web/controller/WADO-RS/rendered/study.js b/api/dicom-web/controller/WADO-RS/rendered/study.js index 46b2d88e..1acd21e6 100644 --- a/api/dicom-web/controller/WADO-RS/rendered/study.js +++ b/api/dicom-web/controller/WADO-RS/rendered/study.js @@ -34,6 +34,7 @@ class RetrieveRenderedStudyController extends Controller { for(let imagePathObj of pathGroupOfInstancesInStudy) { let instanceFramesObj = await renderedService.getInstanceFrameObj(imagePathObj); + if(_.isUndefined(instanceFramesObj)) continue; let dicomNumberOfFrames = _.get(instanceFramesObj, "00280008.Value.0", 1); dicomNumberOfFrames = parseInt(dicomNumberOfFrames); await renderedService.writeRenderedImages(this.request, dicomNumberOfFrames, instanceFramesObj, multipartWriter); diff --git a/api/dicom-web/controller/WADO-RS/service/WADO-RS.service.js b/api/dicom-web/controller/WADO-RS/service/WADO-RS.service.js index 7e4ee982..c6e0f0c1 100644 --- a/api/dicom-web/controller/WADO-RS/service/WADO-RS.service.js +++ b/api/dicom-web/controller/WADO-RS/service/WADO-RS.service.js @@ -168,7 +168,11 @@ class InstanceImagePathFactory extends ImagePathFactory { async getImagePaths() { let imagePath = await dicomModel.getPathOfInstance(this.uids); - this.imagePaths = [imagePath]; + + if(imagePath) + this.imagePaths = [imagePath]; + else + this.imagePaths = []; } } diff --git a/api/dicom-web/controller/WADO-RS/service/rendered.service.js b/api/dicom-web/controller/WADO-RS/service/rendered.service.js index 49d1ef3c..9711a76c 100644 --- a/api/dicom-web/controller/WADO-RS/service/rendered.service.js +++ b/api/dicom-web/controller/WADO-RS/service/rendered.service.js @@ -4,6 +4,7 @@ const fs = require("fs"); const sharp = require("sharp"); const { Dcm2JpgExecutor } = require("../../../../../models/DICOM/dcm4che/wrapper/org/github/chinlinlee/dcm2jpg/Dcm2JpgExecutor"); const { Dcm2JpgExecutor$Dcm2JpgOptions } = require("../../../../../models/DICOM/dcm4che/wrapper/org/github/chinlinlee/dcm2jpg/Dcm2JpgExecutor$Dcm2JpgOptions"); +const notImageSOPClass = require("../../../../../models/DICOM/dicomWEB/notImageSOPClass"); const Magick = require("../../../../../models/magick"); const _ = require("lodash"); @@ -105,6 +106,7 @@ const { raccoonConfig } = require("../../../../../config-class"); async function getInstanceFrameObj(iParam, otherFields={}) { let { studyUID, seriesUID, instanceUID } = iParam; try { + /** @type { import("mongoose").FilterQuery } */ let query = { $and: [ { @@ -115,6 +117,11 @@ async function getInstanceFrameObj(iParam, otherFields={}) { }, { instanceUID: instanceUID + }, + { + "00080016.Value": { + $nin: notImageSOPClass + } } ] }; diff --git a/models/DICOM/dicom-json-model.js b/models/DICOM/dicom-json-model.js index 213c5b87..a0c031c6 100644 --- a/models/DICOM/dicom-json-model.js +++ b/models/DICOM/dicom-json-model.js @@ -238,6 +238,10 @@ class DicomJsonModel { return _.get(this.dicomJson, "00020010.Value.0"); } + getSopClassUid() { + return _.get(this.dicomJson, "00080016.Value.0"); + } + getStudyDate() { return _.get(this.dicomJson, "00080020.Value.0"); } diff --git a/models/DICOM/dicomWEB/notImageSOPClass.js b/models/DICOM/dicomWEB/notImageSOPClass.js index ae649a76..2f53e73b 100644 --- a/models/DICOM/dicomWEB/notImageSOPClass.js +++ b/models/DICOM/dicomWEB/notImageSOPClass.js @@ -1,77 +1,112 @@ /** - * ### 非影像類SOP Class - -1.2.840.10008.5.1.4.1.1.104.1 Encapsulated PDF Storage -1.2.840.10008.5.1.4.1.1.11.1 Grayscale Softcopy Presentation State Storage SOP Class -1.2.840.10008.5.1.4.1.1.11.2 Color Softcopy Presentation State Storage SOP Class -1.2.840.10008.5.1.4.1.1.11.3 Pseudocolor Softcopy Presentation Stage Storage SOP Class -1.2.840.10008.5.1.4.1.1.11.4 Blending Softcopy Presentation State Storage SOP Class - -1.2.840.10008.5.1.4.1.1.481.2 Radiation Therapy Dose Storage -1.2.840.10008.5.1.4.1.1.481.3 Radiation Therapy Structure Set Storage -1.2.840.10008.5.1.4.1.1.481.4 Radiation Therapy Beams Treatment Record Storage -1.2.840.10008.5.1.4.1.1.481.5 Radiation Therapy Plan Storage -1.2.840.10008.5.1.4.1.1.481.6 Radiation Therapy Brachy Treatment Record Storage -1.2.840.10008.5.1.4.1.1.481.7 Radiation Therapy Treatment Summary Record Storage -1.2.840.10008.5.1.4.1.1.481.8 Radiation Therapy Ion Plan Storage -1.2.840.10008.5.1.4.1.1.481.9 Radiation Therapy Ion Beams Treatment Record Storage - -1.2.840.10008.5.1.4.1.1.66 Raw Data Storage -1.2.840.10008.5.1.4.1.1.66.1 Spatial Registration Storage -1.2.840.10008.5.1.4.1.1.66.2 Spatial Fiducials Storage -1.2.840.10008.5.1.4.1.1.66.3 Deformable Spatial Registration Storage -1.2.840.10008.5.1.4.1.1.66.4 Segmentation Storage -1.2.840.10008.5.1.4.1.1.67 Real World Value Mapping Storage - -1.2.840.10008.5.1.4.1.1.88.11 Basic Text SR -1.2.840.10008.5.1.4.1.1.88.22 Enhanced SR -1.2.840.10008.5.1.4.1.1.88.33 Comprehensive SR -1.2.840.10008.5.1.4.1.1.88.40 Procedure Log Storage -1.2.840.10008.5.1.4.1.1.88.50 Mammography CAD SR -1.2.840.10008.5.1.4.1.1.88.59 Key Object Selection Document -1.2.840.10008.5.1.4.1.1.88.65 Chest CAD SR -1.2.840.10008.5.1.4.1.1.88.67 X-Ray Radiation Dose SR - -1.2.840.10008.5.1.4.1.1.9.1.1 12-lead ECG Waveform Storage -1.2.840.10008.5.1.4.1.1.9.1.2 General ECG Waveform Storage -1.2.840.10008.5.1.4.1.1.9.1.3 Ambulatory ECG Waveform Storage -1.2.840.10008.5.1.4.1.1.9.2.1 Hemodynamic Waveform Storage -1.2.840.10008.5.1.4.1.1.9.3.1 Cardiac Electrophysiology Waveform Storage -1.2.840.10008.5.1.4.1.1.9.4.1 Basic Voice Audio Waveform Storage + * The list of sop class name that one's name not contains "image storage" */ -module.exports = [ - "1.2.840.10008.5.1.4.1.1.104.1", +module.exports=[ + "1.2.840.10008.5.1.4.1.1.4.2", + "1.2.840.10008.5.1.4.1.1.6.2", + "1.2.840.10008.5.1.4.1.1.9.1.1", + "1.2.840.10008.5.1.4.1.1.9.1.2", + "1.2.840.10008.5.1.4.1.1.9.1.3", + "1.2.840.10008.5.1.4.1.1.9.2.1", + "1.2.840.10008.5.1.4.1.1.9.3.1", + "1.2.840.10008.5.1.4.1.1.9.4.1", + "1.2.840.10008.5.1.4.1.1.9.4.2", + "1.2.840.10008.5.1.4.1.1.9.5.1", + "1.2.840.10008.5.1.4.1.1.9.6.1", + "1.2.840.10008.5.1.4.1.1.9.6.2", + "1.2.840.10008.5.1.4.1.1.9.7.1", + "1.2.840.10008.5.1.4.1.1.9.7.2", + "1.2.840.10008.5.1.4.1.1.9.7.3", + "1.2.840.10008.5.1.4.1.1.9.7.4", + "1.2.840.10008.5.1.4.1.1.9.8.1", "1.2.840.10008.5.1.4.1.1.11.1", "1.2.840.10008.5.1.4.1.1.11.2", "1.2.840.10008.5.1.4.1.1.11.3", "1.2.840.10008.5.1.4.1.1.11.4", - "1.2.840.10008.5.1.4.1.1.481.2", - "1.2.840.10008.5.1.4.1.1.481.3", - "1.2.840.10008.5.1.4.1.1.481.4", - "1.2.840.10008.5.1.4.1.1.481.5", - "1.2.840.10008.5.1.4.1.1.481.6", - "1.2.840.10008.5.1.4.1.1.481.7", - "1.2.840.10008.5.1.4.1.1.481.8", - "1.2.840.10008.5.1.4.1.1.481.9", + "1.2.840.10008.5.1.4.1.1.11.5", + "1.2.840.10008.5.1.4.1.1.11.6", + "1.2.840.10008.5.1.4.1.1.11.7", + "1.2.840.10008.5.1.4.1.1.11.8", + "1.2.840.10008.5.1.4.1.1.11.9", + "1.2.840.10008.5.1.4.1.1.11.10", + "1.2.840.10008.5.1.4.1.1.11.11", + "1.2.840.10008.5.1.4.1.1.11.12", + "1.2.840.10008.5.1.4.1.1.30", "1.2.840.10008.5.1.4.1.1.66", "1.2.840.10008.5.1.4.1.1.66.1", "1.2.840.10008.5.1.4.1.1.66.2", "1.2.840.10008.5.1.4.1.1.66.3", "1.2.840.10008.5.1.4.1.1.66.4", + "1.2.840.10008.5.1.4.1.1.66.5", + "1.2.840.10008.5.1.4.1.1.66.6", "1.2.840.10008.5.1.4.1.1.67", + "1.2.840.10008.5.1.4.1.1.68.1", + "1.2.840.10008.5.1.4.1.1.68.2", + "1.2.840.10008.5.1.4.1.1.77.1.5.3", + "1.2.840.10008.5.1.4.1.1.77.1.5.8", + "1.2.840.10008.5.1.4.1.1.78.1", + "1.2.840.10008.5.1.4.1.1.78.2", + "1.2.840.10008.5.1.4.1.1.78.3", + "1.2.840.10008.5.1.4.1.1.78.4", + "1.2.840.10008.5.1.4.1.1.78.5", + "1.2.840.10008.5.1.4.1.1.78.6", + "1.2.840.10008.5.1.4.1.1.78.7", + "1.2.840.10008.5.1.4.1.1.78.8", + "1.2.840.10008.5.1.4.1.1.79.1", + "1.2.840.10008.5.1.4.1.1.80.1", + "1.2.840.10008.5.1.4.1.1.81.1", + "1.2.840.10008.5.1.4.1.1.82.1", "1.2.840.10008.5.1.4.1.1.88.11", "1.2.840.10008.5.1.4.1.1.88.22", "1.2.840.10008.5.1.4.1.1.88.33", + "1.2.840.10008.5.1.4.1.1.88.34", + "1.2.840.10008.5.1.4.1.1.88.35", "1.2.840.10008.5.1.4.1.1.88.40", "1.2.840.10008.5.1.4.1.1.88.50", "1.2.840.10008.5.1.4.1.1.88.59", "1.2.840.10008.5.1.4.1.1.88.65", "1.2.840.10008.5.1.4.1.1.88.67", - "1.2.840.10008.5.1.4.1.1.9.1.1", - "1.2.840.10008.5.1.4.1.1.9.1.2", - "1.2.840.10008.5.1.4.1.1.9.1.3", - "1.2.840.10008.5.1.4.1.1.9.2.1", - "1.2.840.10008.5.1.4.1.1.9.3.1", - "1.2.840.10008.5.1.4.1.1.9.4.1", - "1.2.840.10008.5.1.4.1.1.91.1" + "1.2.840.10008.5.1.4.1.1.88.68", + "1.2.840.10008.5.1.4.1.1.88.69", + "1.2.840.10008.5.1.4.1.1.88.70", + "1.2.840.10008.5.1.4.1.1.88.71", + "1.2.840.10008.5.1.4.1.1.88.72", + "1.2.840.10008.5.1.4.1.1.88.73", + "1.2.840.10008.5.1.4.1.1.88.74", + "1.2.840.10008.5.1.4.1.1.88.75", + "1.2.840.10008.5.1.4.1.1.88.76", + "1.2.840.10008.5.1.4.1.1.90.1", + "1.2.840.10008.5.1.4.1.1.91.1", + "1.2.840.10008.5.1.4.1.1.104.1", + "1.2.840.10008.5.1.4.1.1.104.2", + "1.2.840.10008.5.1.4.1.1.104.3", + "1.2.840.10008.5.1.4.1.1.104.4", + "1.2.840.10008.5.1.4.1.1.104.5", + "1.2.840.10008.5.1.4.1.1.131", + "1.2.840.10008.5.1.4.1.1.200.2", + "1.2.840.10008.5.1.4.1.1.200.8", + "1.2.840.10008.5.1.4.1.1.481.2", + "1.2.840.10008.5.1.4.1.1.481.3", + "1.2.840.10008.5.1.4.1.1.481.4", + "1.2.840.10008.5.1.4.1.1.481.5", + "1.2.840.10008.5.1.4.1.1.481.6", + "1.2.840.10008.5.1.4.1.1.481.7", + "1.2.840.10008.5.1.4.1.1.481.8", + "1.2.840.10008.5.1.4.1.1.481.9", + "1.2.840.10008.5.1.4.1.1.481.10", + "1.2.840.10008.5.1.4.1.1.481.11", + "1.2.840.10008.5.1.4.1.1.481.12", + "1.2.840.10008.5.1.4.1.1.481.13", + "1.2.840.10008.5.1.4.1.1.481.14", + "1.2.840.10008.5.1.4.1.1.481.15", + "1.2.840.10008.5.1.4.1.1.481.16", + "1.2.840.10008.5.1.4.1.1.481.17", + "1.2.840.10008.5.1.4.1.1.481.18", + "1.2.840.10008.5.1.4.1.1.481.19", + "1.2.840.10008.5.1.4.1.1.481.20", + "1.2.840.10008.5.1.4.1.1.481.21", + "1.2.840.10008.5.1.4.1.1.481.22", + "1.2.840.10008.5.1.4.1.1.481.25", + "1.2.840.10008.5.1.4.34.7", + "1.2.840.10008.5.1.4.34.10" ];