9
9
### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##
10
10
# Copyright (C) 2011 Christian Haselgrove
11
11
12
- import sys
13
- import os
14
- import stat
15
- import errno
16
- import time
17
- import locale
18
- import logging
19
- import fuse
20
- import nibabel as nib
21
- import nibabel .dft as dft
22
-
23
- from optparse import OptionParser , Option
24
-
25
- uid = os .getuid ()
26
- gid = os .getgid ()
27
- encoding = locale .getdefaultlocale ()[1 ]
28
-
29
- fuse .fuse_python_api = (0 , 2 )
30
-
31
- logger = logging .getLogger ('nibabel.dft' )
32
-
33
- class FileHandle :
34
-
35
- def __init__ (self , fno ):
36
- self .fno = fno
37
- self .keep_cache = False
38
- self .direct_io = False
39
- return
40
-
41
- def __str__ (self ):
42
- return 'FileHandle(%d)' % self .fno
43
-
44
- class DICOMFS (fuse .Fuse ):
45
-
46
- def __init__ (self , * args , ** kwargs ):
47
- self .followlinks = kwargs .pop ('followlinks' , False )
48
- fuse .Fuse .__init__ (self , * args , ** kwargs )
49
- self .fhs = {}
50
- return
51
-
52
- def get_paths (self ):
53
- paths = {}
54
- for study in dft .get_studies (self .dicom_path , self .followlinks ):
55
- pd = paths .setdefault (study .patient_name_or_uid (), {})
56
- patient_info = 'patient information\n '
57
- patient_info = 'name: %s\n ' % study .patient_name
58
- patient_info += 'ID: %s\n ' % study .patient_id
59
- patient_info += 'birth date: %s\n ' % study .patient_birth_date
60
- patient_info += 'sex: %s\n ' % study .patient_sex
61
- pd ['INFO' ] = patient_info .encode ('ascii' , 'replace' )
62
- study_datetime = '%s_%s' % (study .date , study .time )
63
- study_info = 'study info\n '
64
- study_info += 'UID: %s\n ' % study .uid
65
- study_info += 'date: %s\n ' % study .date
66
- study_info += 'time: %s\n ' % study .time
67
- study_info += 'comments: %s\n ' % study .comments
68
- d = {'INFO' : study_info .encode ('ascii' , 'replace' )}
69
- for series in study .series :
70
- series_info = 'series info\n '
71
- series_info += 'UID: %s\n ' % series .uid
72
- series_info += 'number: %s\n ' % series .number
73
- series_info += 'description: %s\n ' % series .description
74
- series_info += 'rows: %d\n ' % series .rows
75
- series_info += 'columns: %d\n ' % series .columns
76
- series_info += 'bits allocated: %d\n ' % series .bits_allocated
77
- series_info += 'bits stored: %d\n ' % series .bits_stored
78
- series_info += 'storage instances: %d\n ' % len (series .storage_instances )
79
- d [series .number ] = {'INFO' : series_info .encode ('ascii' , 'replace' ),
80
- '%s.nii' % series .number : (series .nifti_size , series .as_nifti ),
81
- '%s.png' % series .number : (series .png_size , series .as_png )}
82
- pd [study_datetime ] = d
83
- return paths
84
-
85
- def match_path (self , path ):
86
- wd = self .get_paths ()
87
- if path == '/' :
88
- logger .debug ('return root' )
89
- return wd
90
- for part in path .lstrip ('/' ).split ('/' ):
91
- logger .debug ("path:%s part:%s" % (path , part ))
92
- if part not in wd :
93
- return None
94
- wd = wd [part ]
95
- logger .debug ('return' )
96
- return wd
97
-
98
- def readdir (self , path , fh ):
99
- logger .info ('readdir %s' % (path ,))
100
- matched_path = self .match_path (path )
101
- if matched_path is None :
102
- return - errno .ENOENT
103
- logger .debug ('matched %s' % (matched_path ,))
104
- fnames = [ k .encode ('ascii' , 'replace' ) for k in matched_path .keys () ]
105
- fnames .append ('.' )
106
- fnames .append ('..' )
107
- return [ fuse .Direntry (f ) for f in fnames ]
108
-
109
- def getattr (self , path ):
110
- logger .debug ('getattr %s' % path )
111
- matched_path = self .match_path (path )
112
- logger .debug ('matched: %s' % (matched_path ,))
113
- now = time .time ()
114
- st = fuse .Stat ()
115
- if isinstance (matched_path , dict ):
116
- st .st_mode = stat .S_IFDIR | 0755
117
- st .st_ctime = now
118
- st .st_mtime = now
119
- st .st_atime = now
120
- st .st_uid = uid
121
- st .st_gid = gid
122
- st .st_nlink = len (matched_path )
123
- return st
124
- if isinstance (matched_path , str ):
125
- st .st_mode = stat .S_IFREG | 0644
126
- st .st_ctime = now
127
- st .st_mtime = now
128
- st .st_atime = now
129
- st .st_uid = uid
130
- st .st_gid = gid
131
- st .st_size = len (matched_path )
132
- st .st_nlink = 1
133
- return st
134
- if isinstance (matched_path , tuple ):
135
- st .st_mode = stat .S_IFREG | 0644
136
- st .st_ctime = now
137
- st .st_mtime = now
138
- st .st_atime = now
139
- st .st_uid = uid
140
- st .st_gid = gid
141
- st .st_size = matched_path [0 ]()
142
- st .st_nlink = 1
143
- return st
144
- return - errno .ENOENT
145
-
146
- def open (self , path , flags ):
147
- logger .debug ('open %s' % (path ,))
148
- matched_path = self .match_path (path )
149
- if matched_path is None :
150
- return - errno .ENOENT
151
- for i in range (1 , 10 ):
152
- if i not in self .fhs :
153
- if isinstance (matched_path , str ):
154
- self .fhs [i ] = matched_path
155
- elif isinstance (matched_path , tuple ):
156
- self .fhs [i ] = matched_path [1 ]()
157
- else :
158
- raise - errno .EFTYPE
159
- return FileHandle (i )
160
- raise - errno .ENFILE
161
-
162
- # not done
163
- def read (self , path , size , offset , fh ):
164
- logger .debug ('read' )
165
- logger .debug (path )
166
- logger .debug (size )
167
- logger .debug (offset )
168
- logger .debug (fh )
169
- return self .fhs [fh .fno ][offset :offset + size ]
170
-
171
- def release (self , path , flags , fh ):
172
- logger .debug ('release' )
173
- logger .debug (path )
174
- logger .debug (fh )
175
- del self .fhs [fh .fno ]
176
- return
177
-
178
- def get_opt_parser ():
179
- # use module docstring for help output
180
- p = OptionParser (
181
- usage = "%s [OPTIONS] <DIRECTORY CONTAINING DICOMSs> <mount point>"
182
- % os .path .basename (sys .argv [0 ]),
183
- version = "%prog " + nib .__version__ )
184
-
185
- p .add_options ([
186
- Option ("-v" , "--verbose" , action = "count" ,
187
- dest = "verbose" , default = 0 ,
188
- help = "make noise. Could be specified multiple times" ),
189
- ])
190
-
191
- p .add_options ([
192
- Option ("-L" , "--follow-links" , action = "store_true" ,
193
- dest = "followlinks" , default = False ,
194
- help = "Follow symbolic links in DICOM directory" ),
195
- ])
196
- return p
12
+ from nibabel .cmdline .dicomfs import main
197
13
198
14
if __name__ == '__main__' :
199
- parser = get_opt_parser ()
200
- (opts , files ) = parser .parse_args ()
201
-
202
- if opts .verbose :
203
- logger .addHandler (logging .StreamHandler (sys .stdout ))
204
- logger .setLevel (opts .verbose > 1 and logging .DEBUG or logging .INFO )
205
-
206
- if len (files ) != 2 :
207
- sys .stderr .write ("Please provide two arguments:\n %s\n " % parser .usage )
208
- sys .exit (1 )
209
-
210
- fs = DICOMFS (dash_s_do = 'setsingle' , followlinks = opts .followlinks )
211
- fs .parse (['-f' , '-s' , files [1 ]])
212
- fs .dicom_path = files [0 ].decode (encoding )
213
- try :
214
- fs .main ()
215
- except fuse .FuseError :
216
- # fuse prints the error message
217
- sys .exit (1 )
218
-
219
- sys .exit (0 )
220
-
221
- # eof
15
+ main ()
0 commit comments