daemon DICOMweb store proxying to pacs in c-store protocol

Related tags

Guides postcstore
Overview

POSTCSTORE

versionado

versión autor comentario
2021-11-02 Jacques Fauquex versión inicial
2021-11-02 Jacques Fauquex aetLocal en la ruta del servicio.
compuesto de los parámetros del pacs de destino
2021-11-03 Jacques Fauquex header application/dicom+xml en caso 1
2021-11-03 Jacques Fauquex aet autorizado
2021-11-04 Jacques Fauquex dirPath, scu/scp in path

Servicio REST POSTCSTORE

demonio que escucha un puerto http para recibir Archivos DICOM por protocolo HTTP POST DICOM STORE y los manda a un pacs DIMSE por protocolo C-STORE mediante la libraría dcmtk.

Los parametros de ejecución son:

  • httpPort
  • dirPath (for files received)
  • destHost
  • destPort
  • aet autorizado
  • ...

HTTP POST

POST scu/scp/studies

(no implementamos POST service/studies/{studyIUID} en esta ocasión)

scu y scp son los aets usados para mandar los archivos al pacs por c-store.

Content-Type

  • multipart/related;type=application/dicom;boundary=myBoundary
  • multipart/related;type=application/dicom+xml;boundary=myBoundary
  • application/dicom+json
  • application/dicom+json+dckv
  • application/dicom+json+edckv

(Content-Length: uint | Content-Encoding: encoding)

puede estar presente uno u otro de estos headers, pero no los dos en un mismo request.

Content-Length sirve par un body que no sea multipart.

Content-Encoding (por ejemplo: Content-Encoding: gzip) puede aplicarse a body multipart o no.

Accept

Reservamos el uso de accept para definir en próximas etapas opciones de body de respuestas.

query parameters

ninguno

payload

el o los recursos enviados en el body del POST

Casos de uso

Inicialmente implementamos los casos "dicom" multiples archivos y "dicom+xml" dicom metadata y xml encapsulado de un solo archivo.

En otras iteraciones, implementaremos application/dicom+json, y los media-types propietarios application/dicom+dckv y application/dicom+edckv

dicom

archivos dicom binario

header

Content-Type: multipart/related;type=application/dicom; boundary=myBoundary

body (repetible)

\r\n--myBoundary--\r\n
Content-Type: application/dicom\r\n\r\n
<DICM>

tail

\r\n--myBoundary--\r\n

dicom+xml

metadata DICOM en xml

que contiene

Observar el uri "bulk" que se refiere al Content-Location que sigue en el POST

header

Content-Type: multipart/related; type=application/dicom+xml; boundary=myBoundary

body (repetible)

\r\n--myBoundary--\r\n
Content-Type: application/dicom+xml\r\n\r\n
transfer-syntax=1.2.840.10008.1.2.1\r\n\r\n
<NativeDicomModel>
\r\n\r\n--myboundary
\r\nContent-Type: text/XML
\r\nContent-Location: bulk
\r\n\r\n
<xml>

tail

\r\n--myBoundary--\r\n

Response

En la primera iteración devolverá exclusivamente un status

code descripción
200(OK) The origin server successfully stored all Instances.
202(Accepted) The origin server stored some of the Instances but warnings or failures exist for others. Additional information regarding this error may be found in the response message body.
204(NoContent) There were no adequate resources in the body
206(PartialContent) Some of the resources have been sent but not all
400(BadRequest) The origin server was unable to store any instances due to bad syntax.
409(Conflict) The request was formed correctly but the origin server was unable to store any instances due to a conflict in the request (e.g., unsupported SOP Class or Study Instance UID mismatch). This may also be used to indicate that the origin server was unable to store any instances for a mixture of reasons.
415(UnsupportedMediaType) The origin server does not support the media type specified in the Content-Type header field of the request

Ejemplo python de cliente dicom+xml

