diff --git a/api/dicom-web/controller/WADO-RS/rendered/instanceFrames.js b/api/dicom-web/controller/WADO-RS/rendered/instanceFrames.js index 6baa8a39..7df99692 100644 --- a/api/dicom-web/controller/WADO-RS/rendered/instanceFrames.js +++ b/api/dicom-web/controller/WADO-RS/rendered/instanceFrames.js @@ -1,7 +1,6 @@ const _ = require("lodash"); const renderedService = require("../service/rendered.service"); -const dicomModel = require("../../../../../models/mongodb/models/dicom"); -const { MultipartWriter } = require("../../../../../utils/multipartWriter"); +const { InstanceImagePathFactory } = require("../service/WADO-RS.service"); const errorResponse = require("../../../../../utils/errorResponse/errorResponseMessage"); const { ApiLogger } = require("../../../../../utils/logs/api-logger"); const { Controller } = require("../../../../controller.class"); @@ -34,58 +33,22 @@ class RetrieveRenderedInstanceFramesController extends Controller { } try { - let imagePathObj = await dicomModel.getPathOfInstance(this.request.params); + let renderedImageMultipartWriter = new renderedService.RenderedImageMultipartWriter( + this.request, + this.response, + InstanceImagePathFactory, + renderedService.InstanceFramesListWriter + ); - if(!imagePathObj) { - return this.responseNotFound(); - } + let buffer = await renderedImageMultipartWriter.write(); - let instanceFramesObj = await renderedService.getInstanceFrameObj(this.request.params); - 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); - - for(let i = 0; i < frameNumber.length ; i++) { - let frame = frameNumber[i]; - if (frame > dicomNumberOfFrames) { - let badRequestMessage = errorResponse.getBadRequestErrorMessage(`Bad frame number , This instance NumberOfFrames is : ${dicomNumberOfFrames} , But request ${frameNumber}`); - this.response.writeHead(badRequestMessage.HttpStatus, { - "Content-Type": "application/dicom+json" - }); - - let badRequestMessageStr = JSON.stringify(badRequestMessage); - - this.apiLogger.logger.warn(badRequestMessageStr); - - return this.response.end(JSON.stringify(badRequestMessageStr)); - } - } - - let transferSyntax = _.get(instanceFramesObj, "00020010.Value.0"); - if (frameNumber.length == 1) { - let postProcessResult = await renderedService.postProcessFrameImage(this.request, frameNumber[0], instanceFramesObj, transferSyntax); - if (postProcessResult.status) { - this.response.writeHead(200, { - "Content-Type": "image/jpeg" - }); - 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]}`); - } else { - let multipartWriter = new MultipartWriter([], this.request, this.response); - await renderedService.writeSpecificFramesRenderedImages(this.request, frameNumber, instanceFramesObj, multipartWriter); - multipartWriter.writeFinalBoundary(); - - this.apiLogger.logger.info(`Get instance's frame successfully, instance UID: ${instanceUID}, frame numbers: ${frameNumber}`); - - return this.response.end(); + this.apiLogger.logger.info(`Get instance's frame successfully, instance UID: ${instanceUID}, frame number: ${JSON.stringify(frameNumber)}`); + + if (buffer instanceof Buffer) { + return this.response.end(buffer, "binary"); } + + return this.response.end(); } catch(e) { console.error(e); this.response.writeHead(500, { @@ -94,18 +57,6 @@ 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 7a4b6401..e71810c5 100644 --- a/api/dicom-web/controller/WADO-RS/rendered/instances.js +++ b/api/dicom-web/controller/WADO-RS/rendered/instances.js @@ -1,11 +1,10 @@ const _ = require("lodash"); const mongoose = require("mongoose"); const renderedService = require("../service/rendered.service"); -const { MultipartWriter } = require("../../../../../utils/multipartWriter"); +const { InstanceImagePathFactory } = require("../service/WADO-RS.service"); const errorResponse = require("../../../../../utils/errorResponse/errorResponseMessage"); const { ApiLogger } = require("../../../../../utils/logs/api-logger"); const { Controller } = require("../../../../controller.class"); -const dicomModel = require("../../../../../models/mongodb/models/dicom"); class RetrieveRenderedInstancesController extends Controller { constructor(req, res) { @@ -29,21 +28,14 @@ class RetrieveRenderedInstancesController extends Controller { } try { - let imagePathObj = await dicomModel.getPathOfInstance(this.request.params); - - 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); - multipartWriter.writeFinalBoundary(); - } + let renderedImageMultipartWriter = new renderedService.RenderedImageMultipartWriter( + this.request, + this.response, + InstanceImagePathFactory, + renderedService.InstanceFramesWriter + ); + + await renderedImageMultipartWriter.write(); apiLogger.logger.info(`Write Multipart Successfully, study's series' instances' rendered images, study UID: ${this.request.params.studyUID}, series UID: ${this.request.params.seriesUID}, instance UID: ${this.request.params.instanceUID}`); return this.response.end(); diff --git a/api/dicom-web/controller/WADO-RS/rendered/series.js b/api/dicom-web/controller/WADO-RS/rendered/series.js index d3e35e70..bfa027f3 100644 --- a/api/dicom-web/controller/WADO-RS/rendered/series.js +++ b/api/dicom-web/controller/WADO-RS/rendered/series.js @@ -1,7 +1,7 @@ const mongoose = require("mongoose"); const _ = require("lodash"); const renderedService = require("../service/rendered.service"); -const { MultipartWriter } = require("../../../../../utils/multipartWriter"); +const { SeriesImagePathFactory } = require("../service/WADO-RS.service"); const errorResponse = require("../../../../../utils/errorResponse/errorResponseMessage"); const { logger } = require("../../../../../utils/logs/log"); const { Controller } = require("../../../../controller.class"); @@ -23,24 +23,14 @@ class RetrieveRenderedSeriesController extends Controller { } try { - let instancesInSeries = await mongoose.model("dicomSeries").getPathGroupOfInstances(this.request.params); - - if (instancesInSeries.length > 0) { - let multipartWriter = new MultipartWriter([], this.request, this.response); - - 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); - } - multipartWriter.writeFinalBoundary(); - } else { - this.response.writeHead(404, { - "content-type": "application/dicom+json" - }); - } + let renderedImageMultipartWriter = new renderedService.RenderedImageMultipartWriter( + this.request, + this.response, + SeriesImagePathFactory, + renderedService.SeriesFramesWriter + ); + + await renderedImageMultipartWriter.write(); logger.info(`[WADO-RS] [path: ${this.request.originalUrl}] [Write Multipart Successfully, study's series' rendered instances, study UID: ${this.request.params.studyUID}, series UID: ${this.request.params.seriesUID}]`); diff --git a/api/dicom-web/controller/WADO-RS/rendered/study.js b/api/dicom-web/controller/WADO-RS/rendered/study.js index 1acd21e6..9a8e14f9 100644 --- a/api/dicom-web/controller/WADO-RS/rendered/study.js +++ b/api/dicom-web/controller/WADO-RS/rendered/study.js @@ -1,7 +1,9 @@ const mongoose = require("mongoose"); const _ = require("lodash"); const renderedService = require("../service/rendered.service"); -const { MultipartWriter } = require("../../../../../utils/multipartWriter"); +const { + StudyImagePathFactory +} = require("../service/WADO-RS.service"); const errorResponse = require("../../../../../utils/errorResponse/errorResponseMessage"); const { ApiLogger } = require("../../../../../utils/logs/api-logger"); const { Controller } = require("../../../../controller.class"); @@ -27,24 +29,15 @@ class RetrieveRenderedStudyController extends Controller { } try { - let pathGroupOfInstancesInStudy = await mongoose.model("dicomStudy").getPathGroupOfInstances(this.request.params); - if (pathGroupOfInstancesInStudy.length > 0) { - let multipartWriter = new MultipartWriter([], this.request, this.response); - - 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); - } - multipartWriter.writeFinalBoundary(); - } else { - this.response.writeHead(404, { - "content-type": "application/dicom+json" - }); - } + let renderedImageMultipartWriter = new renderedService.RenderedImageMultipartWriter( + this.request, + this.response, + StudyImagePathFactory, + renderedService.StudyFramesWriter + ); + + await renderedImageMultipartWriter.write(); apiLogger.logger.info(`Write Multipart Successfully, study's rendered instances, study UID: ${this.request.params.studyUID}`); 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 c6e0f0c1..469a160e 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 @@ -246,6 +246,7 @@ module.exports.getAcceptType = getAcceptType; module.exports.supportInstanceMultipartType = supportInstanceMultipartType; module.exports.sendNotSupportedMediaType = sendNotSupportedMediaType; module.exports.addHostnameOfBulkDataUrl = addHostnameOfBulkDataUrl; +module.exports.ImagePathFactory = ImagePathFactory; module.exports.StudyImagePathFactory = StudyImagePathFactory; module.exports.SeriesImagePathFactory = SeriesImagePathFactory; module.exports.InstanceImagePathFactory = InstanceImagePathFactory; 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 9711a76c..1e3b7a81 100644 --- a/api/dicom-web/controller/WADO-RS/service/rendered.service.js +++ b/api/dicom-web/controller/WADO-RS/service/rendered.service.js @@ -2,11 +2,14 @@ const path = require("path"); const mongoose = require("mongoose"); const fs = require("fs"); const sharp = require("sharp"); +const _ = require("lodash"); 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 { MultipartWriter } = require("../../../../../utils/multipartWriter"); const notImageSOPClass = require("../../../../../models/DICOM/dicomWEB/notImageSOPClass"); const Magick = require("../../../../../models/magick"); -const _ = require("lodash"); +const errorResponse = require("../../../../../utils/errorResponse/errorResponseMessage"); +const { logger } = require("../../../../../utils/logs/log"); const { raccoonConfig } = require("../../../../../config-class"); @@ -98,6 +101,170 @@ const { raccoonConfig } = require("../../../../../config-class"); } } } + +class RenderedImageMultipartWriter { + + /** + * + * @param {import('express').Request} req + * @param {import('express').Response} res + * @param {boolean} isMultiple + * @param {typeof import('./WADO-RS.service.js').ImagePathFactory} imagePathFactory + * @param {typeof FramesWriter} + */ + constructor(req, res, imagePathFactory, framesWriterClass) { + /** @type {import('express').Request} */ + this.request = req; + /** @type {import('express').Response} */ + this.response = res; + /** @type {import('./WADO-RS.service.js').ImagePathFactory} */ + this.imagePathFactory = new imagePathFactory(req.params); + /** @type {typeof FramesWriter} */ + this.framesWriterClass = framesWriterClass; + } + + async write() { + await this.imagePathFactory.getImagePaths(); + let checkAllImageExistResult = await this.imagePathFactory.checkAllImageExist(); + this.response.statusCode = checkAllImageExistResult.code; + if (!checkAllImageExistResult.status) { + this.response.setHeader("Content-Type", "application/dicom+json"); + return this.response.json(checkAllImageExistResult); + } + + let framesWriter = new this.framesWriterClass( + this.request, + this.response, + this.imagePathFactory.imagePaths + ); + return await framesWriter.write(); + } +} + +class FramesWriter { + /** + * + * @param {import("../../../../../utils/typeDef/WADO-RS/WADO-RS.def").ImagePathObj[]} imagePaths + */ + constructor(req, res, imagePaths) { + this.request = req; + this.response = res; + this.imagePaths = imagePaths; + } + + async write() { + let multipartWriter = new MultipartWriter([], this.request, this.response); + for(let imagePathObj of this.imagePaths) { + let instanceFramesObj = await getInstanceFrameObj(imagePathObj); + if(_.isUndefined(instanceFramesObj)) continue; + let dicomNumberOfFrames = _.get(instanceFramesObj, "00280008.Value.0", 1); + dicomNumberOfFrames = parseInt(dicomNumberOfFrames); + await writeRenderedImages(this.request, dicomNumberOfFrames, instanceFramesObj, multipartWriter); + } + multipartWriter.writeFinalBoundary(); + } +} + +class StudyFramesWriter extends FramesWriter { + /** + * + * @param {import("../../../../../utils/typeDef/WADO-RS/WADO-RS.def").ImagePathObj[]} imagePaths + */ + constructor(req, res, imagePaths) { + super(req, res, imagePaths); + } +} + +class SeriesFramesWriter extends FramesWriter { + constructor(req, res, imagePaths) { + super(req, res, imagePaths); + } +} + +class InstanceFramesWriter extends FramesWriter { + constructor(req, res, imagePaths) { + super(req, res, imagePaths); + } + + async write() { + let multipartWriter = new MultipartWriter([], this.request, this.response); + let instanceFramesObj = await getInstanceFrameObj(this.imagePaths[0]); + 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 writeRenderedImages(this.request, dicomNumberOfFrames, instanceFramesObj, multipartWriter); + multipartWriter.writeFinalBoundary(); + } +} + +class InstanceFramesListWriter extends FramesWriter { + constructor(req, res, imagePaths) { + super(req, res, imagePaths); + this.instanceFramesObj = {}; + this.dicomNumberOfFrames = 1; + } + + async write() { + let {frameNumber} = this.request.params; + + this.instanceFramesObj = await getInstanceFrameObj(this.imagePaths[0]); + if (_.isUndefined(this.instanceFramesObj)) { + return this.response.status(400).json( + errorResponse.getBadRequestErrorMessage(`instance: ${this.request.params.instanceUID} doesn't have pixel data`) + ); + } + this.dicomNumberOfFrames = _.get(this.instanceFramesObj, "00280008.Value.0", 1); + this.dicomNumberOfFrames = parseInt(this.dicomNumberOfFrames); + + if (this.isInvalidFrameNumber()) return; + + if (frameNumber.length == 1) { + return this.writeSingleFrame(); + } else { + let multipartWriter = new MultipartWriter([], this.request, this.response); + await writeSpecificFramesRenderedImages(this.request, frameNumber, this.instanceFramesObj, multipartWriter); + multipartWriter.writeFinalBoundary(); + return true; + } + } + + isInvalidFrameNumber() { + for(let i = 0; i < this.request.params.frameNumber.length ; i++) { + let frame = this.request.params.frameNumber[i]; + if (frame > this.dicomNumberOfFrames) { + let badRequestMessage = errorResponse.getBadRequestErrorMessage(`Bad frame number , \ +This instance NumberOfFrames is : ${this.dicomNumberOfFrames} , But request ${JSON.stringify(this.request.params.frameNumber)}`); + this.response.writeHead(badRequestMessage.HttpStatus, { + "Content-Type": "application/dicom+json" + }); + + let badRequestMessageStr = JSON.stringify(badRequestMessage); + + logger.warn(badRequestMessageStr); + + return this.response.end(JSON.stringify(badRequestMessageStr)); + } + } + return false; + } + + async writeSingleFrame() { + let postProcessResult = await postProcessFrameImage(this.request, this.request.params.frameNumber[0], this.instanceFramesObj); + if (postProcessResult.status) { + this.response.writeHead(200, { + "Content-Type": "image/jpeg" + }); + + return postProcessResult.magick.toBuffer(); + } + throw new Error(`Can not process this image, instanceUID: ${this.instanceFramesObj.instanceUID}, frameNumber: ${this.request.frameNumber[0]}`); + } +} + /** * * @param {Object} iParam @@ -260,4 +427,9 @@ module.exports.handleViewport = handleViewport; module.exports.getInstanceFrameObj = getInstanceFrameObj; module.exports.postProcessFrameImage = postProcessFrameImage; module.exports.writeRenderedImages = writeRenderedImages; -module.exports.writeSpecificFramesRenderedImages = writeSpecificFramesRenderedImages; \ No newline at end of file +module.exports.writeSpecificFramesRenderedImages = writeSpecificFramesRenderedImages; +module.exports.RenderedImageMultipartWriter = RenderedImageMultipartWriter; +module.exports.StudyFramesWriter = StudyFramesWriter; +module.exports.SeriesFramesWriter = SeriesFramesWriter; +module.exports.InstanceFramesWriter = InstanceFramesWriter; +module.exports.InstanceFramesListWriter = InstanceFramesListWriter; \ No newline at end of file