Skip to content

Commit

Permalink
feat: add writeFrames in multipartWriter
Browse files Browse the repository at this point in the history
- Use `MultipartWriter.writeFrames` instead of `writeframesMultipart`
- Add express response object to constructor
- Add express request object to constructor
- Refactor every res of arg to `this.res`
- Add `setHeaderMultipartRelatedContentType`  to
set content type of headers
- Add `writeContentLocation` to write content location
  • Loading branch information
Chinlinlee committed Mar 29, 2022
1 parent 2f3510f commit 222c033
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 29 deletions.
8 changes: 4 additions & 4 deletions api/dicom-web/controller/wado-rs-framenumber.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ const mongodb = require('../../../models/mongodb');
const mongoFunc = require('../../../models/mongodb/func');
const _ = require('lodash');
const DICOMWebHandleError = require('../../../models/DICOMWeb/httpMessage');
const { writeframesMultipart} = require('../../../models/DICOMWeb')
const { MultipartWriter } = require('../../../utils/multipartWriter');

let multipartFunc = {};
multipartFunc["image/jpeg"] = {
Expand Down Expand Up @@ -44,9 +44,9 @@ multipartFunc["image/jpeg"] = {
DICOMWebHandleError.sendBadRequestMessage(res , `Bad frame number , This instance NumberOfFrames is : ${dicomNumberOfFrames} , But request ${maxFrameNumber}`);
return resolve(false);
}
res.set('content-type',`multipart/related; type=${type}`)
await writeframesMultipart(req , res , imagesPath , type , frameList)
return resolve(true);
let multipartWriter = new MultipartWriter(imagesPath, res, req);
await multipartWriter.writeFrames(type, frameList);
return resolve(true);
}
DICOMWebHandleError.sendNotFoundMessage(req , res);
return resolve(false);
Expand Down
12 changes: 6 additions & 6 deletions api/dicom-web/controller/wado-rs.js
Original file line number Diff line number Diff line change
Expand Up @@ -217,20 +217,20 @@ let multipartFunc = {
getStudyDicom : async function (iParam , res , type) {
logger.info(`[Write DICOM files of study] [Params: ${JSON.stringify(iParam)}]`);
let imagesPath = await mongoFunc.getStudyImagesPath(iParam);
let multipartWriter = new MultipartWriter(imagesPath);
return multipartWriter.writeDICOMFiles(res, type);
let multipartWriter = new MultipartWriter(imagesPath, res);
return multipartWriter.writeDICOMFiles(type);
} ,
getSeriesDicom : async function (iParam , res , type) {
logger.info(`[Write DICOM files of series] [Params: ${JSON.stringify(iParam)}]`);
let seriesImagesPath = await mongoFunc.getSeriesImagesPath(iParam);
let multipartWriter = new MultipartWriter(seriesImagesPath);
return multipartWriter.writeDICOMFiles(res, type);
let multipartWriter = new MultipartWriter(seriesImagesPath, res);
return multipartWriter.writeDICOMFiles(type);
} ,
getInstance : async function (iParam , res , type) {
logger.info(`[Write DICOM files of instance] [Params: ${JSON.stringify(iParam)}]`);
let imagesPath = await mongoFunc.getInstanceImagePath(iParam);
let multipartWriter = new MultipartWriter(imagesPath);
return multipartWriter.writeDICOMFiles(res, type);
let multipartWriter = new MultipartWriter(imagesPath, res);
return multipartWriter.writeDICOMFiles(type);
}
} ,
}
Expand Down
120 changes: 101 additions & 19 deletions utils/multipartWriter.js
Original file line number Diff line number Diff line change
@@ -1,56 +1,100 @@
const { logger } = require('../utils/log');
const uuid = require('uuid');
const fs = require('fs');
const _ = require('lodash');
const dicomParser = require('dicom-parser');
const { streamToBuffer } = require('@jorgeferrero/stream-to-buffer');
const { dcm2jpegCustomCmd } = require('../models/dcmtk');
const DICOM_STORE_ROOTPATH = process.env.DICOM_STORE_ROOTPATH;