Este ejemplo se encuentra en html5cda. Crea la metadata dicom en formato dicom+xml para el documento encapsulado . Finalmente junta ambos en un request POST DICOM /studies

    seriesuid = '2.25.{}'.format(int(str(uuid.uuid4()).replace('-', ''), 16))
    xml_dcm = '<?xml version="1.0" encoding="UTF-8"?>'
    xml_dcm += '<NativeDicomModel xml-space="preserved">'
    xml_dcm += '<DicomAttribute keyword="FileMetaInformationVersion" tag="00020001" vr="OB"><InlineBinary>AAE=</InlineBinary></DicomAttribute>'
    xml_dcm += '<DicomAttribute keyword="MediaStorageSOPClassUID" tag="00020002" vr="UI"><Value number="1">1.2.840.10008.5.1.4.1.1.104.2</Value></DicomAttribute>'
    xml_dcm += '<DicomAttribute keyword="MediaStorageSOPInstanceUID" tag="00020003" vr="UI"><Value number="1">{}</Value></DicomAttribute>'.format(
        informeuid)
    xml_dcm += '<DicomAttribute keyword="TransferSyntaxUID" tag="00020010" vr="UI"><Value number="1">1.2.840.10008.1.2</Value></DicomAttribute>'
    xml_dcm += '<DicomAttribute keyword="ImplementationClassUID" tag="00020012" vr="UI"><Value number="1">2.16.858.0.2.9.62.0.1.0.217215590012</Value></DicomAttribute>'
    xml_dcm += '<DicomAttribute keyword="ImplementationVersionName" tag="00020013" vr="SH"><Value number="1">JESROS OPENDICOM</Value></DicomAttribute>'
    xml_dcm += '<DicomAttribute keyword="SpecificCharacterSet" tag="00080005" vr="CS"><Value number="1">ISO_IR 100</Value></DicomAttribute>'
    xml_dcm += '<DicomAttribute keyword="SOPClassUID" tag="00080016" vr="UI"><Value number="1">1.2.840.10008.5.1.4.1.1.104.2</Value></DicomAttribute>'
    xml_dcm += '<DicomAttribute keyword="SOPInstanceUID" tag="00080018" vr="UI"><Value number="1">{}</Value></DicomAttribute>'.format(
        informeuid)
    xml_dcm += '<DicomAttribute keyword="TimezoneOffsetFromUTC" tag="00080201" vr="SH"><Value number="1">-0300</Value></DicomAttribute>'
    xml_dcm += '<DicomAttribute keyword="PatientName" tag="00100010" vr="PN"><PersonName number="1"><Alphabetic><FamilyName>{}</FamilyName></Alphabetic></PersonName></DicomAttribute>'.format(
        values_submit['PatientName'][0])
    xml_dcm += '<DicomAttribute keyword="PatientID" tag="00100020" vr="LO"><Value number="1">{}</Value></DicomAttribute>'.format(
        values_submit['PatientID'][0])
    xml_dcm += '<DicomAttribute keyword="IssuerOfPatientID" tag="00100021" vr="LO"><Value number="1">{}</Value></DicomAttribute>'.format(
        values_submit['PatientIDIssuer'][0])
    xml_dcm += '<DicomAttribute keyword="PatientBirthDate" tag="00100030" vr="DA"><Value number="1">{}</Value></DicomAttribute>'.format(
        values_submit['PatientBirthDate'][0])
    xml_dcm += '<DicomAttribute keyword="PatientSex" tag="00100040" vr="CS"><Value number="1">{}</Value></DicomAttribute>'.format(
        values_submit['PatientSex'][0])
    xml_dcm += '<DicomAttribute keyword="StudyInstanceUID" tag="0020000D" vr="UI"><Value number="1">{}</Value></DicomAttribute>'.format(
        values_submit['StudyIUID'][0])
    xml_dcm += '<DicomAttribute keyword="Modality" tag="00080060" vr="CS"><Value number="1">DOC</Value></DicomAttribute>'
    xml_dcm += '<DicomAttribute keyword="SeriesInstanceUID" tag="0020000E" vr="UI"><Value number="1">{}</Value></DicomAttribute>'.format(
        seriesuid)
    xml_dcm += '<DicomAttribute keyword="SeriesNumber" tag="00200011" vr="IS"><Value number="1">-16</Value></DicomAttribute>'
    xml_dcm += '<DicomAttribute keyword="SeriesDescription" tag="0008103E" vr="LO"><Value number="1">ClinicalDocument</Value></DicomAttribute>'
    xml_dcm += '<DicomAttribute keyword="SeriesDate" tag="00080021" vr="DA"><Value number="1">{}</Value></DicomAttribute>'.format(
        datetime.now().strftime("%Y%m%d"))
    xml_dcm += '<DicomAttribute keyword="SeriesTime" tag="00080031" vr="TM"><Value number="1">{}</Value></DicomAttribute>'.format(
        datetime.now().strftime("%H%M%S"))
    xml_dcm += '<DicomAttribute keyword="PerformedProcedureStepStartDate" tag="00400244" vr="DA"><Value number="1">{}</Value></DicomAttribute>'.format(
        datetime.now().strftime("%Y%m%d"))
    xml_dcm += '<DicomAttribute keyword="PerformedProcedureStepStartTime" tag="00400245" vr="TM"><Value number="1">{}</Value></DicomAttribute>'.format(
        datetime.now().strftime("%H%M%S"))
    xml_dcm += '<DicomAttribute keyword="Manufacturer" tag="00080070" vr="LO"><Value number="1">opendicom (Jesros SA)</Value></DicomAttribute>'
    xml_dcm += '<DicomAttribute keyword="InstitutionAddress" tag="00080081" vr="ST"><Value number="1">Agesic, Torre Ejecutiva Torre Sur, Liniers 1324, Montevideo, Uruguay</Value></DicomAttribute>'
    xml_dcm += '<DicomAttribute keyword="SoftwareVersions" tag="00181020" vr="LO"><Value number="1">2.0</Value></DicomAttribute>'
    xml_dcm += '<DicomAttribute keyword="ConversionType" tag="00080064" vr="CS"><Value number="1">WSD</Value></DicomAttribute>'
    xml_dcm += '<DicomAttribute keyword="InstanceNumber" tag="00200013" vr="IS"><Value number="1">1</Value></DicomAttribute>'
    xml_dcm += '<DicomAttribute keyword="ContentDate" tag="00080023" vr="DA"><Value number="1">{}</Value></DicomAttribute>'.format(
        datetime.now().strftime("%Y%m%d"))
    xml_dcm += '<DicomAttribute keyword="ContentTime" tag="00080033" vr="TM"><Value number="1">{}</Value></DicomAttribute>'.format(
        datetime.now().strftime("%H%M%S"))
    xml_dcm += '<DicomAttribute keyword="AcquisitionDateTime" tag="0008002A" vr="DT"><Value number="1">{}{}</Value></DicomAttribute>'.format(
        datetime.now().strftime("%Y%m%d"), datetime.now().strftime("%H%M%S"))
    xml_dcm += '<DicomAttribute keyword="BurnedInAnnotation" tag="00280301" vr="CS"><Value number="1">YES</Value></DicomAttribute>'
    xml_dcm += '<DicomAttribute keyword="DocumentTitle" tag="00420010" vr="ST"><Value number="1">INFORME IMAGENOLOGICO</Value></DicomAttribute>'
    xml_dcm += '<DicomAttribute keyword="HL7InstanceIdentifier" tag="0040E001" vr="ST"><Value number="1">{}</Value></DicomAttribute>'.format(
        autenticado.id)
    xml_dcm += '<DicomAttribute keyword="MIMETypeOfEncapsulatedDocument" tag="00420012" vr="LO"><Value number="1">text/xml</Value></DicomAttribute>'
    xml_dcm += '<DicomAttribute keyword="EncapsulatedDocument" tag="00420011" vr="OB"><BulkData uri="bulk"/></DicomAttribute>'
    xml_dcm += '</NativeDicomModel>'

 
