import os from pydicom import dcmread from pydicom.data import get_testdata_files from pydicom.dataset import Dataset from pynetdicom import AE from pynetdicom.sop_class import ModalityWorklistInformationFind # Initialise the Application Entity and specify the listen port ae = AE() # Add a requested presentation context ae.add_supported_context(ModalityWorklistInformationFind) # Implement the AE.on_c_store callback def on_c_find(ds, context, info): print(ds) """Respond to a C-FIND request Identifier `ds`. Parameters ---------- ds : pydicom.dataset.Dataset The Identifier dataset send by the peer. context : namedtuple The presentation context that the dataset was sent under. info : dict Information about the association and query/retrieve request. Yields
logger = logging.getLogger('pynetdicom') # Implement a handler evt.EVT_C_STORE def handle_store(event): """Handle a C-STORE request event.""" # Decode the C-STORE request's *Data Set* parameter to a pydicom Dataset ds = event.dataset # Add the File Meta Information ds.file_meta = event.file_meta # Save the dataset using the SOP Instance UID as the filename ds.save_as(ds.SOPInstanceUID, write_like_original=False) # Return a 'Success' status return 0x0000 handlers = [(evt.EVT_C_STORE, handle_store)] # Initialise the Application Entity # ae = AE() ae = AE(ae_title=b'abc') # Add the supported presentation contexts ae.supported_contexts = StoragePresentationContexts # Start listening for incoming association requests ae.start_server(('', 4100), evt_handlers=handlers)
def main(args=None): """Run the application.""" if args is not None: sys.argv = args args = _setup_argparser() if args.version: print('getscu.py v{}'.format(__version__)) sys.exit() APP_LOGGER = setup_logging(args, 'getscu') APP_LOGGER.debug('getscu.py v{0!s}'.format(__version__)) APP_LOGGER.debug('') # Create query (identifier) dataset try: # If you're looking at this to see how QR Get works then `identifer` # is a pydicom Dataset instance with your query keys, e.g.: # identifier = Dataset() # identifier.QueryRetrieveLevel = 'PATIENT' # identifier.PatientName = '*' identifier = create_dataset(args, APP_LOGGER) except Exception as exc: APP_LOGGER.exception(exc) sys.exit(1) # Exclude these SOP Classes _exclusion = [ PlannedImagingAgentAdministrationSRStorage, PerformedImagingAgestAdministrationSRStorage, EncapsulatedSTLStorage, ] store_contexts = [ cx for cx in StoragePresentationContexts if cx.abstract_syntax not in _exclusion ] # Create application entity # Binding to port 0 lets the OS pick an available port ae = AE(ae_title=args.calling_aet) ae.acse_timeout = args.acse_timeout ae.dimse_timeout = args.dimse_timeout ae.network_timeout = args.network_timeout # Extended Negotiation - SCP/SCU Role Selection ext_neg = [] ae.add_requested_context(PatientRootQueryRetrieveInformationModelGet) ae.add_requested_context(StudyRootQueryRetrieveInformationModelGet) ae.add_requested_context(PatientStudyOnlyQueryRetrieveInformationModelGet) for cx in store_contexts: ae.add_requested_context(cx.abstract_syntax) # Add SCP/SCU Role Selection Negotiation to the extended negotiation # We want to act as a Storage SCP ext_neg.append(build_role(cx.abstract_syntax, scp_role=True)) if args.study: query_model = StudyRootQueryRetrieveInformationModelGet elif args.psonly: query_model = PatientStudyOnlyQueryRetrieveInformationModelGet else: query_model = PatientRootQueryRetrieveInformationModelGet # Extended Negotiation - SOP Class Extended ext_opts = [args.relational_retrieval, args.enhanced_conversion] if any(ext_opts): app_info = b'' for option in ext_opts: app_info += b'\x01' if option else b'\x00' item = SOPClassExtendedNegotiation() item.sop_class_uid = query_model item.service_class_application_information = app_info ext_neg.append(item) # Request association with remote assoc = ae.associate(args.addr, args.port, ae_title=args.called_aet, ext_neg=ext_neg, evt_handlers=[(evt.EVT_C_STORE, handle_store, [args, APP_LOGGER])], max_pdu=args.max_pdu) if assoc.is_established: # Send query responses = assoc.send_c_get(identifier, query_model) for (status, rsp_identifier) in responses: # If `status.Status` is one of the 'Pending' statuses then # `rsp_identifier` is the C-GET response's Identifier dataset if status and status.Status in [0xFF00, 0xFF01]: # `rsp_identifier` is a pydicom Dataset containing a query # response. You may want to do something interesting here... pass assoc.release() else: sys.exit(1)
def receive_store(nr_assoc, ds_per_assoc, write_ds=False, use_yappi=False): """Run a Storage SCP and transfer datasets with sequential storescu's. Parameters ---------- nr_assoc : int The total number of (sequential) associations that will be made. ds_per_assoc : int The number of C-STORE requests sent per successful association. write_ds : bool, optional True to write the received dataset to file, False otherwise (default). use_yappi : bool, optional True to use the yappi profiler, False otherwise (default). """ if use_yappi: init_yappi() def handle(event): if write_ds: # TODO: optimise write using event.request.DataSet instead # Standard write using dataset decode and re-encode tfile = tempfile.TemporaryFile(mode='w+b') ds = event.dataset ds.file_meta = event.file_meta ds.save_as(tfile) return 0x0000 ae = AE() ae.acse_timeout = 5 ae.dimse_timeout = 5 ae.network_timeout = 5 ae.add_supported_context(DATASET.SOPClassUID, ImplicitVRLittleEndian) server = ae.start_server(('', 11112), block=False, evt_handlers=[(evt.EVT_C_STORE, handle)]) time.sleep(0.5) start_time = time.time() run_times = [] is_successful = True for ii in range(nr_assoc): p = start_storescu(ds_per_assoc) # Block until transfer is complete p.wait() if p.returncode != 0: is_successful = False break if is_successful: print("C-STORE SCP transferred {} total datasets over {} " "association(s) in {:.2f} s".format(nr_assoc * ds_per_assoc, nr_assoc, time.time() - start_time)) else: print("C-STORE SCP benchmark failed") server.shutdown()
def send_store(nr_assoc, ds_per_assoc, use_yappi=False): """Send a number of sequential C-STORE requests. Parameters ---------- nr_assoc : int The total number of (sequential) associations that will be made. ds_per_assoc : int The number of C-STORE requests sent per successful association. use_yappi : bool, optional True to use the yappi profiler, False otherwise (default). """ if use_yappi: init_yappi() # Start SCP server = start_storescp() time.sleep(0.5) ae = AE() ae.acse_timeout = 5 ae.dimse_timeout = 5 ae.network_timeout = 5 ae.add_requested_context(DATASET.SOPClassUID, ImplicitVRLittleEndian) # Start timer start_time = time.time() run_times = [] is_successful = True for ii in range(nr_assoc): if not is_successful: break assoc = ae.associate('localhost', 11112) if assoc.is_established: for jj in range(ds_per_assoc): try: status = assoc.send_c_store(DATASET) if status and status.Status != 0x0000: is_successful = False break except RuntimeError: is_successful = False break assoc.release() if is_successful: run_times.append(time.time() - start_time) else: is_successful = False break if is_successful: print("C-STORE SCU transferred {} total datasets over {} " "association(s) in {:.2f} s".format(nr_assoc * ds_per_assoc, nr_assoc, time.time() - start_time)) else: print("C-STORE SCU benchmark failed") server.terminate()
def FnMwlScp(): # Implement the handler for evt.EVT_C_FIND def handle_find(event): """Handle a C-FIND request event.""" ds = event.identifier #print(ds) # Import stored SOP Instances instances = [] instances = FnInfoMsql() matching = [] #if 'QueryRetrieveLevel' not in ds: # Failure # yield 0xC000, None # return if ds.PatientName != '0': matching = [ inst for inst in instances if inst.PatientName == ds.PatientName ] if ds.StudyInstanceUID != '0': matching = [ inst for inst in instances if inst.StudyInstanceUID == ds.StudyInstanceUID ] # print('matching:',matching) # Skip the other possibile values... # Skip the other possible attributes... # Skip the other QR levels... for instance in matching: # Check if C-CANCEL has been received if event.is_cancelled: yield (0xFE00, None) return identifier = Dataset() identifier.PatientName = instance.PatientName identifier.Modality = instance.Modality identifier.StudyDate = ds.StudyDate #print('inst:',instance.SOPInstanceUID) identifier.SOPInstanceUID = instance.SOPInstanceUID identifier.SeriesDescription = instance.SeriesDescription identifier.ProtocolName = instance.ProtocolName identifier.StudyDescription = instance.StudyDescription # Pending yield (0xFF00, identifier) handlers = [(evt.EVT_C_FIND, handle_find)] # Initialise the Application Entity and specify the listen port ae = AE() # Add the supported presentation context ae.add_supported_context(ModalityWorklistInformationFind) # print (ae) ae.title = b'ANY-SCP' #print (ae) # Start listening for incoming association requests ae.start_server(('', 11140), evt_handlers=handlers)
from pynetdicom.sop_class import UltrasoundMultiframeImageStorage logger = logging.getLogger(__name__) logger.setLevel(level=logging.INFO) handler = logging.FileHandler("storage_scu_log.txt") handler.setLevel(logging.INFO) formatter = logging.Formatter( '%(asctime)s - %(name)s - %(levelname)s - %(message)s') handler.setFormatter(formatter) console = logging.StreamHandler() console.setLevel(logging.INFO) logger.addHandler(handler) logger.addHandler(console) ae = AE(ae_title=b'MY_STORAGE_SCU') ae.add_requested_context(UID('1.2.840.10008.5.1.4.1.1.3.1')) # ae.add_requested_context(UltrasoundMultiframeImageStorage) for cx in ae.requested_contexts: print(cx) # assoc = ae.associate('192.168.3.5', 4100) assoc = ae.associate('127.0.0.1', 4100) if assoc.is_established: logger.info('assoc is established') # dataset = dcmread('./MRI.dcm') dataset = dcmread('./IMG00001') # `status` is the response from the peer to the store request # but may be an empty pydicom Dataset if the peer timed out or # sent an invalid dataset.
def setup(self): ae = AE() self.assoc = Association(ae, MODE_REQUESTOR)
return status_ds handlers = [(evt.EVT_C_STORE, handle_store)] # Test output-directory if args.output_directory is not None: if not os.access(args.output_directory, os.W_OK | os.X_OK): APP_LOGGER.error('No write permissions or the output ' 'directory may not exist:') APP_LOGGER.error(" {0!s}".format(args.output_directory)) sys.exit() # Create application entity ae = AE(ae_title=args.aetitle) # Add presentation contexts with specified transfer syntaxes for context in StoragePresentationContexts: ae.add_supported_context(context.abstract_syntax, transfer_syntax) for context in VerificationPresentationContexts: ae.add_supported_context(context.abstract_syntax, transfer_syntax) ae.maximum_pdu_size = args.max_pdu # Set timeouts ae.network_timeout = args.timeout ae.acse_timeout = args.acse_timeout ae.dimse_timeout = args.dimse_timeout ae.start_server((args.bind_addr, args.port), evt_handlers=handlers)
def main(args=None): """Run the application.""" if args is not None: sys.argv = args args = _setup_argparser() if args.version: print('qrscp.py v{}'.format(__version__)) sys.exit() APP_LOGGER = setup_logging(args, 'qrscp') APP_LOGGER.debug('qrscp.py v{0!s}'.format(__version__)) APP_LOGGER.debug('') APP_LOGGER.debug('Using configuration from:'.format(args.config)) APP_LOGGER.debug(' {}'.format(args.config)) APP_LOGGER.debug('') config = ConfigParser() config.read(args.config) if args.ae_title: config['DEFAULT']['ae_title'] = args.ae_title if args.port: config['DEFAULT']['port'] = args.port if args.max_pdu: config['DEFAULT']['max_pdu'] = args.max_pdu if args.acse_timeout: config['DEFAULT']['acse_timeout'] = args.acse_timeout if args.dimse_timeout: config['DEFAULT']['dimse_timeout'] = args.dimse_timeout if args.network_timeout: config['DEFAULT']['network_timeout'] = args.network_timeout if args.bind_address: config['DEFAULT']['bind_address'] = args.bind_address if args.database_location: config['DEFAULT']['database_location'] = args.database_location if args.instance_location: config['DEFAULT']['instance_location'] = args.instance_location # Log configuration settings _log_config(config, APP_LOGGER) app_config = config['DEFAULT'] dests = {} for ae_title in config.sections(): dest = config[ae_title] # Convert to bytes and validate the AE title ae_title = validate_ae_title(ae_title.encode("ascii"), use_short=True) dests[ae_title] = (dest['address'], dest.getint('port')) # Use default or specified configuration file current_dir = os.path.abspath(os.path.dirname(__file__)) instance_dir = os.path.join(current_dir, app_config['instance_location']) db_path = os.path.join(current_dir, app_config['database_location']) # The path to the database db_path = 'sqlite:///{}'.format(db_path) db.create(db_path) # Clean up the database and storage directory if args.clean: response = input( "This will delete all instances from both the storage directory " "and the database. Are you sure you wish to continue? [yes/no]: " ) if response != 'yes': sys.exit() if clean(db_path, APP_LOGGER): sys.exit() else: sys.exit(1) # Try to create the instance storage directory os.makedirs(instance_dir, exist_ok=True) ae = AE(app_config['ae_title']) ae.maximum_pdu_size = app_config.getint('max_pdu') ae.acse_timeout = app_config.getfloat('acse_timeout') ae.dimse_timeout = app_config.getfloat('dimse_timeout') ae.network_timeout = app_config.getfloat('network_timeout') ## Add supported presentation contexts # Verification SCP ae.add_supported_context(VerificationSOPClass, ALL_TRANSFER_SYNTAXES) # Storage SCP - support all transfer syntaxes for cx in AllStoragePresentationContexts: ae.add_supported_context( cx.abstract_syntax, ALL_TRANSFER_SYNTAXES, scp_role=True, scu_role=False ) # Query/Retrieve SCP ae.add_supported_context(PatientRootQueryRetrieveInformationModelFind) ae.add_supported_context(PatientRootQueryRetrieveInformationModelMove) ae.add_supported_context(PatientRootQueryRetrieveInformationModelGet) ae.add_supported_context(StudyRootQueryRetrieveInformationModelFind) ae.add_supported_context(StudyRootQueryRetrieveInformationModelMove) ae.add_supported_context(StudyRootQueryRetrieveInformationModelGet) # Set our handler bindings handlers = [ (evt.EVT_C_ECHO, handle_echo, [args, APP_LOGGER]), (evt.EVT_C_FIND, handle_find, [db_path, args, APP_LOGGER]), (evt.EVT_C_GET, handle_get, [db_path, args, APP_LOGGER]), (evt.EVT_C_MOVE, handle_move, [dests, db_path, args, APP_LOGGER]), ( evt.EVT_C_STORE, handle_store, [instance_dir, db_path, args, APP_LOGGER] ), ] # Listen for incoming association requests ae.start_server( (app_config['bind_address'], app_config.getint('port')), evt_handlers=handlers )
transfer_syntax.remove(ExplicitVRLittleEndian) transfer_syntax.insert(0, ExplicitVRLittleEndian) if args.prefer_big and ExplicitVRBigEndian in transfer_syntax: transfer_syntax.remove(ExplicitVRBigEndian) transfer_syntax.insert(0, ExplicitVRBigEndian) def on_c_echo(context, info): """Optional implementation of the AE.on_c_echo callback.""" # Return a Success response to the peer # We could also return a pydicom Dataset with a (0000, 0900) Status # element return 0x0000 # Create application entity ae = AE(ae_title=args.aetitle, port=args.port) ae.add_supported_context(VerificationSOPClass, transfer_syntax) ae.maximum_pdu_size = args.max_pdu # Set timeouts ae.network_timeout = args.timeout ae.acse_timeout = args.acse_timeout ae.dimse_timeout = args.dimse_timeout # Set callback ae.on_c_echo = on_c_echo ae.start()
logger = logging.getLogger(__name__) logger.setLevel(level=logging.INFO) handler = logging.FileHandler("storage_scu_log.txt") handler.setLevel(logging.INFO) formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s\ - %(message)s') handler.setFormatter(formatter) logger.addHandler(handler) console = logging.StreamHandler() console.setLevel(logging.INFO) logger.addHandler(console) ds = dcmread('/Volumes/Transcend/mediclouds/PACS/MRI.dcm') # ds = dcmread('/Volumes/Transcend/mediclouds/PACS/IMG00001') ae = AE(ae_title=b'ilab_scu') ae.requested_contexts = StoragePresentationContexts # ae.add_requested_context(VerificationPresentationContexts) # ae.add_requested_context(VerificationSOPClass) # for cx in ae.requested_contexts: # print(cx) assoc = ae.associate('192.168.3.5', 4100, ae_title=b'lkjds') if assoc.is_established: logger.info('assoc is established') dataset = dcmread('./MRI.dcm') # dataset = dcmread('./IMG00001') # `status` is the response from the peer to the store request
def main(args=None): """Run the application.""" if args is not None: sys.argv = args args = _setup_argparser() if args.version: print(f'movescu.py v{__version__}') sys.exit() APP_LOGGER = setup_logging(args, 'movescu') APP_LOGGER.debug(f'movescu.py v{__version__}') APP_LOGGER.debug('') # Create query (identifier) dataset try: # If you're looking at this to see how QR Move works then `identifer` # is a pydicom Dataset instance with your query keys, e.g.: # identifier = Dataset() # identifier.QueryRetrieveLevel = 'PATIENT' # identifier.PatientName = '*' identifier = create_dataset(args, APP_LOGGER) except Exception as exc: APP_LOGGER.exception(exc) sys.exit(1) # Create application entity ae = AE() # Start the Store SCP (optional) scp = None if args.store: transfer_syntax = ALL_TRANSFER_SYNTAXES[:] store_handlers = [(evt.EVT_C_STORE, handle_store, [args, APP_LOGGER])] ae.ae_title = args.store_aet for cx in AllStoragePresentationContexts: ae.add_supported_context(cx.abstract_syntax, transfer_syntax) scp = ae.start_server(('', args.store_port), block=False, evt_handlers=store_handlers) ae.ae_title = args.calling_aet ae.acse_timeout = args.acse_timeout ae.dimse_timeout = args.dimse_timeout ae.network_timeout = args.network_timeout ae.requested_contexts = QueryRetrievePresentationContexts ae.supported_contexts = [] # Query/Retrieve Information Models if args.study: query_model = StudyRootQueryRetrieveInformationModelMove elif args.psonly: query_model = PatientStudyOnlyQueryRetrieveInformationModelMove else: query_model = PatientRootQueryRetrieveInformationModelMove # Extended Negotiation ext_neg = [] ext_opts = [args.relational_retrieval, args.enhanced_conversion] if any(ext_opts): app_info = b'' for option in ext_opts: app_info += b'\x01' if option else b'\x00' item = SOPClassExtendedNegotiation() item.sop_class_uid = query_model item.service_class_application_information = app_info ext_neg = [item] # Request association with remote AE assoc = ae.associate(args.addr, args.port, ae_title=args.called_aet, max_pdu=args.max_pdu, ext_neg=ext_neg) if assoc.is_established: # Send query move_aet = args.move_aet or args.calling_aet responses = assoc.send_c_move(identifier, move_aet, query_model) for (status, rsp_identifier) in responses: # If `status.Status` is one of the 'Pending' statuses then # `rsp_identifier` is the C-MOVE response's Identifier dataset if status and status.Status in [0xFF00, 0xFF01]: # `rsp_identifier` is a pydicom Dataset containing a query # response. You may want to do something interesting here... pass assoc.release() _EXIT_VALUE = 0 else: _EXIT_VALUE = 1 # Shutdown the Storage SCP (if used) if scp: scp.shutdown() sys.exit(_EXIT_VALUE)
def _send_ctimage(hostname, port, transfersyntax): ae = AE() ae.add_requested_context(CTImageStorage, transfersyntax) assoc = ae.associate(hostname, int(port)) return assoc
def __init__(self, port=11112): self.ae = AE(port=port) self.ae.supported_contexts = VerificationPresentationContexts self.ae.add_supported_context('1.2.3.4') DummyBaseSCP.__init__(self) self.status = 0x0000
def main(args=None): """Run the application.""" if args is not None: sys.argv = args args = _setup_argparser() if args.version: print('findscu.py v{}'.format(__version__)) sys.exit() APP_LOGGER = setup_logging(args, 'findscu') APP_LOGGER.debug('findscu.py v{0!s}'.format(__version__)) APP_LOGGER.debug('') # Create query (identifier) dataset try: # If you're looking at this to see how QR Find works then `identifer` # is a pydicom Dataset instance with your query keys, e.g.: # identifier = Dataset() # identifier.QueryRetrieveLevel = 'PATIENT' # identifier.PatientName = '' identifier = create_dataset(args, APP_LOGGER) except Exception as exc: APP_LOGGER.exception(exc) raise exc sys.exit(1) # Create application entity # Binding to port 0 lets the OS pick an available port ae = AE(ae_title=args.calling_aet) # Set timeouts ae.acse_timeout = args.acse_timeout ae.dimse_timeout = args.dimse_timeout ae.network_timeout = args.network_timeout # Set the Presentation Contexts we are requesting the Find SCP support ae.requested_contexts = (QueryRetrievePresentationContexts + BasicWorklistManagementPresentationContexts) # Query/Retrieve Information Models if args.worklist: query_model = ModalityWorklistInformationFind elif args.study: query_model = StudyRootQueryRetrieveInformationModelFind elif args.psonly: query_model = PatientStudyOnlyQueryRetrieveInformationModelFind else: query_model = PatientRootQueryRetrieveInformationModelFind # Request association with (QR/BWM) Find SCP assoc = ae.associate(args.addr, args.port, ae_title=args.called_aet, max_pdu=args.max_pdu) if assoc.is_established: # Send C-FIND request, `responses` is a generator responses = assoc.send_c_find(identifier, query_model) # Used to generate filenames if args.write used fname = generate_filename() for (status, rsp_identifier) in responses: # If `status.Status` is one of the 'Pending' statuses then # `rsp_identifier` is the C-FIND response's Identifier dataset if status and status.Status in [0xFF00, 0xFF01]: if args.write: rsp_identifier.file_meta = get_file_meta( assoc, query_model) rsp_identifier.save_as(next(fname), write_like_original=False) # Release the association assoc.release() else: sys.exit(1)
transfer_syntax = [ImplicitVRLittleEndian] except: transfer_syntax = [ImplicitVRLittleEndian] #-------------------------- CREATE AE and ASSOCIATE --------------------------- if args.version: print('echoscu.py v%s' % (VERSION)) sys.exit() LOGGER.debug('echoscu.py v%s', VERSION) LOGGER.debug('') # Create local AE # Binding to port 0, OS will pick an available port ae = AE(ae_title=args.calling_aet) ae.add_requested_context(VerificationSOPClass, transfer_syntax) # Set timeouts ae.network_timeout = args.timeout ae.acse_timeout = args.acse_timeout ae.dimse_timeout = args.dimse_timeout # Request association with remote AE assoc = ae.associate(args.peer, args.port, ae_title=args.called_aet, max_pdu=args.max_pdu) # If we successfully Associated then send N DIMSE C-ECHOs
def main(args=None): """Run the application.""" if args is not None: sys.argv = args args = _setup_argparser() if args.version: print('storescu.py v{__version__}') sys.exit() APP_LOGGER = setup_logging(args, 'storescu') APP_LOGGER.debug('storescu.py v{__version__}') APP_LOGGER.debug('') lfiles, badfiles = get_files(args.path, args.recurse) for bad in badfiles: APP_LOGGER.error("Cannot access path: {bad}") ae = AE(ae_title=args.calling_aet) ae.acse_timeout = args.acse_timeout ae.dimse_timeout = args.dimse_timeout ae.network_timeout = args.network_timeout if args.required_contexts: # Only propose required presentation contexts lfiles, contexts = get_contexts(lfiles, APP_LOGGER) try: for abstract, transfer in contexts.items(): for tsyntax in transfer: ae.add_requested_context(abstract, tsyntax) except ValueError: raise ValueError( "More than 128 presentation contexts required with " "the '--required-contexts' flag, please try again " "without it or with fewer files" ) else: # Propose the default presentation contexts if args.request_little: transfer_syntax = [ExplicitVRLittleEndian] elif args.request_big: transfer_syntax = [ExplicitVRBigEndian] elif args.request_implicit: transfer_syntax = [ImplicitVRLittleEndian] else: transfer_syntax = [ ExplicitVRLittleEndian, ImplicitVRLittleEndian, DeflatedExplicitVRLittleEndian, ExplicitVRBigEndian ] for cx in StoragePresentationContexts: ae.add_requested_context(cx.abstract_syntax, transfer_syntax) if not lfiles: APP_LOGGER.warning("No suitable DICOM files found") sys.exit() # Request association with remote assoc = ae.associate( args.addr, args.port, ae_title=args.called_aet, max_pdu=args.max_pdu ) if assoc.is_established: ii = 1 for fpath in lfiles: APP_LOGGER.info('Sending file: {fpath}') try: ds = dcmread(fpath) status = assoc.send_c_store(ds, ii) ii += 1 except InvalidDicomError: APP_LOGGER.error('Bad DICOM file: {fpath}') except Exception as exc: APP_LOGGER.error("Store failed: {fpath}") APP_LOGGER.exception(exc) assoc.release() else: sys.exit(1)
LOGGER.setLevel(logging.INFO) pynetdicom_logger = logging.getLogger('pynetdicom') pynetdicom_logger.setLevel(logging.INFO) if args.debug: LOGGER.setLevel(logging.DEBUG) pynetdicom_logger = logging.getLogger('pynetdicom') pynetdicom_logger.setLevel(logging.DEBUG) LOGGER.debug('$getscu.py v{0!s}'.format(VERSION)) LOGGER.debug('') # Create application entity # Binding to port 0 lets the OS pick an available port ae = AE(ae_title=args.calling_aet, port=0) for context in QueryRetrievePresentationContexts: ae.add_requested_context(context.abstract_syntax) for context in StoragePresentationContexts[:115]: ae.add_requested_context(context.abstract_syntax) # Add SCP/SCU Role Selection Negotiation to the extended negotiation # We want to act as a Storage SCP ext_neg = [] for context in StoragePresentationContexts: role = SCP_SCU_RoleSelectionNegotiation() role.sop_class_uid = context.abstract_syntax role.scp_role = True role.scu_role = False ext_neg.append(role)
ds.file_meta = meta # Set the transfer syntax attributes of the dataset ds.is_little_endian = context.transfer_syntax.is_little_endian ds.is_implicit_VR = context.transfer_syntax.is_implicit_VR # Save the dataset using the SOP Instance UID as the filename ds.save_as(ds.SOPInstanceUID, write_like_original=False) # Return a 'Success' status return 0x0000 handlers = [(evt.EVT_C_STORE, handle_store)] ae = AE() ae.add_requested_context(StudyRootQueryRetrieveInformationModelGet) # Add the requested presentation context (Storage SCP) ae.add_requested_context(CTImageStorage) # Create an SCP/SCU Role Selection Negotiation item for CT Image Storage role = build_role(CTImageStorage, scp_role=True) # Create our Identifier (query) dataset # We need to supply a Unique Key Attribute for each level above the # Query/Retrieve level ds = Dataset() ds.QueryRetrieveLevel = 'SERIES' # Unique key for PATIENT level ds.PatientID = '8435'