Skip to content

Commit 421837e

Browse files
committed
added dicomfs file
1 parent 47ae69a commit 421837e

File tree

1 file changed

+225
-0
lines changed

1 file changed

+225
-0
lines changed

nibabel/cmdline/dicomfs.py

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

0 commit comments

Comments
 (0)