url = settings.OID_URL[institution.oid]['stow']
    headers = {'Content-Type': 'multipart/related; type=application/dicom+xml; boundary=myboundary'}
    data = '\r\n--myboundary\r\nContent-Type: application/dicom+xml; transfer-syntax=1.2.840.10008.1.2.1\r\n\r\n{}\r\n\r\n--myboundary\r\nContent-Type: text/XML\r\nContent-Location: bulk\r\n\r\n{}\r\n--myboundary--'.format(
        xml_dcm, xml_cda)
    requests.post(url, headers=headers, data=data.encode('utf-8'))
You might also like...
A powerful, protocol-oriented library for working with the keychain in Swift.

Locksmith A powerful, protocol-oriented library for working with the keychain in Swift. 📱 iOS 8.0+ 💻 Mac OS X 10.10+ ⌚️ watchOS 2 📺 tvOS 🚀 I make

Solana + RxSolana This is a open source library on pure swift for Solana protocol

The objective is to create a cross platform, fully functional, highly tested and less depencies as posible. The project is still at initial stage. Lots of changes chan happen to the exposed api.

Tech blog about Put Generic Protocol as Variable Type. How Combine Publisher put into AnyPublisher

How to Put Generic Protocol as Variable Type Have you ever put a Protocol on a variable? I believe you do. The Delegate pattern is using a lot in UIKi

