{"id":13812442,"url":"https://github.com/PantelisGeorgiadis/dcmjs-dimse","last_synced_at":"2025-05-14T22:30:40.290Z","repository":{"id":38205058,"uuid":"358926898","full_name":"PantelisGeorgiadis/dcmjs-dimse","owner":"PantelisGeorgiadis","description":"DICOM DIMSE implementation for Node.js using the dcmjs library","archived":false,"fork":false,"pushed_at":"2025-05-09T13:18:00.000Z","size":1970,"stargazers_count":79,"open_issues_count":2,"forks_count":15,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-05-09T13:18:14.685Z","etag":null,"topics":["dicom","dimse","pacs"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/PantelisGeorgiadis.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"PantelisGeorgiadis"}},"created_at":"2021-04-17T16:21:52.000Z","updated_at":"2025-05-09T13:14:44.000Z","dependencies_parsed_at":"2023-02-12T21:35:13.828Z","dependency_job_id":"35e27b32-d26c-4991-bad7-641b27395104","html_url":"https://github.com/PantelisGeorgiadis/dcmjs-dimse","commit_stats":{"total_commits":41,"total_committers":6,"mean_commits":6.833333333333333,"dds":0.3902439024390244,"last_synced_commit":"e5f1bc136ee9e24ef033d62cd8c5d028e0361467"},"previous_names":[],"tags_count":47,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PantelisGeorgiadis%2Fdcmjs-dimse","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PantelisGeorgiadis%2Fdcmjs-dimse/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PantelisGeorgiadis%2Fdcmjs-dimse/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PantelisGeorgiadis%2Fdcmjs-dimse/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/PantelisGeorgiadis","download_url":"https://codeload.github.com/PantelisGeorgiadis/dcmjs-dimse/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254239445,"owners_count":22037713,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dicom","dimse","pacs"],"created_at":"2024-08-04T04:00:51.949Z","updated_at":"2025-05-14T22:30:40.277Z","avatar_url":"https://github.com/PantelisGeorgiadis.png","language":"JavaScript","funding_links":["https://github.com/sponsors/PantelisGeorgiadis"],"categories":["Libraries"],"sub_categories":["JavaScript"],"readme":"[![NPM version][npm-version-image]][npm-url] [![NPM downloads][npm-downloads-image]][npm-url] [![build][build-image]][build-url] [![MIT License][license-image]][license-url] \n\n# dcmjs-dimse\nDICOM DIMSE implementation for Node.js using Steve Pieper's [dcmjs][dcmjs-url] library.\nThis library was inspired by [fo-dicom][fo-dicom-url] and [mdcm][mdcm-url].\nPart of the networking code was taken from [dicom-dimse][dicom-dimse-url].\n\n### Note\n**This effort is a work-in-progress and should not be used for production or clinical purposes.**\n\n### Install\n\n\tnpm install dcmjs-dimse\n\n### Build\n\n\tnpm install\n\tnpm run build\n\n### Features\n- Implements C-ECHO, C-FIND, C-STORE, C-MOVE, C-GET, C-CANCEL, N-CREATE, N-ACTION, N-DELETE, N-EVENT-REPORT, N-GET and N-SET services as SCU and SCP.\n- Supports secure DICOM TLS connections and user identity negotiation.\n- Transcodes sent and received datasets among all major accepted transfer syntaxes (using the [dcmjs-codecs][dcmjs-codecs-url] library).\n- Allows custom DICOM implementations (Implementation Class UID and Implementation Version).\n- Provides asynchronous event handlers and streaming support for incoming SCP requests.\n\n\n#### Supported Transfer Syntaxes\n- Implicit VR Little Endian (1.2.840.10008.1.2)\n- Explicit VR Little Endian (1.2.840.10008.1.2.1)\n- Explicit VR Big Endian (1.2.840.10008.1.2.2)\n- RLE Lossless (1.2.840.10008.1.2.5)\n- JPEG Baseline - Process 1 (1.2.840.10008.1.2.4.50)\n- JPEG Lossless, Nonhierarchical, First-Order Prediction - Processes 14 [Selection Value 1] (1.2.840.10008.1.2.4.70)\n- JPEG-LS Lossless Image Compression (1.2.840.10008.1.2.4.80)\n- JPEG-LS Lossy Image Compression - Near-Lossless (1.2.840.10008.1.2.4.81)\n- JPEG 2000 Image Compression - Lossless Only (1.2.840.10008.1.2.4.90)\n- JPEG 2000 Image Compression (1.2.840.10008.1.2.4.91)\n- High Throughput JPEG 2000 Image Compression - Lossless Only (1.2.840.10008.1.2.4.201)\n- High Throughput JPEG 2000 with RPCL Options Image Compression - Lossless Only (1.2.840.10008.1.2.4.202)\n- High Throughput JPEG 2000 Image Compression (1.2.840.10008.1.2.4.203)\n\n### Examples\n\n#### C-Echo SCU\n```js\nconst dcmjsDimse = require('dcmjs-dimse');\nconst { Client } = dcmjsDimse;\nconst { CEchoRequest } = dcmjsDimse.requests;\nconst { Status } = dcmjsDimse.constants;\n\nconst client = new Client();\nconst request = new CEchoRequest();\nrequest.on('response', (response) =\u003e {\n  if (response.getStatus() === Status.Success) {\n    console.log('Happy!');\n  }\n});\nclient.addRequest(request);\nclient.on('networkError', (e) =\u003e {\n  console.log('Network error: ', e);\n});\nclient.send('127.0.0.1', 12345, 'SCU', 'ANY-SCP');\n```\n\n#### C-Find SCU (Studies)\n```js\nconst dcmjsDimse = require('dcmjs-dimse');\nconst { Client } = dcmjsDimse;\nconst { CFindRequest } = dcmjsDimse.requests;\nconst { Status } = dcmjsDimse.constants;\n\nconst client = new Client();\nconst request = CFindRequest.createStudyFindRequest({ PatientID: '12345', PatientName: '*' });\nrequest.on('response', (response) =\u003e {\n  if (response.getStatus() === Status.Pending \u0026\u0026 response.hasDataset()) {\n    console.log(response.getDataset());\n  }\n});\nclient.addRequest(request);\nclient.on('networkError', (e) =\u003e {\n  console.log('Network error: ', e);\n});\nclient.send('127.0.0.1', 12345, 'SCU', 'ANY-SCP');\n```\n\n#### C-Store SCU\n```js\nconst dcmjsDimse = require('dcmjs-dimse');\nconst { Client, Transcoding } = dcmjsDimse;\nconst { CStoreRequest } = dcmjsDimse.requests;\nconst { TransferSyntax } = dcmjsDimse.constants;\n\n// Optionally initialize encapsulated syntaxes transcoding.\n// If transcoding is not initialized, only uncompressed\n// syntaxes would be able to be transcoded.\nawait Transcoding.initializeAsync();\n\nconst client = new Client();\nconst request = new CStoreRequest('test.dcm');\nrequest.setAdditionalTransferSyntaxes([TransferSyntax.Jpeg2000Lossless]);\nclient.addRequest(request);\nclient.on('networkError', (e) =\u003e {\n  console.log('Network error: ', e);\n});\nclient.send('127.0.0.1', 12345, 'SCU', 'ANY-SCP');\n```\n\n#### C-Move SCU\n```js\nconst dcmjsDimse = require('dcmjs-dimse');\nconst { Client } = dcmjsDimse;\nconst { CMoveRequest } = dcmjsDimse.requests;\nconst { Status } = dcmjsDimse.constants;\n\nconst client = new Client();\nconst request = CMoveRequest.createStudyMoveRequest('DEST-AE', studyInstanceUid);\nrequest.on('response', (response) =\u003e {\n  if (response.getStatus() === Status.Pending) {\n    console.log('Remaining: ' + response.getRemaining());\n    console.log('Completed: ' + response.getCompleted());\n    console.log('Warning: ' + response.getWarnings());\n    console.log('Failed: ' + response.getFailures());\n  }\n});\nclient.addRequest(request);\nclient.on('networkError', (e) =\u003e {\n  console.log('Network error: ', e);\n});\nclient.send('127.0.0.1', 12345, 'SCU', 'ANY-SCP');\n```\n\n#### C-Get SCU\n```js\nconst dcmjsDimse = require('dcmjs-dimse');\nconst { Client } = dcmjsDimse;\nconst { CGetRequest } = dcmjsDimse.requests;\nconst { CStoreResponse } = dcmjsDimse.responses;\nconst { Status } = dcmjsDimse.constants;\n\nconst client = new Client();\nconst request = CGetRequest.createStudyGetRequest(studyInstanceUid);\nrequest.on('response', (response) =\u003e {\n  if (response.getStatus() === Status.Pending) {\n    console.log('Remaining: ' + response.getRemaining());\n    console.log('Completed: ' + response.getCompleted());\n    console.log('Warning: ' + response.getWarnings());\n    console.log('Failed: ' + response.getFailures());\n  }\n});\nclient.on('cStoreRequest', (request, callback) =\u003e {\n  console.log(request.getDataset());\n\n  const response = CStoreResponse.fromRequest(request);\n  response.setStatus(Status.Success);\n  callback(response);\n});\nclient.addRequest(request);\nclient.on('networkError', (e) =\u003e {\n  console.log('Network error: ', e);\n});\nclient.send('127.0.0.1', 12345, 'SCU', 'ANY-SCP');\n```\n\n#### SCP\n```js\nconst dcmjsDimse = require('dcmjs-dimse');\nconst { Dataset, Server, Scp, Transcoding } = dcmjsDimse;\nconst { CEchoResponse, CFindResponse, CStoreResponse } = dcmjsDimse.responses;\nconst {\n  Status,\n  PresentationContextResult,\n  UserIdentityType,\n  RejectResult,\n  RejectSource,\n  RejectReason,\n  TransferSyntax,\n  SopClass,\n  StorageClass,\n} = dcmjsDimse.constants;\n\nclass DcmjsDimseScp extends Scp {\n  constructor(socket, opts) {\n    super(socket, opts);\n    this.association = undefined;\n  }\n\n  // Handle incoming association requests\n  associationRequested(association) {\n    this.association = association;\n\n    // Evaluate calling/called AET and reject association, if needed\n    if (this.association.getCallingAeTitle() !== 'SCU') {\n      this.sendAssociationReject(\n        RejectResult.Permanent,\n        RejectSource.ServiceUser,\n        RejectReason.CallingAeNotRecognized\n      );\n      return;\n    }\n\n    // Evaluate user identity and reject association, if needed\n    if (\n      this.association.getNegotiateUserIdentity() \u0026\u0026\n      this.association.getUserIdentityPositiveResponseRequested()\n    ) {\n      if (\n        this.association.getUserIdentityType() === UserIdentityType.UsernameAndPasscode \u0026\u0026\n        this.association.getUserIdentityPrimaryField() === 'USERNAME' \u0026\u0026\n        this.association.getUserIdentitySecondaryField() === 'PASSWORD'\n      ) {\n        this.association.setUserIdentityServerResponse('');\n        this.association.setNegotiateUserIdentityServerResponse(true);\n      } else {\n        this.sendAssociationReject(\n          RejectResult.Permanent,\n          RejectSource.ServiceUser,\n          RejectReason.NoReasonGiven\n        );\n        return;\n      }\n    }\n\n    // Optionally set the preferred max PDU length\n    this.association.setMaxPduLength(65536);\n\n    const contexts = association.getPresentationContexts();\n    contexts.forEach((c) =\u003e {\n      const context = association.getPresentationContext(c.id);\n      if (\n        context.getAbstractSyntaxUid() === SopClass.Verification ||\n        context.getAbstractSyntaxUid() === SopClass.StudyRootQueryRetrieveInformationModelFind ||\n        context.getAbstractSyntaxUid() === StorageClass.MrImageStorage\n        // Accept other presentation contexts, as needed\n      ) {\n        const transferSyntaxes = context.getTransferSyntaxUids();\n        transferSyntaxes.forEach((transferSyntax) =\u003e {\n          if (\n            transferSyntax === TransferSyntax.ImplicitVRLittleEndian ||\n            transferSyntax === TransferSyntax.ExplicitVRLittleEndian\n          ) {\n            context.setResult(PresentationContextResult.Accept, transferSyntax);\n          } else {\n            context.setResult(PresentationContextResult.RejectTransferSyntaxesNotSupported);\n          }\n        });\n      } else {\n        context.setResult(PresentationContextResult.RejectAbstractSyntaxNotSupported);\n      }\n    });\n    this.sendAssociationAccept();\n  }\n\n  // Handle incoming C-ECHO requests\n  cEchoRequest(request, callback) {\n    const response = CEchoResponse.fromRequest(request);\n    response.setStatus(Status.Success);\n    \n    callback(response);\n  }\n\n  // Handle incoming C-FIND requests\n  cFindRequest(request, callback) {\n    console.log(request.getDataset());\n\n    const pendingResponse = CFindResponse.fromRequest(request);\n    pendingResponse.setDataset(new Dataset({ PatientID: '12345', PatientName: 'JOHN^DOE' }));\n    pendingResponse.setStatus(Status.Pending);\n\n    const finalResponse = CFindResponse.fromRequest(request);\n    finalResponse.setStatus(Status.Success);\n\n    callback([pendingResponse, finalResponse]);\n  }\n\n  // Handle incoming C-STORE requests\n  cStoreRequest(request, callback) {\n    console.log(request.getDataset());\n\n    const response = CStoreResponse.fromRequest(request);\n    response.setStatus(Status.Success);\n\n    callback(response);\n  }\n\n  // Handle incoming association release requests\n  associationReleaseRequested() {\n    this.sendAssociationReleaseResponse();\n  }\n}\n\n// Optionally initialize encapsulated syntaxes transcoding.\n// If transcoding is not initialized, only uncompressed\n// syntaxes would be able to be transcoded.\nawait Transcoding.initializeAsync();\n\nconst server = new Server(DcmjsDimseScp);\nserver.on('networkError', (e) =\u003e {\n  console.log('Network error: ', e);\n});\nserver.listen(port);\n\n// When done\nserver.close();\n```\nPlease check the respecting [Wiki][dcmjs-dimse-wiki-examples-url] section for more examples.\n\n### Related libraries\n* [dcmjs-imaging][dcmjs-imaging-url] - DICOM image and overlay rendering for Node.js and browser using dcmjs.\n* [dcmjs-codecs][dcmjs-codecs-url] - DICOM file and dataset transcoding for Node.js and browser using dcmjs.\n* [dcmjs-ecg][dcmjs-ecg-url] - DICOM electrocardiography (ECG) rendering for Node.js and browser using dcmjs.\n\n### License\ndcmjs-dimse is released under the MIT License.\n\n### Sponsors\nThe following organizations supported the dcmjs-dimse development.\n* [HeartLab][sponsors-heartlab-url] - A Cardiology Imaging Platform That Lets You Work Smarter.\n\n[npm-url]: https://npmjs.org/package/dcmjs-dimse\n[npm-version-image]: https://img.shields.io/npm/v/dcmjs-dimse.svg?style=flat\n[npm-downloads-image]: http://img.shields.io/npm/dm/dcmjs-dimse.svg?style=flat\n\n[build-url]: https://github.com/PantelisGeorgiadis/dcmjs-dimse/actions/workflows/build.yml\n[build-image]: https://github.com/PantelisGeorgiadis/dcmjs-dimse/actions/workflows/build.yml/badge.svg?branch=master\n\n[license-image]: https://img.shields.io/badge/license-MIT-blue.svg?style=flat\n[license-url]: LICENSE.txt\n\n[dcmjs-url]: https://github.com/dcmjs-org/dcmjs\n[fo-dicom-url]: https://github.com/fo-dicom/fo-dicom\n[mdcm-url]: https://github.com/fo-dicom/mdcm\n[dicom-dimse-url]: https://github.com/OHIF/dicom-dimse\n[dcmjs-imaging-url]: https://github.com/PantelisGeorgiadis/dcmjs-imaging\n[dcmjs-codecs-url]: https://github.com/PantelisGeorgiadis/dcmjs-codecs\n[dcmjs-ecg-url]: https://github.com/PantelisGeorgiadis/dcmjs-ecg\n\n[dcmjs-dimse-wiki-examples-url]: https://github.com/PantelisGeorgiadis/dcmjs-dimse/wiki/Examples\n\n[sponsors-heartlab-url]: https://heartlab.com\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FPantelisGeorgiadis%2Fdcmjs-dimse","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FPantelisGeorgiadis%2Fdcmjs-dimse","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FPantelisGeorgiadis%2Fdcmjs-dimse/lists"}