Mercurial > hg > orthanc
comparison OrthancServer/Resources/Samples/ImportDicomFiles/OrthancImport.py @ 4337:7707fa761b71
OrthancImport.py sample
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Wed, 02 Dec 2020 11:01:59 +0100 |
parents | |
children | d9473bd5ed43 |
comparison
equal
deleted
inserted
replaced
4336:9b38aadd4a99 | 4337:7707fa761b71 |
---|---|
1 #!/usr/bin/env python | |
2 | |
3 # Orthanc - A Lightweight, RESTful DICOM Store | |
4 # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics | |
5 # Department, University Hospital of Liege, Belgium | |
6 # Copyright (C) 2017-2020 Osimis S.A., Belgium | |
7 # | |
8 # This program is free software: you can redistribute it and/or | |
9 # modify it under the terms of the GNU General Public License as | |
10 # published by the Free Software Foundation, either version 3 of the | |
11 # License, or (at your option) any later version. | |
12 # | |
13 # This program is distributed in the hope that it will be useful, but | |
14 # WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
16 # General Public License for more details. | |
17 # | |
18 # You should have received a copy of the GNU General Public License | |
19 # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
20 | |
21 | |
22 import argparse | |
23 import bz2 | |
24 import gzip | |
25 import os | |
26 import requests | |
27 import sys | |
28 import tarfile | |
29 import zipfile | |
30 | |
31 from requests.auth import HTTPBasicAuth | |
32 | |
33 | |
34 | |
35 parser = argparse.ArgumentParser(description = 'Command-line tool to import files or archives into Orthanc.') | |
36 parser.add_argument('--url', | |
37 default = 'http://localhost:8042', | |
38 help = 'URL to the REST API of the Orthanc server') | |
39 parser.add_argument('--username', | |
40 default = 'orthanc', | |
41 help = 'Username to the REST API') | |
42 parser.add_argument('--password', | |
43 default = 'orthanc', | |
44 help = 'Password to the REST API') | |
45 parser.add_argument('--force', help = 'Do not warn the user about deletion', | |
46 action = 'store_true') | |
47 parser.add_argument('--clear', help = 'Remove the content of the Orthanc database', | |
48 action = 'store_true') | |
49 parser.add_argument('--verbose', help = 'Be verbose', | |
50 action = 'store_true') | |
51 parser.add_argument('--ignore-errors', help = 'Do not stop if encountering non-DICOM files', | |
52 action = 'store_true') | |
53 parser.add_argument('files', metavar = 'N', nargs = '*', | |
54 help = 'Files to import') | |
55 | |
56 | |
57 args = parser.parse_args() | |
58 | |
59 if args.clear and not args.force: | |
60 print(""" | |
61 WARNING: This script will remove all the content of your | |
62 Orthanc instance running on %s! | |
63 | |
64 Are you sure ["yes" to go on]?""" % args.server) | |
65 | |
66 if sys.stdin.readline().strip() != 'yes': | |
67 print('Aborting...') | |
68 exit(0) | |
69 | |
70 | |
71 | |
72 IMPORTED_STUDIES = set() | |
73 COUNT_ERROR = 0 | |
74 COUNT_SUCCESS = 0 | |
75 | |
76 def UploadBuffer(dicom): | |
77 global IMPORTED_STUDIES | |
78 global COUNT_ERROR | |
79 global COUNT_SUCCESS | |
80 | |
81 auth = HTTPBasicAuth(args.username, args.password) | |
82 r = requests.post('%s/instances' % args.url, auth = auth, data = dicom) | |
83 | |
84 try: | |
85 r.raise_for_status() | |
86 except: | |
87 COUNT_ERROR += 1 | |
88 if args.ignore_errors: | |
89 if args.verbose: | |
90 print(' not a valid DICOM file, ignoring it') | |
91 return | |
92 else: | |
93 raise | |
94 | |
95 info = r.json() | |
96 COUNT_SUCCESS += 1 | |
97 | |
98 if not info['ParentStudy'] in IMPORTED_STUDIES: | |
99 IMPORTED_STUDIES.add(info['ParentStudy']) | |
100 | |
101 r2 = requests.get('%s/instances/%s/tags?short' % (args.url, info['ID']), | |
102 auth = auth) | |
103 r2.raise_for_status() | |
104 tags = r2.json() | |
105 | |
106 print('') | |
107 print('New imported study:') | |
108 print(' Orthanc ID of the patient: %s' % info['ParentPatient']) | |
109 print(' Orthanc ID of the study: %s' % info['ParentStudy']) | |
110 print(' DICOM Patient ID: %s' % tags['0010,0020']) | |
111 print(' DICOM Study Instance UID: %s' % tags['0020,000d']) | |
112 print('') | |
113 | |
114 | |
115 def UploadFile(path): | |
116 with open(path, 'rb') as f: | |
117 dicom = f.read() | |
118 if args.verbose: | |
119 print('Uploading: %s (%dMB)' % (path, len(dicom) / (1024 * 1024))) | |
120 | |
121 UploadBuffer(dicom) | |
122 | |
123 | |
124 def UploadBzip2(path): | |
125 with bz2.BZ2File(path, 'rb') as f: | |
126 dicom = f.read() | |
127 if args.verbose: | |
128 print('Uploading: %s (%dMB)' % (path, len(dicom) / (1024 * 1024))) | |
129 | |
130 UploadBuffer(dicom) | |
131 | |
132 | |
133 def UploadGzip(path): | |
134 with gzip.open(path, 'rb') as f: | |
135 dicom = f.read() | |
136 if args.verbose: | |
137 print('Uploading: %s (%dMB)' % (path, len(dicom) / (1024 * 1024))) | |
138 | |
139 UploadBuffer(dicom) | |
140 | |
141 | |
142 def UploadTar(path, decoder): | |
143 if args.verbose: | |
144 print('Uncompressing tar archive: %s' % path) | |
145 with tarfile.open(path, decoder) as tar: | |
146 for item in tar: | |
147 if item.isreg(): | |
148 f = tar.extractfile(item) | |
149 dicom = f.read() | |
150 f.close() | |
151 | |
152 if args.verbose: | |
153 print('Uploading: %s (%dMB)' % (item.name, len(dicom) / (1024 * 1024))) | |
154 | |
155 UploadBuffer(dicom) | |
156 | |
157 | |
158 def UploadZip(path): | |
159 if args.verbose: | |
160 print('Uncompressing ZIP archive: %s' % path) | |
161 with zipfile.ZipFile(path, 'r') as zip: | |
162 for item in zip.infolist(): | |
163 # WARNING - "item.is_dir()" would be better, but is not available in Python 2.7 | |
164 if item.file_size > 0: | |
165 dicom = zip.read(item.filename) | |
166 | |
167 if args.verbose: | |
168 print('Uploading: %s (%dMB)' % (item.filename, len(dicom) / (1024 * 1024))) | |
169 | |
170 UploadBuffer(dicom) | |
171 | |
172 | |
173 def DecodeFile(path): | |
174 extension = os.path.splitext(path) [1] | |
175 | |
176 if path.endswith('.tar.bz2'): | |
177 UploadTar(path, 'r:bz2') | |
178 elif path.endswith('.tar.gz'): | |
179 UploadTar(path, 'r:gz') | |
180 elif extension == '.zip': | |
181 UploadZip(path) | |
182 elif extension == '.tar': | |
183 UploadTar(path, 'r') | |
184 elif extension == '.bz2': | |
185 UploadBzip2(path) | |
186 elif extension == '.gz': | |
187 UploadGzip(path) | |
188 else: | |
189 UploadFile(path) | |
190 | |
191 | |
192 if args.clear: | |
193 print('Removing the content of Orthanc') | |
194 | |
195 auth = HTTPBasicAuth(args.username, args.password) | |
196 r = requests.get('%s/studies' % args.url, auth = auth) | |
197 r.raise_for_status() | |
198 | |
199 print(' %d studies are being removed...' % len(r.json())) | |
200 | |
201 for study in r.json(): | |
202 requests.delete('%s/studies/%s' % (args.url, study), auth = auth).raise_for_status() | |
203 | |
204 print('Orthanc is now empty') | |
205 print('') | |
206 | |
207 | |
208 for path in args.files: | |
209 if os.path.isfile(path): | |
210 DecodeFile(path) | |
211 elif os.path.isdir(path): | |
212 for root, dirs, files in os.walk(path): | |
213 for name in files: | |
214 DecodeFile(os.path.join(root, name)) | |
215 else: | |
216 raise Exception('Missing file or directory: %s' % path) | |
217 | |
218 | |
219 print('') | |
220 print('Status:') | |
221 print(' %d DICOM instances properly imported' % COUNT_SUCCESS) | |
222 print(' %d DICOM studies properly imported' % len(IMPORTED_STUDIES)) | |
223 print(' Error in %d files' % COUNT_ERROR) | |
224 print('') |