A Protocol-Oriented NotificationCenter which is type safe, thread safe and with memory safety
A Protocol-Oriented NotificationCenter which is type safe, thread safe and with memory safety

A Protocol-Oriented NotificationCenter which is type safe, thread safe and with memory safety. Type Safe No more userInfo dictionary and Downcasting,

A powerful, protocol-oriented library for working with the keychain in Swift.

Locksmith A powerful, protocol-oriented library for working with the keychain in Swift. 📱 iOS 8.0+ 💻 Mac OS X 10.10+ ⌚️ watchOS 2 📺 tvOS 🚀 I make

Interface-oriented router for discovering modules, and injecting dependencies with protocol in Objective-C and Swift.
Interface-oriented router for discovering modules, and injecting dependencies with protocol in Objective-C and Swift.

ZIKRouter An interface-oriented router for managing modules and injecting dependencies with protocol. The view router can perform all navigation types

Protocol oriented, Cocoa UI abstractions based library that helps to handle view controllers composition, navigation and deep linking tasks in the iOS application. Can be used as the universal replacement for the Coordinator pattern.
Google Analytics tracker for Apple tvOS provides an easy integration of Google Analytics’ measurement protocol for Apple TV.

Google Analytics tracker for Apple tvOS by Adswerve About Google Analytics tracker for Apple tvOS provides an easy integration of Google Analytics’ me

A protocol-centric, type and queue safe key-value workflow.
A protocol-centric, type and queue safe key-value workflow.

Light-weight, strict protocol-first styled PropertyKit helps you to easily and safely handle guaranteed values, keys or types on various situations of

Bitcoin protocol toolkit for Swift
Bitcoin protocol toolkit for Swift

Welcome to BitcoinKit The BitcoinKit library is a Swift implementation of the Bitcoin protocol which support both BCH and BTC. Improving the mobile ec

A functional utility belt implemented as Swift 2.0 protocol extensions.