class MultipartWriter {
/**
*
* @param {Array<string>} pathsOfImages The path list of the images
* @param {import('express').Response} res The express response
* @param {import('express').Request} req
*/
constructor(pathsOfImages) {
constructor(pathsOfImages, res, req={}) {
this.BOUNDARY = `${uuid.v4()}-${uuid.v4()}-raccoon`;
this.pathsOfImages = pathsOfImages;
this.res = res;
this.req = req;
//this.responseData = "";
}
async writeBoundary(res, isFirst=false) {

/**
* Write the boundary
* @param {boolean} isFirst Do not write \r\n\r\n when start if true
*/
async writeBoundary(isFirst=false) {
if (isFirst) {
res.write(`--${this.BOUNDARY}\r\n`);
this.res.write(`--${this.BOUNDARY}\r\n`);
} else {
this.res.write(`\r\n\r\n--${this.BOUNDARY}\r\n`);
}
}

/**
* Write final boundary
*/
async writeFinalBoundary() {
this.res.write(`\r\n--${this.BOUNDARY}--`);
}
/**
* Write the content-type. <br/>
* If have transferSyntax, write content-type and transfer-syntax.
* @param {string} type
* @param {string} transferSyntax
*/
async writeContentType(type, transferSyntax="") {
if (transferSyntax) {
this.res.write(`Content-Type: ${type};transfer-syntax=${transferSyntax}\r\n`);
} else {
res.write(`\r\n\r\n--${this.BOUNDARY}\r\n`);
this.res.write(`Content-Type: ${type}\r\n`);
}
}

async writeFinalBoundary(res) {
res.write(`\r\n--${this.BOUNDARY}--`);
/**
* Write the content-length
* @param {number} length length of content
*/
async writeContentLength(length) {
this.res.write('Content-length: ' + length + '\r\n\r\n');
}

async writeContentType(res, type) {
res.write(`Content-Type: ${type}\r\n`);
async writeContentLocation() {
this.res.write(`Content-Location : ${this.req.protocol}://${this.req.headers.host}${this.req.originalUrl}\r\n`);
}

async writeContentLength(res, length) {
res.write('Content-length: ' + length + '\r\n\r\n');
/**
* Write the buffer in response
* @param {Buffer} buffer
*/
async writeBufferData(buffer) {
this.res.write(buffer);
}

async writeBufferData(res, buffer) {
res.write(buffer);
/**
* Set the content-type to "multipart/related; type=${type}; boundary=${boundary}"
* @param {string} type the type of the whole content
*/
async setHeaderMultipartRelatedContentType(type) {
this.res.set("content-type", `multipart/related; type="${type}"; boundary=${this.BOUNDARY}`);
}

async writeDICOMFiles(res, type) {
async writeDICOMFiles(type) {
try {
if (this.pathsOfImages) {
res.set("content-type", `multipart/related; type="${type}"; boundary=${this.BOUNDARY}`);
this.setHeaderMultipartRelatedContentType(type);
for (let i = 0; i < this.pathsOfImages.length; i++) {
console.log(`${DICOM_STORE_ROOTPATH}${this.pathsOfImages[i]}`);
let fileBuffer = await streamToBuffer(fs.createReadStream(`${DICOM_STORE_ROOTPATH}${this.pathsOfImages[i]}`));
this.writeBoundary(res, i===0);
this.writeContentType(res, type);
this.writeContentLength(res, fileBuffer.length);
this.writeBufferData(res, fileBuffer);
this.writeBoundary(i===0);
this.writeContentType(type);
this.writeContentLength(fileBuffer.length);
this.writeBufferData(fileBuffer);
}
this.writeFinalBoundary(res);
this.writeFinalBoundary();
return true;
}
return false;
Expand All @@ -59,6 +103,44 @@ class MultipartWriter {
return false;
}
}

async writeFrames(type, frameList) {
this.setHeaderMultipartRelatedContentType();
let dicomFilename = `${DICOM_STORE_ROOTPATH}${this.pathsOfImages[0]}`;
let jpegFile = dicomFilename.replace(/\.dcm\b/gi, "");
let minFrameNumber = _.min(frameList);
let maxFrameNumber = _.max(frameList);
let frameNumberCount = maxFrameNumber - minFrameNumber + 1;
if (minFrameNumber == maxFrameNumber) {
frameNumberCount = 1;
}
let execCmd = "";
if (process.env.ENV == "windows") {
execCmd = `models/dcmtk/dcmtk-3.6.5-win64-dynamic/bin/dcmj2pnm.exe --write-jpeg "${dicomFilename}" "${jpegFile}" --frame-range ${minFrameNumber} ${frameNumberCount}`;
} else if (process.env.ENV == "linux") {
execCmd = `dcmj2pnm --write-jpeg "${dicomFilename}" "${jpegFile}" --frame-range ${minFrameNumber} ${frameNumberCount}`;
}
let dcm2jpegStatus = await dcm2jpegCustomCmd(execCmd);
if (dcm2jpegStatus) {
for (let x = 0; x < frameList.length; x++) {
let frameJpegFile = dicomFilename.replace(/\.dcm\b/gi, `.${frameList[x] - 1}.jpg`);
let fileBuffer = fs.readFileSync(frameJpegFile);
let dicomFileBuffer = fs.readFileSync(dicomFilename);
let dicomDataSet = dicomParser.parseDicom(dicomFileBuffer, {
untilTag: "x7fe00010"
});
let transferSyntax = dicomDataSet.string('x00020010');
this.writeBoundary(x==0);
this.writeContentType(type, transferSyntax);
this.writeContentLength(fileBuffer.length);
this.writeContentLocation();
this.writeBufferData(fileBuffer);
}
this.writeFinalBoundary();
return true;
}
return false;
}
}


Expand Down

0 comments on commit 222c033

Please sign in to comment.