diff --git a/src/dimse/parseMeta.ts b/src/dimse/parseMeta.ts index b6c6e69..f190f49 100644 --- a/src/dimse/parseMeta.ts +++ b/src/dimse/parseMeta.ts @@ -58,6 +58,32 @@ function parseFile(filename: string): Promise { const sliceThickness = dataset.string('x00180050'); const sliceLocation = dataset.string('x00201041'); + // MR-specific tags for overlay + // TODO: buat ini dynamic berdasarkan includefields atau modality + const spacingBetweenSlices = dataset.string('x00180088'); + const percentPhaseFieldOfView = dataset.string('x00180094'); + const acquisitionMatrixElement = dataset.elements.x00181310; + const acquisitionMatrix = acquisitionMatrixElement + ? [ + dataset.uint16('x00181310', 0), + dataset.uint16('x00181310', 1), + dataset.uint16('x00181310', 2), + dataset.uint16('x00181310', 3), + ] + : null; + const scanningSequence = dataset.string('x00180020'); + const repetitionTime = dataset.string('x00180080'); + const echoTime = dataset.string('x00180081'); + const inversionTime = dataset.string('x00180082'); + const receiveCoilName = dataset.string('x00181250'); + const mrAcquisitionType = dataset.string('x00180023'); + const phaseEncodingDirection = dataset.string('x00181312'); + const echoTrainLength = dataset.string('x00180091'); + const flipAngle = dataset.string('x00181314'); + const pixelBandwidth = dataset.string('x00180095'); + const acquisitionTime = dataset.string('x00080032'); + const parallelAcquisitionTechnique = dataset.string('x00181316'); + // append to all results const result: ElementType = { '00100010': { Value: [{ Alphabetic: patientName }], vr: 'PN' }, @@ -88,7 +114,23 @@ function parseFile(filename: string): Promise { '00200013': { Value: [instanceNumber], vr: 'IS' }, '00180050': { Value: [sliceThickness], vr: 'DS' }, '00201041': { Value: [sliceLocation], vr: 'DS' }, + '00180088': { Value: [spacingBetweenSlices], vr: 'DS' }, + '00180094': { Value: [percentPhaseFieldOfView], vr: 'DS' }, + ...(acquisitionMatrix && { '00181310': { Value: acquisitionMatrix, vr: 'US' } }), + '00180020': { Value: [scanningSequence], vr: 'CS' }, + '00180080': { Value: [repetitionTime], vr: 'DS' }, + '00180081': { Value: [echoTime], vr: 'DS' }, + '00180082': { Value: [inversionTime], vr: 'DS' }, + '00181250': { Value: [receiveCoilName], vr: 'SH' }, + '00180023': { Value: [mrAcquisitionType], vr: 'CS' }, + '00181312': { Value: [phaseEncodingDirection], vr: 'CS' }, + '00180091': { Value: [echoTrainLength], vr: 'IS' }, + '00181314': { Value: [flipAngle], vr: 'DS' }, + '00180095': { Value: [pixelBandwidth], vr: 'DS' }, + '00080032': { Value: [acquisitionTime], vr: 'TM' }, + '00181316': { Value: [parallelAcquisitionTechnique], vr: 'CS' }, }; + resolve(result); }); }); @@ -105,7 +147,7 @@ export function parseMeta(json: object, studyInstanceUID: string, seriesInstance const sopInstanceUid = json[key]['00080018'].Value[0]; const pathname = path.join(storagePath, studyInstanceUID, sopInstanceUid); parsing.push(parseFile(pathname)); - + } return Promise.all(parsing); } diff --git a/src/routes/routes.ts b/src/routes/routes.ts index 62eb669..ed70bcb 100644 --- a/src/routes/routes.ts +++ b/src/routes/routes.ts @@ -51,15 +51,16 @@ module.exports = function (server: FastifyInstance, opts: unknown, done: () => v const hasStudyDate = query.StudyDate !== undefined; if (!hasMedicalRecord && !hasAccessionNumber && !hasPatientName && !hasStudyInstanceUID && !hasStudyDate) { + // TODO: buat startDate tgl H-1 karena terkadang kena Bug beda timezone +-7 di file DICOM nya const startDate = moment().format('YYYYMMDD'); const endDate = moment().format('YYYYMMDD'); query.StudyDate = `${startDate}-${endDate}`; - + // Add time range filter (entire day) const startTime = '000000'; const endTime = '235959'; query['00080030'] = `${startTime}-${endTime}`; // StudyTime (0008,0030) - + logger.info(`Adding default date range filter: ${query.StudyDate}`); logger.info(`Adding default time range filter: ${query['00080030']}`); } @@ -67,14 +68,14 @@ module.exports = function (server: FastifyInstance, opts: unknown, done: () => v logger.info(`Querying studies with filters: ${JSON.stringify(query)}`); const json = deepmerge.all(await doFind(QUERY_LEVEL.STUDY, query), options); - + // Karena by default hasilnya urut StudyTime (ascending), // Maka, jika butuh latest first (descending), maka dibalik urutannya if (Array.isArray(json) && json.length > 0) { logger.info(`Reversing order of ${json.length} studies to show latest first`); json.reverse(); } - + return reply.send(json); } catch (error) { logger.error(error); @@ -410,6 +411,25 @@ module.exports = function (server: FastifyInstance, opts: unknown, done: () => v } }); + server.get<{ + Params: IParamsImage; + Querystring: QueryParams; + }>('/rs/studies/:studyInstanceUid/series/:seriesInstanceUid/instances/:sopInstanceUid/metadata', async (req, reply) => { + const { studyInstanceUid, seriesInstanceUid, sopInstanceUid } = req.params; + const { query } = req; + query.StudyInstanceUID = studyInstanceUid; + query.SeriesInstanceUID = seriesInstanceUid; + query.SOPInstanceUID = sopInstanceUid; + + try { + const rsp = await fetchMeta(query, studyInstanceUid, seriesInstanceUid); + return reply.send(rsp); + } catch (error) { + logger.error(error); + return reply.send(500); + } + }); + done(); };