Oriole [![CI Status](http://img.shields.io/travis/Tyler Thompson/Oriole.svg?style=flat)](https://travis-ci.org/Tyler Thompson/Oriole) Oriole is a set

Implemented MVVM-C (Coordinator) architecture pattern for the project. Which is satisfying SOLID principles altogether. Protocol oriented development has been followed.

BreakingBad BreakingBad API doc Implemented MVVM-C (Coordinator) architecture pattern for the project. Which is satisfying SOLID principples altogethe

A simple protocol package that does nothing

HasResult A simple protocol package that does nothing. The HasResult protocol has a simple result property and a ResultType associated type. This is m

A protocol that allows any class to be printed as if it were a struct or a JSON object.

ReflectedStringConvertible A protocol that extends CustomStringConvertible and uses reflection to add a detailed textual representation to any class.

A protocol to serialize Swift structs and classes for encoding and decoding.
A protocol to serialize Swift structs and classes for encoding and decoding.

Serpent (previously known as Serializable) is a framework made for creating model objects or structs that can be easily serialized and deserialized fr

URLEmbeddedView automatically caches the object that is confirmed the Open Graph Protocol.
URLEmbeddedView automatically caches the object that is confirmed the Open Graph Protocol.

URLEmbeddedView Features Simple interface for fetching Open Graph Data Be able to display Open Graph Data Automatically caching Open Graph Data Automa

🎧 Protocol driven object observation

Listenable Swift object that provides an observable platform for multiple listeners. Requirements iOS 9.0+ Xcode 9.x+ Swift 4 Installation Listenable

Language Server Protocol (LSP) client for Swift

LanguageClient This is a Swift library for abstracting and interacting with language servers that implement the Language Server Protocol. It is built

Protocol to handle initial Loadings, Empty Views and Error Handling in a ViewController & views
Protocol to handle initial Loadings, Empty Views and Error Handling in a ViewController & views

StatusProvider Protocol to handle initial Loadings, Empty Views and Error Handling in a ViewController & views CocoaPods Podfile pod 'StatusProvider'

Owner
Software For Medical Images
null
iOS protocol-oriented MVVM examples

MVVM-Example Protocol-Oriented MVVM example apps. Sample projects: MVVM-Example - A Settings screen that has one settings – put your app in Minion Mod

Ivan Magda 52 May 5, 2022
Store Onions 🧅

OnionStash Layered Data Onion Layers ID Optional: Type Optional: Meta Value Layerable public protocol Layerable { func idLayer() -> String func ty

Zach Eriksen 1 Oct 19, 2021
Post-exploitation multiplexor daemon, used for surveillance and remote access

DevilSpawn About DevilSpawn is a post exploitation multiplexor daemon which is an surveillance tool written in Python. It gives you a command line ses

Dylan Elmbark Sandström 2 Nov 15, 2022
🍎 An App to check whether a non-App Store app is in App Store.

AppStorify ?? An App to check whether a non-App Store app is in App Store. Benfits Use App Store's upgrade mechanism instead of app's. App Store apps

seedgou 58 Dec 7, 2022
Store-App - Store app made for IOS using Swift programming language

Store-App Store app views products, cart, and using login from https://fakestore

Anas Khalil 2 Jan 1, 2022
tl;dr You love Swift's Codable protocol and use it everywhere

tl;dr You love Swift's Codable protocol and use it everywhere, who doesn't! Here is an easy and very light way to store and retrieve -reasonable amoun

Omar Albeik 452 Oct 17, 2022
Gifu adds protocol-based, performance-aware animated GIF support to UIKit.

Gifu adds protocol-based, performance-aware animated GIF support to UIKit. (It's also a prefecture in Japan). Install Swift Package Manager Add the fo

Reda Lemeden 2.8k Jan 7, 2023
Protocol oriented, type safe, scalable design system foundation swift framework for iOS.

Doric: Design System Foundation Design System foundation written in Swift. Protocol oriented, type safe, scalable framework for iOS. Features Requirem

Jay 93 Dec 6, 2022
URLEmbeddedView automatically caches the object that is confirmed the Open Graph Protocol.

URLEmbeddedView Features Simple interface for fetching Open Graph Data Be able to display Open Graph Data Automatically caching Open Graph Data Automa

Taiki Suzuki 643 Dec 20, 2022
Restofire is a protocol oriented networking client for Alamofire

Restofire is a protocol oriented networking client for Alamofire. Features Requirements Installation Usage License Features Global Configuration for h

Restofire 381 Sep 29, 2022