### N-Create, N-Action, N-Set, N-Delete SCU Example (Print) Source: https://github.com/pantelisgeorgiadis/dcmjs-dimse/wiki/Examples This example demonstrates a complete workflow for N-Create, N-Action, N-Set, and N-Delete operations using the dcmjs-dimse client, specifically for a print job scenario. It includes setting up presentation contexts, creating film sessions and film boxes, setting image data, printing, and finally deleting the created objects. Ensure all necessary imports are present and the client is properly initialized. ```javascript const dcmjsDimse = require('dcmjs-dimse'); const { Client, Dataset } = dcmjsDimse; const { PresentationContext } = dcmjsDimse.association; const { NActionRequest, NCreateRequest, NDeleteRequest, NSetRequest } = dcmjsDimse.requests; const { SopClass, Status, TransferSyntax } = dcmjsDimse.constants; const client = new Client(); const pc = new PresentationContext( 0, SopClass.BasicGrayscalePrintManagementMeta, TransferSyntax.ImplicitVRLittleEndian ); client.addAdditionalPresentationContext(pc); let filmSessionCreateRequest; let filmBoxCreateRequest; let imageBoxSetRequest; let filmBoxPrintRequest; let filmBoxDeleteRequest; let filmSessionDeleteRequest; // Create film session filmSessionCreateRequest = new NCreateRequest( SopClass.BasicFilmSession, '', // No need to provide a UID SopClass.BasicGrayscalePrintManagementMeta ); filmSessionCreateRequest.setDataset( new Dataset({ FilmDestination: 'MAGAZINE', FilmSessionLabel: '', MediumType: '', NumberOfCopies: 1, PrintPriority: 'MED', }) ); filmSessionCreateRequest.on('response', (response) => { if (response.getStatus() === Status.Success) { // Set the referenced film session sequence of the film box creation request // that is returned in the response of the film session creation request const filmBoxDataset = filmBoxCreateRequest.getDataset(); filmBoxDataset.setElement('ReferencedFilmSessionSequence', [ { ReferencedSOPClassUID: SopClass.BasicFilmSession, ReferencedSOPInstanceUID: response.getAffectedSopInstanceUid(), }, ]); // Set the requested SOP instance UID of the film session delete request // that is returned in the response of the film session creation request filmSessionDeleteRequest.setRequestedSopInstanceUid(response.getAffectedSopInstanceUid()); } }); client.addRequest(filmSessionCreateRequest); // Create film box filmBoxCreateRequest = new NCreateRequest( SopClass.BasicFilmBox, '', // No need to provide a UID SopClass.BasicGrayscalePrintManagementMeta ); filmBoxCreateRequest.setDataset( new Dataset({ ConfigurationInformation: '', FilmOrientation: 'PORTRAIT', FilmSizeID: '14INX14IN', ImageDisplayFormat: 'STANDARD\1,1', MagnificationType: 'CUBIC', }) ); filmBoxCreateRequest.on('response', (response) => { if (response.getStatus() === Status.Success) { // Set the requested SOP instance UID of the film box print request // that is returned in the response of the film box creation request filmBoxPrintRequest.setRequestedSopInstanceUid(response.getAffectedSopInstanceUid()); // Set the requested SOP instance UID of the film box delete request // that is returned in the response of the film box creation request filmBoxDeleteRequest.setRequestedSopInstanceUid(response.getAffectedSopInstanceUid()); // Set the requested SOP instance UID of the image box set creation request // that is returned in the response of the film box creation request const dataset = response.getDataset(); const referencedImageBoxSequenceItem = dataset.getElement('ReferencedImageBoxSequence'); imageBoxSetRequest.setRequestedSopInstanceUid( referencedImageBoxSequenceItem.ReferencedSOPInstanceUID ); } }); client.addRequest(filmBoxCreateRequest); // Set image box imageBoxSetRequest = new NSetRequest( SopClass.BasicGrayscaleImageBox, '', // UID will be set once received SopClass.BasicGrayscalePrintManagementMeta ); // Create a random image const width = 256; const height = 256; const pixels = new Uint8Array(width * height); for (let i = 0; i < height; i++) { for (let j = 0; j < width; j++) { pixels[j * width + i] = Math.floor(Math.random() * Math.pow(2, 8) - 1); } } imageBoxSetRequest.setDataset( new Dataset({ ImageBoxPosition: 1, Polarity: 'NORMAL', RequestedDecimateCropBehavior: 'CROP', BasicGrayscaleImageSequence: [ { _vrMap: { PixelData: 'OB', }, Columns: width, Rows: height, BitsAllocated: 8, BitsStored: 8, HighBit: 7, PixelRepresentation: 0, SamplesPerPixel: 1, PhotometricInterpretation: 'MONOCHROME2', PixelData: [pixels.buffer], }, ], }) ); client.addRequest(imageBoxSetRequest); // Print film box! filmBoxPrintRequest = new NActionRequest( SopClass.BasicFilmBox, '', // UID will be set once received 0x001, SopClass.BasicGrayscalePrintManagementMeta ); client.addRequest(filmBoxPrintRequest); // Delete film box filmBoxDeleteRequest = new NDeleteRequest( SopClass.BasicFilmBox, '', // UID will be set once received SopClass.BasicGrayscalePrintManagementMeta ); client.addRequest(filmBoxDeleteRequest); // Delete film session filmSessionDeleteRequest = new NDeleteRequest( SopClass.BasicFilmSession, '', // UID will be set once received ``` -------------------------------- ### N-Create, N-Action, N-Set, N-Delete SCU Example Source: https://github.com/pantelisgeorgiadis/dcmjs-dimse/wiki/Examples Demonstrates setting up and sending N-Create, N-Action, N-Set, and N-Delete requests using the DCMJS client. Ensure the client is properly configured before sending requests. ```javascript const client = new DicomClient(); // N-Create Request Example (e.g., Film Session) const filmSessionCreateRequest = new NCreateRequest(); filmSessionCreateRequest.sopClassUid = SopClass.BasicGrayscalePrintManagementMeta; client.addRequest(filmSessionCreateRequest); // N-Action Request Example (e.g., Print) const printActionRequest = new NActionRequest(); printActionRequest.sopClassUid = SopClass.BasicGrayscalePrintManagementMeta; client.addRequest(printActionRequest); // N-Set Request Example (e.g., Update Film Session) const filmSessionSetRequest = new NSetRequest(); filmSessionSetRequest.sopClassUid = SopClass.BasicGrayscalePrintManagementMeta; client.addRequest(filmSessionSetRequest); // N-Delete Request Example (e.g., Film Session) const filmSessionDeleteRequest = new NDeleteRequest(); filmSessionDeleteRequest.sopClassUid = SopClass.BasicGrayscalePrintManagementMeta; client.addRequest(filmSessionDeleteRequest); // Send requests client.send('127.0.0.1', 104, 'SCU', 'ANY-SCP'); ``` -------------------------------- ### Install dcmjs-dimse Source: https://context7.com/pantelisgeorgiadis/dcmjs-dimse/llms.txt Install the dcmjs-dimse library using npm. ```bash npm install dcmjs-dimse ``` -------------------------------- ### Perform N-CREATE Request to Create SOP Instance Source: https://context7.com/pantelisgeorgiadis/dcmjs-dimse/llms.txt Use NCreateRequest to create a new managed SOP instance on a remote peer. This example shows how to construct the request with necessary dataset elements like StudyInstanceUID and ReferencedSOPSequence, and how to handle the response to get the created SOP instance UID. ```javascript const dcmjsDimse = require('dcmjs-dimse'); const { Client, Dataset } = dcmjsDimse; const { NCreateRequest } = dcmjsDimse.requests; const { SopClass, StorageClass, Status } = dcmjsDimse.constants; const client = new Client(); const request = new NCreateRequest(SopClass.InstanceAvailabilityNotification, ''); request.setDataset(new Dataset({ StudyInstanceUID: Dataset.generateDerivedUid(), ReferencedPerformedProcedureStepSequence: [], ReferencedSeriesSequence: [{ SeriesInstanceUID: Dataset.generateDerivedUid(), ReferencedSOPSequence: [{ ReferencedSOPClassUID: StorageClass.MrImageStorage, ReferencedSOPInstanceUID: Dataset.generateDerivedUid(), RetrieveAETitle: 'ARCHIVE', InstanceAvailability: 'ONLINE', }], }], })); request.on('response', (response) => { if (response.getStatus() === Status.Success) { console.log('Created SOP instance:', response.getAffectedSopInstanceUid()); } }); client.addRequest(request); client.on('networkError', (err) => console.error(err)); client.send('127.0.0.1', 11112, 'MY-SCU', 'ANY-SCP'); ``` -------------------------------- ### Perform C-STORE SCU with dcmjs-dimse Source: https://github.com/pantelisgeorgiadis/dcmjs-dimse/blob/master/README.md This example shows how to send a C-STORE request as a SCU. It includes optional initialization for encapsulated syntaxes transcoding and allows specifying additional transfer syntaxes. ```javascript const dcmjsDimse = require('dcmjs-dimse'); const { Client, Transcoding } = dcmjsDimse; const { CStoreRequest } = dcmjsDimse.requests; const { TransferSyntax } = dcmjsDimse.constants; // Optionally initialize encapsulated syntaxes transcoding. // If transcoding is not initialized, only uncompressed // syntaxes would be able to be transcoded. await Transcoding.initializeAsync(); const client = new Client(); const request = new CStoreRequest('test.dcm'); request.setAdditionalTransferSyntaxes([TransferSyntax.Jpeg2000Lossless]); client.addRequest(request); client.on('networkError', (e) => { console.log('Network error: ', e); }); client.send('127.0.0.1', 12345, 'SCU', 'ANY-SCP'); ``` -------------------------------- ### N-Create SCU (Instance Availability Notification) Example Source: https://github.com/pantelisgeorgiadis/dcmjs-dimse/wiki/Examples Sends an N-Create request to notify of instance availability. Sets up a dataset with series and SOP information. ```javascript const dcmjsDimse = require('dcmjs-dimse'); const { Client, Dataset } = dcmjsDimse; const { NCreateRequest } = dcmjsDimse.requests; const { SopClass, Status, StorageClass } = dcmjsDimse.constants; const client = new Client(); const request = new NCreateRequest(SopClass.InstanceAvailabilityNotification, ''); request.setDataset( new Dataset({ StudyInstanceUID: Dataset.generateDerivedUid(), ReferencedPerformedProcedureStepSequence: [], ReferencedSeriesSequence: [ { SeriesInstanceUID: Dataset.generateDerivedUid(), ReferencedSOPSequence: [ { ReferencedSOPClassUID: StorageClass.MrImageStorage, ReferencedSOPInstanceUID: Dataset.generateDerivedUid(), RetrieveAETitle: 'ANY-SCP', InstanceAvailability: 'ONLINE', }, ], }, ], }) ); request.on('response', (response) => { if (response.getStatus() === Status.Success) { console.log('Notified!'); } }); client.addRequest(request); client.on('networkError', (e) => { console.log('Network error: ', e); }); client.send('127.0.0.1', 12345, 'SCU', 'ANY-SCP'); ``` -------------------------------- ### N-Action SCU (Storage Commitment) Example Source: https://github.com/pantelisgeorgiadis/dcmjs-dimse/wiki/Examples Performs an N-Action request for Storage Commitment. Requires lingering the association to receive a synchronous response. ```javascript const dcmjsDimse = require('dcmjs-dimse'); const { Client, Dataset } = dcmjsDimse; const { NActionRequest } = dcmjsDimse.requests; const { NEventReportResponse } = dcmjsDimse.responses; const { SopClass, Status, StorageClass } = dcmjsDimse.constants; const client = new Client(); const request = new NActionRequest( SopClass.StorageCommitmentPushModel, Dataset.generateDerivedUid(), 0x0001 ); request.setDataset( new Dataset({ TransactionUID: Dataset.generateDerivedUid(), ReferencedSOPSequence: [ { ReferencedSOPClassUID: StorageClass.MrImageStorage, ReferencedSOPInstanceUID: Dataset.generateDerivedUid(), }, ], }) ); client.addRequest(request); client.on('nEventReportRequest', (request, callback) => { console.log(request.getDataset()); const response = NEventReportResponse.fromRequest(request); response.setStatus(Status.Success); callback(response); }); client.on('networkError', (e) => { console.log('Network error: ', e); }); // Linger the association to get a synchronous // storage commitment response client.send('127.0.0.1', 12345, 'SCU', 'ANY-SCP', { associationLingerTimeout: 5000, }); ``` -------------------------------- ### N-Get SCU (Printer) Example Source: https://github.com/pantelisgeorgiadis/dcmjs-dimse/wiki/Examples Executes an N-Get request to retrieve printer information. Specifies the SOP Class and instance UID, along with requested attributes. ```javascript const dcmjsDimse = require('dcmjs-dimse'); const { Client } = dcmjsDimse; const { NGetRequest } = dcmjsDimse.requests; const { SopClass, Status } = dcmjsDimse.constants; const client = new Client(); const request = new NGetRequest(SopClass.Printer, '1.2.840.10008.5.1.1.17', [ 'PrinterStatus', 'PrinterStatusInfo', 'PrinterName', 'Manufacturer', 'ManufacturersModelName', 'DeviceSerialNumber', 'SoftwareVersions', 'DeviceSerialNumber', 'DateOfLastCalibration', 'TimeOfLastCalibration', ]); request.on('response', (response) => { if (response.getStatus() === Status.Success) { console.log(response.getDataset()); } }); client.addRequest(request); client.on('networkError', (e) => { console.log('Network error: ', e); }); client.send('127.0.0.1', 12345, 'SCU', 'ANY-SCP'); ``` -------------------------------- ### SCP Implementation in JavaScript Source: https://github.com/pantelisgeorgiadis/dcmjs-dimse/wiki/Examples Implement a DICOM SCP server by extending the Scp class. Handle association requests, user identity negotiation, and presentation context negotiation. This example shows how to accept or reject associations based on AET and user identity, and how to negotiate supported SOP classes and transfer syntaxes. ```javascript const dcmjsDimse = require('dcmjs-dimse'); const { Dataset, Server, Scp } = dcmjsDimse; const { CEchoResponse, CFindResponse, CStoreResponse } = dcmjsDimse.responses; const { Status, PresentationContextResult, RejectResult, RejectSource, RejectReason, TransferSyntax, SopClass, StorageClass, UserIdentityType, } = dcmjsDimse.constants; class DcmjsDimseScp extends Scp { constructor(socket, opts) { super(socket, opts); this.association = undefined; } // Handle incoming association requests associationRequested(association) { this.association = association; // Evaluate calling/called AET and reject association, if needed if (this.association.getCallingAeTitle() !== 'SCU') { this.sendAssociationReject( RejectResult.Permanent, RejectSource.ServiceUser, RejectReason.CallingAeNotRecognized ); return; } // Evaluate user identity and reject association, if needed if ( this.association.getNegotiateUserIdentity() && this.association.getUserIdentityPositiveResponseRequested() ) { if ( this.association.getUserIdentityType() === UserIdentityType.UsernameAndPasscode && this.association.getUserIdentityPrimaryField() === 'Username' && this.association.getUserIdentitySecondaryField() === 'Password' ) { this.association.setUserIdentityServerResponse(''); this.association.setNegotiateUserIdentityServerResponse(true); } else { this.sendAssociationReject( RejectResult.Permanent, RejectSource.ServiceUser, RejectReason.NoReasonGiven ); return; } } // Optionally set the preferred max PDU length this.association.setMaxPduLength(65536); const contexts = association.getPresentationContexts(); contexts.forEach((c) => { const context = association.getPresentationContext(c.id); if ( context.getAbstractSyntaxUid() === SopClass.Verification || context.getAbstractSyntaxUid() === SopClass.StudyRootQueryRetrieveInformationModelFind || context.getAbstractSyntaxUid() === StorageClass.MrImageStorage // Accept other presentation contexts, as needed ) { const transferSyntaxes = context.getTransferSyntaxUids(); transferSyntaxes.forEach((transferSyntax) => { if ( transferSyntax === TransferSyntax.ImplicitVRLittleEndian || transferSyntax === TransferSyntax.ExplicitVRLittleEndian ) { context.setResult(PresentationContextResult.Accept, transferSyntax); } else { context.setResult(PresentationContextResult.RejectTransferSyntaxesNotSupported); } }); } else { context.setResult(PresentationContextResult.RejectAbstractSyntaxNotSupported); } }); this.sendAssociationAccept(); } // Handle incoming C-ECHO requests cEchoRequest(request, callback) { const response = CEchoResponse.fromRequest(request); response.setStatus(Status.Success); callback(response); } // Handle incoming C-FIND requests cFindRequest(request, callback) { console.log(request.getDataset()); const pendingResponse = CFindResponse.fromRequest(request); pendingResponse.setDataset(new Dataset({ PatientID: '12345', PatientName: 'JOHN^DOE' })); pendingResponse.setStatus(Status.Pending); const finalResponse = CFindResponse.fromRequest(request); finalResponse.setStatus(Status.Success); callback([pendingResponse, finalResponse]); } // Handle incoming C-STORE requests cStoreRequest(request, callback) { console.log(request.getDataset()); const response = CStoreResponse.fromRequest(request); response.setStatus(Status.Success); callback(response); } // Handle incoming association release requests associationReleaseRequested() { this.sendAssociationReleaseResponse(); } } // Optionally initialize encapsulated syntaxes transcoding. // If transcoding is not initialized, only uncompressed // syntaxes would be able to be transcoded. await Transcoding.initializeAsync(); const server = new Server(DcmjsDimseScp); server.on('networkError', (e) => { console.log('Network error: ', e); }); server.listen(port); // When done server.close(); ``` -------------------------------- ### Perform N-ACTION Request for Storage Commitment Source: https://context7.com/pantelisgeorgiadis/dcmjs-dimse/llms.txt Use NActionRequest to invoke an action on a remote SOP instance, such as requesting storage commitment. This example demonstrates setting up the request, including the Storage Commitment Request action type and referenced SOP instances, and handling the asynchronous N-EVENT-REPORT response. ```javascript const dcmjsDimse = require('dcmjs-dimse'); const { Client, Dataset } = dcmjsDimse; const { NActionRequest } = dcmjsDimse.requests; const { NEventReportResponse } = dcmjsDimse.responses; const { SopClass, StorageClass, Status } = dcmjsDimse.constants; const client = new Client(); const request = new NActionRequest( SopClass.StorageCommitmentPushModel, Dataset.generateDerivedUid(), 0x0001 // Storage Commitment Request action type ); request.setDataset(new Dataset({ TransactionUID: Dataset.generateDerivedUid(), ReferencedSOPSequence: [ { ReferencedSOPClassUID: StorageClass.MrImageStorage, ReferencedSOPInstanceUID: '1.2.3.4.5.6.7.8.9.0', }, ], })); request.on('response', (response) => { console.log('N-ACTION response status:', response.getStatus()); }); // Handle the asynchronous N-EVENT-REPORT (commitment result) client.on('nEventReportRequest', (eventRequest, callback) => { const ds = eventRequest.getDataset(); console.log('Committed UIDs:', JSON.stringify(ds.getElement('ReferencedSOPSequence'))); const response = NEventReportResponse.fromRequest(eventRequest); response.setStatus(Status.Success); callback(response); }); client.addRequest(request); client.on('networkError', (err) => console.error(err)); // Linger 5 s to receive the synchronous N-EVENT-REPORT client.send('127.0.0.1', 11112, 'MY-SCU', 'COMMIT-SCP', { associationLingerTimeout: 5000 }); ``` -------------------------------- ### Client Initialization and C-ECHO Request Source: https://context7.com/pantelisgeorgiadis/dcmjs-dimse/llms.txt Demonstrates how to initialize the Client, create a C-ECHO request, add it to the client's queue, and send it to a remote SCP. It also shows how to handle network errors and retrieve session statistics upon connection closure. ```APIDOC ## Client Initialization and C-ECHO Request ### Description Initializes a DICOM DIMSE client and sends a C-ECHO request to a specified host and port. This snippet illustrates basic client setup, request creation, and event handling for network errors and connection closure. ### Method `client.send(host, port, callingAeTitle, calledAeTitle)` ### Endpoint N/A (This is an SDK method, not an HTTP endpoint) ### Parameters - **host** (string) - The hostname or IP address of the remote SCP. - **port** (number) - The network port of the remote SCP. - **callingAeTitle** (string) - The Application Entity Title of the local SCU. - **calledAeTitle** (string) - The Application Entity Title of the remote SCP. ### Request Example ```javascript const dcmjsDimse = require('dcmjs-dimse'); const { Client } = dcmjsDimse; const { CEchoRequest } = dcmjsDimse.requests; const { Status } = dcmjsDimse.constants; const client = new Client(); const request = new CEchoRequest(); request.on('response', (response) => { if (response.getStatus() === Status.Success) { console.log('C-ECHO succeeded'); } }); client.addRequest(request); client.on('networkError', (err) => console.error('Network error:', err)); client.on('closed', () => { const stats = client.getStatistics(); console.log('Session stats:', stats.toString()); }); // connect to host, port with calling AET and called AET client.send('127.0.0.1', 11112, 'MY-SCU', 'ANY-SCP'); ``` ### Response - **Events**: `connected`, `associationAccepted`, `associationReleased`, `associationRejected`, `closed`, `networkError`, `cStoreRequest`, `nEventReportRequest`. - **`response.getStatus()`**: Returns the status code of the C-ECHO response. - **`client.getStatistics()`**: Returns an object with session statistics. ``` -------------------------------- ### C-Get SCU Client Implementation Source: https://github.com/pantelisgeorgiadis/dcmjs-dimse/blob/master/README.md This snippet shows how to initialize a dcmjs-dimse client, create a C-Get request for a specific study UID, and handle incoming responses. It also includes a handler for C-Store requests and network errors. ```javascript const dcmjsDimse = require('dcmjs-dimse'); const { Client } = dcmjsDimse; const { CGetRequest } = dcmjsDimse.requests; const { CStoreResponse } = dcmjsDimse.responses; const { Status } = dcmjsDimse.constants; const client = new Client(); const request = CGetRequest.createStudyGetRequest(studyInstanceUid); request.on('response', (response) => { if (response.getStatus() === Status.Pending) { console.log('Remaining: ' + response.getRemaining()); console.log('Completed: ' + response.getCompleted()); console.log('Warning: ' + response.getWarnings()); console.log('Failed: ' + response.getFailures()); } }); client.on('cStoreRequest', (request, callback) => { console.log(request.getDataset()); const response = CStoreResponse.fromRequest(request); response.setStatus(Status.Success); callback(response); }); client.addRequest(request); client.on('networkError', (e) => { console.log('Network error: ', e); }); client.send('127.0.0.1', 12345, 'SCU', 'ANY-SCP'); ``` -------------------------------- ### Basic Client C-ECHO Request Source: https://context7.com/pantelisgeorgiadis/dcmjs-dimse/llms.txt Demonstrates a basic C-ECHO request using the dcmjs-dimse Client. Ensure the server is running and accessible. ```javascript const dcmjsDimse = require('dcmjs-dimse'); const { Client } = dcmjsDimse; const { CEchoRequest } = dcmjsDimse.requests; const { Status } = dcmjsDimse.constants; const client = new Client(); const request = new CEchoRequest(); request.on('response', (response) => { if (response.getStatus() === Status.Success) { console.log('C-ECHO succeeded'); } }); client.addRequest(request); client.on('networkError', (err) => console.error('Network error:', err)); client.on('closed', () => { const stats = client.getStatistics(); console.log('Session stats:', stats.toString()); // e.g. "Sent: 512 Bytes, Received: 128 Bytes" }); // connect to host, port with calling AET and called AET client.send('127.0.0.1', 11112, 'MY-SCU', 'ANY-SCP'); ``` -------------------------------- ### Perform N-GET Request to Retrieve Attribute Values Source: https://context7.com/pantelisgeorgiadis/dcmjs-dimse/llms.txt Use NGetRequest to retrieve attribute values from an existing SOP instance on a remote peer, such as querying printer status. This example specifies the SOP Class, SOP Instance UID, and the list of attributes to retrieve, then logs the retrieved printer status and name if successful. ```javascript const dcmjsDimse = require('dcmjs-dimse'); const { Client } = dcmjsDimse; const { NGetRequest } = dcmjsDimse.requests; const { SopClass, Status } = dcmjsDimse.constants; const client = new Client(); const request = new NGetRequest( SopClass.Printer, '1.2.840.10008.5.1.1.17', // Well-known printer SOP instance UID ['PrinterStatus', 'PrinterStatusInfo', 'PrinterName', 'Manufacturer', 'SoftwareVersions'] ); request.on('response', (response) => { if (response.getStatus() === Status.Success && response.hasDataset()) { const ds = response.getDataset(); console.log('Printer status:', ds.getElement('PrinterStatus')); console.log('Printer name:', ds.getElement('PrinterName')); } }); client.addRequest(request); client.on('networkError', (err) => console.error(err)); client.send('127.0.0.1', 11112, 'MY-SCU', 'PRINT-SCP'); ``` -------------------------------- ### Streaming C-STORE SCP Implementation Source: https://context7.com/pantelisgeorgiadis/dcmjs-dimse/llms.txt Override `createStoreWritableStream` and `createDatasetFromStoreWritableStream` to stream incoming C-STORE data to disk. This avoids out-of-memory issues with large images. Requires `dcmjs-dimse`, `fs`, `os`, and `path` modules. ```javascript const dcmjsDimse = require('dcmjs-dimse'); const { Dataset, Server, Scp } = dcmjsDimse; const { CStoreResponse } = dcmjsDimse.responses; const { Status, PresentationContextResult, TransferSyntax, StorageClass } = dcmjsDimse.constants; const fs = require('fs'); const os = require('os'); const path = require('path'); class StreamingScp extends Scp { constructor(socket, opts) { super(socket, opts); } // Return a file-backed Writable instead of the default in-memory stream createStoreWritableStream(acceptedPresentationContext, request) { const tmpPath = path.join(os.tmpdir(), `${Date.now()}_${Math.random()}.tmp`); return fs.createWriteStream(tmpPath); } // Build a Dataset from the completed file stream createDatasetFromStoreWritableStream(writable, acceptedPresentationContext, callback) { writable.on('finish', () => { const buf = fs.readFileSync(writable.path); callback(new Dataset(buf, acceptedPresentationContext.getAcceptedTransferSyntaxUid())); fs.unlinkSync(writable.path); }); writable.on('error', () => callback(undefined)); } associationRequested(association) { association.getPresentationContexts().forEach(({ id }) => { const ctx = association.getPresentationContext(id); if (Object.values(StorageClass).includes(ctx.getAbstractSyntaxUid())) { ctx.getTransferSyntaxUids().forEach((ts) => { if ([TransferSyntax.ImplicitVRLittleEndian, TransferSyntax.ExplicitVRLittleEndian].includes(ts)) { ctx.setResult(PresentationContextResult.Accept, ts); } else { ctx.setResult(PresentationContextResult.RejectTransferSyntaxesNotSupported); } }); } else { ctx.setResult(PresentationContextResult.RejectAbstractSyntaxNotSupported); } }); this.sendAssociationAccept(); } cStoreRequest(request, callback) { const response = CStoreResponse.fromRequest(request); response.setStatus(Status.Success); callback(response); } associationReleaseRequested() { this.sendAssociationReleaseResponse(); } } const server = new Server(StreamingScp); server.listen(11112); ``` -------------------------------- ### CGetRequest — C-GET (Retrieve Directly to SCU) Source: https://context7.com/pantelisgeorgiadis/dcmjs-dimse/llms.txt `CGetRequest` retrieves instances directly to the SCU over the same association. Incoming instances are delivered via the `cStoreRequest` event on the client. ```APIDOC ## CGetRequest — C-GET (Retrieve Directly to SCU) `CGetRequest` retrieves instances directly to the SCU over the same association. Incoming instances are delivered via the `cStoreRequest` event on the client. ```js const dcmjsDimse = require('dcmjs-dimse'); const { Client } = dcmjsDimse; const { CGetRequest } = dcmjsDimse.requests; const { CStoreResponse } = dcmjsDimse.responses; const { Status } = dcmjsDimse.constants; const fs = require('fs'); const client = new Client(); const studyInstanceUid = '1.2.840.113619.2.5.1762583153.215519.978957063.78'; const request = CGetRequest.createStudyGetRequest(studyInstanceUid); request.on('response', (response) => { if (response.getStatus() === Status.Pending) { console.log(`Progress: ${response.getCompleted()}/${response.getCompleted() + response.getRemaining()}`); } }); // Handle each incoming C-STORE sub-operation client.on('cStoreRequest', (storeRequest, callback) => { const dataset = storeRequest.getDataset(); const sopInstanceUid = dataset.getElement('SOPInstanceUID'); dataset.toFile(`received_${sopInstanceUid}.dcm`, (err) => { if (err) console.error('Save error:', err); }); const response = CStoreResponse.fromRequest(storeRequest); response.setStatus(Status.Success); callback(response); }); client.addRequest(request); client.on('networkError', (err) => console.error(err)); client.send('127.0.0.1', 11112, 'MY-SCU', 'QRSCP'); ``` ``` -------------------------------- ### Transcoding Source: https://context7.com/pantelisgeorgiadis/dcmjs-dimse/llms.txt Provides static methods to initialize the dcmjs-codecs WebAssembly engine and transcode Dataset objects between transfer syntaxes. ```APIDOC ## Transcoding `Transcoding` provides static methods to initialize the dcmjs-codecs WebAssembly engine and transcode `Dataset` objects between transfer syntaxes. ```js const { Transcoding, Dataset } = require('dcmjs-dimse'); const { TransferSyntax } = require('dcmjs-dimse').constants; (async () => { // Initialize native codec WASM (required for encapsulated syntaxes) await Transcoding.initializeAsync({ logCodecsInfo: false, logCodecsTrace: false, // webAssemblyModulePathOrUrl: '/custom/path/to/codecs.wasm' // optional }); console.log('Transcoding initialized:', Transcoding.isInitialized()); // true // Load a JPEG 2000 compressed dataset const ds = Dataset.fromFile('compressed.dcm'); console.log('Original transfer syntax:', ds.getTransferSyntaxUid()); // Transcode to uncompressed Explicit VR Little Endian const uncompressed = Transcoding.transcodeDataset(ds, TransferSyntax.ExplicitVRLittleEndian); uncompressed.toFile('uncompressed.dcm'); console.log('Transcoded to:', uncompressed.getTransferSyntaxUid()); // Transcode to JPEG-LS Lossless const jls = Transcoding.transcodeDataset(ds, TransferSyntax.JpegLsLossless); jls.toFile('lossless.dcm'); // Release the WASM module when done Transcoding.release(); })(); ``` ``` -------------------------------- ### Manage Presentation Contexts and Associations Source: https://context7.com/pantelisgeorgiadis/dcmjs-dimse/llms.txt Configures a DICOM Client with presentation contexts, including a meta-SOP class, and adds requests like N-CREATE for a Film Session. Handles network errors and association closure. ```javascript const dcmjsDimse = require('dcmjs-dimse'); const { Client } = dcmjsDimse; const { PresentationContext } = dcmjsDimse.association; const { NCreateRequest } = dcmjsDimse.requests; const { SopClass, TransferSyntax } = dcmjsDimse.constants; const client = new Client(); // Add a meta-SOP class presentation context manually // (needed for print management and other grouped services) const pc = new PresentationContext( 0, SopClass.BasicGrayscalePrintManagementMeta, TransferSyntax.ImplicitVRLittleEndian ); client.addAdditionalPresentationContext(pc); const filmSession = new NCreateRequest( SopClass.BasicFilmSession, '', SopClass.BasicGrayscalePrintManagementMeta ); filmSession.on('response', (response) => { console.log('Film session UID:', response.getAffectedSopInstanceUid()); }); client.addRequest(filmSession); client.on('networkError', (err) => console.error(err)); client.send('127.0.0.1', 104, 'PRINT-SCU', 'PRINT-SCP'); ``` -------------------------------- ### Client with TLS and User Identity Options Source: https://context7.com/pantelisgeorgiadis/dcmjs-dimse/llms.txt Configures the dcmjs-dimse Client with advanced options including TLS security and username/password user identity. Ensure certificate files exist and are correctly referenced. ```javascript const { Client, Implementation } = require('dcmjs-dimse'); const { CEchoRequest } = require('dcmjs-dimse').requests; const { UserIdentityType } = require('dcmjs-dimse').constants; const fs = require('fs'); // Override default implementation class UID and version Implementation.setImplementationClassUid('1.2.826.0.1.3680043.10.854'); Implementation.setImplementationVersion('MY-APP-V1'); const client = new Client(); client.addRequest(new CEchoRequest()); client.on('networkError', (err) => console.error(err)); client.send('pacs.hospital.org', 11114, 'MY-SCU', 'PACS-SCP', { connectTimeout: 5000, // ms to wait for TCP connect associationTimeout: 10000, // ms to wait for association accept pduTimeout: 30000, // ms to wait for next PDU associationLingerTimeout: 2000,// ms to keep association open after all requests finish logCommandDatasets: false, logDatasets: false, securityOptions: { key: fs.readFileSync('client-key.pem'), cert: fs.readFileSync('client-cert.pem'), ca: fs.readFileSync('ca-cert.pem'), rejectUnauthorized: true, minVersion: 'TLSv1.2', }, userIdentity: { type: UserIdentityType.UsernameAndPasscode, positiveResponseRequested: true, primaryField: 'myusername', secondaryField: 'mypassword', }, asyncOps: { maxAsyncOpsInvoked: 4, maxAsyncOpsPerformed: 4, }, }); ``` -------------------------------- ### Perform C-FIND Queries (Study, Series, Worklist) Source: https://context7.com/pantelisgeorgiadis/dcmjs-dimse/llms.txt Executes C-FIND queries for studies, series, and modality worklists. Requires Client and CFindRequest imports. Responses are handled via 'response' events. ```javascript const dcmjsDimse = require('dcmjs-dimse'); const { Client } = dcmjsDimse; const { CFindRequest } = dcmjsDimse.requests; const { Status, Priority } = dcmjsDimse.constants; const client = new Client(); // Study-level query const studyRequest = CFindRequest.createStudyFindRequest( { PatientID: '12345', StudyDate: '20230101-20231231', ModalitiesInStudy: 'CT' }, Priority.High ); studyRequest.on('response', (response) => { if (response.getStatus() === Status.Pending && response.hasDataset()) { const ds = response.getDataset(); console.log('Study UID:', ds.getElement('StudyInstanceUID')); console.log('Patient:', ds.getElement('PatientName')); } }); client.addRequest(studyRequest); // Series-level query const seriesRequest = CFindRequest.createSeriesFindRequest({ StudyInstanceUID: '1.2.3.4.5', Modality: '', SeriesInstanceUID: '', }); seriesRequest.on('response', (response) => { if (response.getStatus() === Status.Pending && response.hasDataset()) { console.log('Series UID:', response.getDataset().getElement('SeriesInstanceUID')); } }); client.addRequest(seriesRequest); // Modality worklist query const worklistRequest = CFindRequest.createWorklistFindRequest({ PatientName: '*', Modality: 'MR' }); worklistRequest.on('response', (response) => { if (response.getStatus() === Status.Pending && response.hasDataset()) { console.log('Worklist item:', JSON.stringify(response.getDataset().getElements())); } }); client.addRequest(worklistRequest); client.on('networkError', (err) => console.error(err)); client.send('127.0.0.1', 11112, 'MY-SCU', 'ANY-SCP'); ``` -------------------------------- ### NCreateRequest — N-CREATE Source: https://context7.com/pantelisgeorgiadis/dcmjs-dimse/llms.txt Creates a new managed SOP instance on the remote peer (e.g. Instance Availability Notification, print film session). ```APIDOC ## NCreateRequest — N-CREATE `NCreateRequest` creates a new managed SOP instance on the remote peer (e.g. Instance Availability Notification, print film session). ```js const dcmjsDimse = require('dcmjs-dimse'); const { Client, Dataset } = dcmjsDimse; const { NCreateRequest } = dcmjsDimse.requests; const { SopClass, StorageClass, Status } = dcmjsDimse.constants; const client = new Client(); const request = new NCreateRequest(SopClass.InstanceAvailabilityNotification, ''); request.setDataset(new Dataset({ StudyInstanceUID: Dataset.generateDerivedUid(), ReferencedPerformedProcedureStepSequence: [], ReferencedSeriesSequence: [{ SeriesInstanceUID: Dataset.generateDerivedUid(), ReferencedSOPSequence: [{ ReferencedSOPClassUID: StorageClass.MrImageStorage, ReferencedSOPInstanceUID: Dataset.generateDerivedUid(), RetrieveAETitle: 'ARCHIVE', InstanceAvailability: 'ONLINE', }], }], })); request.on('response', (response) => { if (response.getStatus() === Status.Success) { console.log('Created SOP instance:', response.getAffectedSopInstanceUid()); } }); client.addRequest(request); client.on('networkError', (err) => console.error(err)); client.send('127.0.0.1', 11112, 'MY-SCU', 'ANY-SCP'); ``` ``` -------------------------------- ### Client.abort() and Client.cancel() Source: https://context7.com/pantelisgeorgiadis/dcmjs-dimse/llms.txt Demonstrates how to terminate an active DICOM association using `client.abort()` and how to cancel an in-progress C-FIND, C-MOVE, or C-GET request using `client.cancel()`. ```APIDOC ## Client.abort() and Client.cancel() `client.abort()` terminates the active association with an A-ABORT. `client.cancel()` sends a C-CANCEL for an in-progress C-FIND, C-MOVE, or C-GET request. ### Request Example ```js const dcmjsDimse = require('dcmjs-dimse'); const { Client } = dcmjsDimse; const { CFindRequest } = dcmjsDimse.requests; const { Status, AbortSource, AbortReason } = dcmjsDimse.constants; const client = new Client(); const request = CFindRequest.createStudyFindRequest({ PatientName: '*' }); let responseCount = 0; request.on('response', (response) => { if (response.getStatus() === Status.Pending && response.hasDataset()) { responseCount++; console.log('Match:', response.getDataset().getElement('PatientName')); if (responseCount >= 10) { // Cancel the C-FIND after 10 results client.cancel(request); } } }); client.addRequest(request); client.on('networkError', (err) => { console.error('Network error:', err); }); client.send('127.0.0.1', 11112, 'MY-SCU', 'ANY-SCP'); // Force abort on a timeout (if needed) setTimeout(() => { try { client.abort(AbortSource.ServiceUser, AbortReason.NotSpecified); } catch (e) { /* network may already be closed */ } }, 15000); ``` ``` -------------------------------- ### Initialize and Transcode DICOM Datasets Source: https://context7.com/pantelisgeorgiadis/dcmjs-dimse/llms.txt Initializes the WebAssembly codecs and transcodes a DICOM dataset to different transfer syntaxes. Ensure the WASM module is released when done. ```javascript const { Transcoding, Dataset } = require('dcmjs-dimse'); const { TransferSyntax } = require('dcmjs-dimse').constants; (async () => { // Initialize native codec WASM (required for encapsulated syntaxes) await Transcoding.initializeAsync({ logCodecsInfo: false, logCodecsTrace: false, // webAssemblyModulePathOrUrl: '/custom/path/to/codecs.wasm' // optional }); console.log('Transcoding initialized:', Transcoding.isInitialized()); // true // Load a JPEG 2000 compressed dataset const ds = Dataset.fromFile('compressed.dcm'); console.log('Original transfer syntax:', ds.getTransferSyntaxUid()); // Transcode to uncompressed Explicit VR Little Endian const uncompressed = Transcoding.transcodeDataset(ds, TransferSyntax.ExplicitVRLittleEndian); uncompressed.toFile('uncompressed.dcm'); console.log('Transcoded to:', uncompressed.getTransferSyntaxUid()); // Transcode to JPEG-LS Lossless const jls = Transcoding.transcodeDataset(ds, TransferSyntax.JpegLsLossless); jls.toFile('lossless.dcm'); // Release the WASM module when done Transcoding.release(); })(); ```