pynifti-0.20100607.1/0000775000175000017500000000000011414646040013522 5ustar michaelmichaelpynifti-0.20100607.1/Makefile0000664000175000017500000000776611414645202015201 0ustar michaelmichaelCOVERAGE_REPORT=coverage HTML_DIR=build/html LATEX_DIR=build/latex WWW_DIR=build/website DOCSRC_DIR=doc # # Determine details on the Python/system # PYVER := $(shell python -V 2>&1 | cut -d ' ' -f 2,2 | cut -d '.' -f 1,2) DISTUTILS_PLATFORM := \ $(shell \ python -c "import distutils.util; print distutils.util.get_platform()") # # Building # all: build # build included 3rd party pieces (if present) 3rd: 3rd-stamp 3rd-stamp: find 3rd -mindepth 1 -maxdepth 1 -type d | \ while read d; do \ [ -f "$$d/Makefile" ] && $(MAKE) -C "$$d"; \ done touch $@ build: build-stamp build-stamp: 3rd python setup.py config --noisy python setup.py build_ext python setup.py build_py # to overcome the issue of not-installed _clib.so ln -sf ../build/lib.$(DISTUTILS_PLATFORM)-$(PYVER)/nifti/_clib.so nifti/ ln -sf ../build/src.$(DISTUTILS_PLATFORM)-$(PYVER)/nifti/clib.py nifti/ touch $@ # # Cleaning # clean: -rm -rf build -rm *-stamp -rm nifti/clib.py nifti/_clib.so find 3rd -mindepth 2 -maxdepth 2 -type f -name '*-stamp' | xargs -L10 rm -f distclean: clean -rm MANIFEST -rm tests/*.pyc -rm $(COVERAGE_REPORT) @find . -name '*.py[co]' \ -o -name '*.a' \ -o -name '*,cover' \ -o -name '.coverage' \ -o -iname '*~' \ -o -iname '*.kcache' \ -o -iname '*.pstats' \ -o -iname '*.prof' \ -o -iname '#*#' | xargs -L10 rm -f -rm -r dist -rm build-stamp apidoc-stamp -rm tests/data/*.hdr.* tests/data/*.img.* tests/data/something.nii \ tests/data/noise* tests/data/None.nii # # Little helpers # $(WWW_DIR): if [ ! -d $(WWW_DIR) ]; then mkdir -p $(WWW_DIR); fi # # Tests # test: unittest testdoc testmanual ut-%: build @cd tests && PYTHONPATH=.. python test_$*.py unittest: build @cd tests && PYTHONPATH=.. python main.py testdoc: build # go into data, because docs assume now data dir @cd tests/data && PYTHONPATH=../../ nosetests --with-doctest ../../nifti/ testmanual: build # go into data, because docs assume now data dir @cd tests/data && PYTHONPATH=../../ nosetests --with-doctest --doctest-extension=.txt ../../doc/ coverage: build @cd tests && { \ export PYTHONPATH=..; \ python-coverage -x main.py; \ python-coverage -r -i -o /usr >| ../$(COVERAGE_REPORT); \ grep -v '100%$$' ../$(COVERAGE_REPORT); \ python-coverage -a -i -o /usr; } # # Documentation # htmldoc: build cd $(DOCSRC_DIR) && PYTHONPATH=$(CURDIR) $(MAKE) html pdfdoc: build cd $(DOCSRC_DIR) && PYTHONPATH=$(CURDIR) $(MAKE) latex cd $(LATEX_DIR) && $(MAKE) all-pdf # # Website # website: website-stamp website-stamp: $(WWW_DIR) htmldoc pdfdoc cp -r $(HTML_DIR)/* $(WWW_DIR) cp $(LATEX_DIR)/*.pdf $(WWW_DIR) touch $@ upload-website: website rsync -rzhvp --delete --chmod=Dg+s,g+rw $(WWW_DIR)/* \ web.sourceforge.net:/home/groups/n/ni/niftilib/htdocs/pynifti/ # # Sources # pylint: distclean # do distclean first to silence SWIG's sins pylint --rcfile doc/misc/pylintrc nifti # # Distributions # # we need to build first to be able to update the manpage orig-src: build # clean existing dist dir first to have a single source tarball to process -rm -rf dist # update manpages PYTHONPATH=. help2man -N -n "compute peristimulus timeseries of fMRI data" \ bin/pynifti_pst > man/pynifti_pst.1 # now clean $(MAKE) distclean # check versions grep -iR 'version[ ]*[=:]' * | python tools/checkversion.py # let python create the source tarball python setup.py sdist --formats=gztar # rename to proper Debian orig source tarball and move upwards # to keep it out of the Debian diff file=$$(ls -1 dist); \ ver=$${file%*.tar.gz}; \ ver=$${ver#pynifti-*}; \ mv dist/$$file ../pynifti_$$ver.tar.gz bdist_rpm: 3rd python setup.py bdist_rpm \ --doc-files "doc" \ --packager "Michael Hanke " \ --vendor "Michael Hanke " # build MacOS installer -- depends on patched bdist_mpkg for Leopard bdist_mpkg: 3rd python tools/mpkg_wrapper.py setup.py build_ext python tools/mpkg_wrapper.py setup.py install .PHONY: orig-src pylint apidoc pynifti-0.20100607.1/TODO0000664000175000017500000000503211414645202014211 0ustar michaelmichael* Implement support for slice timing related NIfTI information. * Implement support for intent codes. * Valgrind reports a memory leak. It seems to be releated to some string operation on the header data, as it also happens when image data from ndarrays is used and never saved to file or inserted into the Nifti image struct. However, so far I do not yet fully understand it. Yarik's wishes sorted - please remove or fulfill: ------------------------------------------------- - as it is now: getHeader returns a header dictionary which is not binded to the object. so direct manipulation to it such as inNifti.header['bla']='bleh' are lost and the only way to introduce a change to the field seems to operate as h = inNifti.header h['bla'] = 'bleh' inNifti.header = h which is at least should be documented in capital letters! ;-) Proposed solution: introduce private __header, which would result in singleton behavior of getHeader -- on first call it does all the querying from self.__nimg and nhdr2dict, but on consequtive calls - simply return __header. may be nhdr (result of _nim2nhdr) should be also stored as __nhdr to avoid consequtive invocations of a costly function Then updateHeader should * allow not specified hdrdict (default to None) * not query __nimg if __header/__nhdr is not None and simply use nhdr=self.__nhdr * if hdrdict=None (ie not specified) make a copy hdrdict == self.__header.copy(), so del commands dont' do evil things, and proceed further ;-) save method also should invoke updateHeader I guess so that if there were any changes to the header dictionary, they get saved.. Michael's comment: ------------------ Although this would be nice to have, I really think it could be the source of some ugly bugs. Maintaining a separate copy of the header means that PyNifit has to keep track of all possible dependencies between the image properties by itself, instead of relying on the nifticlib to do. this. I'd prefer to implement as much accessor methods or properties as necessary to make calls to the header property superflous. BTW: The same behavior is true for the qform and sform properties (including their inverse versions). Possibly wrong/incorrect/wontfix suggestions: --------------------------------------------- - [gs]etVoxDims should work with all dimensions up to 7 as they are defined in nifti1_io.h hanke: maybe, but that would mix different units, which I'd rather not do. pynifti-0.20100607.1/AUTHOR0000664000175000017500000000005111414645202014442 0ustar michaelmichaelMichael Hanke pynifti-0.20100607.1/Changelog0000664000175000017500000002705011414645624015347 0ustar michaelmichael.. -*- mode: rst -*- .. _changelog: PyNIfTI Development Changelog ----------------------------- Modifications are done by Michael Hanke, if not indicated otherwise. 'Closes' statement IDs refer to the Debian bug tracking system and can be queried by visiting the URL:: http://bugs.debian.org/ The full VCS changelog is available here: http://git.debian.org/?p=pkg-exppsy/pynifti.git;a=shortlog;h=upstream Unreleased changes Changes described here are not yet released, but available from VCS repository. None yet. Releases ~~~~~~~~ * 0.20100706.1 (Tue, 6 Jul 2010) * Bugfix: NiftiFormat.vx2s() used the qform not the sform. Thanks to Tom Holroyd for reporting. * 0.20100412.1 (Mon, 12 Apr 2010) * Bugfix: Unfortunate interaction between Python garbage collection and C library caused memory problems. Thanks to Yaroslav Halchenko for the diagnose and fix. * 0.20090303.1 (Tue, 3 Mar 2009) * Bugfix: Updating the NIfTI header from a dictionary was broken. * Bugfix: Removed left-over print statement in extension code. * Bugfix: Prevent saving of bogus 'None.nii' images when the filename was previously assign, before calling NiftiImage.save() (Closes: #517920). * Bugfix: Extension length was to short for all `edata` whos length matches n*16-8, for a integer n. * 0.20090205.1 (Thu, 5 Feb 2009) * This release is the first in a series that aims stabilize the API and finally result in PyNIfTI 1.0 with full support of the NIfTI1 standard. * The whole package was restructured. The included renaming `nifti.nifti(image,format,clibs)` to `nifti.(image,format,clibs)`. Redirect modules make sure that existing user code will not break, but they will issue a DeprecationWarning and will be removed with the release of PyNIfTI 1.0. * Added a special extension that can embed any serializable Python object into the NIfTI file header. The contents of this extension is automatically expanded upon request into the `.meta` attribute of each NiftiImage. When saving files to disk the content of the dictionary is also automatically dumped into this extension. Embedded meta data is not loaded automatically, since this has security implications, because code from the file header is actually executed. The documentation explicitely mentions this risk. * Added :class:`~nifti.extensions.NiftiExtensions`. This is a container-like handler to access and manipulate NIfTI1 header extensions. * Exposed :class:`~nifti.image.MemMappedNiftiImage` in the root module. * Moved :func:`~nifti.utils.cropImage` into the :mod:`~nifti.utils` module. * From now on Sphinx is used to generate the documentation. This includes a module reference that replaces that old API reference. * Added methods :meth:`~nifti.format.NiftiFormat.vx2q` and :meth:`~nifti.format.NiftiFormat.vx2s` to convert voxel indices into coordinates defined by qform or sform respectively. * Updating the `cal_min` and `cal_max` values in the NIfTI header when saving a file is now conditional, but remains enabled by default. * Full set of methods to query and modify axis units. This includes expanding the previous `xyzt_units` field in the header dictionary into editable `xyz_unit` and `time_unit` fields. The former `xyzt_units` field is no longer available. See: :meth:`~nifti.format.NiftiFormat.getXYZUnit`, :meth:`~nifti.format.NiftiFormat.setXYZUnit`, :meth:`~nifti.format.NiftiFormat.getTimeUnit`, :meth:`~nifti.format.NiftiFormat.setTimeUnit`, :attr:`~nifti.format.NiftiFormat.xyz_unit`, :attr:`~nifti.format.NiftiFormat.time_unit` * Full set of methods to query and manuipulate qform and sform codes. See: :meth:`~nifti.format.NiftiFormat.getQFormCode`, :meth:`~nifti.format.NiftiFormat.setQFormCode`, :meth:`~nifti.format.NiftiFormat.getSFormCode`, :meth:`~nifti.format.NiftiFormat.setSFormCode`, :attr:`~nifti.format.NiftiFormat.qform_code`, :attr:`~nifti.format.NiftiFormat.sform_code` * Each image instance is now able to generate a human-readable dump of its most important header information via `__str__()`. * :class:`~nifti.image.NiftiImage` objects can now be pickled. * Switched to NumPy's distutils for building the package. Cleaned and simplified the build procedure. Added optimization flags to SWIG call. * :attr:`nifti.image.NiftiImage.filename` can now also be used to assign a filename. * Introduced :data:`nifti.__version__` as canonical version string. * Removed `updateQFormFromQuarternion()` from the list of public methods of :class:`~nifti.format.NiftiFormat`. This is an internal method that should not be used in user code. However, a redirect to the new method will remain in-place until PyNIfTI 1.0. * Bugfix: :meth:`~nifti.image.NiftiImage.getScaledData` returns a unmodified data array if `slope` is set to zero (as required by the NIfTI standard). Thanks to Thomas Ross for reporting. * Bugfix: Unicode filenames are now handled properly, as long as they do not contain pure-unicode characters (since the NIfTI library does not support them). Thanks to Gaël Varoquaux for reporting this issue. * 0.20081017.1 (Fri, 17 Oct 2008) * Updated included minimal copy of the nifticlibs to version 1.1.0. * Few changes to the Makefiles to enhance Posix compatibility. Thanks to Chris Burns. * When building on non-Debian systems, only add include and library paths pointing to the local nifticlibs copy, when it is actually built. On Debian system the local copy is still not used at all, as a proper nifticlibs package is guaranteed to be available. * Added minimal setup_egg.py for setuptools users. Thanks to Gaël Varoquaux. * PyNIfTI now does a proper wrapping of the image data with NumPy arrays, which no longer leads to accidental memory leaks, when accessing array data that has not been copied before (e.g. via the *data* property of NiftiImage). Thanks to Gaël Varoquaux for mentioning this possibility. * 0.20080710.1 (Thu, 7 Jul 2008) * Bugfix: Pointer bug introduced by switch to new NumPy API in 0.20080624 Thanks to Christopher Burns for fixing it. * Bugfix: Honored DeprecationWarning: sync() -> flush() for memory mapped arrays. Again thanks to Christopher Burns. * More unit tests and other improvements (e.g. fixed circular imports) done by Christopher Burns. * 0.20080630.1 (Tue, 30 Jun 2008) * Bugfix: NiftiImage caused a memory leak by not calling the NiftiFormat destructor. * Bugfix: Merged bashism-removal patch from Debian packaging. * 0.20080624.1 (Tue, 24 Jun 2008) * Converted all documentation (including docstrings) into the restructured text format. * Improved Makefile. * Included configuration and Makefile support for profiling, API doc generation (via epydoc) and code quality checks (with PyLint). * Consistently import NumPy as N. * Bugfix: Proper handling of [qs]form codes, which previously have not been handled at all. Thanks to Christopher Burns for pointing it out. * Bugfix: Make NiftiFormat work without setFilename(). Thanks to Benjamin Thyreau for reporting. * Bugfix: setPixDims() stored meaningless values. * Use new NumPy API and replace deprecated function calls (`PyArray_FromDimsAndData`). * Initial support for memory mapped access to uncompressed NIfTI files (`MemMappedNiftiImage`). * Add a proper Makefile and setup.cfg for compiling PyNIfTI under Windows with MinGW. * Include a minimal copy of the most recent nifticlibs (just libniftiio and znzlib; version 1.0), to lower the threshold to build PyNIfTI on systems that do not provide a developer package for those libraries. * 0.20070930.1 (Sun, 30 Sep 2007) * Relicense under the MIT license, to be compatible with SciPy license. http://www.opensource.org/licenses/mit-license.php * Updated documentation. * 0.20070917.1 (Mon, 17 Sep 2007) * Bugfix: Can now update NIfTI header data when no filename is set (Closes: #442175). * Unloading of image data without a filename set is no checked and prevented as it would damage data integrity and the image data could not be recovered. * Added 'pixdim' property (Yaroslav Halchenko). * 0.20070905.1 (Wed, 5 Sep 2007) * Fixed a bug in the qform/quaternion handling that caused changes to the qform to vanish when saving to file (Yaroslav Halchenko). * Added more unit tests. * 'dim' vector in the NIfTI header is now guaranteed to only contain non-zero elements. This caused problems with some applications. * 0.20070803.1 (Fri, 3 Aug 2007) * Does not depend on SciPy anymore. * Initial steps towards a unittest suite. * pynifti_pst can now print the peristimulus signal matrix for a single voxel (onsets x time) for easier processing of this information in external applications. * utils.getPeristimulusTimeseries() can now be used to compute mean and variance of the signal (among others). * pynifti_pst is able to compute more than just the mean peristimulus timeseries (e.g. variance and standard deviation). * Set default image description when saving a file if none is present. * Improved documentation. * 0.20070425.1 (Wed, 25 Apr 2007) * Improved documentation. Added note about the special usage of the header property. Also added notes about the relevant properties in the docstring of the corresponding accessor methods. * Added property and accessor methods to access/modify the repetition time of timeseries (dt). * Added functions to manipulate the pixdim values. * Added utils.py with some utility functions. * Added functions/property to determine the bounding box of an image. * Fixed a bug that caused a corrupted sform matrix when converting a NumPy array and a header dictionary into a NIfTI image. * Added script to compute peristimulus timeseries (pynifti_pst). * Package now depends on python-scipy. * 0.20070315.1 (Thu, 15 Mar 2007) * Removed functionality for "NiftiImage.save() raises an IOError exception when writing the image file fails." (Yaroslav Halchenko) * Added ability to force a filetype when setting the filename or saving a file. * Reverse the order of the 'header' and 'load' argument in the NiftiImage constructor. 'header' is now first as it seems to be used more often. * Improved the source code documentation. * Added getScaledData() method to NiftiImage that returns a copy of the data array that is scaled with the slope and intercept stored in the NIfTI header. * 0.20070301.2 (Thu, 1 Mar 2007) * Fixed wrong link to the source tarball in README.html. * 0.20070301.1 (Thu, 1 Mar 2007) * Initial upload to the Debian archive. (Closes: #413049) * NiftiImage.save() raises an IOError exception when writing the image file fails. * Added extent, volextent, and timepoints properties to NiftiImage class (Yaroslav Halchenko). * 0.20070220.1 (Tue, 20 Feb 2007) * NiftiFile class is renamed to NiftiImage. * SWIG-wrapped libniftiio functions are no available in the nifticlib module. * Fixed broken NiftiImage from Numpy array constructor. * Added initial documentation in README.html. * Fulfilled a number of Yarik's wishes ;) * 0.20070214.1 (Wed, 14 Feb 2007) * Does not depend on libfslio anymore. * Up to seven-dimensional dataset are supported (as much as NIfTI can do). * The complete NIfTI header dataset is modifiable. * Most image properties are accessable via class attributes and accessor methods. * Improved documentation (but still a long way to go). * 0.20061114 (Tue, 14 Nov 2006) * Initial release. pynifti-0.20100607.1/COPYING0000664000175000017500000000250611414645202014557 0ustar michaelmichael.. -*- mode: rst; fill-column: 78 -*- .. ex: set sts=4 ts=4 sw=4 et tw=79: .. _license: ******* License ******* The PyNIfTI package, including all examples, code snippets and attached documentation is covered by the MIT license. :: The MIT License Copyright (c) 2006-2010 Michael Hanke Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. pynifti-0.20100607.1/nifti/0000775000175000017500000000000011414646040014633 5ustar michaelmichaelpynifti-0.20100607.1/nifti/niftiformat.py0000664000175000017500000000117411414645202017531 0ustar michaelmichael#emacs: -*- mode: python-mode; py-indent-offset: 4; indent-tabs-mode: nil -*- #ex: set sts=4 ts=4 sw=4 et: ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ## # # See COPYING file distributed along with the PyNIfTI package for the # copyright and license terms. # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ## """Only here for backward compatibility.""" __docformat__ = 'restructuredtext' from warnings import warn warn("This module has been renamed to 'nifti.format'. This redirect will be removed with PyNIfTI 1.0.", DeprecationWarning) from nifti.format import * pynifti-0.20100607.1/nifti/extensions.py0000664000175000017500000002005711414645202017407 0ustar michaelmichael#emacs: -*- mode: python-mode; py-indent-offset: 4; indent-tabs-mode: nil -*- #ex: set sts=4 ts=4 sw=4 et: ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ## # # See COPYING file distributed along with the PyNIfTI package for the # copyright and license terms. # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ## """This module provides a container-like interface to NIfTI1 header extensions. """ __docformat__ = 'restructuredtext' # the NIfTI pieces import nifti.clib as ncl # # type maps # nifti_ecode_map = \ {"ignore": ncl.NIFTI_ECODE_IGNORE, "dicom": ncl.NIFTI_ECODE_DICOM, "afni": ncl.NIFTI_ECODE_AFNI, "comment": ncl.NIFTI_ECODE_COMMENT, "xcede": ncl.NIFTI_ECODE_XCEDE, "jimdiminfo": ncl.NIFTI_ECODE_JIMDIMINFO, "workflow_fwds": ncl.NIFTI_ECODE_WORKFLOW_FWDS, "freesurfer": ncl.NIFTI_ECODE_FREESURFER, # for now just conquer the next available ECODE "pypickle": 16, # later replace by the following when new niftilib is released #"pypickle": ncl.NIFTI_ECODE_PYPICKLE, } nifti_ecode_inv_map = dict([(v, k) for k, v in nifti_ecode_map.iteritems()]) # # little helpers # def _any2ecode(code, check_num=True): """Convert literal NIFTI_ECODEs into numerical ones. Both numerical and literal codes are check for validity by default. However, setting `check_num` to `False` will disable this check for numerical codes. """ if isinstance(code, str): if not code in nifti_ecode_map.keys(): raise ValueError, \ "Unknown ecode '%s'. Must be one of '%s'" \ % (code, str(nifti_ecode_map.keys())) code = nifti_ecode_map[code] elif check_num: if not code in nifti_ecode_map.values(): raise ValueError, \ "Unknown ecode '%s'. Must be one of '%s'" \ % (str(code), str(nifti_ecode_map.values())) return code # # classes # class NiftiExtensions(object): """NIfTI1 header extension handler. This class wraps around a NIfTI1 struct and provides container-like access to NIfTI1 header extensions. It is basically a hibrid between a list and a dictionary. The reason for this is that the NIfTI header allows for a *list* of extensions, but additionally each extension is associated with some type (`ecode` or extension code). This is some form of *mapping*, however, the ecodes are not necessarily unique (e.g. multiple comments). The current list of known extensions is documented here: http://nifti.nimh.nih.gov/nifti-1/documentation/faq#Q21 The usage is best explained by a few examples. All examples assume a NIfTI image to be loaded: >>> from nifti import NiftiImage >>> nim = NiftiImage('example4d.nii.gz') Access to the extensions is provided through the `extensions` attribute of the NiftiImage class: >>> type(nim.extensions) How many extensions are avialable? >>> len(nim.extensions) 2 How many comments? Any AFNI extension? >>> nim.extensions.count('comment') 2 Show me all `ecodes` of all extensions: >>> nim.extensions.ecodes [6, 6] Add an `AFNI` extension: >>> nim.extensions += ('afni', 'Some voodoo') >>> nim.extensions.ecodes [6, 6, 4] Delete superfluous comment extension: >>> del nim.extensions[1] Access the last extension, which should be the `AFNI` one: >>> nim.extensions[-1] 'Some voodoo' Wipe them all: >>> nim.extensions.clear() >>> len(nim.extensions) 0 """ def __init__(self, raw_nimg, source=None): """ :Parameters: raw_nimg: nifti_image struct This is the raw NIfTI image struct pointer. It is typically provided by :attr:`nifti.format.NiftiFormat.raw_nimg`. source: list(2-tuple) This is an optional list for extension tuples (ecode, edata). Each element of this list will be appended as a new extension. """ # raw NIfTI image struct instance self.__raw_nimg = raw_nimg # wrapped extension list self.__rewrapExtList() if source: for ext in source: self.append(ext) def __rewrapExtList(self): """Grab a fresh pointer to the C extension array. """ self.__elist = ncl.extensionArray_frompointer(self.__raw_nimg.ext_list) def __len__(self): return self.__raw_nimg.num_ext def __getitem__(self, key): # first try access by ascii ecode if isinstance(key, str): key = _any2ecode(key) # search for first matching ecode for c, d in self.iteritems(): if c == key: return d else: # support 'reverse' access by negative indices if key < 0: key += len(self) if key < len(self): return self.__elist[key].edata raise IndexError, \ "Invalid extension ID '%s'." % `key` def __iter__(self): for i in xrange(len(self)): yield self[i] def iteritems(self): """A generator method that returns a 2-tuple (ecode, edata) on each iteration. It can be used in the same fashion as `dict.iteritems()`. """ for i in xrange(len(self)): yield (self.__elist[i].ecode, self.__elist[i].edata) def __contains__(self, ecode): return _any2ecode(ecode) in [c for c, d in self.iteritems()] def count(self, code): """Returns the number of extensions matching a given *ecode*. :Parameter: code: int | str The ecode can be specified either literal or as numerical value. """ # don't check numerical value to prevent unnecessary exceptions code = _any2ecode(code, check_num=False) count = 0 for c, d in self.iteritems(): if c == code: count += 1 return count def ecodes(self): """Returns a list of ecodes for all extensions. """ return [c for c, d in self.iteritems()] def append(self, extension): """Append a new extension. :Parameter: extension: 2-tuple An extension is given by a `(ecode, edata)` tuple, where `ecode` can be either literal or numerical and `edata` is any kind of data. Note: Currently, `edata` can only be stuff whos len(edata) matches its size in bytes, e.g. str. """ ecode, edata = extension # check and potentially convert ecodes ecode = _any2ecode(ecode) # +1 to still include the stop bit if the extension length is n*16-8 ret = ncl.nifti_add_extension(self.__raw_nimg, edata, len(edata) + 1, ecode) if not ret == 0: raise RuntimeError, \ "Could not add extension. Expect the world to end!" # make sure to rewrap the extension list to compensate for # changes the the C datatype/pointer madness self.__rewrapExtList() def __delitem__(self, key): # first try if we have an ascii ecode if isinstance(key, str): key = _any2ecode(key) key = self.ecodes.index(key) exts = [e for i, e in enumerate(self.iteritems()) if i != key] # tabula rasa self.clear() # and put remains extensions back for e in exts: self += e def clear(self): """Remove all extensions. """ # tabula rasa ncl.nifti_free_extensions(self.__raw_nimg) def __del__(self): self.clear() def __iadd__(self, extension): self.append(extension) return self def __str__(self): return "extensions(%s)" % str([e for e in self.iteritems()]) ecodes = property(fget=ecodes) pynifti-0.20100607.1/nifti/imgfx.py0000664000175000017500000000533111414645202016320 0ustar michaelmichael#emacs: -*- mode: python-mode; py-indent-offset: 4; indent-tabs-mode: nil -*- #ex: set sts=4 ts=4 sw=4 et: ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ## # # See COPYING file distributed along with the PyNIfTI package for the # copyright and license terms. # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ## """Functions operating on images""" # NOTE: This is for functions which exclusively use the public interface of the # NiftiImage class (i.e. convenience stuff that anybody could do). Moreover, # these functions have to run without having to import 'nifti.image' itself, # so they can be assigned to the NiftiImage class itself, as additional methods. __docformat__ = 'restructuredtext' import numpy as N def getBoundingBox(nim): """Get the bounding box an image. The bounding box is the smallest box covering all non-zero elements. :Returns: tuple(2-tuples) | None It returns as many (min, max) tuples as there are image dimensions. The order of dimensions is identical to that in the data array. `None` is returned of the images does not contain non-zero elements. Examples: >>> from nifti import NiftiImage >>> nim = NiftiImage(N.zeros((12, 24, 32))) >>> nim.bbox is None True >>> nim.data[3,10,13] = 1 >>> nim.data[6,20,26] = 1 >>> nim.bbox ((3, 6), (10, 20), (13, 26)) >>> nim.crop() >>> nim.data.shape (4, 11, 14) >>> nim.bbox ((0, 3), (0, 10), (0, 13)) .. seealso:: :attr:`nifti.image.NiftiImage.bbox`, :func:`nifti.imgfx.crop` """ nz = nim.data.squeeze().nonzero() bbox = [] for dim in nz: # check if there are nonzero elements at all if not len(dim): return None bbox.append((dim.min(), dim.max())) return tuple(bbox) def crop(nim, bbox=None): """Crop an image. :Parameters: bbox: list(2-tuples) | None Each tuple has the (min,max) values for a particular image dimension. If `None`, the images actual bounding box is used for cropping. .. seealso:: :attr:`nifti.image.NiftiImage.bbox`, :func:`nifti.imgfx.getBoundingBox` """ if bbox is None: bbox = getBoundingBox(nim) # if image has no non.zero elements do nothing if bbox is None: # XXX: or raise something? return # build crop command # XXX: the following looks rather stupid -- cannot recall why I did this cmd = 'nim.data.squeeze()[' cmd += ','.join(['%i:%i' % (dim[0], dim[1] + 1) for dim in bbox ]) cmd += ']' # crop the image data array and assign it to the array nim.data = eval(cmd) pynifti-0.20100607.1/nifti/__init__.py0000664000175000017500000000171411414645717016761 0ustar michaelmichael#emacs: -*- mode: python-mode; py-indent-offset: 4; indent-tabs-mode: nil -*- #ex: set sts=4 ts=4 sw=4 et: ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ## # # See COPYING file distributed along with the PyNIfTI package for the # copyright and license terms. # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ## """This module provides Python bindings to the NIfTI data format. The PyNIfTI module is a Python interface to the NIfTI I/O libraries. Using PyNIfTI, one can easily read and write NIfTI and ANALYZE images from within Python. The :class:`~nifti.image.NiftiImage` class provides pythonic access to the full header information and for a maximum of interoperability the image data is made available via NumPy arrays. """ __docformat__ = 'restructuredtext' # expose the two main classes from nifti.image import NiftiImage, MemMappedNiftiImage # canonical version string __version__ = '0.20100607.1' pynifti-0.20100607.1/nifti/image.py0000664000175000017500000005414611414645202016300 0ustar michaelmichael#emacs: -*- mode: python-mode; py-indent-offset: 4; indent-tabs-mode: nil -*- #ex: set sts=4 ts=4 sw=4 et: ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ## # # See COPYING file distributed along with the PyNIfTI package for the # copyright and license terms. # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ## """This module provides two classes for accessing NIfTI files. * :class:`~nifti.image.NiftiImage` (traditional load-as-much-as-you-can approach) * :class:`~nifti.image.MemMappedNiftiImage` (memory-mapped access to uncompressed NIfTI files) """ __docformat__ = 'restructuredtext' import cPickle from warnings import warn import numpy as N # the NIfTI pieces import nifti import nifti.clib as ncl from nifti.format import NiftiFormat from nifti.utils import splitFilename, nifti2numpy_dtype_map import nifti.imgfx as imgfx class NiftiImage(NiftiFormat): """Wrapper class for convenient access to NIfTI images. An image can either be loaded from a file or created from a NumPy ndarray. Either way is automatically determined by the type of the 'source' argument. If `source` is a string, it is assumed to be a filename an ndarray is treated as such. All NIfTI header information is conveniently exposed via Python data types. This functionality is provided by the :class:`~nifti.format.NiftiFormat` base class. Please refer to its documentation for the full list of its methods and properties. .. seealso:: :class:`~nifti.format.NiftiFormat`, :class:`~nifti.image.MemMappedNiftiImage` """ # # object constructors, destructors and generic Python interface # def __init__(self, source, header=None, load=False, **kwargs): """ :Parameters: source: str | ndarray If source is a string, it is assumed to be a filename and an attempt will be made to open the corresponding NIfTI file. In case of an ndarray the array data will be used for the to be created nifti image and a matching nifti header is generated. If an object of a different type is supplied as 'source' a ValueError exception will be thrown. header: dict Additional header data might be supplied. However, dimensionality and datatype are determined from the ndarray and not taken from a header dictionary. load: Boolean If set to True the image data will be loaded into memory. This is only useful if loading a NIfTI image from file. This flag is almost useless, as the data will be loaded automatically whenever it is accessed. **kwargs: Additional stuff is passed to :class:`~nifti.format.NiftiFormat`. """ # setup all nifti header related stuff NiftiFormat.__init__(self, source, header, **kwargs) # where the data will go to self._data = None # load data if type(source) == N.ndarray: # assign data from source array self._data = source[:] elif type(source) in (str, unicode): # only load image data from file if requested if load: self.load() else: raise ValueError, \ "Unsupported source type. Only NumPy arrays and filename " \ + "string are supported." def __del__(self): self.unload() # it is required to call base class destructors! NiftiFormat.__del__(self) def __reduce__(self): # little helper to make NiftiImage objects compatible with pickling return (NiftiImage, (self.data, self.header)) def save(self, filename=None, filetype = 'NIFTI', update_minmax=True): """Save the image to a file. If the image was created using array data (i.e., not loaded from a file) a filename has to be specified. If not yet done already, the image data will be loaded into memory before saving the file. :Parameters: filename: str | None The name of the target file (typically including its extension). Filenames might be provided as unicode strings. However, as the underlying library does not support unicode, they must be ascii-encodable, i.e. must not contain pure unicode characters. Usually setting the filename also determines the filetype (NIfTI/ANALYZE). Please see :meth:`~nifti.image.NiftiImage.setFilename` for some more details. If None, an image loaded from a file will cause the original image to be overwritten. filetype: str Provide intented filetype. Please see the documentation of the `setFilename()` method for some more details. update_minmax: bool Whether the image header's min and max values should be updated according to the current image data. .. warning:: There will be no exception if writing fails for any reason, as the underlying function nifti_write_hdr_img() from libniftiio does not provide any feedback. Suggestions for improvements are appreciated. """ if not filename is None: # make sure filename is not unicode try: filename = str(filename) except UnicodeEncodeError: raise UnicodeError, \ "The filename must not contain unicode characters, since " \ "the NIfTI library cannot handle them." # If image data is not yet loaded, do it now. # It is important to do it already here, because nifti_image_load # depends on the correct filename set in the nifti_image struct # and this will be modified in this function! self.load() # set a default description if there is none if not self.description: self.description = \ 'Written by PyNIfTI version %s' % nifti.__version__ # update header information if update_minmax: self.updateCalMinMax() # saving for the first time? if not self.filename or filename: if not filename: raise ValueError, \ "When saving an image for the first time a filename " \ + "has to be specified." self.setFilename(filename, filetype) # if still no data is present data source has been an array # -> allocate memory in nifti struct and assign data to it if not self.raw_nimg.data: if not ncl.allocateImageMemory(self.raw_nimg): raise RuntimeError, "Could not allocate memory for image data." else: raise RuntimeError, "This should never happen! Please report me!" # This assumes that the nimg struct knows about the correct datatype and # dimensions of the array a = ncl.wrapImageDataWithArray(self.raw_nimg) a[:] = self._data[:] # # embed meta data # if len(self.meta.keys()): self.extensions += ('pypickle', cPickle.dumps(self.meta, protocol=0)) # now save it ncl.nifti_image_write_hdr_img(self.raw_nimg, 1, 'wb') # yoh comment: unfortunately return value of nifti_image_write_hdr_img # can't be used to track the successful completion of save # raise IOError, 'An error occured while attempting to save the image # file.' # take data pointer away from nifticlibs so we can let Python manage # the memory ncl.detachDataFromImage(self.raw_nimg) # and finally clean 'pypickle' extension again, since its data is in # 'meta' self._removePickleExtension() def copy(self): """Return a copy of the image. """ return NiftiImage(self.data.copy(), self.header) # # little helpers # def _haveImageData(self): """Returns if the image data is accessible -- either loaded into memory or memory mapped. See: `load()`, `unload()` .. warning:: This is an internal method. Neither its availability nor its API is guarenteed. """ return (not self._data == None) def load(self): """Load the image data into memory, if it is not already accessible. It is save to call this method several times successively. """ # do nothing if there already is data # which included memory mapped arrays not just data in memory if self._haveImageData(): return if ncl.nifti_image_load( self.raw_nimg ) < 0: raise RuntimeError, "Unable to load image data." self._data = ncl.wrapImageDataWithArray(self.raw_nimg) # take data pointer away from nifticlibs so we can let Python manage # the memory ncl.detachDataFromImage(self.raw_nimg) def unload(self): """Unload image data and free allocated memory. This methods does nothing in case of memory mapped files. """ # simply assign none. The data array will free itself when the # reference count goes to zero. self._data = None def updateCalMinMax(self): """Update the image data maximum and minimum value in the nifti header. """ self.raw_nimg.cal_max = float(self.data.max()) self.raw_nimg.cal_min = float(self.data.min()) def updateHeader(self, hdrdict): """Deprecated method only here for backward compatibility. Please refer to NiftiFormat.updateFromDict() """ warn("updateHeader function is deprecated and will be removed with " \ "PyNIfTI 1.0. Please use updateFromDict instead.", DeprecationWarning) NiftiFormat.updateFromDict(self, hdrdict) # # converters # def getScaledData(self): """Returns a scaled copy of the data array. Scaling is done by multiplying with the slope and adding the intercept that is stored in the NIfTI header. In compliance with the NIfTI standard scaling is only performed in case of a non-zero slope value. The original data array is returned otherwise. :Returns: ndarray """ data = self.asarray(copy = True) # NIfTI standard says: scaling only if non-zero slope if self.slope: data *= self.slope data += self.intercept return data # XXX The whole thing needs more thought. # # def iterVolumes(self): # """Volume generator. # # For images with four or less dimensions this methods provides # a generator for volumes. When called on images with less than # four dimensions a single item is returned that is guaranteed # to be three-dimensional (by adding missing axes if necessary). # # Examples: # # >>> nim = NiftiImage(N.random.rand(4,2,3,2)) # >>> vols = [v for v in nim.iterVolumes()] # >>> len(vols) # 4 # # >>> nim = NiftiImage(N.random.rand(3,2)) # >>> vols = [v for v in nim.iterVolumes()] # >>> len(vols) # 1 # >>> vols[0].data.shape # (1, 3, 2) # """ # if len(self.data.shape) > 4: # raise ValueError, \ # "Cannot handle image with more than 4 dimensions" # # # only one volume or less (single slice) # if len(self.data.shape) < 4: # yield NiftiImage(N.array(self.data, ndmin=3), # self.header) # return # # # 4d images # for v in self.data: # yield NiftiImage(v, self.header) # # getters and setters # def setDataArray(self, data): """ """ # XXX should probably add more checks self._updateNimgFromArray(data) self._data = data def getDataArray(self): """Return the NIfTI image data wrapped into a NumPy array. .. seealso:: :attr:`~nifti.image.NiftiImage.data` """ return self.asarray(False) def asarray(self, copy = True): """Convert the image data into a ndarray. :Parameters: copy: Boolean If set to False the array only wraps the image data, while True will return a copy of the data array. """ # make sure data is accessible self.load() if copy: return self._data.copy() else: return self._data def setFilename(self, filename, filetype = 'NIFTI'): """Set the filename for the NIfTI image. Setting the filename also determines the filetype. If the filename ends with '.nii' the type will be set to NIfTI single file. A '.hdr' extension can be used for NIfTI file pairs. If the desired filetype is ANALYZE the extension should be '.img'. However, one can use the '.hdr' extension and force the filetype to ANALYZE by setting the filetype argument to ANALYZE. Setting filetype if the filename extension is '.nii' has no effect, the file will always be in NIFTI format. If the filename carries an additional '.gz' the resulting file(s) will be compressed. Uncompressed NIfTI single files are the default filetype that will be used if the filename has no valid extension. The '.nii' extension is appended automatically. The 'filetype' argument can be used to force a certain filetype when no extension can be used to determine it. 'filetype' can be one of the nifticlibs filtetypes or any of 'NIFTI', 'NIFTI_GZ', 'NIFTI_PAIR', 'NIFTI_PAIR_GZ', 'ANALYZE', 'ANALYZE_GZ'. Setting the filename will cause the image data to be loaded into memory if not yet done already. This has to be done, because without the filename of the original image file there would be no access to the image data anymore. As a side-effect a simple operation like setting a filename may take a significant amount of time (e.g. for a large 4d dataset). By passing an empty string or none as filename one can reset the filename and detach the NiftiImage object from any file on disk. Examples: ================ ================================== Filename Output of save() ---------------- ---------------------------------- exmpl.nii exmpl.nii (NIfTI) exmpl.hdr exmpl.hdr, exmpl.img (NIfTI) exmpl.img exmpl.hdr, exmpl.img (ANALYZE) exmpl exmpl.nii (NIfTI) exmpl.hdr.gz exmpl.hdr.gz, exmpl.img.gz (NIfTI) ---------------- ---------------------------------- exmpl.gz exmpl.gz.nii (uncompressed NIfTI) ================ ================================== Setting the filename is also possible by assigning to the 'filename' property. .. seealso:: :meth:`~nifti.format.NiftiFormat.getFilename`, :attr:`~nifti.image.NiftiImage.filename` """ # If image data is not yet loaded, do it now. # It is important to do it already here, because nifti_image_load # depends on the correct filename set in the nifti_image struct # and this will be modified in this function! self.load() # if no filename is given simply reset it to nothing if not filename: self.raw_nimg.fname = '' self.raw_nimg.iname = '' return # separate basename and extension base, ext = splitFilename(filename) # if no extension default to nifti single files if ext == '': if filetype == 'NIFTI' \ or filetype == ncl.NIFTI_FTYPE_NIFTI1_1: ext = 'nii' elif filetype == 'NIFTI_PAIR' \ or filetype == ncl.NIFTI_FTYPE_NIFTI1_2: ext = 'hdr' elif filetype == 'ANALYZE' \ or filetype == ncl.NIFTI_FTYPE_ANALYZE: ext = 'img' elif filetype == 'NIFTI_GZ': ext = 'nii.gz' elif filetype == 'NIFTI_PAIR_GZ': ext = 'hdr.gz' elif filetype == 'ANALYZE_GZ': ext = 'img.gz' else: raise RuntimeError, "Unhandled filetype." # Determine the filetype and set header and image filename # appropriately. # nifti single files are easy if ext == 'nii.gz' or ext == 'nii': self.raw_nimg.fname = base + '.' + ext self.raw_nimg.iname = base + '.' + ext self.raw_nimg.nifti_type = ncl.NIFTI_FTYPE_NIFTI1_1 # uncompressed nifti file pairs elif ext in [ 'hdr', 'img' ]: self.raw_nimg.fname = base + '.hdr' self.raw_nimg.iname = base + '.img' if ext == 'hdr' and not filetype.startswith('ANALYZE'): self.raw_nimg.nifti_type = ncl.NIFTI_FTYPE_NIFTI1_2 else: self.raw_nimg.nifti_type = ncl.NIFTI_FTYPE_ANALYZE # compressed file pairs elif ext in [ 'hdr.gz', 'img.gz' ]: self.raw_nimg.fname = base + '.hdr.gz' self.raw_nimg.iname = base + '.img.gz' if ext == 'hdr.gz' and not filetype.startswith('ANALYZE'): self.raw_nimg.nifti_type = ncl.NIFTI_FTYPE_NIFTI1_2 else: self.raw_nimg.nifti_type = ncl.NIFTI_FTYPE_ANALYZE else: raise RuntimeError, "Unhandled filetype." # need to redefine, since we need to redefine to 'filename' property def getFilename(self): """Please see :meth:`nifti.format.NiftiFormat.getFilename` for the documentation.""" return NiftiFormat.getFilename(self) # # class properties # # read only data = property(fget=getDataArray, fset=setDataArray) # read and write filename = property(fget=getFilename, fset=setFilename) bbox = property(fget=imgfx.getBoundingBox, fset=imgfx.crop) class MemMappedNiftiImage(NiftiImage): """Memory mapped access to uncompressed NIfTI files. This access mode might be the prefered one whenever only a small part of the image data has to be accessed or the memory is not sufficient to load the whole dataset. Please note, that memory-mapping is not required when exclusively header information shall be accessed. The :class:`~nifti.format.NiftiFormat` class and by default also the :class:`~nifti.image.NiftiImage` class will not load any image data into memory. .. note:: The class is mostly useful for read-only access to the NIfTI image data. It currently neither supports saving changed header fields nor storing meta data. """ # # object constructors, destructors and generic Python interface # def __init__(self, source): """Create a NiftiImage object. This method decides whether to load a nifti image from file or create one from ndarray data, depending on the datatype of `source`. :Parameters: source: str | ndarray If source is a string, it is assumed to be a filename and an attempt will be made to open the corresponding NIfTI file. In case of an ndarray the array data will be used for the to be created nifti image and a matching nifti header is generated. If an object of a different type is supplied as 'source' a ValueError exception will be thrown. """ NiftiImage.__init__(self, source) # not working on compressed files if ncl.nifti_is_gzfile(self.raw_nimg.iname): raise RuntimeError, \ "Memory mapped access is only supported for " \ "uncompressed files." # determine byte-order if ncl.nifti_short_order() == 1: byteorder_flag = '<' else: byteorder_flag = '>' # create memmap array self._data = N.memmap( self.raw_nimg.iname, shape=self.extent[::-1], offset=self.raw_nimg.iname_offset, dtype=byteorder_flag + \ nifti2numpy_dtype_map[self.raw_nimg.datatype], mode='r+') def __del__(self): self._data.flush() # it is required to call base class destructors! NiftiFormat.__del__(self) # # little helpers # def load(self): """Does nothing for memory mapped images. """ return def unload(self): """Does nothing for memory mapped images. """ return def save(self): """Save the image. This methods does nothing except for syncing the file on the disk. Please note that the NIfTI header might not be completely up-to-date. For example, the min and max values might be outdated, but this class does not automatically update them, because it would require to load and search through the whole array. """ self._data.flush() # # getters and setters # def setFilename(self, filename, filetype = 'NIFTI'): """Does not work for memory mapped images and therefore raises an exception. """ raise RuntimeError, \ "Filename modifications are not supported for memory mapped " \ "images." # need to redefine, since we need to redefine to 'filename' property def getFilename(self): """Please see :meth:`nifti.format.NiftiFormat.getFilename` for the documentation.""" return NiftiFormat.getFilename(self) # need to redefine, since we need to redefine to 'filename' property def getDataArray(self): """Please see :meth:`nifti.format.NiftiImage.getDataArray` for the documentation.""" return NiftiImage.getDataArray(self) # # class properties # # read only data = property(fget=getDataArray) filename = property(fget=getFilename) # # Assign extra methods # NiftiImage.crop = imgfx.crop pynifti-0.20100607.1/nifti/niftiimage.py0000664000175000017500000000117211414645202017321 0ustar michaelmichael#emacs: -*- mode: python-mode; py-indent-offset: 4; indent-tabs-mode: nil -*- #ex: set sts=4 ts=4 sw=4 et: ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ## # # See COPYING file distributed along with the PyNIfTI package for the # copyright and license terms. # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ## """Only here for backward compatibility.""" __docformat__ = 'restructuredtext' from warnings import warn warn("This module has been renamed to 'nifti.image'. This redirect will be removed with PyNIfTI 1.0.", DeprecationWarning) from nifti.image import * pynifti-0.20100607.1/nifti/format.py0000664000175000017500000013634311414645253016514 0ustar michaelmichael#emacs: -*- mode: python-mode; py-indent-offset: 4; indent-tabs-mode: nil -*- #ex: set sts=4 ts=4 sw=4 et: ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ## # # See COPYING file distributed along with the PyNIfTI package for the # copyright and license terms. # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ## """This modules provides a class representation of a NIfTI image header. The interface provides pythonic access to NIfTI properties using Python datatypes. """ __docformat__ = 'restructuredtext' import cPickle from warnings import warn import numpy as N # the NIfTI pieces import nifti.clib as ncl from nifti.extensions import NiftiExtensions from nifti.utils import nhdr2dict, updateNiftiHeaderFromDict, \ Ndtype2niftidtype, nifti_xform_map, nifti_xform_inv_map, nifti_units_map, \ _checkUnit, valid_xyz_unit_codes, valid_time_unit_codes, \ nifti2numpy_dtype_map class NiftiFormat(object): """NIfTI header representation. NIfTI header can be created by loading information from an existing NIfTI file or by creating a matching NIfTI header for a ndarray. In addition, a number of methods to manipulate the header information are provided. However, this class is not able to write a NIfTI header back to disk. Please refer to the NIfTIImage class for this functionality. .. note:: Handling of NIfTI header extensions is provided by the :class:`~nifti.extensions.NiftiExtensions` class (see its documentation for more information). Access to an instance of this class is available through the `NiftiFormat.extensions` attribute. """ # # object constructors, destructors and generic Python interface # def __init__(self, source, header=None, loadmeta=False): """ The constructor decides whether to load a nifti image header from file or create one from ndarray data, depending on the datatype of `source`. :Parameters: source: str | ndarray If source is a string, it is assumed to be a filename and an attempt will be made to open the corresponding NIfTI file. Filenames might be provided as unicode strings. However, as the underlying library does not support unicode, they must be ascii-encodable, i.e. must not contain pure unicode characters. In case of an ndarray the array data will be used for the to be created nifti image and a matching nifti header is generated. If an object of a different type is supplied as 'source' a ValueError exception will be thrown. header: dict Additional header data might be supplied if image data is not loaded from a file. However, dimensionality and datatype are determined from the ndarray and not taken from a header dictionary. """ self.__nimg = None # prepare empty meta dict self.meta = {} # placeholder for extensions interface self.extensions = None if type(source) == N.ndarray: self.__newFromArray(source, header) elif type(source) in (str, unicode): self.__newFromFile(source, loadmeta) else: raise ValueError, \ "Unsupported source type. Only NumPy arrays and filename " \ + "string are supported." def __newFromArray(self, data, hdr=None): """Create a `nifti_image` struct from a ndarray. :Parameters: data: ndarray Source ndarray. hdr: dict Optional dictionary with NIfTI header data. .. warning:: This is an internal method. Neither its availability nor its API is guarenteed. """ if hdr == None: hdr = {} # check array if len(data.shape) > 7: raise ValueError, \ "NIfTI does not support data with more than 7 dimensions." # create template nifti header struct niptr = ncl.nifti_simple_init_nim() nhdr = ncl.nifti_convert_nim2nhdr(niptr) # intermediate cleanup ncl.nifti_image_free(niptr) # convert virgin nifti header to dict to merge properties # with supplied information and array properties hdic = nhdr2dict(nhdr) # copy data from supplied header dict for k, v in hdr.iteritems(): hdic[k] = v # finally set header data that is determined by the data array # convert NumPy to nifti datatype hdic['datatype'] = Ndtype2niftidtype(data) # make sure there are no zeros in the dim vector # especially not in #4 as FSLView doesn't like that hdic['dim'] = [ 1 for i in hdic['dim'] ] # set number of dims hdic['dim'][0] = len(data.shape) # set size of each dim (and reverse the order to match nifti format # requirements) for i, s in enumerate(data.shape): hdic['dim'][len(data.shape)-i] = s # set magic field to mark as nifti file hdic['magic'] = 'n+1' self._rebuildNimgFromHdrAndDict(nhdr, hdic) def __newFromFile(self, filename, loadmeta): """Open a NIfTI file. :Parameters: filename: str Filename of the to be opened image file. .. warning:: This is an internal method. Neither its availability nor its API is guarenteed. """ # make sure filename is not unicode try: filename = str(filename) except UnicodeEncodeError: raise UnicodeError, \ "The filename must not contain unicode characters, since " \ "the NIfTI library cannot handle them." # do not load image data! self.__nimg = ncl.nifti_image_read(filename, 0) if not self.__nimg: raise RuntimeError, "Error while opening NIfTI file '%s'." % \ filename # simply create extension interface since nifticlib took care of # loading all extensions already self.extensions = NiftiExtensions(self.raw_nimg) # unpickle meta data if present if loadmeta and 'pypickle' in self.extensions: if self.extensions.count('pypickle') > 1: warn("Handling more than one 'pypickle' extension is not " "supported. Will continue using the first detected " "extension.") # unpickle meta data self.meta = cPickle.loads(self.extensions['pypickle']) # and remove the pickle extension to not confuse data integrity when # users would add something to it manually, i.e. via # self.extensions['pypickle'] self._removePickleExtension() def __del__(self): # enforce del on extensions wrapper so Python GC doesn't try # to free it up later on causing writes to freed memory. del self.extensions if self.__nimg: ncl.nifti_image_free(self.__nimg) def __str__(self): lines = [] lines.append('extent' + str(self.extent)) lines.append('dtype(' \ + nifti2numpy_dtype_map[self.raw_nimg.datatype] \ + ')') s = 'voxels(' s += 'x'.join(["%f" % d for d in self.voxdim]) if self.xyz_unit: s += ' ' + self.getXYZUnit(as_string=True) lines.append(s + ')') if self.timepoints > 1: s = "timepoints(%i, dt=%f" % (self.timepoints, self.rtime) if self.time_unit: s += ' ' + self.getTimeUnit(as_string=True) s += ')' lines.append(s) if self.slope: lines.append("scaling(slope=%f, intercept=%f)" \ % (self.slope, self.intercept)) if self.qform_code: lines.append("qform(%s)" % self.getQFormCode(as_string=True)) lines.append("qform_orientation(%s)" \ % ', '.join(self.getQOrientation(as_string=True))) if self.sform_code: lines.append("sform(%s)" % self.getSFormCode(as_string=True)) lines.append("sform_orientation(%s)" \ % ', '.join(self.getSOrientation(as_string=True))) if self.description: lines.append("descr('%s')" % self.description) if len(self.meta.keys()): lines.append("meta(%s)" % str(self.meta.keys())) return '' # # converters # def asDict(self): """Returns the header data of the `NiftiImage` in a dictionary. :Returns: dict The dictionary contains all NIfTI header information. Additionally, it might also contain a special 'meta' item that contains the meta data currently assigned to this instance. .. note:: Modifications done to the returned dictionary do not cause any modifications in the NIfTI image itself. Please use :meth:`~nifti.format.NiftiFormat.updateFromDict` to apply changes to the image. .. seealso:: :meth:`~nifti.format.NiftiFormat.updateFromDict`, :attr:`~nifti.format.NiftiFormat.header` """ # Convert nifti_image struct into nifti1 header struct. # This get us all data that will actually make it into a # NIfTI file. nhdr = ncl.nifti_convert_nim2nhdr(self.raw_nimg) # pass extensions as well ret = nhdr2dict(nhdr, extensions=self.extensions) if len(self.meta.keys()): ret['meta'] = self.meta return ret def updateFromDict(self, hdrdict): """Update NIfTI header information. Updated header data is read from the supplied dictionary. One cannot modify dimensionality and datatype of the image data. If such information is present in the header dictionary it is removed before the update. If resizing or datatype casting are required one has to convert the image data into a separate array and perform resize and data manipulations on this array. When finished, the array can be converted into a nifti file by calling the NiftiImage constructor with the modified array as 'source' and the nifti header of the original NiftiImage object as 'header'. .. note:: If the provided dictionary contains a 'meta' item its content is used to overwrite any potentially existing meta data. dictionary. The same behavior will be used for 'extensions'. If extensions are defined in the provided dictionary all currently existing extensions will be overwritten. .. seealso:: :meth:`~nifti.format.NiftiFormat.asDict`, :attr:`~nifti.format.NiftiFormat.header` """ # rebuild nifti header from current image struct nhdr = ncl.nifti_convert_nim2nhdr(self.__nimg) # remove settings from the hdrdict that are determined by # the data set and must not be modified to preserve data integrity if hdrdict.has_key('datatype'): del hdrdict['datatype'] if hdrdict.has_key('dim'): del hdrdict['dim'] self._rebuildNimgFromHdrAndDict(nhdr, hdrdict) def vx2q(self, coord): """Transform a voxel's index into coordinates (qform-defined). :Parameter: coord: 3-tuple A voxel's index in the volume fiven as three positive integers (i, j, k). :Returns: vector .. seealso:: :meth:`~nifti.format.NiftiFormat.setQForm`, :meth:`~nifti.format.NiftiFormat.getQForm` :attr:`~nifti.format.NiftiFormat.qform` """ # add dummy one to row vector coord_ = N.r_[coord, [1.0]] # apply affine transformation result = N.dot(self.qform, coord_) # return 3D coordinates return result[0:-1] def vx2s(self, coord): """Transform a voxel's index into coordinates (sform-defined). :Parameter: coord: 3-tuple A voxel's index in the volume fiven as three positive integers (i, j, k). :Returns: vector .. seealso:: :meth:`~nifti.format.NiftiFormat.setSForm`, :meth:`~nifti.format.NiftiFormat.getSForm` :attr:`~nifti.format.NiftiFormat.sform` """ # add dummy one to row vector coord_ = N.r_[coord, [1.0]] # apply affine transformation result = N.dot(self.sform, coord_) # return 3D coordinates return result[0:-1] # # private helpers # def _updateNimgFromArray(self, val): """Update all relevant items in the nimg struct to match a given array's properties. We can only savely modify the respective nimg items since the data array is disconnected from the struct all the time. .. warning:: This is an internal method. Neither its availability nor its API is guarenteed. """ # convert dtype and store in struct self.raw_nimg.datatype = Ndtype2niftidtype(val) # wrap dims dim = ncl.intArray_frompointer(self.raw_nimg.dim) # make sure there are no zeros in the dim vector # especially not in #4 as FSLView doesn't like that target_dim = N.ones(7, dtype='int') # reverse the array shape target_dim[:len(val.shape)] = val.shape[::-1] # set number of dims dim[0] = len(val.shape) # assign remaining dim vector for i in range(7): dim[i+1] = target_dim[i] # expand dim vector self.raw_nimg.ndim = dim[0] self.raw_nimg.nx = dim[1] self.raw_nimg.ny = dim[2] self.raw_nimg.nz = dim[3] self.raw_nimg.nt = dim[4] self.raw_nimg.nu = dim[5] self.raw_nimg.nv = dim[6] self.raw_nimg.nw = dim[7] def _rebuildNimgFromHdrAndDict(self, nhdr, hdic): """ .. warning:: This is an internal method. Neither its availability nor its API is guarenteed. """ # first updated the header struct from the provided dictionary # data updateNiftiHeaderFromDict(nhdr, hdic) # if no filename was set already (e.g. image from array) set a temp # name now, as otherwise nifti_convert_nhdr2nim will fail have_temp_filename = False if not self.__nimg: # we are creating from scratch new_nimg = ncl.nifti_convert_nhdr2nim(nhdr, 'pynifti_none') have_temp_filename = True elif not self.filename: # rebuild but no filename yet self.__nimg.fname = 'pynifti_updateheader_temp_name' self.__nimg.iname = 'pynifti_updateheader_temp_name' new_nimg = ncl.nifti_convert_nhdr2nim(nhdr, 'pynifti_none') have_temp_filename = True else: # recreate nifti image struct using current filename new_nimg = ncl.nifti_convert_nhdr2nim(nhdr, self.filename) if not new_nimg: raise RuntimeError, \ "Could not create NIfTI image struct from header." # rescue all extensions if self.extensions: # need to create a new extensions wrapper around the new # nifti image struct new_ext = NiftiExtensions( new_nimg, [ext for ext in self.extensions.iteritems()]) else: # just create an empty wrapper new_ext = NiftiExtensions(new_nimg) # replace old image struct by new one # be careful with memory leak (still not checked whether successful) # assign the new image struct self.__nimg = new_nimg # and the extensions self.extensions = new_ext # reset filename if temp name was set if have_temp_filename: self.__nimg.fname = '' self.__nimg.iname = '' # # merge new extensions # if hdic.has_key('extensions'): # wipe current set of extensions self.extensions.clear() for e in hdic['extensions']: self.extensions.append(e) # # assign new meta data if hdic.has_key('meta'): self.meta = hdic['meta'] def _removePickleExtension(self): """Remove the 'pypickle' extension from the raw NIfTI image struct. Its content is expanded into the `meta` attribute in a NiftiImage instance. .. warning:: This is an internal method. Neither its availability nor its API is guarenteed. """ if 'pypickle' in self.extensions: del self.extensions['pypickle'] def updateQFormFromQuaternion(self): """Only here for backward compatibility.""" from warnings import warn warn("The method has been renamed to " \ "NiftiFormat.__updateQFormFromQuaternion and should not be used " \ "in user code. This redirect will be removed with PyNIfTI 1.0.", \ DeprecationWarning) self.__updateQFormFromQuaternion() def __updateQFormFromQuaternion(self): """Recalculates the qform matrix (and the inverse) from the quaternion representation. .. warning:: This is an internal method. Neither its availability nor its API is guarenteed. """ # recalculate qform self.__nimg.qto_xyz = ncl.nifti_quatern_to_mat44 ( self.__nimg.quatern_b, self.__nimg.quatern_c, self.__nimg.quatern_d, self.__nimg.qoffset_x, self.__nimg.qoffset_y, self.__nimg.qoffset_z, self.__nimg.dx, self.__nimg.dy, self.__nimg.dz, self.__nimg.qfac ) # recalculate inverse self.__nimg.qto_ijk = \ ncl.nifti_mat44_inverse( self.__nimg.qto_xyz ) # # getters and setters # def getVoxDims(self): """Returns a 3-tuple a voxel dimensions/size in (x,y,z). .. seealso:: :meth:`~nifti.format.NiftiFormat.setVoxDims`, :attr:`~nifti.format.NiftiFormat.voxdim` """ return (self.__nimg.dx, self.__nimg.dy, self.__nimg.dz) def setVoxDims(self, value): """Set voxel dimensions/size. The qform matrix and its inverse will be recalculated automatically. :Parameter: value: 3-tuple of floats Have to be given in (x,y,z) order. .. seealso:: :meth:`~nifti.format.NiftiFormat.getVoxDims`, :attr:`~nifti.format.NiftiFormat.voxdim` """ if len(value) != 3: raise ValueError, 'Requires 3-tuple.' self.__nimg.dx = float(value[0]) self.__nimg.dy = float(value[1]) self.__nimg.dz = float(value[2]) self.__updateQFormFromQuaternion() def setPixDims(self, value): """Set the pixel dimensions. :Parameter: value: sequence Up to 7 values (max. number of dimensions supported by the NIfTI format) are allowed in the sequence. The supplied sequence can be shorter than seven elements. In this case only present values are assigned starting with the first dimension (spatial: x). .. note:: Calling `setPixDims()` with a length-3 sequence equals calling `setVoxDims()`. .. seealso:: :meth:`~nifti.format.NiftiFormat.setVoxDims`, :meth:`~nifti.format.NiftiFormat.getPixDims`, :attr:`~nifti.format.NiftiFormat.pixdim` """ if len(value) > 7: raise ValueError, \ 'The Nifti format does not support more than 7 dimensions.' pixdim = ncl.floatArray_frompointer( self.__nimg.pixdim ) for i, val in enumerate(value): pixdim[i+1] = float(val) # The nifticlib uses dimension deltas (dx, dy, dz, dt...) to store # the pixdim values (in addition to the pixdim array). When # saving the image to a file, the deltas are used, not the pixdims. # The nifti_update_dims_from_array sync's the deltas with the pixdims. # (It also syncs the dim array with it's duplicate scalar variables.) ncl.nifti_update_dims_from_array(self.__nimg) def getPixDims(self): """Returns the pixel dimensions on all 7 dimensions. The function is similar to `getVoxDims()`, but instead of the 3d spatial dimensions of a voxel it returns the dimensions of an image pixel on all 7 dimensions supported by the NIfTI dataformat. .. seealso:: :meth:`~nifti.format.NiftiFormat.getVoxDims`, :meth:`~nifti.format.NiftiFormat.setPixDims`, :attr:`~nifti.format.NiftiFormat.pixdim` """ return \ tuple([ ncl.floatArray_frompointer(self.__nimg.pixdim)[i] for i in range(1,8) ] ) def getExtent(self): """Returns the shape of the dataimage. :Returns: tuple: Tuple with the size in voxel/timepoints. The order of dimensions is (x,y,z,t,u,v,w). If the image has less dimensions than 7 the return tuple will be shortened accordingly. Please note that the order of dimensions is different from the tuple returned by calling `NiftiImage.data.shape`! .. seealso:: :meth:`~nifti.format.NiftiFormat.getVolumeExtent`, :meth:`~nifti.format.NiftiFormat.getTimepoints`, :attr:`~nifti.format.NiftiFormat.extent` """ # wrap dim array in nifti image struct dims_array = ncl.intArray_frompointer(self.__nimg.dim) dims = [ dims_array[i] for i in range(8) ] return tuple( dims[1:dims[0]+1] ) def getVolumeExtent(self): """Returns the size/shape of the volume(s) in the image as a tuple. :Returns: tuple: Either a 3-tuple or 2-tuple or 1-tuple depending on the available dimensions in the image. The order of dimensions in the tuple is (x [, y [, z ] ] ). .. seealso:: :meth:`~nifti.format.NiftiFormat.getExtent`, :attr:`~nifti.format.NiftiFormat.volextent` """ # it is save to do this even if self.extent is shorter than 4 items return self.extent[:3] def getTimepoints(self): """Returns the number of timepoints in the image. In case of a 3d (or less dimension) image this method returns 1. .. seealso:: :attr:`~nifti.format.NiftiFormat.timepoints` """ if len(self.extent) < 4: return 1 else: return self.extent[3] def getRepetitionTime(self): """Returns the temporal distance between the volumes in a timeseries. .. seealso:: :meth:`~nifti.format.NiftiFormat.setRepetitionTime`, :attr:`~nifti.format.NiftiFormat.rtime` """ return self.__nimg.dt def setRepetitionTime(self, value): """Set the repetition time of a NIfTI image (dt). .. seealso:: :meth:`~nifti.format.NiftiFormat.getRepetitionTime`, :attr:`~nifti.format.NiftiFormat.rtime` """ self.__nimg.dt = float(value) def setSlope(self, value): """Set the slope attribute in the NIfTI header. Setting the slope to zero, will disable scaling. .. seealso:: :attr:`~nifti.format.NiftiFormat.slope`, :attr:`~nifti.format.NiftiFormat.intercept` """ self.__nimg.scl_slope = float(value) def setIntercept(self, value): """Set the intercept attribute in the NIfTI header. The intercept is only considered for scaling in case of a non-zero slope value. .. seealso:: :attr:`~nifti.format.NiftiFormat.slope`, :attr:`~nifti.format.NiftiFormat.intercept` """ self.__nimg.scl_inter = float(value) def setDescription(self, value): """Set the description element in the NIfTI header. :Parameter: value: str Description -- must not be longer than 79 characters. .. seealso:: :attr:`~nifti.format.NiftiFormat.description` """ if len(value) > 79: raise ValueError, \ "The NIfTI format only supports descriptions shorter than " \ "80 chars. (got length %i)" % len(value) self.__nimg.descrip = value def setXFormCode(self, xform, code): """Set the type of space described by the NIfTI transformations. The NIfTI format defines five coordinate system types which are used to describe the target space of a transformation (qform or sform). Please note, that the last four transformation types are only available in the NIfTI format and not when saving into ANALYZE. 'unkown', `NIFTI_XFORM_UNKNOWN`, 0: Transformation is arbitrary. This is the ANALYZE compatibility mode. In this case no *sform* matrix will be written, even when stored in NIfTI and not in ANALYZE format. Additionally, only the pixdim parts of the *qform* matrix will be saved (upper-left 3x3). 'scanner', `NIFTI_XFORM_SCANNER_ANAT`, 1: Scanner-based anatomical coordinates. 'aligned', `NIFTI_XFORM_ALIGNED_ANAT`, 2: Coordinates are aligned to another file's coordinate system. 'talairach', `NIFTI_XFORM_TALAIRACH`, 3: Coordinate system is shifted to have its origin (0,0,0) at the anterior commissure, as in the Talairach-Tournoux Atlas. 'mni152', `NIFTI_XFORM_MNI_152`, 4: Coordinates are in MNI152 space. :Parameters: xform: 'qform' | 'q' | 'sform' | 's' Which of the two NIfTI transformations to set. code: str | `NIFTI_XFORM_CODE` | int (0..4) The Transformation code can be specified either by a string, the `NIFTI_XFORM_CODE` defined in the nifti1.h header file (accessible via the `nifti.clib` module, or the corresponding integer value. .. seealso:: :meth:`~nifti.format.NiftiFormat.setQFormCode`, :meth:`~nifti.format.NiftiFormat.getQFormCode`, :meth:`~nifti.format.NiftiFormat.setSFormCode`, :meth:`~nifti.format.NiftiFormat.getSFormCode`, :attr:`~nifti.format.NiftiFormat.qform_code`, :attr:`~nifti.format.NiftiFormat.sform_code` """ if isinstance(code, str): if not code in nifti_xform_map.keys(): raise ValueError, \ "Unknown xform code '%s'. Must be one of '%s'" \ % (code, str(nifti_xform_map.keys())) code = nifti_xform_map[code] else: if not code in nifti_xform_map.values(): raise ValueError, \ "Unknown xform code '%s'. Must be one of '%s'" \ % (str(code), str(nifti_xform_map.values())) if xform == 'qform' or xform == 'q': self.raw_nimg.qform_code = code elif xform == 'sform' or xform == 's': self.raw_nimg.sform_code = code else: raise ValueError, "Unkown transformation '%s'" % xform def setQFormCode(self, code): """Set the qform code. .. note:: This is a convenience frontend for :meth:`~nifti.format.NiftiFormat.setXFormCode`. Please see its documentation for more information. """ self.setXFormCode('qform', code) def getQFormCode(self, as_string = False): """Return the qform code. By default NIfTI xform codes are returned, but if `as_string` is set to true a string representation ala 'talairach' is returned instead. .. seealso:: :meth:`~nifti.format.NiftiFormat.getQFormCode`, :attr:`~nifti.format.NiftiFormat.qform_code` """ code = self.raw_nimg.qform_code if as_string: code = nifti_xform_inv_map[code] return code def getSFormCode(self, as_string = False): """Return the sform code. By default NIfTI xform codes are returned, but if `as_string` is set to true a string representation ala 'talairach' is returned instead. .. seealso:: :meth:`~nifti.format.NiftiFormat.getSFormCode`, :attr:`~nifti.format.NiftiFormat.sform_code` """ code = self.raw_nimg.sform_code if as_string: code = nifti_xform_inv_map[code] return code def setSFormCode(self, code): """Set the sform code. .. note:: This is a convenience frontend for :meth:`~nifti.format.NiftiFormat.setXFormCode`. Please see its documentation for more information. """ self.setXFormCode('sform', code) def getSForm(self): """Returns the sform matrix. .. note:: The returned sform matrix is not bound to the object. Therefore it cannot be successfully modified in-place. Modifications to the sform matrix can only be done by setting a new sform matrix .. seealso:: :meth:`~nifti.format.NiftiFormat.setSForm`, :meth:`~nifti.format.NiftiFormat.setSFormCode`, :meth:`~nifti.format.NiftiFormat.getSFormCode`, :attr:`~nifti.format.NiftiFormat.sform`, :attr:`~nifti.format.NiftiFormat.sform_inv`, :attr:`~nifti.format.NiftiFormat.sform_code` """ return ncl.mat442array(self.__nimg.sto_xyz) def setSForm(self, m, code='mni152'): """Sets the sform matrix. The supplied value has to be a 4x4 matrix. The matrix elements will be converted to floats. By definition the last row of the sform matrix has to be (0,0,0,1). However, different values can be assigned, but will not be stored when the NIfTI image is saved to a file. The inverse sform matrix will be automatically recalculated. :Parameters: m: 4x4 ndarray The sform matrix. code: str | `NIFTI_XFORM_CODE` | int (0..4) The type of the coordinate system the sform matrix is describing. By default this coordinate system is assumed to be the MNI152 space. Please refer to the :meth:`~nifti.format.NiftiFormat.setXFormCode` method for a full list of possible codes and their meaning. .. seealso:: :meth:`~nifti.format.NiftiFormat.getSForm`, :meth:`~nifti.format.NiftiFormat.setSFormCode`, :meth:`~nifti.format.NiftiFormat.getSFormCode`, :attr:`~nifti.format.NiftiFormat.sform`, :attr:`~nifti.format.NiftiFormat.sform_code` """ if m.shape != (4, 4): raise ValueError, "SForm matrix has to be of size 4x4." # make sure it is float m = m.astype('float') ncl.set_mat44( self.__nimg.sto_xyz, m[0,0], m[0,1], m[0,2], m[0,3], m[1,0], m[1,1], m[1,2], m[1,3], m[2,0], m[2,1], m[2,2], m[2,3], m[3,0], m[3,1], m[3,2], m[3,3] ) # recalculate inverse self.__nimg.sto_ijk = \ ncl.nifti_mat44_inverse( self.__nimg.sto_xyz ) # set sform code, which decides how the sform matrix is interpreted self.setXFormCode('sform', code) def getInverseSForm(self): """Returns the inverse sform matrix. .. note:: The inverse sform matrix cannot be modified in-place. One needs to set a new sform matrix instead. The corresponding inverse matrix is then re-calculated automatically. .. seealso:: :meth:`~nifti.format.NiftiFormat.getSForm`, :attr:`~nifti.format.NiftiFormat.sform`, :attr:`~nifti.format.NiftiFormat.sform_inv`, """ return ncl.mat442array(self.__nimg.sto_ijk) def getQForm(self): """Returns the qform matrix. .. note:: The returned qform matrix is not bound to the object. Therefore it cannot be successfully modified in-place. Modifications to the qform matrix can only be done by setting a new qform matrix .. seealso:: :meth:`~nifti.format.NiftiFormat.setQForm`, :meth:`~nifti.format.NiftiFormat.setQFormCode`, :meth:`~nifti.format.NiftiFormat.getQFormCode`, :meth:`~nifti.format.NiftiFormat.getQuaternion`, :meth:`~nifti.format.NiftiFormat.getQOffset`, :meth:`~nifti.format.NiftiFormat.setQuaternion`, :meth:`~nifti.format.NiftiFormat.setQOffset`, :meth:`~nifti.format.NiftiFormat.setQFac`, :attr:`~nifti.format.NiftiFormat.qform`, :attr:`~nifti.format.NiftiFormat.qform_inv`, :attr:`~nifti.format.NiftiFormat.qform_code`, :attr:`~nifti.format.NiftiFormat.quatern`, :attr:`~nifti.format.NiftiFormat.qoffset`, :attr:`~nifti.format.NiftiFormat.qfac` """ return ncl.mat442array(self.__nimg.qto_xyz) def getInverseQForm(self): """Returns the inverse qform matrix. .. note:: The inverse qform matrix cannot be modified in-place. One needs to set a new qform matrix instead. The corresponding inverse matrix is then re-calculated automatically. .. seealso:: :meth:`~nifti.format.NiftiFormat.getQForm`, :attr:`~nifti.format.NiftiFormat.qform`, :attr:`~nifti.format.NiftiFormat.qform_inv`, """ return ncl.mat442array(self.__nimg.qto_ijk) def setQForm(self, m, code='scanner'): """Sets the qform matrix. The supplied value has to be a 4x4 matrix. The matrix will be converted to float. The inverse qform matrix and the quaternion representation will be automatically recalculated. :Parameters: m: 4x4 ndarray The qform matrix. code: str | `NIFTI_XFORM_CODE` | int (0..4) The type of the coordinate system the qform matrix is describing. By default this coordinate system is assumed to be the scanner space. Please refer to the :meth:`~nifti.format.NiftiFormat.setXFormCode` method for a full list of possible codes and their meaning. .. seealso:: :meth:`~nifti.format.NiftiFormat.getQForm`, :meth:`~nifti.format.NiftiFormat.setQFormCode`, :meth:`~nifti.format.NiftiFormat.getQFormCode`, :meth:`~nifti.format.NiftiFormat.getQuaternion`, :meth:`~nifti.format.NiftiFormat.getQOffset`, :meth:`~nifti.format.NiftiFormat.setQuaternion`, :meth:`~nifti.format.NiftiFormat.setQOffset`, :meth:`~nifti.format.NiftiFormat.setQFac`, :attr:`~nifti.format.NiftiFormat.qform`, :attr:`~nifti.format.NiftiFormat.qform_inv`, :attr:`~nifti.format.NiftiFormat.qform_code`, :attr:`~nifti.format.NiftiFormat.quatern`, :attr:`~nifti.format.NiftiFormat.qoffset`, :attr:`~nifti.format.NiftiFormat.qfac` """ if m.shape != (4, 4): raise ValueError, "QForm matrix has to be of size 4x4." # make sure it is float m = m.astype('float') ncl.set_mat44( self.__nimg.qto_xyz, m[0,0], m[0,1], m[0,2], m[0,3], m[1,0], m[1,1], m[1,2], m[1,3], m[2,0], m[2,1], m[2,2], m[2,3], m[3,0], m[3,1], m[3,2], m[3,3] ) # recalculate inverse self.__nimg.qto_ijk = \ ncl.nifti_mat44_inverse( self.__nimg.qto_xyz ) # update quaternions ( self.__nimg.quatern_b, self.__nimg.quatern_c, self.__nimg.quatern_d, self.__nimg.qoffset_x, self.__nimg.qoffset_y, self.__nimg.qoffset_z, self.__nimg.dx, self.__nimg.dy, self.__nimg.dz, self.__nimg.qfac ) = \ ncl.nifti_mat44_to_quatern( self.__nimg.qto_xyz ) # set qform code, which decides how the qform matrix is interpreted self.setXFormCode('qform', code) def setQuaternion(self, value, code='scanner'): """Set Quaternion from 3-tuple (qb, qc, qd). The qform matrix and it's inverse are re-computed automatically. :Parameters: value: length-3 sequence qb, qc and qd quaternions. code: str | `NIFTI_XFORM_CODE` | int (0..4) The type of the coordinate system the corresponding qform matrix is describing. By default this coordinate system is assumed to be the scanner space. Please refer to the :meth:`~nifti.format.NiftiFormat.setXFormCode` method for a full list of possible codes and their meaning. .. seealso:: :meth:`~nifti.format.NiftiFormat.getQForm`, :meth:`~nifti.format.NiftiFormat.setQForm`, :meth:`~nifti.format.NiftiFormat.setQFormCode`, :meth:`~nifti.format.NiftiFormat.getQFormCode`, :meth:`~nifti.format.NiftiFormat.getQuaternion`, :meth:`~nifti.format.NiftiFormat.getQOffset`, :meth:`~nifti.format.NiftiFormat.setQOffset`, :meth:`~nifti.format.NiftiFormat.setQFac`, :attr:`~nifti.format.NiftiFormat.qform`, :attr:`~nifti.format.NiftiFormat.qform_inv`, :attr:`~nifti.format.NiftiFormat.qform_code`, :attr:`~nifti.format.NiftiFormat.quatern`, :attr:`~nifti.format.NiftiFormat.qoffset`, :attr:`~nifti.format.NiftiFormat.qfac` """ if len(value) != 3: raise ValueError, 'Requires 3-tuple.' self.__nimg.quatern_b = float(value[0]) self.__nimg.quatern_c = float(value[1]) self.__nimg.quatern_d = float(value[2]) self.__updateQFormFromQuaternion() self.setXFormCode('qform', code) def getQuaternion(self): """Returns a 3-tuple containing (qb, qc, qd). .. seealso:: :meth:`~nifti.format.NiftiFormat.setQuaternion`, :attr:`~nifti.format.NiftiFormat.qform`, :attr:`~nifti.format.NiftiFormat.quatern` """ return( ( self.__nimg.quatern_b, self.__nimg.quatern_c, self.__nimg.quatern_d ) ) def setQOffset(self, value, code='scanner'): """Set QOffset from 3-tuple (qx, qy, qz). The qform matrix and its inverse are re-computed automatically. Besides reading it is also possible to set the qoffset by assigning to the `qoffset` property. :Parameters: value: length-3 sequence qx, qy and qz offsets. code: str | `NIFTI_XFORM_CODE` | int (0..4) The type of the coordinate system the corresponding qform matrix is describing. By default this coordinate system is assumed to be the scanner space. Please refer to the :meth:`~nifti.format.NiftiFormat.setXFormCode` method for a full list of possible codes and their meaning. .. seealso:: :meth:`~nifti.format.NiftiFormat.getQOffset`, :attr:`~nifti.format.NiftiFormat.qform`, :attr:`~nifti.format.NiftiFormat.qoffset` """ if len(value) != 3: raise ValueError, 'Requires 3-tuple.' self.__nimg.qoffset_x = float(value[0]) self.__nimg.qoffset_y = float(value[1]) self.__nimg.qoffset_z = float(value[2]) self.__updateQFormFromQuaternion() self.setXFormCode('qform', code) def getQOffset(self): """Returns a 3-tuple containing (qx, qy, qz). .. seealso:: :meth:`~nifti.format.NiftiFormat.setQOffset`, :attr:`~nifti.format.NiftiFormat.qform`, :attr:`~nifti.format.NiftiFormat.qoffset` """ return( ( self.__nimg.qoffset_x, self.__nimg.qoffset_y, self.__nimg.qoffset_z ) ) def setQFac(self, value, code='scanner'): """Set qfac (scaling factor of qform matrix). The qform matrix and its inverse are re-computed automatically. Besides reading it is also possible to set the qfac by assigning to the `qfac` property. :Parameters: value: float Scaling factor. code: str | `NIFTI_XFORM_CODE` | int (0..4) The type of the coordinate system the corresponding qform matrix is describing. By default this coordinate system is assumed to be the scanner space. Please refer to the :meth:`~nifti.format.NiftiFormat.setXFormCode` method for a full list of possible codes and their meaning. .. seealso:: :attr:`~nifti.format.NiftiFormat.qform`, :attr:`~nifti.format.NiftiFormat.qfac` """ self.__nimg.qfac = float(value) self.__updateQFormFromQuaternion() self.setXFormCode('qform', code) def getQOrientation(self, as_string = False): """Returns to orientation of the i, j and k axis as stored in the qform matrix. By default NIfTI orientation codes are returned, but if `as_string` is set to true a string representation ala 'Left-to-right' is returned instead. :Returns: list orientations fo the x, y and z axis respectively. .. seealso:: :attr:`~nifti.format.NiftiFormat.qform` """ codes = ncl.nifti_mat44_to_orientation(self.__nimg.qto_xyz) if as_string: return [ ncl.nifti_orientation_string(i) for i in codes ] else: return codes def getSOrientation(self, as_string = False): """Returns to orientation of the i, j and k axis as stored in the sform matrix. By default NIfTI orientation codes are returned, but if `as_string` is set to true a string representation ala 'Left-to-right' is returned instead. :Returns: list orientations fo the x, y and z axis respectively. .. seealso:: :attr:`~nifti.format.NiftiFormat.sform` """ codes = ncl.nifti_mat44_to_orientation(self.__nimg.sto_xyz) if as_string: return [ ncl.nifti_orientation_string(i) for i in codes ] else: return codes def getXYZUnit(self, as_string = False): """Return 3D-space unit. By default NIfTI unit codes are returned, but if `as_string` is set to true a string representation ala 'mm' is returned instead. .. seealso:: :meth:`~nifti.format.NiftiFormat.setXYZUnit`, :attr:`~nifti.format.NiftiFormat.xyz_unit` """ code = self.__nimg.xyz_units if as_string: code = ncl.nifti_units_string(code) return code def setXYZUnit(self, value): """Set the unit of the spatial axes. :Parameter: value: int | str The unit can either be given as a NIfTI unit code or as any of the plain text abbrevations returned by :meth:'~nifti.format.NiftiFormat.getXYZUnit` .. seealso:: :meth:`~nifti.format.NiftiFormat.getXYZUnit`, :attr:`~nifti.format.NiftiFormat.xyz_unit` """ # check for valid codes according to NIfTI1 standard code = _checkUnit(value, valid_xyz_unit_codes) self.raw_nimg.xyz_units = code def getTimeUnit(self, as_string = False): """Return unit of temporal (4th) axis. By default NIfTI unit codes are returned, but if `as_string` is set to true a string representation ala 's' is returned instead. .. seealso:: :meth:`~nifti.format.NiftiFormat.setTimeUnit`, :attr:`~nifti.format.NiftiFormat.time_unit` """ code = self.__nimg.time_units if as_string: code = ncl.nifti_units_string(code) return code def setTimeUnit(self, value): """Set the unit of the temporal axis (4th). :Parameter: value: int | str The unit can either be given as a NIfTI unit code or as any of the plain text abbrevations returned by :meth:'~nifti.format.NiftiFormat.getTimeUnit` .. seealso:: :meth:`~nifti.format.NiftiFormat.getTimeUnit`, :attr:`~nifti.format.NiftiFormat.time_unit` """ # check for valid codes according to NIfTI1 standard code = _checkUnit(value, valid_time_unit_codes) self.raw_nimg.time_units = code def getFilename(self): """Returns the filename. To distinguish ANALYZE from 2-file NIfTI images the image filename is returned for ANALYZE images while the header filename is returned for NIfTI files. .. seealso:: :attr:`~nifti.format.NiftiFormat.filename` """ if self.__nimg.nifti_type == ncl.NIFTI_FTYPE_ANALYZE: return self.__nimg.iname else: return self.__nimg.fname # # class properties # # read only nvox = property(fget=lambda self: self.__nimg.nvox) max = property(fget=lambda self: self.__nimg.cal_max) min = property(fget=lambda self: self.__nimg.cal_min) sform_inv = property(fget=getInverseSForm) qform_inv = property(fget=getInverseQForm) extent = property(fget=getExtent) volextent = property(fget=getVolumeExtent) timepoints = property(fget=getTimepoints) raw_nimg = property(fget=lambda self: self.__nimg) filename = property(fget=getFilename) # read and write slope = property(fget=lambda self: self.__nimg.scl_slope, fset=setSlope) intercept = property(fget=lambda self: self.__nimg.scl_inter, fset=setIntercept) voxdim = property(fget=getVoxDims, fset=setVoxDims) pixdim = property(fget=getPixDims, fset=setPixDims) description = property(fget=lambda self: self.__nimg.descrip, fset=setDescription) header = property( fget=asDict, fset=updateFromDict, doc="""Access to a dictionary version of the NIfTI header data. .. note:: This property cannot be used like this:: nimg.header['something'] = 'new value' Instead one has to get the header dictionary, modify and later reassign it:: h = nimg.header h['something'] = 'new value' nimg.header = h .. seealso:: :meth:`~nifti.format.NiftiFormat.asDict`, :meth:`~nifti.format.NiftiFormat.updateFromDict` """) sform = property(fget=getSForm, fset=setSForm) sform_code = property(fget=getSFormCode, fset=setSFormCode) qform = property(fget=getQForm, fset=setQForm) qform_code = property(fget=getQFormCode, fset=setQFormCode) quatern = property(fget=getQuaternion, fset=setQuaternion) qoffset = property(fget=getQOffset, fset=setQOffset) qfac = property(fget=lambda self: self.__nimg.qfac, fset=setQFac) rtime = property(fget=getRepetitionTime, fset=setRepetitionTime) xyz_unit = property(fget=getXYZUnit, fset=setXYZUnit) time_unit = property(fget=getTimeUnit, fset=setTimeUnit) pynifti-0.20100607.1/nifti/clib.i0000664000175000017500000002043611414645202015722 0ustar michaelmichael/* emacs: -*- mode: python-mode; py-indent-offset: 4; indent-tabs-mode: nil -*- ex: set sts=4 ts=4 sw=4 et: *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** * * SWIG interface to wrap the low-level NIfTI IO libs for Python * * See COPYING file distributed along with the PyNIfTI package for the * copyright and license terms. * *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */ %define DOCSTRING " This module provide the all functions and datatypes implemented in the low-level C library libniftiio and the NIfTI-1 header. At the moment no additional documentation is provided here. Please see the intensively documented source code of the nifti C libs to learn about the capabilities of the library. " %enddef %module (package="nifti", docstring=DOCSTRING) clib %{ #include #include #include #include /* low tech wrapper function to set values of a mat44 struct */ static void set_mat44(mat44* m, float a1, float a2, float a3, float a4, float b1, float b2, float b3, float b4, float c1, float c2, float c3, float c4, float d1, float d2, float d3, float d4 ) { m->m[0][0] = a1; m->m[0][1] = a2; m->m[0][2] = a3; m->m[0][3] = a4; m->m[1][0] = b1; m->m[1][1] = b2; m->m[1][2] = b3; m->m[1][3] = b4; m->m[2][0] = c1; m->m[2][1] = c2; m->m[2][2] = c3; m->m[2][3] = c4; m->m[3][0] = d1; m->m[3][1] = d2; m->m[3][2] = d3; m->m[3][3] = d4; } /* convert mat44 struct into a numpy float array */ static PyObject* mat442array(mat44 _mat) { npy_intp dims[2] = {4,4}; PyObject* array = 0; array = PyArray_SimpleNew ( 2, dims, NPY_FLOAT ); /* mat44 subscription is [row][column] */ PyArrayObject* a = (PyArrayObject*) array; float* data = (float *)a->data; int i,j; for (i = 0; i<4; i+=1) { for (j = 0; j<4; j+=1) { data[4*i+j] = _mat.m[i][j]; } } return PyArray_Return ( (PyArrayObject*) array ); } /******************************************************** * * Wrapping the image array with a NumPy array. * * This is a revised version following the solution * outlined here: http://blog.enthought.com/?p=62 * *******************************************************/ /* define a new python object type that performs the array data de-allocation when the ref count goes to zero */ typedef struct { PyObject_HEAD void *memory; } _MyDeallocObject; static void _mydealloc_dealloc(_MyDeallocObject *self) { free(self->memory); self->ob_type->tp_free((PyObject *)self); } static PyTypeObject _MyDeallocType = { PyObject_HEAD_INIT(NULL) 0, "mydeallocator", sizeof(_MyDeallocObject), 0, _mydealloc_dealloc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT, "Internal deallocator object", }; static PyObject* wrapImageDataWithArray(nifti_image* _img) { if (!_img) { PyErr_SetString( PyExc_RuntimeError, "Zero pointer passed instead of valid nifti_image struct."); return(NULL); } int array_type=0; /* translate nifti datatypes to numpy datatypes */ switch(_img->datatype) { case NIFTI_TYPE_UINT8: array_type = NPY_UBYTE; break; case NIFTI_TYPE_INT8: array_type = NPY_BYTE; break; case NIFTI_TYPE_UINT16: array_type = NPY_USHORT; break; case NIFTI_TYPE_INT16: array_type = NPY_SHORT; break; case NIFTI_TYPE_UINT32: array_type = NPY_UINT; break; case NIFTI_TYPE_INT32: array_type = NPY_INT; break; case NIFTI_TYPE_UINT64: case NIFTI_TYPE_INT64: array_type = NPY_LONG; break; case NIFTI_TYPE_FLOAT32: array_type = NPY_FLOAT; break; case NIFTI_TYPE_FLOAT64: array_type = NPY_DOUBLE; break; case NIFTI_TYPE_COMPLEX128: array_type = NPY_CFLOAT; break; case NIFTI_TYPE_COMPLEX256: array_type = NPY_CDOUBLE; break; default: PyErr_SetString(PyExc_RuntimeError, "Unsupported datatype"); return(NULL); } /* array object */ PyObject* volarray = 0; /* Get the number of dimensions from the niftifile and * reverse the order for the conversion to a numpy array. * Doing so will make users access to the data more convenient: * a 3d volume from a 4d file can be index by a single number. */ int ndims, k; /* Array dimensions need to be an integer type whose byte size matches * the pointer size on the compiled platform. This way the dimension * along that array axis is only limited by the available memory. * The Numpy C-API provides a type npy_intp for this purpose. * This is required by all PyArray_New* functions. */ npy_intp ar_dim[7]; /* first item in dim array stores the number of dims */ ndims = (int) _img->dim[0]; /* reverse the order */ for (k=0; kdim[ndims-k]; } /* create numpy array */ volarray = PyArray_SimpleNewFromData(ndims, ar_dim, array_type, _img->data); /* create deallocator */ PyObject* newobj=NULL; newobj = PyObject_New(_MyDeallocObject, &_MyDeallocType); /* assign the image data pointer */ ((_MyDeallocObject *)newobj)->memory = _img->data; /* let the deallocator manage the array memory management */ PyArray_BASE(volarray) = newobj; return PyArray_Return ( (PyArrayObject*) volarray ); } static void detachDataFromImage(nifti_image* _nim) { _nim->data = NULL; } int allocateImageMemory(nifti_image* _nim) { if (_nim == NULL) { fprintf(stderr, "NULL pointer passed to allocateImageMemory()"); return(0); } if (_nim->data != NULL) { fprintf( stderr, "There seems to be allocated memory already (valid nim->data pointer found)."); return(0); } /* allocate memory */ _nim->data = (void*) calloc(1,nifti_get_volsize(_nim)); if (_nim->data == NULL) { fprintf(stderr, "Failed to allocate %d bytes for image data\n", (int)nifti_get_volsize(_nim)); return(0); } return(1); } int xyzt2space(char val) { return XYZT_TO_SPACE(val); } int xyzt2time(char val) { return XYZT_TO_TIME(val); } char spacetime2xyzt(int sp, int t) { return SPACE_TIME_TO_XYZT(sp, t); } %} %init %{ import_array(); /* initialize the new Python type for memory deallocation */ _MyDeallocType.tp_new = PyType_GenericNew; if (PyType_Ready(&_MyDeallocType) < 0) return; %} %include "typemaps.i" /* Need to put before nifti1_io.h to overwrite function prototype with this * typemap. */ void nifti_mat44_to_quatern( mat44 R , float *OUTPUT, float *OUTPUT, float *OUTPUT, float *OUTPUT, float *OUTPUT, float *OUTPUT, float *OUTPUT, float *OUTPUT, float *OUTPUT, float *OUTPUT ); void nifti_mat44_to_orientation( mat44 R , int *OUTPUT, int *OUTPUT, int *OUTPUT ); %include znzlib.h %include nifti1.h %include nifti1_io.h static PyObject * wrapImageDataWithArray(nifti_image* _img); static void detachDataFromImage(nifti_image* _nim); int allocateImageMemory(nifti_image* _nim); static PyObject* mat442array(mat44 _mat); static void set_mat44(mat44* m, float a1, float a2, float a3, float a4, float b1, float b2, float b3, float b4, float c1, float c2, float c3, float c4, float d1, float d2, float d3, float d4 ); int xyzt2space(char val); int xyzt2time(char val); char spacetime2xyzt(int sp, int t); %include "cpointer.i" %pointer_functions(short, shortp); %pointer_functions(int, intp); %pointer_functions(unsigned int, uintp); %pointer_functions(float, floatp); %pointer_functions(double, doublep); %pointer_functions(char, charp); %include "carrays.i" %array_class(short, shortArray); %array_class(int, intArray); %array_class(unsigned int, uintArray); %array_class(float, floatArray); %array_class(double, doubleArray); %array_class(nifti1_extension, extensionArray); pynifti-0.20100607.1/nifti/utils.py0000664000175000017500000004312411414645202016350 0ustar michaelmichael#emacs: -*- mode: python-mode; py-indent-offset: 4; indent-tabs-mode: nil -*- #ex: set sts=4 ts=4 sw=4 et: ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ## # # See COPYING file distributed along with the PyNIfTI package for the # copyright and license terms. # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ## """Utility functions for PyNifti""" __docformat__ = 'restructuredtext' import numpy as N import nifti.clib as ncl # # type maps, codes and other NIfTI header stuff # filetypes = [ 'ANALYZE', 'NIFTI', 'NIFTI_PAIR', 'ANALYZE_GZ', 'NIFTI_GZ', 'NIFTI_PAIR_GZ' ] """Typecodes of all supported NIfTI image formats.""" N2nifti_dtype_map = { N.uint8: ncl.NIFTI_TYPE_UINT8, N.int8 : ncl.NIFTI_TYPE_INT8, N.uint16: ncl.NIFTI_TYPE_UINT16, N.int16 : ncl.NIFTI_TYPE_INT16, N.uint32: ncl.NIFTI_TYPE_UINT32, N.int32 : ncl.NIFTI_TYPE_INT32, N.uint64: ncl.NIFTI_TYPE_UINT64, N.int64 : ncl.NIFTI_TYPE_INT64, N.float32: ncl.NIFTI_TYPE_FLOAT32, N.float64: ncl.NIFTI_TYPE_FLOAT64, N.complex128: ncl.NIFTI_TYPE_COMPLEX128 } """Mapping of NumPy datatypes to NIfTI datatypes.""" nifti2numpy_dtype_map = \ { ncl.NIFTI_TYPE_UINT8: 'u1', ncl.NIFTI_TYPE_INT8: 'i1', ncl.NIFTI_TYPE_UINT16: 'u2', ncl.NIFTI_TYPE_INT16: 'i2', ncl.NIFTI_TYPE_UINT32: 'u4', ncl.NIFTI_TYPE_INT32: 'i4', ncl.NIFTI_TYPE_UINT64: 'u8', ncl.NIFTI_TYPE_INT64: 'i8', ncl.NIFTI_TYPE_FLOAT32: 'f4', ncl.NIFTI_TYPE_FLOAT64: 'f8', ncl.NIFTI_TYPE_COMPLEX128: 'c16' } """Mapping of NIfTI to NumPy datatypes (necessary for handling memory mapped array with proper byte-order handling.""" nifti_units_map = \ {"unknown": ncl.NIFTI_UNITS_UNKNOWN, "m": ncl.NIFTI_UNITS_METER, "mm": ncl.NIFTI_UNITS_MM, "um": ncl.NIFTI_UNITS_MICRON, "s": ncl.NIFTI_UNITS_SEC, "ms": ncl.NIFTI_UNITS_MSEC, "us": ncl.NIFTI_UNITS_USEC, "Hz": ncl.NIFTI_UNITS_HZ, "ppm": ncl.NIFTI_UNITS_PPM, "rad/s": ncl.NIFTI_UNITS_RADS, } # encode bits of NIfTI1 standard valid_xyz_unit_codes = range(8) valid_time_unit_codes = range(0, 64, 8) def Ndtype2niftidtype(array): """Return the NIfTI datatype id for a corresponding NumPy datatype. """ # get the real datatype from N type dictionary dtype = N.typeDict[str(array.dtype)] if not N2nifti_dtype_map.has_key(dtype): raise ValueError, "Unsupported datatype '%s'" % str(array.dtype) return N2nifti_dtype_map[dtype] nifti_xform_map = \ { 'unknown': ncl.NIFTI_XFORM_UNKNOWN, 'scanner': ncl.NIFTI_XFORM_SCANNER_ANAT, 'aligned': ncl.NIFTI_XFORM_ALIGNED_ANAT, 'talairach': ncl.NIFTI_XFORM_TALAIRACH, 'mni152': ncl.NIFTI_XFORM_MNI_152, } nifti_xform_inv_map = dict([(v, k) for k, v in nifti_xform_map.iteritems()]) # # utility functions # def time2vol( t, tr, lag=0.0, decimals=0 ): """ Translates a time 't' into a volume number. By default function returns the volume number that is closest in time. Volumes are assumed to be recorded exactly (and completely) after tr/2, e.g. if 'tr' is 2 secs the first volume is recorded at exactly one second. 't' might be a single value, a sequence or an array. The repetition 'tr' might be specified directly, but can also be a NiftiImage object. In the latter case the value of 'tr' is determined from the 'rtime' property of the NiftiImage object. 't' and 'tr' can be given in an arbitrary unit (but both have to be in the same unit). The 'lag' argument can be used to shift the times by constant offset. Please note that numpy.round() is used to round to interger value (rounds to even numbers). The 'decimals' argument will be passed to numpy.round(). """ # transform to numpy array for easy handling tmp = N.array(t) # Use rtime from tr if it exists. This will be true for NiftiImage objects. if hasattr(tr, 'rtime'): tr = tr.rtime vol = N.round( ( tmp + lag + tr/2 ) / tr, decimals ) return vol def applyFxToVolumes( ts, vols, fx, **kwargs ): """ Apply a function on selected volumes of a timeseries. 'ts' is a 4d timeseries. It can be a NiftiImage or a ndarray. In case of a ndarray one has to make sure that the time is on the first axis. 'ts' can actually be of any dimensionality, but datasets aka volumes are assumed to be along the first axis. 'vols' is either a sequence of sequences or a 2d array indicating which volumes fx should be applied to. Each row defines a set of volumes. 'fx' is a callable function to get an array of the selected volumes as argument. Additonal arguments may be specified as keyword arguments and are passed to 'fx'. The output will be a 4d array with one computed volume per row in the 'vols' array. """ # get data array from nifti image or assume data array is # already present if hasattr(ts, 'data') and isinstance(ts.data, N.ndarray): data = ts.data else: data = ts out = [] for vol in vols: out.append( fx( data[ N.array( vol ) ], **kwargs ) ) return N.array( out ) def getPeristimulusTimeseries( ts, onsetvols, nvols = 10, fx = N.mean ): """ Returns 4d array with peristimulus timeseries. :Parameters: ts: source 4d timeseries onsetvols: sequence of onsetvolumes to be averaged over nvols: length of the peristimulus timeseries in volumes (starting from onsetvol) fx: function to be applied to the list of corresponding volumes. Typically this will be mean(), so it is default, but it could also be var() or something different. The supplied function is to be able to handle an 'axis=0' argument similiar to NumPy's mean(), var(), ... """ selected = [ [ o + offset for o in onsetvols ] \ for offset in range( nvols ) ] if fx == tuple: return applyFxToVolumes( ts, selected, fx ) else: return applyFxToVolumes( ts, selected, fx, axis=0 ) # # little helpers # def nhdr2dict(nhdr, extensions=None): """Convert a NIfTI header struct into a python dictionary. While most elements of the header struct will be translated 1:1 some (e.g. sform matrix) are converted into more convenient datatypes (i.e. 4x4 matrix instead of 16 separate values). :Parameters: nhdr: nifti_1_header extensions: NiftiExtensions instance All extensions will be merged into the returned dictionary under the special `extensions` key. :Returns: dict """ h = {} # the following header elements are converted in a simple loop # as they do not need special handling auto_convert = [ 'session_error', 'extents', 'sizeof_hdr', 'slice_duration', 'slice_start', 'cal_max', 'intent_p1', 'intent_p2', 'intent_p3', 'intent_code', 'sform_code', 'cal_min', 'scl_slope', 'slice_code', 'bitpix', 'descrip', 'glmin', 'dim_info', 'glmax', 'data_type', 'aux_file', 'intent_name', 'vox_offset', 'db_name', 'scl_inter', 'magic', 'datatype', 'regular', 'slice_end', 'qform_code', 'toffset' ] # now just dump all attributes into a dict for attr in auto_convert: h[attr] = eval('nhdr.' + attr) # handle a few special cases # handle 'pixdim': carray -> list pixdim = ncl.floatArray_frompointer(nhdr.pixdim) h['pixdim'] = [ pixdim[i] for i in range(8) ] # handle dim: carray -> list dim = ncl.shortArray_frompointer(nhdr.dim) h['dim'] = [ dim[i] for i in range(8) ] # handle sform: carrays -> (4x4) ndarray srow_x = ncl.floatArray_frompointer( nhdr.srow_x ) srow_y = ncl.floatArray_frompointer( nhdr.srow_y ) srow_z = ncl.floatArray_frompointer( nhdr.srow_z ) h['sform'] = N.array( [ [ srow_x[i] for i in range(4) ], [ srow_y[i] for i in range(4) ], [ srow_z[i] for i in range(4) ], [ 0.0, 0.0, 0.0, 1.0 ] ] ) # handle qform stuff: 3 numbers -> list h['quatern'] = [ nhdr.quatern_b, nhdr.quatern_c, nhdr.quatern_d ] h['qoffset'] = [ nhdr.qoffset_x, nhdr.qoffset_y, nhdr.qoffset_z ] # some more postprocessing # expand units h['xyz_unit'] = ncl.xyzt2space(nhdr.xyzt_units) h['time_unit'] = ncl.xyzt2time(nhdr.xyzt_units) if not extensions: return h # # handle extensions # # simply store a tuple of code (i.e. extension type) and extension data h['extensions'] = [e for e in extensions.iteritems()] return h def updateNiftiHeaderFromDict(nhdr, hdrdict): """Update a NIfTI header struct with data from a dictionary. The supplied dictionary might contain additonal data elements that do not match any nifti header element. These are silently ignored. Several checks are performed to ensure validity of the resulting nifti header struct. If any check fails a ValueError exception will be thrown. However, some tests are still missing. :Parameters: nhdr: nifti_1_header To be updated NIfTI header struct (in-place update). hdrdict: dict Dictionary containing information intented to be merged into the NIfTI header struct. """ # this function is still incomplete. add more checks if hdrdict.has_key('data_type'): if len(hdrdict['data_type']) > 9: raise ValueError, \ "Nifti header property 'data_type' must not be longer " \ + "than 9 characters." nhdr.data_type = hdrdict['data_type'] if hdrdict.has_key('db_name'): if len(hdrdict['db_name']) > 79: raise ValueError, "Nifti header property 'db_name' must " \ + "not be longer than 17 characters." nhdr.db_name = hdrdict['db_name'] if hdrdict.has_key('extents'): nhdr.extents = hdrdict['extents'] if hdrdict.has_key('session_error'): nhdr.session_error = hdrdict['session_error'] if hdrdict.has_key('regular'): if len(hdrdict['regular']) > 1: raise ValueError, \ "Nifti header property 'regular' has to be a single " \ + "character." nhdr.regular = hdrdict['regular'] if hdrdict.has_key('dim_info'): if len(hdrdict['dim_info']) > 1: raise ValueError, \ "Nifti header property 'dim_info' has to be a " \ + "single character." nhdr.dim_info = hdrdict['dim_info'] if hdrdict.has_key('dim'): dim = ncl.shortArray_frompointer(nhdr.dim) for i in range(8): dim[i] = hdrdict['dim'][i] if hdrdict.has_key('intent_p1'): nhdr.intent_p1 = hdrdict['intent_p1'] if hdrdict.has_key('intent_p2'): nhdr.intent_p2 = hdrdict['intent_p2'] if hdrdict.has_key('intent_p3'): nhdr.intent_p3 = hdrdict['intent_p3'] if hdrdict.has_key('intent_code'): nhdr.intent_code = hdrdict['intent_code'] if hdrdict.has_key('datatype'): nhdr.datatype = hdrdict['datatype'] if hdrdict.has_key('bitpix'): nhdr.bitpix = hdrdict['bitpix'] if hdrdict.has_key('slice_start'): nhdr.slice_start = hdrdict['slice_start'] if hdrdict.has_key('pixdim'): pixdim = ncl.floatArray_frompointer(nhdr.pixdim) for i in range(8): pixdim[i] = hdrdict['pixdim'][i] if hdrdict.has_key('vox_offset'): nhdr.vox_offset = hdrdict['vox_offset'] if hdrdict.has_key('scl_slope'): nhdr.scl_slope = hdrdict['scl_slope'] if hdrdict.has_key('scl_inter'): nhdr.scl_inter = hdrdict['scl_inter'] if hdrdict.has_key('slice_end'): nhdr.slice_end = hdrdict['slice_end'] if hdrdict.has_key('slice_code'): nhdr.slice_code = hdrdict['slice_code'] if hdrdict.has_key('xyz_unit') \ or hdrdict.has_key('time_unit'): # precharge units from current header, in case only one of them is to be # updated tu = ncl.xyzt2space(nhdr.xyzt_units) su = ncl.xyzt2time(nhdr.xyzt_units) # overwrite unit if present if hdrdict.has_key('xyz_unit'): su = _checkUnit(hdrdict['xyz_unit'], valid_xyz_unit_codes) if hdrdict.has_key('time_unit'): tu = _checkUnit(hdrdict['time_unit'], valid_time_unit_codes) # compress both units into hdr format nhdr.xyzt_units = ncl.spacetime2xyzt(su, tu) if hdrdict.has_key('cal_max'): nhdr.cal_max = hdrdict['cal_max'] if hdrdict.has_key('cal_min'): nhdr.cal_min = hdrdict['cal_min'] if hdrdict.has_key('slice_duration'): nhdr.slice_duration = hdrdict['slice_duration'] if hdrdict.has_key('toffset'): nhdr.toffset = hdrdict['toffset'] if hdrdict.has_key('glmax'): nhdr.glmax = hdrdict['glmax'] if hdrdict.has_key('glmin'): nhdr.glmin = hdrdict['glmin'] if hdrdict.has_key('descrip'): if len(hdrdict['descrip']) > 79: raise ValueError, \ "Nifti header property 'descrip' must not be longer " \ + "than 79 characters." nhdr.descrip = hdrdict['descrip'] if hdrdict.has_key('aux_file'): if len(hdrdict['aux_file']) > 23: raise ValueError, \ "Nifti header property 'aux_file' must not be longer " \ + "than 23 characters." nhdr.aux_file = hdrdict['aux_file'] if hdrdict.has_key('qform_code'): nhdr.qform_code = hdrdict['qform_code'] if hdrdict.has_key('sform_code'): nhdr.sform_code = hdrdict['sform_code'] if hdrdict.has_key('quatern'): if not len(hdrdict['quatern']) == 3: raise ValueError, \ "Nifti header property 'quatern' must be float 3-tuple." nhdr.quatern_b = hdrdict['quatern'][0] nhdr.quatern_c = hdrdict['quatern'][1] nhdr.quatern_d = hdrdict['quatern'][2] if hdrdict.has_key('qoffset'): if not len(hdrdict['qoffset']) == 3: raise ValueError, \ "Nifti header property 'qoffset' must be float 3-tuple." nhdr.qoffset_x = hdrdict['qoffset'][0] nhdr.qoffset_y = hdrdict['qoffset'][1] nhdr.qoffset_z = hdrdict['qoffset'][2] if hdrdict.has_key('sform'): if not hdrdict['sform'].shape == (4, 4): raise ValueError, \ "Nifti header property 'sform' must be 4x4 matrix." srow_x = ncl.floatArray_frompointer(nhdr.srow_x) for i in range(4): srow_x[i] = hdrdict['sform'][0][i] srow_y = ncl.floatArray_frompointer(nhdr.srow_y) for i in range(4): srow_y[i] = hdrdict['sform'][1][i] srow_z = ncl.floatArray_frompointer(nhdr.srow_z) for i in range(4): srow_z[i] = hdrdict['sform'][2][i] if hdrdict.has_key('intent_name'): if len(hdrdict['intent_name']) > 15: raise ValueError, \ "Nifti header property 'intent_name' must not be " \ + "longer than 15 characters." nhdr.intent_name = hdrdict['intent_name'] if hdrdict.has_key('magic'): if hdrdict['magic'] != 'ni1' and hdrdict['magic'] != 'n+1': raise ValueError, \ "Nifti header property 'magic' must be 'ni1' or 'n+1'." nhdr.magic = hdrdict['magic'] def splitFilename(filename): """Split a NIfTI filename into basename and extension. :Parameters: filename: str Filename to be split. :Returns: tuple: (basename, extension) The function returns a tuple of basename and extension. If no valid NIfTI filename extension is found, the whole string is returned as basename and the extension string will be empty. """ parts = filename.split('.') if parts[-1] == 'gz': if not parts[-2] in [ 'nii', 'hdr', 'img' ]: return filename, '' else: return '.'.join(parts[:-2]), '.'.join(parts[-2:]) else: if not parts[-1] in [ 'nii', 'hdr', 'img' ]: return filename, '' else: return '.'.join(parts[:-1]), parts[-1] def _checkUnit(value, valid_codes): """Internal helper function to check axis units and convert into codes. :Parameter: value: int | str valid_codes: list :Returns: int .. warning:: This is an internal method. Neither its availability nor its API is guarenteed. """ # is it a code? if isinstance(value, int): if value not in valid_codes: raise ValueError, \ "'%i' is not a valid NIfTI units code. Should be one of" \ " %s." % (value, str([c for c in nifti_units_map.values() if c in valid_codes])) # value seems to be valid return value # must be plain unit then else: if value not in nifti_units_map.keys() \ or nifti_units_map[value] not in valid_codes: raise ValueError, \ "'%s' is not a valid NIfTI unit. Should be one of" \ " %s." % (value, str([c for c in nifti_units_map.keys() if nifti_units_map[c] in valid_codes])) # value seems to be valid return nifti_units_map[value] pynifti-0.20100607.1/nifti/nifticlib.py0000664000175000017500000000117111414645202017147 0ustar michaelmichael#emacs: -*- mode: python-mode; py-indent-offset: 4; indent-tabs-mode: nil -*- #ex: set sts=4 ts=4 sw=4 et: ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ## # # See COPYING file distributed along with the PyNIfTI package for the # copyright and license terms. # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ## """Only here for backward compatibility.""" __docformat__ = 'restructuredtext' from warnings import warn warn("This module has been renamed to 'nifti.clib'. This redirect will be removed with PyNIfTI 1.0.", DeprecationWarning) from nifti.image import * pynifti-0.20100607.1/MANIFEST.in0000664000175000017500000000030511414645202015255 0ustar michaelmichaelinclude AUTHOR COPYING Makefile* MANIFEST.in setup* include Changelog TODO recursive-include doc * recursive-include man * recursive-include 3rd * recursive-include bin * recursive-include tests * pynifti-0.20100607.1/PKG-INFO0000664000175000017500000000126211414646040014620 0ustar michaelmichaelMetadata-Version: 1.0 Name: pynifti Version: 0.20100607.1 Summary: Python interface for the NIfTI IO libraries Home-page: http://niftilib.sf.net/pynifti Author: Michael Hanke Author-email: michael.hanke@gmail.com License: MIT License Description: PyNIfTI aims to provide easy access to NIfTI images from within Python. It uses SWIG-generated wrappers for the NIfTI reference library and provides the NiftiImage class for Python-style access to the image data. While PyNIfTI is not yet complete (i.e. doesn't support everything the C library can do), it already provides access to the most important features of the NIfTI-1 data format and libniftiio capabilities. Platform: UNKNOWN pynifti-0.20100607.1/man/0000775000175000017500000000000011414646040014275 5ustar michaelmichaelpynifti-0.20100607.1/man/pynifti_pst.10000664000175000017500000000674111414646037016745 0ustar michaelmichael.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.38.2. .TH PYNIFTI_PST "1" "July 2010" "pynifti_pst 0.20100607.1" "User Commands" .SH NAME pynifti_pst \- compute peristimulus timeseries of fMRI data .SH SYNOPSIS .B pynifti_pst [\fIoptions\fR] \fI<4dimage> \fR[...] .SH DESCRIPTION pynifti_pst computes the peristimulus signal timecourse for all voxels in a volume at once. Stimulus onsets can be specified as volume numbers or times (will be converted into volume numbers using a supplied repetition time). Onsets can be specified directly on the command line, but can also be read from (multiple) files. Such file are assumed to list one onset per line (as the first value). Empty lines are ignored. This enables pynifti_pst to use e.g. FSL's custom EV files. If several files are specified, the read onsets are combined to a single onset vector. pynifti_pst writes a 4d timeseries image as output. This image can e.g. be loaded into FSLView to look at each voxels signal timecourse in a certain condition by simply clicking on it. .SH OPTIONS .TP \fB\-\-version\fR show program's version number and exit .TP \fB\-h\fR, \fB\-\-help\fR show this help message and exit .TP \fB\-\-verbose\fR print status messages .TP \fB\-n\fR NVOLS, \fB\-\-nvols\fR=\fINVOLS\fR Set the length of the computed peristimulus signal timecourse (in volumes). Default: 10 .TP \fB\-t\fR, \fB\-\-times\fR If supplied, the read values are treated as onset times and will be converted to volume numbers. For each onset the volume that is closest in time will be selected. Volumes are assumed to be recorded exactly (and completely) after tr/2, e.g. if 'tr' is 2 secs the first volume is recorded at exactly one second. Please see the \fB\-\-tr\fR and \fB\-\-offset\fR options to learn how to adjust the conversion. .TP \fB\-\-tr\fR=\fITR\fR Repetition time of the 4d image (temporal difference of two successive volumes). This can be used to override the setting in the 4d image. The repetition time is necessary to convert onset times into volume numbers. If the '\-\-times' option is not set this value has no effect. Please note that repetitions time and the supplied onsets have to be in the same unit. Please note, that if \fB\-\-times\fR is given the tr has to be specified in the same unit as the read onset times. .TP \fB\-\-offset\fR=\fIOFFSET\fR Constant offset applied to the onsets times when converting them to volume numbers. Without setting '\-\- times' this option has no effect'. .TP \fB\-p\fR, \fB\-\-percsigchg\fR Convert the computed timecourse to percent signal change relative to the first (onset) volume. This might not be meaningful when \fB\-\-operation\fR is set to something different than 'mean'. Please note, that the shape of the computes timeseries heavily depends on the first average volume. It might be more meaningful to use a real baseline condition as origin. However, this is not supported yet. Default: False .TP \fB\-\-printvoxel\fR=\fIPRINTVOXEL\fR Print the peristimulus timeseries of a single voxel for all onsets separately. This will print a matrix (onsets x time), where the number of columns is identical to the value of \fB\-\-nvols\fR and the number of rows corresponds to the number of specified onsets. (e.g. 'z,y,x') .TP \fB\-\-operation\fR=\fIOPERATION\fR Choose the math operation that is performed to compute the peristimulus timeseries. By default this is the mean across all stimulations ('mean'). Other possibilities are the standard deviation ('std') and standard error ('sde'). pynifti-0.20100607.1/doc/0000775000175000017500000000000011414646040014267 5ustar michaelmichaelpynifti-0.20100607.1/doc/Makefile0000664000175000017500000000462711414645202015737 0ustar michaelmichael# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = # Internal variables. BUILDROOT = ../build PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDROOT)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html web pickle htmlhelp latex changes linkcheck help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " pickle to make pickle files (usable by e.g. sphinx-web)" @echo " htmlhelp to make HTML files and a HTML help project" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " changes to make an overview over all changed/added/deprecated items" @echo " linkcheck to check all external links for integrity" clean: -rm -rf $(BUILDROOT)/* html: mkdir -p $(BUILDROOT)/html $(BUILDROOT)/doctrees $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDROOT)/html @echo @echo "Build finished. The HTML pages are in $(BUILDROOT)/html." pickle: mkdir -p $(BUILDROOT)/pickle $(BUILDROOT)/doctrees $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDROOT)/pickle @echo @echo "Build finished; now you can process the pickle files or run" @echo " sphinx-web $(BUILDROOT)/pickle" @echo "to start the sphinx-web server." web: pickle htmlhelp: mkdir -p $(BUILDROOT)/htmlhelp $(BUILDROOT)/doctrees $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDROOT)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDROOT)/htmlhelp." latex: mkdir -p $(BUILDROOT)/latex $(BUILDROOT)/doctrees $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDROOT)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDROOT)/latex." @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \ "run these through (pdf)latex." changes: mkdir -p $(BUILDROOT)/changes $(BUILDROOT)/doctrees $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDROOT)/changes @echo @echo "The overview file is in $(BUILDROOT)/changes." linkcheck: mkdir -p $(BUILDROOT)/linkcheck $(BUILDROOT)/doctrees $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDROOT)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDROOT)/linkcheck/output.txt." pynifti-0.20100607.1/doc/contents.txt0000664000175000017500000000026711414645202016671 0ustar michaelmichael.. _contents: ***************************** PyMVPA Documentation Contents ***************************** .. toctree:: intro installation examples modref legal changelog pynifti-0.20100607.1/doc/legal.txt0000777000175000017500000000000011414645202017354 2../COPYINGustar michaelmichaelpynifti-0.20100607.1/doc/_templates/0000775000175000017500000000000011414646040016424 5ustar michaelmichaelpynifti-0.20100607.1/doc/_templates/layout.html0000664000175000017500000000131611414645202020627 0ustar michaelmichael{% extends "!layout.html" %} {% block extrahead %} {% endblock %} {% block rootrellink %}
  • NIfTI Libraries
  • PyNIfTI Home
  • Documentation »
  • {% endblock %} {% block relbar1 %} {{ super() }} {% endblock %} {% block sidebar1 %}{{ sidebar() }}{% endblock %} {% block sidebar2 %}{% endblock %} pynifti-0.20100607.1/doc/_templates/indexsidebar.html0000664000175000017500000000157311414645202021760 0ustar michaelmichael

    Quick links

    Search mailing list archive

    pynifti-0.20100607.1/doc/manual.txt0000664000175000017500000000115611414645202016307 0ustar michaelmichael.. -*- mode: rst; fill-column: 78 -*- .. ex: set sts=4 ts=4 sw=4 et tw=79: ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### # # See COPYING file distributed along with the PyMVPA package for the # copyright and license terms. # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ********************************** PDF version of the PyNIfTI Manual ********************************** The PDF version of the manual is available for download_. .. _download: PyNIfTI-Manual.pdf .. toctree:: intro installation examples modref changelog pynifti-0.20100607.1/doc/conf.py0000664000175000017500000002720611414645202015574 0ustar michaelmichael# -*- coding: utf-8 -*- # # PyNIfTI documentation build configuration file, created by # sphinx-quickstart on Sun May 4 09:06:06 2008. # # This file is execfile()d with the current directory set to its containing dir. # # The contents of this file are pickled, so don't put values in the namespace # that aren't pickleable (module imports are okay, they're removed automatically). # # All configuration values have a default value; values that are commented out # serve to show the default value. import sys, os, re import numpy as N # also import pynifti itself to get the version string import nifti try: import matplotlib matplotlib.use('svg') except: pass ################################################## # Config settings are at the bottom of the file! # ################################################## # If your extensions are in another directory, add it here. If the directory # is relative to the documentation root, use os.path.abspath to make it # absolute, like shown here. #sys.path.append(os.path.abspath('some/directory')) def extractItemListBlock(blocktypes, lines): """Extract a number of lines belonging to an indented block. The block is defined by a minimum indentation level, in turn defined by a line starting with any string given by the 'blocktypes' sequence. It returns the lines matching the block and the start and endline index wrt the original line sequence. WARNING: It may explode if there is more than one block with the same identifier. """ param = None in_block = False indent = None start_line = None end_line = None for i, line in enumerate(lines): # ignore empty lines if line.isspace() or not len(line.strip()): continue # strip leading whitespace sline = line.lstrip() # look for block start if N.any([sline.startswith(bt) for bt in blocktypes]): in_block = True indent = len(line) - len(sline) start_line = i continue # check if end is reached if in_block and len(line) - len(sline) <= indent: end_line = i return param, start_line, end_line # store param block line if in_block: if not param: param = [] param.append(line) # when nothing follows param block if start_line: end_line = len(lines) - 1 return param, start_line, end_line def smoothName(s): """Handle all kinds of voodoo cases, that might disturb RsT """ s = s.strip() s = re.sub('\*', '\*', s) return s def segmentItemList(lines, name): """Parse the lines of a block into segment items of the format used in PyMVPA:: name[: type] (multiline) description """ # assumes no empty lines left! items = [] last_item = None # determine indentation level indent = len(lines[0]) - len(lines[0].lstrip()) for line in lines: # if top level indent, we have a parameter def if indent == len(line) - len(line.lstrip()): # rescue previous one if last_item is not None: items.append(last_item) last_item = None last_item = {'name': None, 'type': None, 'descr': []} # try splitting param def l = line.split(':') if len(l) >= 2: last_item['name'] = smoothName(l[0]) last_item['type'] = u':'.join(l[1:]).strip() elif len(l) == 1: last_item['name'] = smoothName(line) else: print line raise RuntimeError, \ 'Should not have happend, inspect %s' % name else: # it must belong to last_item and be its description if last_item is None: print line raise ValueError, \ 'Parameter description, without parameter in %s' % name last_item['descr'].append(line.strip()) if last_item is not None: items.append(last_item) return items def reformatParameterBlock(lines, name): """Format a proper parameters block from the lines of a docstring version of this block. """ params = segmentItemList(lines, name) out = [] # collection is done, now pretty print for p in params: out.append(':param ' + p['name'] + ': ') if len(p['descr']): # append first description line to previous one out[-1] += p['descr'][0] for l in p['descr'][1:]: out.append(' ' + l) if p['type']: out.append(':type ' + p['name'] + ': ' + p['type']) # safety line out.append(u'') return out def reformatReturnsBlock(lines, name): """Format a proper returns block from the lines of a docstring version of this block. """ ret = segmentItemList(lines, name) if not len(ret) == 1: raise ValueError, \ '%s docstring specifies more than one return value' % name ret = ret[0] out = [] out.append(':rtype: ' + ret['name']) if len(ret['descr']): out.append(':returns:') for l in ret['descr']: out.append(' ' + l) # safety line out.append(u'') return out def reformatExampleBlock(lines, name): """Turn an example block into a verbatim text. """ out = [u'::', u''] out += lines # safety line out.append(u'') return out # demo function to access docstrings for processing def dumpit(app, what, name, obj, options, lines): """ For each docstring this function is called with the following set of arguments: app the Sphinx application object what the type of the object which the docstring belongs to (one of "module", "class", "exception", "function", "method", "attribute") name the fully qualified name of the object obj the object itself options the options given to the directive: an object with attributes inherited_members, undoc_members, show_inheritance and noindex that are true if the flag option of same name was given to the auto directive lines the lines of the docstring (as a list) """ param, pstart, pend = extractItemListBlock([':Parameters:', ':Parameter:'], lines) if param: # make it beautiful param = reformatParameterBlock(param, name) # replace old block with new one lines[pstart:pend] = param returns, rstart, rend = extractItemListBlock([':Returns:'], lines) if returns: returns = reformatReturnsBlock(returns, name) lines[rstart:rend] = returns examples, exstart, exend = extractItemListBlock([':Examples:', ':Example:'], lines) if examples: print 'WARNING: Example in %s should become a proper snippet' % name examples = reformatExampleBlock(examples, name) lines[exstart:exend] = examples # kill things that sphinx does not know ls, lstart, lend = extractItemListBlock(['.. packagetree::'], lines) if ls: del(lines[lstart:lend]) # add empty line at begining of class docs to separate base class list from # class docs (should actually be done by sphinx IMHO) if what == 'class': lines.insert(0, u'') # make this file a sphinx extension itself, to be able to do docstring # post-processing def setup(app): app.connect('autodoc-process-docstring', dumpit) # General configuration # --------------------- # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = ['sphinx.ext.autodoc'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.txt' # The master toctree document. master_doc = 'contents' # General substitutions. project = 'PyNIfTI' copyright = '2006-2009, Michael Hanke' # The default replacements for |version| and |release|, also used in various # other places throughout the built documents. # # The short X.Y version. version = nifti.__version__ # The full version, including alpha/beta/rc tags. release = nifti.__version__ # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. today_fmt = '%B %d, %Y' # List of documents that shouldn't be included in the build. unused_docs = [] # what to put into API doc (just class doc, just init, or both autoclass_content = 'both' # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # Options for HTML output # ----------------------- # The style sheet to use for HTML and HTML Help pages. A file of that name # must exist either in Sphinx' static/ path, or in one of the custom paths # given in html_static_path. html_style = 'pynifti.css' # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". html_title = 'Home' # The name of an image file (within the static path) to place at the top of # the sidebar. #html_logo = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. html_sidebars = {'index': 'indexsidebar.html'} # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {'index': 'index.html'} # If false, no module index is generated. html_use_modindex = False # If true, the reST sources are included in the HTML build as _sources/. #html_copy_source = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. #html_use_opensearch = False # Output file base name for HTML help builder. htmlhelp_basename = 'PyNIfTIdoc' # Options for LaTeX output # ------------------------ # The paper size ('letter' or 'a4'). latex_paper_size = 'a4' # The font size ('10pt', '11pt' or '12pt'). latex_font_size = '10pt' # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, document class [howto/manual]). latex_documents = [ ('manual', 'PyNIfTI-Manual.tex', 'PyNIfTI Manual', 'Michael~Hanke', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = os.path.join('_static', 'logo.pdf') # Additional stuff for the LaTeX preamble. latex_preamble = """ \usepackage{enumitem} \setdescription{style=nextline,font=\\normalfont} """ # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. latex_use_modindex = True pynifti-0.20100607.1/doc/index.txt0000664000175000017500000001330411414645202016137 0ustar michaelmichael.. -*- mode: rst -*- .. ex: set sts=4 ts=4 sw=4 et tw=79: ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### # # See COPYING file distributed along with the PyNIfTI package for the # copyright and license terms. # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### The PyNIfTI module is a Python_ interface to the `NIfTI I/O libraries`_. Using PyNIfTI, one can easily read and write NIfTI and ANALYZE images from within Python. The :class:`~nifti.image.NiftiImage` class provides pythonic access to the full header information and for a maximum of interoperability the image data is made available via NumPy_ arrays. .. _Python: http://www.python.org .. _NIfTI I/O libraries: http://niftilib.sf.net .. _NumPy: http://numpy.scipy.org Documentation ============= * :ref:`User Documentation ` (**the** documentation) * :ref:`Installation Instructions ` * :ref:`Development Changelog ` (see what has changed) * :ref:`Module Reference ` (user-oriented reference, less complex than full API docs) * :ref:`genindex` (access by keywords) * :ref:`search` (online and offline full-text search) Author and License ================== PyNIfTI is written and maintained by `Michael Hanke`_. The author is grateful to the following people who have contributed to PyNIfTI (in order of appearance): * `Yaroslav O. Halchenko`_ * Chris Burns * `Gaël Varoquaux`_ .. _Michael Hanke: http://apsy.gse.uni-magdeburg.de/hanke .. _Yaroslav O. Halchenko: http://www.onerussian.com .. _Gaël Varoquaux: http://gael-varoquaux.info/ PyNIfTI is free-software (beer and speech) and covered by the `MIT License`_. This applies to all source code, documentation, examples and snippets inside the source distribution (including this website). Please see the :ref:`appendix of the manual ` for the copyright statement and the full text of the license. .. _MIT License: http://www.opensource.org/licenses/mit-license.php Download ======== Binary packages --------------- Binary packages are available for: * Debian and Ubuntu (:ref:`installation instructions `) PyMVPA is an `official Debian package`_ (`python-nifti`). Additionally, backports for some Debian and Ubuntu releases are also available. Please read the `package repository instructions`_ to learn about how to obtain them. * RPM-based GNU/Linux distributions (:ref:`installation instructions `) RPM packages are provided through the `OpenSUSE Build Service`_. The currently supported distributions include: CentOS 5, Fedora 9-10, Mandriva 2007-2008, RedHat Enterprise Linux 5, SUSE Linux Enterprise 10, OpenSUSE 10.2 up to 11.0. The build service supports RPM-package repositories (`Suse and Mandriva-related`_ and `Fedora, Redhat and CentOS-related`_) and `1-click-installations`_. * MacOS X (:ref:`installation instructions `) PyNIfTI is available from the MacPorts_ framework. * Windows (:ref:`installation instructions `) An installer for Python 2.5 is available from the `download area`_. If there are no binary packages for your particular operating system or platform, you need to compile your own. The manual contains :ref:`instructions ` to build PyNIfTI in various environments. .. _MacPorts: http://www.macports.org .. _official Debian package: http://packages.debian.org/python-nifti .. _package repository instructions: http://apsy.gse.uni-magdeburg.de/main/index.psp?sec=1&page=hanke/debian&lang=en .. _Suse and Mandriva-related: http://download.opensuse.org/repositories/home:/hankem/ .. _Fedora, Redhat and CentOS-related: http://download.opensuse.org/repositories/home://hankem://rh5/ .. _1-click-installations: http://software.opensuse.org/search?baseproject=ALL&p=1&q=python-nifti .. _OpenSUSE Build Service: https://build.opensuse.org/ Source code ----------- Source code tarballs of PyNIfTI releases are available from the `download area`_. Alternatively, one can also download a tarball of the latest development snapshot_ (i.e. the current state of the *master* branch of the PyNIfTI source code repository). To get access to both the full PyNIfTI history and the latest development code, the PyNIfTI Git_ repository is publicly available. To view the repository, please point your webbrowser to gitweb: http://git.debian.org/?p=pkg-exppsy/pynifti.git To clone (aka checkout) the PyNIfTI repository simply do: :: git clone git://git.debian.org/git/pkg-exppsy/pynifti.git After a short while you will have a `pynifti` directory below your current working directory, that contains the PyNIfTI repository. More detailed instructions on :ref:`installation requirements ` and on how to :ref:`build PyNIfTI from source ` are provided in the manual. .. _download area: http://alioth.debian.org/frs/?group_id=30954 .. _Git: http://git.or.cz/ .. _snapshot: http://git.debian.org/?p=pkg-exppsy/pynifti.git;a=snapshot;h=refs/heads/master;sf=tgz Support ======= If you have problems installing the software or questions about usage, documentation or something else related to PyNIfTI, you can post to the PyNIfTI mailing list. :Mailing list: pkg-exppsy-pynifti@lists.alioth.debian.org [subscription_, archive_] It is recommended that all users subscribe to the mailing list. The mailing list is the preferred way to announce changes and additions to the project. The mailing list archive can also be searched using the *mailing list archive search* located in the sidebar of the PyNIfTI home page. .. _subscription: http://lists.alioth.debian.org/mailman/listinfo/pkg-exppsy-pynifti .. _archive: http://lists.alioth.debian.org/pipermail/pkg-exppsy-pynifti/ pynifti-0.20100607.1/doc/pics/0000775000175000017500000000000011414646040015225 5ustar michaelmichaelpynifti-0.20100607.1/doc/pics/gnuplot_ts.png0000644000175000017500000002713211131415721020130 0ustar michaelmichaelPNG  IHDRܻK IDATxY-P 3}_UJ6hp֊gU$~m@Ж u]wD:m{9hBf{0Dz{}ʨZ<0'K8E "e݋p tAzPI'?zSI'C?yжmy90OM>O_}w?@| m~~1g۶>Qj HF@ @2"dD$# HF@ @2"dD$# HF@ @2"dD$# HF@ @2"dD$# HF@ @2"dD$# HF@ @2"dD$# HF@ @2"dDP׺> @2"dDP׺>@2"dD0 `/@2"X<@."dD$# ~_{Q} >loqxhBBo!}y#Dzqyo?-ur{(`Y+󓀈00'8bᄇ'~DlZv`Y˂ф߇:{? {!XuV m3>A@ m~~hx@2"dD$# ~Zއ-1_|o[fD*]2DyU@"dD3{5@2"dD0)1A@ @2"{:r:G$# ȓ@M"`(TD0!LA@n<`69? ܍0?@2"dD$# HF@D$# HF@׺>{یY4% J`0HD!®)КMTD:*26u> hd Ӳ ULP y%) aȧ 0Џ6>K@,6GH[6$ 8024@e_l~'%#PAF̚J@ͼ^֦/p 2)rs"(f$@<^ pqe[d;_d\! JlKnu]E@X@`Pp8ρ="', ;ҀD[_\sxb lD*m_} a^71 ›߇A>llHrMYssFȻ jCou>i$7RmC/ݮ )Z`|ru'whlXC[kY1pQ~PΌoS| ЫW\3^`V7}H@$Bh`/Wy2r5Y79LƘ 6;.!YVp,w39_q.p1if5&fVXhŘevy1|ŌPF8F~+u݌=ЇC90+uQ׈7QژpwF0"@Gg7?mpH;F^)@Y"hsjSw<6c% `Eό1fFogw(% H"ȋFqDIcq=51ע,7A<cTBO_ڛ-|JҶ ڼ~e n>M&`5)1N6]\cL?S"=T}w$@S\(}}1 m޻aYk&3_c d1 8g:㲱 `cci/ǧ6{f>G;Y}a뜹|\# "HH,8@;"`Om3D@q'zfS2gd{k ^Um8&E g }|"^ӈʀR8DB/:K]Ԫt5!OmgȵD9f'"Vܰ@f"`?αv`}!jVYaF R -.dTsu.׿wgpݧK07W@.;fc557)f4%^` [o"2(0Qes#JyNMѯp@,d\! ` ,uX1}*.QƬ(u >p -$3DwD D=.pἙLQhW.n!# 2`ӓIw^=ps2KY2(x>2 罚|IB0G@+yʎFgdf2jF=7D?nZ9 fE=yʎ{APc>m^_ڴ.w/T^1O q D6 Y1=d}>ʠ܎1()Sof|rDLi ÈEɲ+;m28e1m pF!n|}D.@k1_x CfC۞=F<4(jԿދ?C[y6qzq33ec;Qp =xN)S}QsЬsRP% "{R2n0~OpPI[Azm>X?c31\|G\&'173E2QpaSq,>$P[ܗK=1o|g6Z}2xggV D' bu]rg9=5(s,&u{ Ync#z, x/z{/ڢϏpnWOML8mۯ߶ǯO6? =e^cp/'7J[OR Ʀ$gyЊhB{B4Efe_Q:÷Ɓe~5ڰq\2r"Wc% г<{Ƥw-ͰN\M}hI9Q;ȣVq-Dsԣ1([Woݞjg<~'&5ԧ.WD>k]مfLәs Q2Z|^{k p? x{2uFrK˸6Cv=PwPPKcnYrlkf'>m۲<~W=Jg6, |m&)#L8^1cӷp:Ĉܜwm!dwSD?y[W՟ hsf1Yy{(azDYKW Ǟzګ'0ф}wϳ^}shw.=61|Ү(I:f(2q:M쌽==:[[?e; z:cԡGƶMA}~[~5k>_﵈jƐu.^QrM|fnB$8ckʥe^׻)e}Dpw>(m}YEy=5G6 &8Ks?۳a1󝊣ƪ.?( {ͬ|jbL-C?3羇yMtgЗ`ĮdF}qb9{ E//50DLe;J'$nD;9F{&<&keχv/Pz|=@f"`*G'ݽ #qhuܤ4WulQe9X0joqQNI#caYzV g&mf_h]UYyd#i3`?D0jnϴȘ<*Q5j>5oG˥S%fZSQƑ:o#k4913]ե#UzSg=V\7f2b`|ݘ]G6u"R\OX\J׉ P-ؼG>S,ߑH5G}-FjW\--Z(izxn3_G5Uxhf^<Lun>(+rPfߡOF; kC+Եgbaz Q|~*{f-%]g|:+jYқ D2k_uh},Qe.ۨm!q~x~ʊ SJ- ],FQc2&"[gѿ<-D=Djg޿fH &3uLu(Ҫ>.?^97i,l.LqlsLuiKЎ&e0L̴}dӲ/}E:V}Gs:2"cͨ (%j0]e2gjmj1$(rFmK{bڷfrYn.XaFL@A *ϙ8t9chh3mks)u=lW#} } s1 +xlFg>19] qeLn2z3kΣֹe' Le79dS;Sb+>)1.iGIQ]6Wf /b.ҵrգEKXԉz^m=|y裙Y5p:5/YOY7f @[ Ѩd bh-7lz F8usMVZՑ$cݧim2UȲcs1Q:L΅cǽ׋C|^G>vx&K6'K}Xs$wD2MZ29 (u:gz\E)=ǡoz{ݯ N@FذydrA&hOyi{.wĶ:(F9shsLm>tH@2𼚨Dyҟ@YsŨsю[;-ORh} ׹azEN>MPL`(e64 KOp~@3[<:Sy0\`hCqB] ! 2BF n>+'rY|k2+?u?+IDATKOs` DL8F#30ؖj3Fuq8 M@F݀UL4ڹXx%Q_\˞f)F@R9Q;qզIo)YFWƑv^r%Ϩ7e@/")‚1WKZX|f6S:PL}ɲ=#S]>VG&Rk6z%uLW92Wv]w%wUgyN7[v>pO8kA'˹ q/j @TȤK_[4 `X&7PGXE9㱗>)u7uZ-tc`.x.yG>7fZ=zcD{ay-dbQcrziԷz$)l}F`LI>uĒMf3b-֓Zհ][TOb~=h'LjM>se8KH9QWa,}>D h.#aru,Z I@ [TDܔ.ڵd>%g7edgC'c0 M׍Z~/e/ǐul5R,+ǽω9GF]xp9!' bx&G|-#~#'f~o(@9TO{)GYOB'PW)m|!O@bo"ll@1>5Sߪ66DF G>v˴>}P~<}+Rrm`՘1!&#QB@@@uGxu(cZeogOu9"H7k{9В]n60{oNa}22uspK@5ԗ>d8G)+f$ *W2WSSvh0(OʲsOD=.C@O0"X" (Ldu ^26 g"`6f%xDf0?[r%@ " -'67}#WCyGީ$b*6τE~M:7" }cl % (h4cD.R) #MYsVFtwv /m0 \>$MQ6/%,D@5&yeϜ(׃d^>Њbj,h˚MUh)9CY { slg3/|E@|\Ss< XԣlD\psc{־d پ-0&muE"dD,xWX@"hi%ڹWDp;jk8B@}h{h[˜ hʆNl@"BgG@"8F5o!E]ʗ}o򵮽D0W6 @bu #$# RJ 355^WC)T%  ~Dp.{pЗ \GƜ)Y $# HF@ 侷!L,C f' %f' HF@|o򵮽D|G,@=" ,!@"eL@*"% E6F# ]D{׺zU*@b"Bl@2nj@@@n"dD$# R޶k]{@S"dDm`7E!`4"dD\D$# HF@ >D$# H濽zu]'_u]?{w>VizPI'?zSI'MYs|۶cs_u` ^17=OC@4O*xoz*QғGO=ћ:HO=ПeY_A0!A_̫_;mze= v_!g{տ' H+$# HF@ @2"dDkC u]z{у?z8ZEJ{i]QMGO>"BYuٶmG_zvu_^Au?jѓGGꜺY6p'o?aܲ,7Llz]w X<' ҲHKM҃zGob=W)i] zF@D J{U~I1m__^?zRhhS)zGH?۶A1lPD@@ " iQ2 oϩh:_ζݘ{Q]̊!!يl R v$sĤи|Aw Hv$mCB2?>|2"YIN٭y@ܴu8aj{d >vy,Էx1H: A7Sa֋3ě,& Z6P rҍ?^[-nUQ!hEq ]ScEc@ҏ̋ cJ)Pѩ-':A&Dz7>~`_U9T+ ˄*AWPdTEA@u#QhQ҃*(rF JD$=":.7or8&SePA ?Ê('tV:벵!zf:џ%F%!#J\uVGXU%UQRD b "-}qqxUm,N##ƜE" F#gq6%ކ";g9Rēe:/ GxA͡'D SZkhhhhh|H2bF|&)S~=ׯgllf:| ag}0A;?@m}GO49<<uOAv}{ECAj Ӧ ٽhhhhhh$x,/yfzرg/} ;\lj}{~1Ga\x^37d%m}$͟<4S@ r&E>`˖Z,ʛ$9l4زy/Ju]JZGmSϡϝwm".pB zռ̚,~lbONvL0+V2#Xs |3hs'hw8Ŋ|e8+M0%O#ɬ'_CKgC~Rf_OsKx#XPt{;UO| Wulۊkti9i5ICCCC`Bי-r0 جl̻dQ!9䜷o"m\Rґ&-ld6a3&\d~MO5+>O` hr.EY6f;J؊˩6oI#=:1XkUbOp$HtrQŲʹxG6(S;qE mKg𥥱p===sfoxjkk'}M7~_̻0w.^G:wzz:7tӄ4?}CrV{44444<wMVFQdOCCCCQډ+(} +O?iYGzwIgrDC*CP"DڦHWH7}Lwww`umχFOo/T˴иdX"~u&QQ$3(}NpDh¨}$HieD~~>ĥ6SNE0pjNFFPh5B8Z6Gi8ݯc6?>۷o'5-GLLK,A(XS7pl6gh8JLuXagۚ(E)",]N740>ըc%HKPWv#aűY@ m t~ĂKHOi>^jd~Ymh9IF#?0iii?}4oҗ91@k㏓u:>% oĭ7݆ $%%b VZŎ;Pb D#"̜"d/X3vp RS3h>Y<{[Pj(btz\܌4ٲEjRjXvo}9rkj508 ]Sվl=| kƯ#<իg?Kaa!=ml:wC?НwVM?53Na2B(7xD"*0݈Dރ X&>Z;xZl(!lYi k%il(~#nV?#GuW%y^6lO*L8q>7wSJ#Y+rOB[o[ooҞ3j?S|k_Im|>44̚3!a &]*wdJIvD#QzxXRU@h@0vjwq259L©'ޯƧD})))<^RRBPp,\,z EbkEVTUTO%*+Rhk(đ2U֮^zZ1H``˙A5>ulwww7 dmll@ 0A?vmP?0@(>=ir8ށ,eiYtx{Ԟ6i# b2w{$OZx&fN9IfhQ|3100^?1C8pet:ϻa=d0F1>x<(ʹd2p$G4*3Nr200@0x&".H$2if#*{/z jU;_*;S6Ȳ55LKɰOvV ڂf B甯M- &KMPz͍'VV_T_wIə ٻw/3fk!rdVԴ;x&-- 5  d|>n736@x}"Z[[b֬YTWWSTTDuu50oޅ+"(288Hrr2p7xj~¢R-t^Vʦx6Z7I筛J-`@e蠬ly+!磽=vm9~)={x<ܹs',RYD"56smkcJGCQ665QRZƚs))z|>_zN]ǿ_9~=R=ڞ_^ddYF'먯?cGx8q6'L$IK#ƧkkkCUURRRP&\544N`*a[aɮBq{zY37v^tEӹqjH𕵤7<̶m[HKk_&wƮ( 8F (rψW_pZerF"D2S-~z>JLFQۋ_[ ~Go4}6"K͆9PߒN\ 'ioo'++kD>pGܭ"Fhoo' vM[QiȊCK(J<0V|~|~"GR汶!L475R؎ p~l~ᐌÎ&]W'7Mu hh\}xx,l u4$YD̆!n!(*=O~C_ 2S)) ә29CxK/e~,Z+_n:YM#\?o.ʰl;I$AU&ZG-]4YBT9q`ON%٪QX4^.u;:bgFo2#&+PWwQtvt{N>tz<RSScϩpۭ73k,~_5n7|3#Or5! 'z,]%KLx~?zƚ[n'~ Yў[5эy bfZ/7 Fy܃gxxNvvn`۶miIIIҌ3(//n Rrrr>>Zb:P_W^-7abcadP8 ?U$"(L,"ϱx4KD%3 t "NTǎ[oͿw~:z|CÜ9L@PU93V(]HUGtLI'H xA:y H0 ߥ?~^{nv2335mqq b(ʤ`F(Сn_?>CCi Σгsr;X~ SRSO/g-457q]%%%%X\|$f$D8 Ί+JEСxa01|Ws/<(C.5%+畗_DOT+8rO=;rrrXp!kn.dl#.Xl43Ϡ9|Fܞ1f6mC:w}wR IDAT({񯕛C#TYml@u+ed7B=RMZZ:~!Rz/~싲Gv;#zdpDewk$-@ =CRXi 'DdLtݮ*s6hOXG#Dcmsk7Jt8ptSZ>#AYȑ#{* `wE/I Bռ2C D7c<ՕG8GG_md2qzHi|h}撤[w|-X}i|/PM#/:jKw(d2S PCqq1+V"ɞ4p7̨%TQYŬJihhDBWǽ[nn.r {h4z}4=//^L/`&Xq磩kYm@mN /z1L8.9GUU~DQd``˅,xxɲL @$dY& bXB!^XVDQDEEV+£_'7fu>^0c>eE;z͛^"#+#]l (E0̱@fa٧d hZm&fNNcjjkq8TEUq:RH"ޞn:2ҋC?d]PAͅ^ L_||>~[_W]f0YY7`vpX#rfBO0;;1pM6c\S#2źVQ'ىD u7b+SG,tYAD2ټC 8Lvv6:>FLqqgώu, K]˂ 1MuVgSR5NN7BQ$BYtH{E EQ뵍F#K,d22sFqUG]NϔMnw L//0?~ d"999&bfn\όC,ywlƆ_ ~⻹eZaE 3-AI` tBxaSdw}/i)+ (*uϒÿO^t(//Gq!.\gϞ=|a6in;^SSrᢢGZeO+-˭?iI)T,o[(Ƭ3#d 2VIdq YE(vd7seNQ8\TU\Zv_Q0fXd:όO&}LmL5.ZL&|># # /? GM\wBvN mqa>=}$uh􇙽t F:::lkk$7FcS zngl@/>&P(ٕw.W[uR:I`qVȵԔktZq0:+UvFB!t.6Jjj`ܻ.EՊ(LH&m c2HD(&8ylQGG V8o+L?2卭9sB<•:[B$ p|#Y+(w| ]2 7raԉ9,zkQ%cs8uܽ cx =F?FW̜uiƧ\NR ,RS]Z&Q),,8o\HǗz윯`00gvG׋De imm;p:r~}}Dvz~: F ,]S?!Uo~!?d̀ÅIbW±c\dcu{{ ]P:8p^O GνI(Do Ic݋6嘒]u!LZOQ&c+((rG54.H'%%G=*QŅ/4hK){tP(N'}}}q xצ")))A}>G_(vp8j0-/ʊppl؅vf,)=m_C!~gK"=~$zcs&ӧO#F۶m- [ˣ222Ft:t̞=^ҥK)--g UlyMڼhrٚ+[1C,uٴbp PRRD0v].f6$i-mWOY~n H<(^kS/\BF5ab4]έcV|^ݻIOOƕ?|z,.MMMZhh\$ۯs:S544. = и8prw##ݷpgK.#>'֤,_tin*? g 6ib'lُV|GS:}}dAJf.NA/mdJq>0$~|k_eƼEv/v3D! {ºx5ѾzE593|$?-Nҽ=0؞ ;Xgwb&Ȃ[>F~1V@'oy0o")Ssx>7Osl-l|ufd.YbjUJF^1K,aXL-C48_r}1H~4wյLKGy8@qde<:i:X{ K$7qfR3l׌fb(:lk,+5du׿7m^^ {f 933M4*Ӎ$ R9}3I9m8Elt:Q6!H#n7nS)`˞9YS͒ߦUs /?9y72|cx{;>Uo̼-v5./^ TU$$NŕSBAn!Ee{;YP̆oRR/ȇ>X>{&"aB`~9v+q-y{+jf,Zy7i9zID$IIX-s'pe9$o5.M_ǜZ7QҲ\}+cЏڅsh'l_|ﻘl* hs~;P>6,D" ް O[5)E ʃwcKZEG(bn:coӓ KQ} ,,ϛkj+fAk~)YضS̙3G[q]9zfW5*'x:w}1r>d~k%es9SCԡ:QG TEfmn,f5¡&fVVq-S44O_\KVy`,]!<(0}<9 i,ޑE_ 9nuk*}Okq,?oASQYuIfd摑V;wԎ!˗/,k.->aF/^|UUUx<JJJNFF`Jz{{>}:,cX1chrn73g$>*++deeatz={6a41188Hyy9,SVVNj鱗x --p8LEE߻\.N'0}t  NRRh9s0<l, z `l6UUUx^c#!PYYP(D^^999D"fΜfƌD"RSSINNFQn#"xk,^/EEEg-iӦ)))Xe.ӦMBUU6:Egӽ(DtˏzJt6CP 6( ,DE`0Ueh4J4EUUBP(D""įBh4(ѝTUE`0ahTU?S$?ә(~Ꙧ&r\3iykg{kgh]HΗ$]2?W^Sc X˸O[Y_첵SGx}d旱$GghMgw?U׬Y]k׮eѢEop뭷&$%k߾}' ~ ?pyyy 9jh-[$Ľ/27oov'|ʗihhLI^,Z6+ *|{K/޽{YhQ+V$%kt:*K)K$ɚ*>Jskhh\>,Y2{.a%k֭tuu%DL;v~UU"eE"֯_Yh^ziqx衇:YWFc \2anᆄɺ`H,N>9Bи͌ #(D"=8\/X aϚ(Yeee.7 Wʫ&q#47_eHY$1w܄:v|Uv|꧃K}|x}׬f3sUd04Q{(;9rŋuV 9uVfϞͫd:v;/s_pP[[Kkk+7RUUų>Kff&Yyw9s&O>$ݻp8عs'ӦM㩧-[q߿y***x7Ev=bݺu̝;_~JCC X,?ʆ رc>}Iشi<3~n7p-[P^^ΓO>Iqq1vbxxACQQO?4l޼Y_SUUƍQSSCrr2?JG%!Le`Z'>p@BrD"^ۄE@{bBYwJDN^544. deeMjM|ozG8& njbۑ$)>Wߏ磧d\.7}yzRwkB3 !1`1c$IL>9oy2F $$!hFj4H$hGRwukoZT*2RH$B<X,R*Zf Fd2I$!L( f-1QLPFaH&R9jH IDAT5f_)r1Fk<bl*AOo8cQ|NZ~/}!(_?v3FltytZs_[Cָ_x>(JC6C—:`jq:L-bQfM ՟ϑd0 8NL&z^>χfCUU uȇ~FGG)J̛7VKZ1*ZƳz_%2qnZ|$ITU%VN UUQ@f2:-mZ,͍h678h4 ø\.x &&&*K?( ͆n kmQK,# zD"AP z)Jc4iii_?!M撥7Jk;ɕ6i ߧ5vL,ֆEQ(H$DQ8lVcd&KEQ(LMMFe( tp8訬VgMo\8]5}޽slu1ϟߐ>z?K[WWWWCa}T#rswuu5$C߿)zP,ep6Lho-1l|EH?ןC7 M> Bb4eT*$\^\n^OXAT0;N'fa޽}սVLsFTJD f*rl6$Iz=fD7Y!( DI8Nv ikkK 244D4xEQPU(x.Y&>~8N^tJ&-WRjE!M$)qQ9B&E 1 r90###H$hkkC300x<2sV(bbb#IF,']U,EbPFcQzr} .^ ąjv,YҥKYt)]]]\.t,hTyt:J:&cZ蠽LnUxJ]Ah jm],Q[- tvvىBQy_8Z[[7oϧ,7}z^nD[^bLDGGK, Á`hB;vù{Q~̙ /Z6 {»$g^zZK_}?b|!T.g l6r|7t}#c,k&'7d_].=:uXj+)[wijj`XPUJeF.zW.2>+|GT\;m_yv@>X,255E2djjT*`1XVahp:2 477 '\ٟFvxb֭['^/z,gqyn4vT"ɐ0L8rSSS8(7HN~ww7N|>xAgg'@F.8N"TH$B,cE`",N TUz=tz!* & χ^gll 0XBpV  OAq 4®mꪳko~`ݺu 롟BQj#l[L{.>e34,C2Ʉh3۲d=E>KTBi2:~[d@E- QzNFC&!H+$ x\.`CUoZ" Q:~b><͢w)?̼ 4dZĹ\J@XOY1d kQ.Dh֗i{jL&0t~N(퓓dYYPp(lJ-C72t.˴t;СCݮ+hF>L.bhnnƮ.ބa9F! J %I`>N%rFZpB ,LNNL&Y`6Ij400 >va9,ljzFr6w~j̅p_x#?|Oh44,AWȂZr9TU%,6IVA*4 V]~åuc2ПxX/Ir9 311!_ڊ;FUUzyzNuUUuqL'HhDe("ߧuQz4P+g%O}UVJJB6%z@. ]`Xd;Ed2b :r,|^2nL&|^h4dkf#BAV4 f4h4Je6%HJ% c_A޾;, 5H$B>nc*KTT*E:FIne rUmF: @Cky]-ԮlU5x:_ "G*YpI9GDT"D?%K|6Qst⌑U@U(Usn^wRΩw]zօh:NS2x2j_F;4l)7bOm0}&''%Ao:''q 4Op;N:v:[oDF_kR)JEJ6b_]EúWT(~"t@ X,#rJ%N'rS) ,}Ŋ8p`;BA=(_fYk_F=}vMJt%0?(k^nhoϕFUUϘ\L_/Xti+""02O\>sުʾAQ׊Տ ~W9p8L6"VC*c,k4il1?]C!r`jjJB(~99hR;|:M&+'alr7fYfX=X,x<9v:&Q.u3477阜D"!-|&&tizn7F*. oUѤVZVEA% h~Q\8+#Ͼ=L0xM1 ZL&ۉr9I%e?`XhmmvH$UV |>?v~m9kakʕ VXT&%zb˗/ eõst^t&ZzE,-i#d^TE*B Mg9%v.$i P6t¿Pa&XҬx]޿bcp8l6FcM]-?b:v/Mr9 C+g%"m&N|-G)re3s qe L&S. >VKP`pp>g?«O+J,+@b}޼y7hvz{{Yf k׮pZzzzE355 z r嗳f,Xfq?beNz{{%nU"[7LpH~/<6 /L<;+N~vK/+۴i{Ƚ\}eQԶlr#rZsb?ސs*b>?L򵼩<`$n={T2I%h^"ZSSV~ZZZ$Ch~l͠_N) d4%(D"f3^GT_2_sZ͊ŋe6/x.t{uG㏿=[w|?Yq.Qf櫿,vꆝׅx_\=<|c;Sa3V[u x__eV]ū_O-{8 Y;ִcˆ!n@A IfF<-C-Xa/TV쫠PΒɑIf5h3ZI- _҇7ERITP2 tbH>-` Q'Toćү:b|pd C@Kߠ! >坯 ڽZ44i1mp@yL:Ɲ;FMʇl#2g[ن'Sք9۝ݔ,N* QLO{^seιW[+Xhcy%?IJ8@|(GV[SmvS:lvj*bdD\`徍"f'LVr۴ M?CZ%R.Dz)-_GSSܜ6EjʾX@r*ؘͲlێͿdõ7qN(iY`>|Y@jko;wlݻ1LsV(ظq#sv=ɓO>9/(]mmijjz};Vz=hd2bUU%f%B7^^!Z&4---,9͏iTP(ѣGR{\.H$jLMM155^*P(rD"i1&T*wfӦMܹsV}g[m^ߴ|˟a,R{@`l|5 L{jk>3W(_5ѥprf?|^j666lB/ xl9}o%W^N@XEG-[}X^.z:Y/&?E z\.GP Jqt:-eY=O_|7f, tRjT*hiOq tN_d5"kiifw34PEn$Mlkk+mmm2(FQFGGF%^ABG@Þ}Ƽ희b,:Kl4:&/~ݠF!)UK46:;r{65R<lС %AI-77hHƼP9DeZ@PhѵU(IJƌMcíѧZHESI)\A[(oK\KPMTQL'yjXB'OƉbEQ/+,LSt4jL$'JN=JQJ;inK{y/ڃ㲫oexހ1:dZ %6a3t\zsq^P &5Vϫժ$kkƀn4iؿ S4;gD9Ui{rY"-Sţ?aCi& IDATIh`LsTD&BnkQvpLi Pقj6NS,w.<;&… |rAtE׉Q\ Zx<ZZZjrfRoi7Rz=f?y7wq`3g[V\%.mzv-b|2Oe˓5T}] 3kFW.\ӿ9AQƒ=vNGz8%Uf#O355d,hmo'*'Z] {bCO>@xne+ccc5jJ$y~?^zAdף ʇ0̈́!yG l/%[10{+Z;:]&pg|L(P(IJekX,&?ˍ%Ma2ϊd}aAW8K]@j9UU&'',+#>CQP=']$Kj.ells;VusVE>\П<9N.2b(2H.]Hr9䘛}fz1{\pV'Wf,hdx?.&MTB/hՍt:\.3YdjxGo=^MlaZV jUłf'ml" *Kaf&|G>J!Mqr^Oww7͓s2d2a(JLMMdE ltMl3hImm͚5 (_ .lS… W5뮛}_ ,hG~_^ > `mVLЗ^ziCIѰz3 Uݻɖm|x*<\ZՓҴV%Օ[[[k=pYz:T*r+Hba9t:xS3krB|a=|X8qC1W.¡u2PFvcZ" hk($xBEח- NNhKBFdVUJBTFU+---t:y=:J."Љd؅:O}HKNUd ,y!<>;ĩIYFY& Á֬]q\x<y$455aX$N!L211A*J рܩ"hfv4󌎎H$ø\.3h"cj0.h4J<'c6l6)+(d'''9rSSSߑ\Z!rBLNNNÍeCl)g ҎFJw}w6u 74"믗2ط G>[sucGL /4t:݌?B-NΜ[>3-J\Dɼ~\ ٌl`0B!J!%2:HҭlnK虋U_d2$ILWW4і65"Q އtJ8sigݽݻwO Tp8sk[,D"ZTوEE_իWd:::ĀvBn5vgY2 3֟="7y\NΈOLLLݯT*edbb~k>=_sj%:bH$B__;wdD"w*J4ccc=zݻwsAB`0HGG@KKK ]]]Qo(DxXp]_`cG~9%e|Ɇ=k۶m3/¶oPC_sW_mao}q%5ћw?3 9JO?}f%4ctZf1NoQJAv([^V% vioo'Ҭ@[,Y 2芢>ANeyv e B#B# J\.Gww7RC/bD"YJ/t:,^ .$T*B!vҥK|vEU F磩҄pL477dpݴB6edd|>jb2{q88N5fb10|VE:!'bRTiFFFt:PHtwwISSI$RU'`fxl J$4❵}y뭷eЇv^%kZ_w.8ifP~Z-+Wl9i4VZu~zV"Rx('^鄦ə( t٬ JYt, RL&#'DUh4:-[V5_VIӲ|[*d/T*E\&ZOx\Qe = K/L&Yr%Ӧ R|!UE`]``P"L؄ ՑbXbH,t&[~Td2x^iDQ =NU V(:Nnŋˇp"  l_Q8?!<fw+Y{e˖oOԔdߛkkd2)sm59i#f֭W~ lj;kYDA8PEp4L\?-z"P֣O6 J@. g=j]?NKe5$31pĆ`0H ^ed2' `R~>mx91icx'U.@{iYz*X*q$= )g|bRP(0::*+rh4DQ0rш墥/.dLSb'''D"SVikk#ϓL&%^5N<1l64v.E!c``l6+9V-Qj$Z20_f}EeDk(_V(زmYԳըm/!]jye2gbZr* g(JY*&z-m`%599㑳MMM8NbM52@ f6^n("؈dYqtww}oz=-:S~s?dHRWTQD]d zT*E6S6 V+*c$`0ʌ5 _cb(6ObԈLvb!@#9yZc+۷i%ŋ7嫣!9@4%xt\]*_~Pj6}X<˖Lh& ( -:_̣OWyEz x򧣖_wrAnϙ$\~:DzUѠj}ӈg.$T25B6T ɝE>G__DIWW2 ;~DET*9tnimmCAx<2D"2kf{ccc%T F.+KCCCQ*/hE;7m'SklTxX}_5kΝ Gfߤ1d%:G'#Y(p-0 _xᅆ?o5 rjp w| /l1eU`˪xj x<.ǩN~~ŏmՐVUq1/fiii_8g5긔K/pS>1\&=&HN.B9 f=;vχf#0͒Myz{{ijjmRD[[]]]v(2g28z(D@ss3`Pv,|twwKc*<,7PA"ɤ5l6Dr9ZZZd;I)'5hknnP(9 p)?M$7ksG=?['w5V/\PV5b&Ѿ5#*D'^N 6l8xĺe VlregT@ tu]|ֶl9 b6N,죋(x@ vQCHDYuA:#FDP3Q63> uQ\N+gߝd(xX h-8Ny($%#|+S/qlVfBL$ {ezvA+#A׺. 1<ª591ql|՗^Fanދ#3~BG?xRX\`n?TR~Z}tʚqۿW>5W[F#hyjk@C֎;&a W[x<\,[kJ(*gۍ4Rx A҂`|>/$l6+f^/ϗgG!K_"[=OSѵC8f L&Ϩ1jkN]P{zzXt)M&@Ӆű[}bv< Qu׽ 5HL L&TU%311A8~,djxB׶X,JJ:eijj/DD"A$!t:Yx1=== sN)#vnjjqjD:[oe#TEni?+?5{|bUŬ?/}_<$W_=o~~dqZZZ4W$ՙ2PFe[i1&n-ʩslHQzgӏ\N:YߺBU_^ B4777*|\(t:]:-Zr&]Q@,$2|>hI{].W*ommmL&t%bQ^t\.\T:СC2PE.D_VĆ$N*B4z,1 Ŏ{%IYarrFQ "HnVVȇC$1Ul@.0T*JZ+Hu1rh2HRr EKGpo~nx<.}""9 N/ZFbh4ԔXW}y/pgD&>N"```t:v/=^/ץR|^V_x<"^ :ߘٽakYzV]]&N䓷}Z_І/[KhߛF::v,\P&n€Ak f&s:f(Qx43'4Zh03w8@MQװ><(DU$3" Tx .m9׏ D]e =hc!*B*1/^/Z,q:XV9&Ƙ䴍prVrdX%Y'>Y 4鴤Pu\( DF&i+2!m f@*<fH5~H$"EKGp 2z*b1N$/I21p8zIR(Bss3^@>'3<+ies `;P֪a+XOS1D%Gp{ve][ F4"a]UU"t:-ǿ$MdVx`:0jL(g^DXv(M>J50&Aj"hA *PT?jF2ĕۋN|E-KJS5~$oƮ#L38uD/d+ˌ h4ڵKPZ-Jޑѭ@N ?ޭcU_Wwꏧ<~D;B·F-#YnG;Ǜí[rw6,\pVK 67N[ogd\3<|J;x ===L*wr{޷>6޹Ubf\{ n̫m֐x}vnЫժ̦3̴K2VO-?}HjXc]ۛȺŃ\.cOٻlv?E Jb-N[Wpw.t:=0L4f#=R`=B)FFFF2 ^=/Lz9%~aF4z^q䨝 )#8xy̟zj*߳_/E{2O?ًv}5glllo`&'Nً/9(P1|򴠲^zZZ:"Dxgҥ08XCS.ygR4tOfjUf֢e.qxG-m}2]}4,J"zpA0bߥ@_i 5lwfR?ްkkjyv8]bf͚sfիW7|XSt|Z-cX79Oihh]Y[oֹzF2ͳx8> 9pׅV <>m,\LQz{8pܞ`<.v.ڬs=ݻ}x_M7͝'yaFLfx!Zʭlf3;1+Arv- s9(ʌu1_vf6l%L'ٳgO7ױcǤg)w3y7۰b='H|L|}Oa~AR~>Ue޽Eh-'s{l? VON('>Ѱcm+?r- ?QysvڵkB[z!KX;*|DEŋa߾9'V34voV[hTm}>}7ؿ.]{-q.[Fadd}144oٽ{7.'xl6Kgg'o&z^Әf^{5:;;ٱcQ0Z]vζmp\RHUU8@0d~9s:::xijjb˖-pAqq< mmmٳEQF cضm]]]ܹH(" a4ٹs'b޽1WFÞ={hoog֭nIRT*z- 6m|CoKÇٲe ߿_ns=455o>ٽ{7ZH$(VW_}.^ʲcHO8|M:::ؾ};v!b{-[zy( z:Dss37oCIGxW;8CCC8mkK/Q(ysB]__Xv{e]ܙY8CN¡\^}Ul6ijtww~ oXx3[\.[n=횿+l۶@ Vjkŀ~1_ 觵}{)oy]Um r,_FZ!,X$Wfʕ n7jU 8UU& łFrTFӉn4 +V{(<92 (X  q ww=sٹΞ{vΆ9윻w6{6$c0D$ZcuBB ڄT]]z_շ  +>J)r5pNUTL<łϩ& \)]n}{gqaf#LJ%%%ɕ%甮=>'̧OYa[^ןSڱn˟imA{{n7ks}'m7kI&UImX}Bys\.***p8rϞm磏̛gFY)}CZfΜ9rOUUV˧pG#Kv6+0}Z!_ʒǞp{}/'|2#!S?.~ĉ˕'BBbxnizN:Eaa-'mmu'+J(aF(۷\.Yn}$ ˲eOUn3[# >'=;Hө_uLQ[؊exH#L%c'F΍5T!+0* 5SaPx+|-\wkFE',gM3umu12DBm[g=R]AAąlhU(EEEJH%9:^{m| C֔W]AAaTj}׮])['NiH ɓ'` [xѣ:uU[$EQd޽~WSvI$ٳg+!W_%v]EϔB9Aʍ8p̹qY[%~o?BGqㆽ{VURF6(//wL-[nZm[2BWPP<Phh41o5E~pDQX6_1OqSH-^ho[zPAWPP=:(D#c3e"1#ti1?3ps]b[e– YY,[:{juar[)I+((o;~!\}w n_~5p'xiӦ 6wlUWWcۇlFxѱ-R*!:2r]UUUS~?<>q'/5[\+((ܔO7f3TXL"þCxbxر-z%mڴ)c)[rttt*y::bnǎ;cك*85[j(wx#~_(IV[ P( F_ѧ8wb'3-#b#sVq%VxGO=gΝ/СC,XJ_ӧe W\ƍ1c6lnst|gL:u֑ω'"Hk.&MĚ5k(--oP(wޡ={رcvZ&O̶mPմrX~=3gd͘fjkkd2G/m6\.gϞ@@YkRXXȱc!gYf &L|>w}j˿bV,TTx<XnSN>Cq8|̜9M6aZtW\`0eMr ;{2i+c0JOW )%KF6ںu+?T[S0'/[60uȿ/6޽{95Yfe3ekyzpFG8Dy[yy96-#U^^._*4 ӧO6sxJMpTjz-yRPP &O<(p XFL| ahjVF,~B/_V%In{'@Oc2ػ -EFA@ 1I$RO>_1V&+S˪c$3E,s>1tT(gݞ-EFRN<9c3eѣ0qb*_Xy[xRVhd%f58Ů˕ gxƶj5'NT]AAalڶm2f?S=J}}MMp'Z1me*꺯*DQ6o'o68tSQ;Ξpx;wT]AA!s˗ XˢD!U٭0#ce/Z-+VѾ<87|sc+ܸ* +(( CM?6Y-#sHi;e޳m}ۊl޼y?d}CQ5 z6`9Jؚ¨0T%# %nVm-=<8'k? ,[b"ZTɓ'c2ڶm pOC.ﲊUcϘwCC^ۮhXh "IԺr#1T*]{n7.NJ%{ܹ|V 0O.A@5Q?A8G,]]]`:#[Gk$ͷ! 6y#/]7.)/AF,pUj5H"?дu$)cGz}a\?j޷…Ԩ&covnYS=4hx0J*al8r/FY6c1;^u3y4ϯ܌;\mfOPɵ䡦KJJ= 'N\=HmѨGR%[ޮC*?#uƌIljƏ7ab%+~^U.@o/de^􊋋81K T1y%x;Fcܵjqlݺ?Zw1cL===~N:EEEW\_g|,6oرӧ5< }'}{ᰍEEa/VST͒%Vrrژ3GOI6`Xhiih4xO8q"}}}L&Z[[1͸n$X ׋` Bww7*H$B @ֆfFC(" h… ~\.@H$JJkk+QQLQy<|M&}}}$ DQ`4M?cwtZaZl6@0$kZiooG{ڊhdh4, nLkk+&Ix+bHՂ=ZtuuhAA 0jZmmmz|>8TH"i̞=ڼ=Qk4>#LnN:}<jJwW||AIttp!JJJEQ.΢x+(()V ^.^ŋe^b&lDմ?7$_7=ȓOGx DptDB!jx"P6:;;py(---,[ K}}=dillvGcc#(ry$W\Css3hP[[匿V0.\`ҥ|> V/^$u#B_mjjÕ+WEn7nRrrr󭯯CKKːI[[ۀ{XSSC(N/_pH$BYY:K]]$0}}}}\rED+W'y,HD]]^.ZZZD"\p+Vp%^ ,6tM\EϟOWW>ۼ䲝rPY֭Q.]+9jk+f-Q>;~ֆQtN7S^Ƃ>{'$g|Fk3(#,(g*ok,/4iMr.#[w了:#_}w4m|U&mq6mʕ+G혝tmK8pp8"Oo7PIx9'%)7QW$ 3?HDdzܸ\{z`AȼKΝ{LϞ=;c2V%O>3<-x 'N/5k4<`G~=\!p"*۷oɓYU&09U^~pld_]CϐѠ?FṠ5455gf+SmI[D7K~Q2/%4aժ$;v\R<F^xaIaxaW"fQG`dLRшFs1L'gL&mT1M/q3|˷RbT" cÎ;8uԀ8OSFـ~8u3 yqLf 0b]:cZ3b4bKRrTr lQmak" câE?qsVa^.}>DDVz~3UTEJ9f{ćQZZH$8}D&R*+?^ ;~sr$)cΆu rKIͨPUPAsvRGrM-V/)nٌspg Umm͚5?)La>Y*yuc5YZSqvIkk+͘9]hii۽{7MMMwE[݋b֭ˈ-QYvJbBYA*+1cKxCM47hA%KpLw\rT/^5 f/nVˋ/[^ziz^T>֋.ZFÇSt訠YB6osGlmRޮ6V\t>_&DcǎeV2h4L*ƒU3cT髠p 5垟1cmYygEhbEFtr{/dIQ^m=SVKK\8wTjMF  mL\Z.plO?cs\8,Dăl#g||M&71s)_}>*3gΰk.ϟիO'|Œ31uT>sz-6l… immEEꫯXr%֭'@^^GW^a͚5⋜,:笠JECC>(~!?Oعs'Մa;w.7of̙3nB'NdǎX7tRT}b ֮]9DQصk?Y~=?C 9x .=JE(?wW_oeܸqhZjkkYlׯ7`TTTiooglܸmbŊQis˅jiqBUYd 駟FRq;jf-ZĆ no.]fq=ݍZ܈ơǢa >'O]BhfqdWΧnllqsαj*V^o̔;v0uԌT@/4iEEEcn/jd2i+UV-QY~=o8tEAWP^ي@ *)F0nG #64C6777oH$c2e+el~u?˖R>UAAᆨTNT*W IDAT{*>~T3U\\F dZX&m]غ{~AWPPU$Ig~3cƌ:t z1qa={,h H2eʰ^pqaoV0SŋpܖP(Dmm-ӦMvߚrssq{|2.kPڏF?3gomm-۲8{,fvߺ:l6999և'N`ܹЀ`R7R[dNNJ+)0f̘1't:^{:;;x">~̜9s*Z#5Զ^N쾻wfҤIܖ>;O<1{ᡇ^?R[#GO޽{^RXX8h]} {g>L~~>%%%e+ {nam9rAE[Fjkmx믿>'Ob Z-Qٸq5e EYCWgu zn$c},JЕ~1r8} A ҂rJ^/Jqo˱Ze2bl2/FF2ӧڮL6۔۠ Zle70h~u? ZͤIW[}WnY6wP<?˯`Ӟ1naϾޝ9VCǦiReӇ|Mx1 qn=HD[ygFޱor|WOa/mM[S}(OweQo)0Hgcb#=CSȼ Yp^w]ȉcp܅1wQw3;$;"MH(4Bcs5m$Ɠש>^mjlYeSc3R(‰# Rװc1ܞ1#Om_T**Jy+( zؕ[ֻؒye7ƥ;ĦΐM@]¼?Riegö?+??b]{Ƥ>H5w<j ]b6S7%BRզ08$L&_AA6^#~c*`Llsg6~.қ?R0.Φm_1A;fj 90NՌ'Ğ,Y`mnd,?W6 iHTaj-Y5&r-ۿV8oLXv=F+M|LKьAԙCt:f͚ɓ$FDQ$//F__\\  z Am`3)|ak cKzFxᇙ0aZɓ'0{xF8ǖxx\= w%jApPTTnGVc68q"ňHKK :L8MNJKKFrz466M"Pz"c9"ɡ*v;---L&` ''^OK)((  H$0L& n8z(J<{|yx<9LXfR(~`Z XV **U`ve}lqh4$Ih4ЉT>f:9f0CqSPPx|ۄ?.W_W_cAƒ3&?C*mCy,}x&J@"c>*LEEA(++cܸqhZyݑ7< c_EEEi C0?"MV& ǃ`ҤI7Jv܉##" n7aXr9s:}~__#ؼYͯ׬]_ചؠj?~-*X.J'FUJ(>h4'O&++Kh/((@$MV+ZVK"vS[[Kww7]]].JE,#cDFF(`0HQQ^fxtɒe?|֪Tdl)>vb^\\̔)SXdosłF!L&dc9ʷI&S__OGG PPP^|[O ?Ho$!l&Rd2CYY3fT!(am w^&F((g~L&p%QT|r"!gzD"0x1@2$H v8&&Ξ=!77h4Jee%I$I0&Z[[G׳rJ*++9=YY"˗/+7BA>#L[-AtTVV2c p:X,BjJ$IH$ jb2PiN]]]b1$j@ee%zB Cz=ݨT*q\ႁΜNZ[[5uno߮SYGu:^:(ljNaX}΄a7ZMAAϧ˅@t:I&dggt:q:D"jX,* .ňb撕(b1<deeYYYrš(`4$ m n҃tzϚEIZ@M㝗Ҭ*6No>Joo/k֬wwZ>>g?\\,MCC}6}^硇I|\.N˅`@ @WWxh4J,v|(v |>Z[[q:r,F3i4raԐÄ ZԈ\6\4 RV@ssYN& VGaQ~OnoQ:PDQb fO,C\^TTO~bvO?yqqf̘ {F򨪪jB!IVC$lh4(nBx`0H(";;[h4 }z@$b<`2z477SWWGwNGyy9~+.% Da>/XSP;\|u4=,e'x.\fb(,SMs_qYTsT,Nys9z DPx֤A˱v<gƌ<l߾]L$/_[oŢExUH=퐖'.bHNhnd2a4QՄaz{{x3JE""JwcNxrJi i1.vEE8At~+Y%I";; μoݺŋ@ss m]RUU… )((!I-KnA 2eØL& ˗/N(BRYYI&ٌ:f(VPT$I N~V6Xjݤ#t东\nkOxA8U2JBpŸ́ABA/--__dNT*N>-_"IO?4&InhhtpBF#mmmb0Zf89}gQXy*l6RZh4c:;),,$''B(zV;@$@ 3gtz^/= |C*7j]᫽G?pH7*?\9|m\ Z>~- !"`0 N$Iy_͝zϮѺ]R1n8&M咧=M-&"4Г?[A N&8MF<GRDWWjNG DWT$I s"@SPPV%Iww7)0Aq%4 DB+|C0_>!~joYAA={@j5CvO)wT)hH @vv d2)V%++ IuH9"@4EE4 8}Ǐv|b1 ! Ze@AK9sMFsu)*$%y WFxT*t:drDX#`0(G*(܏x^/zBl6dM2$: fzF Fq=Hqv]r7TVVhoo͆jӂR`2DՒK   "'Npp#zh*(5dH$lF$ϋn!a0oo0l677ժQRi#ށ7fNII x{A ''G (ܼܭ'VZZj%;;[+WTz9`0 DB^+O@n7/_f޽f-ZDYY999l6MƤIQyz r F7}d2N#??Áhl6SSSCsu 7nB!)|3^fۍ"QT\6XQȬ9eg"'zhbmG$ԒMVVְF v]R!_,Q666RZZzOa  =h{{{;ƍS:½%* A0͘L&9ۛfC#-IU*~2e O<Ų|:60=p_~%̝;&3_~~s$IZntz m+ #t//;IW 'djv)ɾoWJ!A2}F$vIWZHG\thpJ'V7h4bZꢽ+hII C $INL&7{~~>EEEp%aܹ̙3GQWWG]]'N3fP^^ zL3V!vZUrW[F. ۍi\:Mb=RA}DNjZŢ 赚#i Wku1f̚*|s;3; pm@~a)QzY{N;B>MOOD"!MnG0͜;w@ hhhĉTUU!}mmmr9JAA. F#(ҿ' wN[[~_NWP>^GZB"H$$|~/~+^yt: L&#d[?Y?žxpj FC,.bI$'Wp`>VzkAN&xh5b7MK2wQ-̪sD"G.,OkHm~n0}nw 1$~4& Dz(cD#CUDΝ;A09} dJ=]h'ٓ9u;S˴\]BێVN-G'Iz%KE~~2˧p Fb`0HG͆[c4ux<륷χnGk&Iw\L6 A8|ـhAӑ… פCXL^Ou+~NN999ȥK50J%ej$$[ţ-'7ĩKH$D:s"^zmTj̀}?'$d_aT_/gOrgR253/"`Q *f9jeе1j1TRqyNΜ=PDR0,Z{F B&.\$Q0?F: p3piAO&vv {N Cyd#)bŬӡVD"tttE__;zV?Vn^GE-=픗SXX^~Av&DQFħj9{\DFA L""F8L U'?2>ҐjvRRBZbF%h+THWg~Bvl6 ɄrL{y>ݠGN cG)c'IJ&61/h̩;y~8 .1iA9<7YANUUz.˚j( ),,cѣh*0::H&rYS>]*5"TWWp8dG[[F\N'6 ˅dppQJ6[g6ҀZ`0veO-x'?L^i$D`/€$2$ G?c L~kgҾ׷I4)AOWXK;L&N%a~Z.vRs8q _"`ZZjB0X ǃ땧u:fY>^Cz="{hmm% H$X, )ǎŋ*(X~\.5AZD"ZBÊ(jDm}*~N\َl);VTTT ~977{tb+ܻn4ɡ98b(<]BU1hT.^;",'Ax+|DYY HabPR\DWwʲl6l6A]@bh4x<$ENgRlnťSrcj%++fy4^l~u0_: x,|TjJ d/͛Qz:JOr9q#3FﴩSS/#AG,&EP(D_pbF8`Liw\L2Źs0L8z=F%o XA2JDŽssq= #%xzEAj2ueӊ IDAT cU\2p&((~7!B!),,sLGhۯBٯ)DN_dh42yd˙5k'3~xrssG3EX:_cZ\S#o)r*stvvTVNQPx0yom%>#?nҞv'ygZݝ1zetI o:fc=4Ygg'n;U29hF$މ &f u$95~z*=}|&z)**brX,gJ zzh0g.C"HC2br1g|δ)]A{bڢ>__R8. Q$&&@J$"4:$)I8A#h봈bh4VCӒE: "8HIL[R1h 5Fd"A$A07wNGAAxxG !ٌ%5XtMJtwO{p7>̭pQ䇊9Ş_lgۿ>ۏ`?!A(o?CW?[ ?}'I [ݗ/ o8s-j {=fJd{?ew]MToOxM Ϙ=Z<g~#qT/!tOK?<\Xh'kdwԄxO]w&WRxflf3݄!*W_(d(]TTĉ),,j!gz,Y%I3iZj<:O{m'v}QM/K" rF+owkn/0eO?S&8`ӗ,"$شmHj=/̒K;uC~:>Lyv*!κIӨP &M0حFV믿Ns^`ظvZ)4qӼ7|y3e?-͜k̉ov9ʡ__Yng.%飙4]W@1nq7Ŏ'qd&f7~ݼy7l"` VA21Bd@O><3sG=D;¯^w&&R\\Lvv ſ q|r$H0@e<<4XX`0+8ӬBBB.OP*PT"ؘE$-.F2:QjqW>oTt;0s~ko_v/k2H$o5~#e ~<|ۋ`@Fhh]QOZ.}Qe^Cwҹ}s<.,%_/EDD ׋hrhJZ~ Nj pmқJ7La20Ls9/NT*Yhc5׈jehhBA\\N3PF @w -f-fRظ4.M`(t}fL.J111vZ[[d2!Jh4UI .9x]" CCCˍFcR/3uNG?CCC4T2DFu HOOf@ؐ P]nRAD\\ܝQ罽!hmmEՒCVV*FzzzA$NTTqqqH.x\T~?]o};v;SOa*DV+DGG? eeel@}ST*Du=N__~====ĐI||<6؊y Aw8l!vOxl,H(ibLmI :… 9us X.jpTTTp}M8ܹs̚5+(3gXp!@ivQt:.8RSSH$hZAVjIHHW (boaǃd {^Zӳ06h4twwP(hT.H$\.WKBB ˅nghhhxnN|F&Q[[~O pqVr:lsf ax%\y|$$$裏j5kV8E*3\)s:HR^/?0t"0׺71j-Zt1=|n;pvf{kZ2x;&HDdd$ .5<111̜9sep8d#~I2in;>|8(ȯCCC$&&HQTmR+?C*:H HDR{{{蠹V+F~wtߏ墸8M}$a~<::d2& NN M8̧)v4+CoB-6-(g"%KGhh(DEE;珑12rC.KXq-]Fdf<ȅ X~=ٜ8qHDFF{!''Ç86oLaa!}rNgL6]vFcc#(JGaa![n%&&jt:|'a9{,Fɓ'ddffrqN'sΑƍСCD"&::-[0uT8@LL mmm455Ν;6m;v@R__Ogg'rSPP͛>cppˑ#GeݺuL2%kZ9}4ٔͱcpt:Ο?Obb"6m"???DBOODFFeOݻQ477ڊJSm6psAٸq#TTTp\;v֭[Gzz:Nf+++#55 6\w|޽(yWW!!!8q<===t5W*`Z9pnK[STTD^^^'y\\III'p'g +JRSS]JMMM@&&dZihhҥK|tvvP(!778JeQl6LgggL&CբPJF ?ZVRH[7TGIԼ\hf0</))!-- ~m֮]˫ \t:ٵk/„s\.oҥKruV-[?ZqL[]u\HR<---jNS?awKɾүR)၂0r

    zzzۅJVp8ذaCP\.ׯ fڵhmnD]8;tt:$..@nԩS P(p:8N}YfΜR Db1̝;JYY^ÁA§{+|>,K bd2 75DCCzU v'%x衇f5?AH$j?~K^,P( 5MƺLZZ"IN:Ʉ]E?|> 11X`BO!ILB&* ֹ{/%pv.\O?.L3<.D³>{wX^b^\D"d2ΦpFFx< Ԉk|>20Ri }XKe|cryJ7L 044D?.k7 8gEPXBn;? ZJfʕwLkkk9s&uXg"ލF#HF!"""Rկm6Fc:ۅ EFFP(v;\Nrr2p8 _133ikma zpla/L&رcǎ&X=me5m>P %%@5BA||<\.L&S5/H]2#k 7pN?fIKK VRI~~>ӦMCxP(dג ;;ExÓQQQASWTw.` xgF (-- %p]˒ ֹٳAzcrBGRG+E" ʐIeȑuXÓ E[#fћ<:BL\63H6dCncYZ `JINGzL=$1O.p'RCRdTvWb؈ dH?t1: N+ۃᖎt+XGޤ`XP[(hWB Bc`A\.g/&92\,gi,# %Dd@(Fc WHJB#`s;ԋB 2$K߅Ugr`=Ȥ2DF|"lz @]ȋN&<$R;M~t}: ]m½{s$qq<,9 V00|"(MuƯЏo C!GF3eʔ@Ⱦ0lqrbccFhN+bMIII:HD=Ê?2%\NP?8da223ExCFjkkzDs@sd DwG9۰ p&p>jٰg>'9{\R@]+CC}}=J:nP&x<)--edggST N gQ ATh"HPTǵZ-Fٌ^3Qq¾{b1b"!!!Io* fQ^^NUUUPZ p`2F \7lY%K"3y\r_0e(y%JV7^"#i|q9y&zzz0L>χT*%,,(T4^j"Jq ۋ&..,lI #::0t:mmm t:;444PSSÉ'BATUUz \7j%(!bXrb5*:6n.nk֭3iÇVr\ex4^Ղ*:Z(,W—|W(H:I81D(hh勞HLLD`R@"y/  .Pv}v={p̙YM$>p!44 +jEٳ dL4+V>SŕB A؇%12H$ N3Z, jvB+ԞJKKtT*f0@Mu:B@RBS2>>pw,ju ]$P^7_ &!!<.\v.-ڊ@{` (rI2,g9z{TQuGvsȑpy|x5`O,4: IDAT^zItMM|>njIHH@V;00@hh(l,"%]]t=55M|ll,"(&?t3耋``fK3p/"AH׍V G3̥RVyw\0e(G<,\~#wB|zN3}F}}}3"YDI!r\b̽w`غ~mzo>6mDyy9H$zFVpl6v~<QQQ&'ҷBV%))PFp@d|ff&yyyb0蠶۷b Y188(X8qϏ4~kOxn9|泜б՜!CKWWפ|tvv />#`l2/jn}l6G"b* pBBBP8N***hkk zb1L6yOGGO &(sHIIqm…A3f Z^U8X 2J̝;7(\$\͛ ݯ{{{ijjh DϻNBBcWcXhhhPO]\.tttAjj*NFf3%(N{{;v]PIaÆ \F6/M8sF#݂)CɶmۂrغukPn7[lCw1\.vQTL2X]ZQƴ%8K٧ZBOl)V+1ߏhXi C\\)))HR#::JUUgϞettt\o \wWLgU϶'j^PFY x.2T(+AkA<|K_<: #5kְzjx<FLߞCb"58{ Fɔ,$++3jv;TTT000@LL ={@7ZinnPp74c*k[.#2\>u\c;wm׵C9}e^baNbQ폨o9N4y޽Axݵ[_dTZ$O>=hue^#5y*c饗Ub3qR M,kԩ5֢ijjSg@5kCEE'N >>{RXXOjj*'ODcO'++O?͆NԩSrJ VVWWϟ'&&?"~ߒFss3qFٰaZjڐJڵiӦzj9{,}}}x<OAA7sqF#G"ٷo999ڵ FT=]H$/~"Z,#JY-7ɞ"BJ %;ED47Lr_ o4 a9nÜ lk|! lݺlD/V9xwv#11v8XLNqZ$Ly+U╄!VFڲG|4***x9tPКb\W VwNqj[j\.N:?rݜ8qEx=v/f``8Ιfr^ɑ^nOjQ՘ q]gl@ jK߫d䌰 p'pM '|b#E[dX,&&&)Ry6iHDLLLptHDllGX^ 8YVS؅رcT ͕Q{B %XAׁܹs?ɓP2!\ge^^3gF˗)Ø> mT!#B<ɌDΞ0Ҩ>Aa#yn"8aI$I1~8g+V\uf-WU?pĵ,4c\.իWrQׅ2cz焥k AϽGFd)p@es75sLzzzF\!++8Qēk _dx#/uuuddd\3XA7wz&׭Vhjl!<\v1mjխήn#al=$'P{O~)N'M- ͎ ))q¹#22⦟EFf6^C?fAvv:!J!u77x͡ x' '3W3La 6& r5/- [rSJ]*#e^G}:c2cҗp8t#Mf2oi47Yy,\n\NAA]sCH#SKol2eJ*))) ׇB±cG8_"v@Pw:ݍpciիW|qr}ɛ oM6/]]$L%7\Nt~zx fڵ|_q]<O63m8ݞvj23%3# ۅ{{}nʹu =nXwhIØU'[<]SIz2(M~f&ETT$rM$wobڂl[/<nQfD+ײhff 3뱸

    ذaqqqTTT000O>!77?)SpiL&N~@kc+deeqa\.CCC;w֯_O~~>G,EMM lܸӧsNT*455RصklٲjjjXr%9998p|֯_OBB t:9r|ᇤq V+FRRSSYvu7潽]t~_1k֬qGJJfgּBq5ommК>T>ko}^q3lH z= Ekk>$=siӦd~o=ӉT*{$q s8r<"H4tVVVRPP!H>xwD"_5,"3#s\2ڽ+y% .kԘ.\@AAd^k~^Lv]* Ͽ5ژ\sDBmm-^VQ+M&95x<㖡ᠥ_GFDD0w}|>DA]y叟?\@ǩC˲$?|~Ell_{#./~~'8$^/~>1>u^GsqEGgg'WZA| 8î"/#6)nް">>ˮ/nPb'z[BEfp@NYYSqDx^ԜTÑ tm>nr/nOؘ(>>rǟ mk?YRARswmlA캟H$̛7/(H$̟?|jܐJKk+]]=lnQR=[EjjJPhniepPw2x}Q+VIRSg5ێ&!=^{)ùaÆ&MOEB-d۶mM[ *TSq{\.[l Z͛G X:nJttvu32r.8WVUR\<NrJE$,CGff-)"@xچ#,r9s=?{7ߺ);vp1|@?t=ͭ)j4hlj%,LjbT*T([2A }~QS~իܭ;O?Ms<36ݻwq"0/\ X'gLg:N&vMo>/%e޽ZÎVq:#m!8xٶu3\n**ٳ{ΞaGp:ޒ2ܵ={>Ⅿ|5kVח9!SN v *&!Jo:OxMlbqЂb1\oGHX2K# C2 IDAT-i?W׿]Gsu)?y ENN<8eɒp:iquإ~Ҧn'qd]6>,(wFh0kZ2LAeJ 5} '2'yJ5y)tFHHH0DՕ'bnS>u~ll*pjyWA7׋^%ϊ' hU\QcqyhL[K$ǫK/S"9ֽOB#"7<ДTG8{nz{:R&/k nČ|Æ#R [>x^__O[[iiikEEEAB SxlJ-T*eڴiyY֐D!.Hn)׵ >},r^xGZ4uh.H^իVyFwz6DCTVp#xظq z]*nFp\@?v)ލ\^Фםt:ٳzI9}LURRyy<v=Uֆf̜Y|Kܫ^1x7,**QZL4Z[۰;=T}V>"mm"PRRBZZZ mM<#..D- 0B\7mMףjMͅ[qawӍ rDHe2Vyl6q_Ig7Qn !\᭳ou\.tE3ͤ {v? }ZÎCCCqBll na J6b8W)LfZ-2޻roMMIpV&GBA~ިF4}~{4Xe)aaY.0J̞={B ݨPG9se^bx̒c*t9DrEHFBC5̟זF|B>̝7hl#)),n磼OGq].jz2y޽ Hx'QȆne;q4.EغS$l-^M"HOT1҈.$q=BrңFAP3\@(#XJ^~eDn⥙qdxwi <Ӹ\k,1w~JQQQ5X%`w^S/,0PNvlG}sG8SLflUs^/j><g>jcws5?9Mdt*Ź }\A{g/?F"gKeAq6OcJv.Tx3R'ʉRn鵼9u$Ru=4gadG͛#>8żYqGGŢؤ,a=Z| |!,] X_3336Ż}]ᭃX,&==}B9"Dddde^"hL1@u:QQQWĉP(ز~o}篈P_j'ZsKHLCqL h4B[k yb{jW^!ҳ♤!A$/F\}*ԪBc ֖/rn˧e8V P{4{V HBB D4` a13;] {;띏gvxkq ' L2$!$@9d@(4G.TUw=穫S |022h89Y9ŴO1/5]k"Co9Npd\JK;vEػԅ$G #>u&# hf6G}QZ$Wȿ^髥TW@ fwB6>/6_ }L4-RUÇ͠P[[AeݻdE 2v[ƈLB\LѠMK?⥋n5rs^Akc g=ѽ\^Dhia!m<5zO.!1D-Z{-Z_ŸH+C?t<}#I2>;|~[RUUo|P$+˻O6N2֬YsuM…dgN22sj _:|b۶n',vNvObpf/L;=>G R_hYV6nY]xC19>Z?ue4M iKiiiaKwwi}{Ŀ1axX+p8˗.B'uj̛ĐץVV+W.=LUUܔwA:98\0ar:4ϚFMM 5A5S4 Vuu5Æ {bI0w [3TTTPVV6h7ZW_O[R,}As--QvFGbxD-SYUEhHb=77mH#y=RzN'׮]sAw:35h*G1ń6d=??G;vtٌj63ȌLssˠhd(-V+GG e??_:::T'&&-0 3HRW^&m|Pq9y0iݜx[kXZ^%tV.%G((< 3sMcذ@˶ÿZ׹7 >jɲ9tl>c^_à,Kb4rNֶ6~2eɓ'5jRˊ^mxnL*O‹1!,&1iN 뾤)N <!NS\UA.o(^|vwPPZŤ h?kOŜ#ikω כMlb>{H޿W N$.~U8v9ϩDkkk)((=( ÇgĈTUUZFQ~-3۷W#>[|8v8wSLܹsڊfc䐚Jvv6ֲzj~p5&LSшbD233INN//;v,YYYw~|;sEQk3~ .kGEEQ__ju~ ܵ8u]ŋ?o|ݾ,uSS f Wl6:6=//si=qf$MElMR9PPefG8dӊSt(N+&d́Qe#:gNISң8mHhu!ƻjIh8z$U2h6$Zz4I׫uu{|Ekİ@^z a]?H`` eۜ. Dd4MéII8UMIĘqx^qdF^K.I`0ifYX,z=it[,t:FN5OOOEd2l2t:]׽xyy!2fo=<<$ oon$˲z=^x^s=yxzGrr$MBQ{yfEQxaEEE7I6$5ȲkX=yzzvݓ^GaXko@\>2mo'ŋinnK%#3} ]7-$N_7.K#&:> TK[G+7r _E@M}w`ݜW׋@L^ek +&xzzԕfd=Y2^[r͟}A(&FRPE; sL0K`ܹniE,gqdz=Zv'Nc رc̚L2ēq9rٳg9=#ҥKܸq11$$k6vNԡ]$OGXX\fZøiOهLY:SQYVʚ{)i`~H*YR9WPcVI~E+S"j^)̍zU#V%=+n԰c:::Xp!BO{ uP2GdF+00mm hN9ȋTv-Yݖ6\;j`B A͠dZ |1& LLPN&1Y|z10LàWmd3)jY5[QU&,f"F ZBU]g+h9in/meMI1tEQ ??n}YݲL>jZ[26|ܩwsNLcN8HH- Ɛ@Lnde#EE Ƶkm z`y)LŲ]pق:f_gD0Fy!2 6h\.[ѐPd EQNv@r2pmS$mn5MLJ :~s寍|Ai06|TU%77-ZN+Wܱ3ZC&3󜧝k4L&E+--%5jϦRVZgW^e&Ol=g#uٜ4WעɔdΙCDG ;?s1ƥ੿U&7} +ߠhOMl0q|6Vu:/NA Rt*99:əd>iԝ~0۱cvmmNE jU-III/gc^\\7.K}3 ^6l9W/n0o<\.h"ƌv99qNc1n|c%)1mG"~LMN욆b6$!I_8BҴp \yuKVP!`fG…s4ߗ+/3gMZRL13+8̘z=Z:SEKQM￟ rt@Z. h_3t^ϏϚƋ/xmwyكq]RB-,~eFyWAR4qisy~G'2oDj=_ET7_>F/Rd%,/ *Eaf- p6-M :TFGE_W_f:n[ekO>ylOX:vrhePrq]~kl6n-͛#I 1ݿK- [ x~*0.]` G xT8}4$c2{RSSMTdNgNpYƁԺE*B X Уt-wMCc?%0u,.g+&5m+Wdʕ˜ Iq#?L7O?}(l8!_+f4+Y+K1%n6cw-oߒNHHx` (" =z3~%z( nђeAy,gX^fhll:Ľ?={ݻwsIMMuSYٙG?Q}{k[(?_ojx&cCU:o,f=55X|0hllں6oa<{7 sI뇿wo*z_"]*{ssN;EqcDd&3az &Mhii`!8bҠ,Elgܱ[ȽrI`+k. Ū&慷[YӧSWANa9 Ҡk_v 矢McЇL$ޛ#7mZNkG~ʙݥ3:흷u彃B< 'goXWWr`h&F1-wKhNz|4mPHb [h듖i`@Ӵ~0̙N4 .,?aB L2҂bb'FaE a\<a$M|_q_yU7_#'-Ħ<ӏϠr%m+FDvӒ/ccVtM0$%%ŭZ4然IDATslb>Y|"/Zܸ%N#11-Z0~A}gylietNjWZDD_BBFqSرڨ999ttX9}: QMؒ~Q~42m(Ã8#J;l$9878xï~IшY'#I#~x k_MvQWllߺMr^oʑlvjѷm6pGݴ|泒kx=Y^BkplEp ßN:m_fUUٹsg.{ g,cz|ʙ345L6=z]DYy ɩ0#<>}ѣGlaavsn[*Nqj:2bCHM6)\ݸkؚ6Ջs$4l89DzJhh(qJ@LW_7n8(@C2&RHa%+yW!fдzl6۷ownՇ LFsk*aK VWWm.:j@LP¢WNqSL8E -K2w +ֽ".-NǤIܢ( CnLa;# sr @CC[if뀴cp^7T_\"_k\Vqk^@ YJVD5hZкZN+,zȟ5;Ä,c>U OOO$I,]4~˷IOOgܹ?cΝ˯k~cX^v 7eΌTHىo56|hk#}gOelD{;acGqi*YpXrt_BKU ;"ntc#9gx`K޽{)..fر̘1CX#o-t[:TT,X&aewrgփ̀L(G}{xxp8Ƈ|js2rD-M Wu@ii &e\ݥii/ >B¸fe]MSf1jGRoG3?9ʟ3 Rk~E]?gf.dXwšC\03gqA˕ΰbkX˼JV/0tZ,}v"}X2&SG͠C{ZZZ(++C::4 z)I)c4HMud>^x{zI6*WT]KNza&1b8F vBoi !"{{wya?thN'], :V<р nmfæ]w-o>jGu^G8߿m .-asp8:t-Z |ו^Yb(Ty%yc瓞)((`ܸq:tÁ[kbA}ȕ2\"88>Dv܉^˗/'|Brr27nۛ\nܸhd?? Ν;u={7nWfԨQddd@{{;&&&իWÇiooLFڵk:IJJL&nܸAnn.^^^lܸd6l؀//_NǮ]HLL> 88lPU}ϪU455ѣGYx1k֬a̘1/,,p܇[qm祥$%% ϣ{va3Ŕ7tC$ZɨEz&g5Ν;iDo0K/a' ''=G{CT.^8;qkɫXڣDee%7`ni%zjsN{9lݺ-7o^4BڔzQҳez2u:#}%&E<`x Qh ̚5-Z:ٳgEKQ̙\ ___1" ¢GJyXXmmmxyy* -u',<==ݮeZlwؚ@ x-ݔ4+l&$$/_q]}w*[^^de]]SU|Ǝ'-_au(++l6j C5իW{]ޛ^>: y'9Uz{ZL&1 œ3!!!+ݮ}=uttk׮{fffUYW׬V+۷oɓ'a]moo'==e˖ݵlFFDGG;v`}j/??>5ƶm^Nۻ쫖`ӦMXeX,ݷ>wune^x>ӳrBץAWUIPUUŨ(>`\9&F-Zԧ&L`03lJJJL&O?twĉ.߷N[aW-^JNNNc}$'sދ۽պ:܋Kn\ 􋨨(HhSY^?`-W5upU7A@E!""b5Yݪ*#b8mM  d~ӦMZBkt:&O-EQHKKs,.qi ww@04')/`Ӧ-4ƅlݹsqUu|qNЍA# Yo9:8kג_4$k+{wѓC4~WiFrw]b'k׮%q2LcHT{v /2Uג/kHgN{QKF";;ހ@ 8-aLs;[6b j/K,Į/xx.gL^9c|`G[>_8c6hCg 4oݶOqӟϾUa2;4@Jx]dT/O͢ 2x1p#%y'v李=nZe^[[>*WT`2鉉<7JGGm[ __^Otkniq+,K G}5TsgPs  hmq% rϠ݁^7UutjzTȲE1BCuj(C89*ӉN ~h&KNUpnGu:e^7p:;?CpNAuJgQ#ҐM>9 _6ak95 n԰|ٻZ֭sVͣadgg( 7(-+sIիWs[Oz=Q_ FPRRJKkH:\("I2aH}iEO@B7 1ԘwN^$@edYBQtCjdEh4b4]zFcauSn0@ӣ)]EI0 Cjorf6ihh߿WݡlRF I۷'::^J2w7'3zÇ{AA[|xzzSصk'G|Ann.OoH]]1@m]#18\V:::ȹE\λu5kwnȑ#]o;&ُf-p8X~=o&MMMddd?$Ԅff)z[t)ө*> >*z*kk8q0~KI߽VJ}U)v}JY|g7O=lMHwUur:^}5UuI<\rVkX<,,xf+?:׾:SlB4Mcܹ@g7|[ƩixzZv|||8^441>1^4@ `LDBC|CLh3j#bX?'򗏷39JEe{7 >f϶u"A񡩩 O[hQ<lۑłcY407 ,㸷رij ['z(q$N]pwF;.e:ͬ0"_Cj1LN[񦤴 _iplF$"#lA1ꑑ!A <;610?:bbNTa,! v>Lꜧ1 ݲ,[t$O-&<$H_~E*f,{w[/SHԽS/.a3:EQ|(wd27򤥥$>> from nifti import * Loading and saving NIfTI files ============================== First we will open the tiny example NIfTI file that is included in the PyNIfTI source tarball. No filename extension is necessary as libniftiio determines it automatically: >>> nim = NiftiImage('example4d') The filename is available via the 'filename' attribute: >>> print nim.filename example4d.nii.gz This indicates a compressed NIfTI image. If you want to save this image as an uncompressed image simply do: >>> nim.save('something.nii') The filetype is determined from the filename. If you want to save to gzipped ANALYZE file pairs instead the following would be an alternative to calling the ``save()`` with a new filename: >>> nim.setFilename('analyze.img.gz') >>> nim.save() Please see the documentation of :meth:`~nifti.image.NiftiImage.setFilename` to learn how the filetypes are determined from the filenames. NIfTI files from array data =========================== The next code snipped demonstrates how to create a 4d NIfTI image containing gaussian noise. First we need to import the NumPy module >>> import numpy as N Now we generate the noise dataset. Let's generate noise for 100 volumes with 16 slices and a 32x32 inplane matrix. >>> noise = N.random.randn(100,16,32,32) Please notice the order in which the dimensions are specified: (t, z, y, x). The datatype of the array is by default `float64`, which can be verified by: >>> noise.dtype dtype('float64') Converting this dataset into a NIfTI image is done by invoking the :class:`~nifti.image.NiftiImage` constructor with the noise dataset as argument: >>> nim = NiftiImage(noise) The relevant header information is extracted from the NumPy array. If you query the header information about the dimensionality of the image, it returns the desired values: >>> print nim.header['dim'] [4, 32, 32, 16, 100, 1, 1, 1] First value shows the number of dimensions in the datset: 4 (good, that's what we wanted). The following numbers are dataset size on the x, y, z, t, u, v, w axis (NIfTI files can handle up to 7 dimensions). Please notice, that the order of dimensions is now 'correct': We have 32x32 inplane resolution, 16 slices in z direction and 100 volumes. Also the datatype was set appropriately: >>> import nifti.clib as ncl >>> nim.header['datatype'] == ncl.NIFTI_TYPE_FLOAT64 True To save the noise file to disk, we can simply call the :meth:`~nifti.image.NiftiImage.save` method: >>> nim.save('noise.nii.gz') Select ROIs =========== Suppose you want to have the first ten volumes of the noise dataset we have previously created in a separate file. First, we open the file: >>> nim = NiftiImage('noise.nii.gz') Now we select the first ten volumes and store them to another file, while preserving as much header information as possible >>> nim2 = NiftiImage(nim.data[:10], nim.header) >>> nim2.save('part.hdr.gz') The :class:`~nifti.image.NiftiImage` constructor takes a dictionary with header information as an optional argument. Settings that are not determined by the array (e.g. size, datatype) are taken from the dictionary and stored to the new NIfTI image. Linear detrending of timeseries (SciPy module is required for this example) =========================================================================== Let's load another 4d NIfTI file and perform a linear detrending, by fitting a straight line to the timeseries of each voxel and substract that fit from the data. Although this might sound complicated at first, thanks to the excellent SciPy module it is just a few lines of code. For this example we will first create a NIfTI image with just a single voxel and 50 timepoints (basically a linear function with some noise): >>> nim = NiftiImage( ... (N.linspace(0,100) + N.random.randn(50)).reshape(50,1,1,1)) >>> nim.timepoints 50 >>> nim.volextent (1, 1, 1) Depending on the datatype of the input image the detrending process might change the datatype from integer to float. As operations that change the (binary) size of the NIfTI image are not supported, we need to make a copy of the data and later create a new NIfTI image. Remember that the array has the time axis as its first dimension (in contrast to the NIfTI file where it is the 4th). >>> from scipy import signal >>> data_detrended = signal.detrend(nim.data, axis=0) Finally, create a new NIfTI image using header information from the original source image. >>> nim_detrended = NiftiImage( data_detrended, nim.header) Make a quick plot of a voxel's timeseries (matplotlib module is required) ========================================================================= Plotting is essential to get a 'feeling' for the data. The Matlab-style plotting via matplotlib_ make it really easy to plot something with (e.g. when running Python interactively via IPython_). Please note, that there are many other possibilities for plotting, e.g. R_ via RPy_ or Gnuplot_ via the `Gnuplot python bindings`_ .. _R: http://www.r-project.org .. _RPy: http://rpy.sourceforge.net However, using matplotlib is really easy. For this example we will plot the two timeseries from the previous example, i.e. the raw and the detrended one. First we import the pylab module: >>> import pylab as P Now we can easly plot both timeseries of the single voxel in our artifical image: >>> line1 = P.plot(nim.data[:, 0, 0, 0]) >>> line2 = P.plot(nim_detrended.data[:, 0, 0, 0,]) A `P.show()` call would render the plot on the screen. .. _Gnuplot python bindings: http://gnuplot-py.sourceforge.net .. _Gnuplot: http://www.gnuplot.info .. _IPython: http://ipython.scipy.org .. _matplotlib: http://matplotlib.sourceforge.net .. _Gnuplot demos: http://gnuplot.sourceforge.net/demo_4.3/index.html Show a slice of a 3d volume (Matplotlib module is required) =========================================================== This example demonstrates howto use the Matlab-style plotting of matplotlib_ to view a slice from a 3d volume. We will actually use a 4D image as data source and limit us to the first volume: >>> nim = NiftiImage('example4d') >>> volume = nim.data[0] If everything went fine, we can now view a slice (x,y): >>> xyplot = P.imshow(volume[16], ... interpolation='nearest', ... cmap=P.cm.gray) Again a call to the `P.show()` function would render the plot on the screen. When you want to have a look at a yz-slice, NumPy array magic comes into play. >>> yzplot = P.imshow(volume[::-1,:,18], ... interpolation='nearest', ... cmap=P.cm.gray) The ``::-1`` notation causes the z-axis to be flipped in the images. This makes a much nicer view, if the used example volume has the z-axis originally oriented upsidedown. Compute and display peristimulus signal timecourse of multiple conditions ========================================================================= Sometimes one wants to look at the signal timecourse of some voxel after a certain stimulation onset. An easy way would be to have some fMRI data viewer that displays a statistical map and one could click on some activated voxel and the peristimulus signal timecourse of some condition in that voxel would be displayed. This can easily be done by using ``pynifti_pst`` and ``FSLView``. ``pynifti_pst`` comes with a manpage that explains all options and arguments. Basically ``pynifti_pst`` needs a 4d image (e.g. an fMRI timeseries; possibly preprocessed/filtered) and some stimulus onset information. This information can either be given directly on the command line or is read from files. Additionally one can specify onsets as volume numbers or as onset times. ``pynifti_pst`` understands the FSL custom EV file format so one can easily use those files as input. An example call could look like this:: pynifti_pst --times --nvols 5 -p uf92.feat/filtered_func_data.nii.gz \ pst_cond_a.nii.gz uf92.feat/custom_timing_files/ev1.txt \ uf92.feat/custom_timing_files/ev2.txt This computes a peristimulus timeseries using the preprocessed fMRI from a FEAT output directory and two custom EV files that both together make up condition A. ``--times`` indicates that the EV files list onset times (not volume ids) and ``--nvols`` requests the mean peristimulus timecourse for 4 volumes after stimulus onset (5 including onset). ``-p`` recodes the peristimulus timeseries into percent signalchange, where the onset is always zero and any following value is the signal change with respect to the onset volume. .. figure:: pics/fslview_pst.png FSLView with ``pynifti_pst`` example. This call produces a simple 4d NIfTI image that can be loaded into FSLView as any other timeseries. The following call can be used to display an FSL zmap from the above results path on top of some anatomy. Additionally the peristimulus timeseries of two conditions are loaded. The figure shows how it could look like. One of the nice features of FSLView is that its timeseries window can remember selected curves, which can be useful to compare signal timecourses from different voxels (blue and green line in the figure). pynifti-0.20100607.1/doc/installation.txt0000664000175000017500000003656411414645202017546 0ustar michaelmichael.. -*- mode: rst -*- .. ex: set sts=4 ts=4 sw=4 et tw=79: ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### # # See COPYING file distributed along with the PyNIfTI package for the # copyright and license terms. # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### .. _installation: ************ Installation ************ It should be fairly easy to get PyNIfTI running on any system. For the most popular platforms and operating systems there are binary packages provided in the respective native packaging format (DEB, RPM or installers). On all other systems PyNIfTI has to be compiled from source -- which should also be pretty straightforward. Binary packages =============== .. _install_debian: GNU/Linux --------- PyNIfTI is available in recent versions of the Debian (since lenny) and Ubuntu (since gutsy in universe) distributions. The name of the binary package is ``python-nifti`` in both cases. * PyNIfTI `versions in Debian`_ * PyNIfTI `versions in Ubuntu`_ Binary packages for some additional Debian and (K)Ubuntu versions are also available. Please visit `Michael Hanke's APT repository`_ to read about how you have to setup your system to retrieve the PyNIfTI package via your package manager and stay in sync with future releases. If you are using Debian lenny (or later) or Ubuntu gutsy (or later) or you have configured your system for `Michael Hanke's APT repository`_ all you have to do to install PyNIfTI is this:: apt-get update apt-get install python-nifti This should pull all necessary dependencies. If it doesn't, it's a bug that should be reported. .. _versions in Debian: http://packages.debian.org/python-nifti .. _versions in Ubuntu: http://packages.ubuntu.com/python-nifti .. _Michael Hanke's APT repository: http://apsy.gse.uni-magdeburg.de/main/index.psp?page=hanke/debian&lang=en&sec=1 .. _install_rpm: Additionally, there are binary packages for several RPM-based distributions, provided through the `OpenSUSE Build Service`_. To install one of these packages first download it from the `OpenSUSE software website`_. Please note, that this site does not only offer OpenSUSE packages, but also binaries for other distributions, including: CentOS 5, Fedora 9-10, Mandriva 2007-2008, RedHat Enterprise Linux 5, SUSE Linux Enterprise 10, OpenSUSE 10.2 up to 11.0. Once downloaded, open a console and invoke (the example command refers to PyMVPA 0.3.1):: rpm -i python-nifti-0.20080710.1-4.1.i386.rpm The OpenSUSE website also offers `1-click-installations`_ for distributions supporting it. A more convenient way to install PyNIfTI and automatically receive software updates is to included one of the `RPM-package repositories`_ in the system's package management configuration. For e.g. OpenSUSE 11.0, simply use Yast to add another repository, using the following URL: http://download.opensuse.org/repositories/home:/hankem/openSUSE_11.0/ For other distributions use the respective package managers (e.g. Yum) to setup the repository URL. The repositories include all core dependencies of PyNIfTI, if they are not available from other repositories of the respective distribution. There are two different repository groups, one for `Suse and Mandriva-related packages`_ and another one for `Fedora, Redhat and CentOS-related packages`_. .. _Suse and Mandriva-related packages: http://download.opensuse.org/repositories/home:/hankem/ .. _Fedora, Redhat and CentOS-related packages: http://download.opensuse.org/repositories/home://hankem://rh5/ .. _1-click-installations: http://software.opensuse.org/search?baseproject=ALL&p=1&q=python-nifti .. _OpenSUSE software website: http://software.opensuse.org/search?baseproject=ALL&p=1&q=python-nifti .. _OpenSUSE Build Service: https://build.opensuse.org/ .. _install_win: Windows ------- A binary installer for a recent Python version is available from the nifticlibs Sourceforge_ project site. There are a few Python distributions for Windows. In theory all of them should work equally well. However, I only tested the standard Python distribution from www.python.org (with version 2.5.2). First you need to download and install Python. Use the Python installer for this job. Yo do not need to install the Python test suite and utility scripts. From now on we will assume that Python was installed in `C:\\Python25` and that this directory has been added to the `PATH` environment variable. In addition you'll need NumPy_. Download a matching NumPy windows installer for your Python version (in this case 2.5) from the `SciPy download page`_ and install it. PyNIfTI does not come with the required `zlib` library, so you also need to download and install it. A binary installer is available from the `GnuWin32 project`_. Install it in some arbitrary folder (just the binaries nothing else), find the `zlib1.dll` file in the `bin` subdirectory and move it in the Windows `system32` directory. Now, you can use the PyNIfTI windows installer to install PyNIfTI on your system. As always: click *Next* as long as necessary and finally *Finish*. If done, verify that everything went fine by opening a command promt and start Python by typing `python` and hit enter. Now you should see the Python prompt. Import the nifti module, which should cause no error messages:: >>> import nifti >>> .. _SciPy download page: http://scipy.org/Download .. _NIfTI libraries: http://niftilib.sourceforge.net/ .. _GnuWin32 project: http://gnuwin32.sourceforge.net/ .. _install_macos: MacOS X ------- The easiest installation method for OSX is via MacPorts_. MacPorts is a package management system for MacOS, which is in some respects very similiar to RPM or APT which are used in most GNU/Linux distributions. However, rather than installing binary packages, it compiles software from source on the target machine. *The MacPort of PyNIfTI is kindly maintained by James Kyle .* .. _MacPorts: http://www.macports.org In the context of PyNIfTI MacPorts is much easier to handle than the previously available installer for Macs. Although the initial overhead to setup MacPorts on a machine is higher than simply installing PyNIfTI using the former installer, MacPorts saves the user a significant amount of time (in the long run). This is due to the fact that this framework will not only take care of updating a PyNIfTI installation automatically whenever a new release is available. It will also provide many of the optional dependencies of PyNIfTI (e.g. NumPy_, nifticlibs) in the same environment and therefore abolishes the need to manually check dozens of websites for updates and deal with an unbelievable number of different installation methods. MacPorts provides a universal binary package installer that is downloadable at http://www.macports.org/install.php After downloading, simply mount the dmg image and double click `MacPorts.pkg`. By default, MacPorts installs to `/opt/local`. After the installation is completed, you must ensure that your paths are set up correctly in order to access the programs and utilities installed by MacPorts. For exhaustive details on editing shell paths please see: http://www.debian.org/doc/manuals/reference/ch-install.en.html#s-bashconf A typical `.bash_profile` set up for MacPorts might look like:: > export PATH=/opt/local/bin:/opt/local/sbin:$PATH > export DYLD_LIBRARY_PATH=/opt/local/lib:$DYLD_LIBRARY_PATH Be sure to source your .bash_profile or close Terminal.app and reopen it for these changes to take effect. Once MacPorts is installed and your environment is properly configured, PyNIfTI is installed using a single command:: > $ sudo port install py25-pynifti If this is your first time using MacPorts Python 2.5 will be automatically installed for you. However, an additional step is needed:: $ sudo port install python_select $ sudo python_select python25 MacPorts has the ability of installing several Python versions at a time, the `python_select` utility ensures that the default Python (located at `/opt/local/bin/python`) points to your preferred version. Upon success, open a terminal window and start Python by typing `python` and hit return. Now try to import the PyNIfTI module by doing: >>> import nifti >>> If no error messages appear, you have succesfully installed PyNIfTI. .. _requirements: .. _buildfromsource: Compile from source =================== If no binary packages are provided for your platfom, you can build PyNIfTI from source. It needs a few things to build and run properly: * Python_ 2.4 or greater * NumPy_ * SWIG_ 1.3.29 (or later) * `NIfTI C libraries`_ Proper developer packages are prefered, but for convenience reasons a minimal copy is included in the PyNIfTI source package. .. _NumPy: http://numpy.scipy.org .. _SWIG: http://www.swig.org Get the sources --------------- Since June 2007 PyNIfTI is part of the niftilibs_ family. The source code of PyNIfTI releases can be obtained from the corresponding Sourceforge_ project site. Alternatively, one can also download a tarball of the latest development snapshot_ (i.e. the current state of the *master* branch of the PyNIfTI source code repository). .. _Sourceforge: http://sourceforge.net/ .. _snapshot: http://git.debian.org/?p=pkg-exppsy/pynifti.git;a=snapshot;h=refs/heads/master;sf=tgz If you want to have access to both, the full PyNIfTI history and the latest development code, you can use the PyNIfTI Git_ repository on the Alioth_ server, a service kindly provided by the `Debian project`_. To view the repository, please point your web browser to gitweb: http://git.debian.org/?p=pkg-exppsy/pynifti.git The gitweb browser also allows to download arbitrary development snapshots of PyNIfTI. For a full clone (aka checkout) of the PyNIfTI repository simply do:: git clone http://git.debian.org/git/pkg-exppsy/pynifti.git .. _niftilibs: http://niftilib.sourceforge.net .. _Git: http://git.or.cz .. _Alioth: http://alioth.debian.org .. _Debian project: http://www.debian.org Compiling: General instructions ------------------------------- Make sure that the compiled nifticlibs and the corresponding headers are available to your compiler. If they are located in a custom directory, you might have to specify ``--include-dirs`` and ``--library-dirs`` options to the build command below. In case, you want to build and use the nifticlibs copy that is shipped with PyNIfTI, this is automatically done for you. Once you have downloaded the sources, extract the tarball and enter the root directory of the extracted sources. If you *do not* have the nifticlibs installed, run:: make in the root of the extracted source tarball. If you have system-wide installed nifticlibs available on your system, instead simply do:: python setup.py build That should build the SWIG wrappers. If this has been done successfully, all you need to do is install the modules by invoking:: sudo python setup.py install If sudo is not configured (or even installed) you might have to use ``su`` instead. Now fire up Python and try importing the module to see if everything is fine. It should look similar to this:: Python 2.4.4 (#2, Oct 20 2006, 00:23:25) [GCC 4.1.2 20061015 (prerelease) (Debian 4.1.1-16.1)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import nifti >>> .. _Python: http://www.python.org .. _NIfTI C libraries: http://niftilib.sourceforge.net Building on Windows Systems --------------------------- On Windows the whole situation is a little more tricky, as the system doesn't come with a compiler by default. Nevertheless, it is easily possible to build PyNIfTI from source. One could use the Microsoft compiler that comes with Visual Studio to do it, but as this is commercial software and not everybody has access to it, I will outline a way that exclusively involves free and open source software. First one needs to install the Python_ and NumPy_, if not done yet. Please refer to the installation intructions for the Windows binary package below. Next we need to obtain and install the MinGW compiler collection. Download the *Automated MinGW Installer* from the `MinGW project website`_. Now, run it and choose to install the `current` package. You will need the *MinGW base tools*, *gcc* **and** *g++* compiler and *MinGW Make*. For the remaining parts of the section, we will assume that MinGW got installed in `C:\\MinGW` and the directory `C:\\MinGW\\bin` has been added to the `PATH` environment variable, to be able to easily access all MinGW tools. Note, that it is not necessary to install `MSYS`_ to build PyNIfTI, but it might handy to have it. In addition, PyNIfTI needs the developer version of the `zlib` library, so you also need to download and install it. A binary installer is available from the `GnuWin32 project`_. It is best to install it into the same directory as MinGW (i.e. `C:\\MinGW` in this example), as all paths will be automatically configured properly. You also need to download SWIG_ (actually *swigwin*, the distribution for Windows). SWIG does not have to be installed, just unzip the file you downloaded and add the root directory of the extracted sources to the `PATH` environment variable (make sure that this directory contains `swig.exe`, if not, you haven't downloaded `swigwin`). Now, we are ready to build PyNIfTI. The easiest way to do this, is to make use of the `Makefile.win` that is shipped with PyNIfTI to build a binary installer package (`.exe`). Make sure, that the settings at the top of `Makefile.win` (the file is located in the root directory of the source distribution) correspond to your Python installation -- if not, first adjust them accordingly before your proceed. When everything is set, do:: mingw32-make -f Makefile.win installer Upon success you can find the installer in the `dist` subdirectory. Install it as described below. .. _MinGW project website: http://www.mingw.org/ .. _MSYS: http://www.mingw.org/msys.shtml MacOS X ------- Since the MacPorts_ system basically compiles from source there should be no need to perform this step manually. However, if one intends to compile without MacPorts_ the `XCode developer tools`_, have to be installed first, as the operating system does not come with a compiler by default. If you want to use or even work on the latest development code, you should also install Git_. There is a `MacOS installer for Git`_, that make this step very easy. .. _XCode developer tools: http://developer.apple.com/tools/xcode/ .. _MacOS installer for Git: http://code.google.com/p/git-osx-installer/ Otherwise follow the :ref:`general build instructions `. MacOS X and MacPython --------------------- When you are comiling PyNIfTI on MacOS X and want to use it with MacPython, please make sure that the NIfTI C libraries are compiled as fat binaries (compiled for both *ppc* and *i386*). Otherwise PyNIfTI extensions will not compile. One can achieve this by adding both architectures to the ``CFLAGS`` definition in the toplevel Makefile of the NIfTI C library source code or in the file `3rd/nifticlibs/Makefile` if you are using the nifticlibs copy that is shipped with the PyNIfTI sources. Like this:: CFLAGS=-Wall -O2 -I. -DHAVE_ZLIB -arch ppc -arch i386 Troubleshooting =============== If you get an error when importing the ``nifti`` module in Python complaining about missing symbols your niftiio library contains references to some unresolved symbols. Try adding ``znzlib`` and ``zlib`` to the linker options the PyNIfTI ``setup.py``, like this:: libraries = [ 'niftiio', 'znz', 'z' ], pynifti-0.20100607.1/doc/intro.txt0000664000175000017500000001524511414645202016171 0ustar michaelmichael.. -*- mode: rst -*- .. ex: set sts=4 ts=4 sw=4 et tw=79: ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### # # See COPYING file distributed along with the PyNIfTI package for the # copyright and license terms. # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### .. _intro: ********************************************* What is NIfTI and what do I need PyNIfTI for? ********************************************* NIfTI ===== NIfTI_ is a new Analyze-style data format, proposed by the `NIfTI Data Format Working Group`_ as a *"short-term measure to facilitate inter-operation of functional MRI data analysis software packages"*. Meanwhile a number of toolkits are NIfTI-aware (e.g. FSL, AFNI, SPM, Freesurfer and a to a certain degree also Brainvoyager). Additionally, dicomnifti_ allows the direct conversion from DICOM images into the NIfTI format. With libnifti_ there is a reference implementation of a C library to read, write and manipulate NIfTI images. The library source code is put into the public domain and a corresponding project is hosted at SourceForge_. In addition to the C library, there is also an IO library written in Java and Matlab functions to make use of NIfTI files from within Matlab. .. _NIfTI: http://nifti.nimh.nih.gov .. _NIfTI Data Format Working Group: http://nifti.nimh.nih.gov/dfwg/beyond-nifti-1 .. _dicomnifti: http://cbi.nyu.edu/software/dinifti.php .. _libnifti: http://niftilib.sf.net/niftilib_overview.html .. _SourceForge: http://sourceforge.net/projects/niftilib Python ====== Unfortunately, it is not that trivial to read NIfTI images with Python. This is particularly sad, because there is a large number of easy-to-use, high-quality libraries for signal processing available for Python (e.g. SciPy). Moreover Python has bindings to almost any important language/program in the fields of maths, statistics and/or engineering. If you want to use R_ to calculate some stats in a Python script, simply use RPy_ and pass any data to R. If you don't care about R, but Matlab is your one and only friend, there are at least two different Python modules to control Matlab from within Python scripts. Python is the glue between all those helpers and the Python user is able to combine as many tools as necessary to solve a given problem -- the easiest way. .. _R: http://www.r-project.org .. _RPy: http://rpy.sourceforge.net/ PyNIfTI ======= PyNIfTI aims to provide easy access to NIfTI images from within Python. It uses SWIG_-generated wrappers for the NIfTI reference library and provides the :class:`~nifti.image.NiftiImage` class for Python-style access to the image data. While PyNIfTI is not yet complete (i.e. doesn't support everything the C library can do), it already provides access to the most important features of the NIfTI-1 data format and *libniftiio* capabilities. The following features are currently implemented: * PyNIfTI can read and write any file format supported by libniftiio. This includes NIfTI (single and pairs) as well as ANALYZE files, both also in gzipped versions. * PyNIfTI provides fast and convenient access to the image data via NumPy_ arrays. This should enable users to process image data with most (if not all) numerical routines available for Python. The NumPy array automatically uses a datatype corresponding to the NIfTI image data -- no unnecessary upcasting is performed. * PyNIfTI provides full read and write access to the NIfTI header data. Header information can be exported to a Python dictionary and can also be updated by using information from a dictionary. * Besides accessing NIfTI data from files, PyNIfTI is able to create NIfTI images from NumPy arrays. The appropriate NIfTI header information is determined from the array properties. Additional header information can be optionally specified -- making it easy to clone NIfTI images if necessary, but with minor modifications. * Most properties of NIfTI images are accessible via attributes and/or accessor functions of the :class:`~nifti.image.NiftiImage`. Inter-dependent properties are automatically updated if necessary (e.g. modifying the Q-Form matrix also updates the pixdim properties and quaternion representation). * All properties are accessible via Python-style datatypes: A 4x4 matrix is an array not 16 individual numbers. * PyNIfTI should be resonably fast. Image data will only be loaded into the memory if necessary. Simply opening a NIfTI file to access some header data is performed with virtually no delay independent of the size of the image. Unless image resizing or datatype conversion must be performed the image data can be shared by the NIfTI image and accessing NumPy arrays, and therefore memory won't be wasted memory with redundant copies of the image data. * Additionally PyNIfTI can access uncompressed NIfTI or ANALYZE files by providing memory-mapped access to them via NumPy's memmap arrays. In this mode it is possible to modified existing files of any size without having to load them in memory first. * PyNIfTI allows to embed arbitrary additional information into the NIfTI file header. .. _SWIG: http://www.swig.org .. _NumPy: http://numpy.scipy.org Scripts ======= Some functions provided by PyNIfTI also might be useful outside the Python environment and it might be useful to export them via some command line scripts. Currently there is only one: ``pynifti_pst`` (pst: peristimulus timecourse). Using this script one can compute the signal timecourse for a certain condition for all voxels in a volume at once. Although it is done by simply averaging the timecourses of the involved events (nothing fancy), this might nevertheless be useful for exploring a dataset and accompanies similar tools like FSL's ``tsplot``. The output of ``pynifti_pst`` can be loaded into FSLView to simultaneously look at statistics and signal timecourses. Please see the corresponding example below. Known issues ============ PyNIfTI currently ignores the origin field of ANALYZE files - it is neither read nor written. A possible workaround is to convert ANALYZE files into the NIfTI format using FSL's ``fslchfiletype``. Things to know ============== When accessing NIfTI image data through NumPy arrays the order of the dimensions is reversed. If the *x, y, z, t* dimensions of a NIfTI image are 64, 64, 32, 456 (as for example reported by ``nifti_tool``), the shape of the NumPy array (e.g. as returned by ``NiftiImage.data``) will be: 456, 32, 64, 64. This is done to be able to slice the data array much easier in the most common cases. For example, if you are interested in a certain volume of a timeseries it is much easier to write ``data[2]`` instead of ``data[:,:,:,2]``, right? pynifti-0.20100607.1/doc/_static/0000775000175000017500000000000011414646040015715 5ustar michaelmichaelpynifti-0.20100607.1/doc/_static/pynifti.css0000664000175000017500000002053211414645202020112 0ustar michaelmichael/** * PyNIfTI stylesheet derived from: * * Alternate Sphinx design * Originally created by Armin Ronacher for Werkzeug, adapted by Georg Brandl. */ #header { margin: 0px; background-color: #335; line-height: 120%; color: #fff; font-weight: bold; font-size: 200%; border-bottom: 5px solid #822; padding-left: 10px; padding-bottom: 0.5em; padding-top: 1em; text-align: left; } body { font-family: Arial, Helvetica, sans-serif; letter-spacing: -0.01em; line-height: 150%; text-align: center; /*background-color: #AFC1C4; */ background-color: #ccc; color: black; padding: 0; border: 1px solid #aaa; margin: 0px 40px 0px 40px; min-width: 740px; } pre { font-family: 'Consolas', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.015em; padding: 0.5em; border: 1px solid #ccc; background-color: #f8f8f8; } td.linenos pre { padding: 0; border: 0; background-color: transparent; color: #aaa; } table.highlighttable { margin-left: 0.5em; } table.highlighttable td { padding: 0 0.5em 0 0.5em; } cite, code, tt { font-family: 'Consolas', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em; } hr { border: 1px solid #abc; margin: 2em; } tt { background-color: #f2f2f2; border-bottom: 1px solid #ddd; color: #333; } tt.descname { background-color: transparent; font-weight: bold; font-size: 1.2em; border: 0; } tt.descclassname { background-color: transparent; border: 0; } tt.xref { background-color: transparent; font-weight: bold; border: 0; } tt.xref.docutils.literal { color: #822; } a tt { background-color: transparent; font-weight: bold; border: 0; color: #CA7900; } a tt:hover { color: #2491CF; } dl { margin-bottom: 15px; } dd p { margin-top: 0px; } dd ul, dd table { margin-bottom: 10px; } dd { margin-top: 3px; margin-bottom: 10px; margin-left: 30px; } .refcount { color: #060; } dt:target, .highlight { background-color: #fbe54e; } dl.glossary dt { font-weight: bold; font-size: 1.1em; } pre { line-height: 120%; } pre a { color: inherit; text-decoration: underline; } div.document { background-color: white; text-align: left; background-image: url(contents.png); background-repeat: repeat-x; } /* div.documentwrapper { width: 100%; } */ div.clearer { clear: both; } div.related h3 { display: none; } div.related ul { background-image: url(navigation.png); height: 2em; list-style: none; border-top: 1px solid #ddd; border-bottom: 1px solid #ddd; margin: 0; padding-left: 10px; } div.related ul li { margin: 0; padding: 0; height: 2em; float: left; } div.related ul li.right { float: right; margin-right: 5px; } div.related ul li a { margin: 0; padding: 0 5px 0 5px; line-height: 1.75em; color: #335; border: 1px solid transparent; } div.related ul li a:hover { border: 1px solid #666; } div.body { margin: 0; padding: 0; } div.bodywrapper { margin: 0 240px 0 0; padding: 0.5em 20px 20px 20px; border-right: 1px solid #ccc; } div.body a { text-decoration: underline; } div.sidebar, div.sphinxsidebar { margin: 0; padding: 0.5em 15px 15px 0; width: 210px; float: right; text-align: left; /* margin-left: -100%; */ } div.sidebar h4, div.sidebar h3, div.sphinxsidebar h4, div.sphinxsidebar h3 { margin: 1em 0 0.5em 0; font-size: 0.9em; padding: 0.1em 0 0.1em 0.5em; color: white; border: 1px solid #86989B; background-color: #335; } div.sphinxsidebar h3 a { color: white; } div.sidebar ul, div.sphinxsidebar ul { padding-left: 1.5em; margin-top: 7px; list-style: none; padding: 0; line-height: 130%; } div.sidebar ul ul, div.sphinxsidebar ul ul { list-style: square; margin-left: 20px; font-size: 0.95em; margin-left: 20px; } p { margin: 0.8em 0 0.5em 0; } h1 { color: #335; font-size: 130%; font-weight: bold; padding-top: 6px; padding-bottom: 2px; border-bottom: 1px dashed silver; } h2 { margin: 1.3em 0 0.2em 0; font-size: 110%; padding: 0; color: #733; } h3 { margin: 1em 0 -0.3em 0; font-size: 100%; font-weight: bold; } h3::before { content: url(item.png); padding-right: 5px; } h4 { color: #335; } /* h1 a, h2 a, h3 a, h4 a, h5 a, h6 a { color: black!important; } */ h1 a.anchor, h2 a.anchor, h3 a.anchor, h4 a.anchor, h5 a.anchor, h6 a.anchor { display: none; margin: 0 0 0 0.3em; padding: 0 0.2em 0 0.2em; color: #aaa!important; } h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor, h5:hover a.anchor, h6:hover a.anchor { display: inline; } h1 a.anchor:hover, h2 a.anchor:hover, h3 a.anchor:hover, h4 a.anchor:hover, h5 a.anchor:hover, h6 a.anchor:hover { color: #777; background-color: #eee; } table { border-collapse: collapse; margin: 0 -0.5em 0 -0.5em; } table td, table th { padding: 0.2em 0.5em 0.2em 0.5em; } div.footer { background-color: #999; color: #666; padding: 3px 8px 3px 0; clear: both; font-size: 0.8em; text-align: right; } div.footer a { color: #86989B; text-decoration: underline; } div.pagination { margin-top: 2em; padding-top: 0.5em; border-top: 1px solid black; text-align: center; } div.sphinxsidebar ul.toc { margin: 1em 0 1em 0; padding: 0 0 0 0.5em; list-style: none; } div.sphinxsidebar ul.toc li { margin: 0.5em 0 0.5em 0; font-size: 0.9em; line-height: 130%; } div.sphinxsidebar ul.toc li p { margin: 0; padding: 0; } div.sphinxsidebar ul.toc ul { margin: 0.2em 0 0.2em 0; padding: 0 0 0 1.8em; } div.sphinxsidebar ul.toc ul li { padding: 0; } div.admonition, div.warning { font-size: 0.9em; margin: 1em 0 0 0; border: 1px solid #86989B; background-color: #f7f7f7; } div.admonition p, div.warning p { margin: 0.5em 1em 0.5em 1em; padding: 0; } div.admonition pre, div.warning pre { margin: 0.4em 1em 0.4em 1em; } div.admonition p.admonition-title, div.warning p.admonition-title { margin: 0; padding: 0.1em 0 0.1em 0.5em; color: white; border-bottom: 1px solid #86989B; font-weight: bold; background-color: #596DA2; } div.warning { border: 1px solid #940000; } div.warning p.admonition-title { background-color: #CF0000; border-bottom-color: #940000; } div.admonition ul, div.admonition ol, div.warning ul, div.warning ol { margin: 0.1em 0.5em 0.5em 3em; padding: 0; } div.versioninfo { margin: 1em 0 0 0; border: 1px solid #ccc; background-color: #DDEAF0; padding: 8px; line-height: 1.3em; font-size: 0.9em; } a.headerlink { color: #c60f0f!important; font-size: 1em; margin-left: 6px; padding: 0 4px 0 4px; text-decoration: none!important; visibility: hidden; } h1:hover > a.headerlink, h2:hover > a.headerlink, h3:hover > a.headerlink, h4:hover > a.headerlink, h5:hover > a.headerlink, h6:hover > a.headerlink, dt:hover > a.headerlink { visibility: visible; } a.headerlink:hover { background-color: #ccc; color: white!important; } table.indextable td { text-align: left; vertical-align: top; } table.indextable dl, table.indextable dd { margin-top: 0; margin-bottom: 0; } table.indextable tr.pcap { height: 10px; } table.indextable tr.cap { margin-top: 10px; background-color: #f2f2f2; } img.toggler { margin-right: 3px; margin-top: 3px; cursor: pointer; } form.pfform { margin: 10px 0 20px 0; } table.contentstable { width: 90%; } table.contentstable p.biglink { line-height: 150%; } a.biglink { font-size: 1.3em; } span.linkdescr { font-style: italic; padding-top: 5px; font-size: 90%; } ul.search { margin: 10px 0 0 20px; padding: 0; } ul.search li { padding: 5px 0 5px 20px; background-image: url(file.png); background-repeat: no-repeat; background-position: 0 7px; } ul.search li a { font-weight: bold; } ul.search li div.context { color: #888; margin: 2px 0 0 30px; text-align: left; } ul.keywordmatches li.goodmatch a { font-weight: bold; } pynifti-0.20100607.1/doc/_static/item.png0000644000175000017500000000057211142610321017352 0ustar michaelmichaelPNG  IHDR 2ϽsRGB4IDATM+q # # This is free software; you can redistribute it and/or # modify it under the terms of the MIT License. # # This package is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the COPYING # file that comes with this package for more details. # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ## import os, sys from optparse import OptionParser import nifti.utils import numpy as N def loadEVFile( filename ): try: file = open( filename ) except IOError: raise ValueError, "Cannot open EV file '%s'" % filename onsets = [] # split each line and ignore empty lines for line in file: e = line.split() if len(e): onsets.append( float( e[0] ) ) return onsets def checkCmdLine(args, opts, min_args): if len(args) < min_args: raise RuntimeError, \ "%s: error: Incorrect number of arguments " \ "(supplied %i, needed %i)." % (sys.argv[0], len(args), min_args) def main(): parser = OptionParser( \ usage="%prog [options] <4dimage> [...]", \ version="%prog " + nifti.__version__, description="""\ %prog computes the peristimulus signal timecourse for all voxels in a volume at once. Stimulus onsets can be specified as volume numbers or times (will be converted into volume numbers using a supplied repetition time). Onsets can be specified directly on the command line, but can also be read from (multiple) files. Such file are assumed to list one onset per line (as the first value). Empty lines are ignored. This enables %prog to use e.g. FSL's custom EV files. If several files are specified, the read onsets are combined to a single onset vector. %prog writes a 4d timeseries image as output. This image can e.g. be loaded into FSLView to look at each voxels signal timecourse in a certain condition by simply clicking on it. """ ) # define options parser.add_option('--verbose', action='store_true', dest='verbose', default=False, help='print status messages') parser.add_option('-n', '--nvols', action='store', dest='nvols', default=10, type="int", help="""\ Set the length of the computed peristimulus signal timecourse (in volumes). Default: 10 """ ) parser.add_option('-t', '--times', action='store_true', dest='times', default=False, help="""\ If supplied, the read values are treated as onset times and will be converted to volume numbers. For each onset the volume that is closest in time will be selected. Volumes are assumed to be recorded exactly (and completely) after tr/2, e.g. if 'tr' is 2 secs the first volume is recorded at exactly one second. Please see the --tr and --offset options to learn how to adjust the conversion. """ ) parser.add_option('--tr', action='store', dest='tr', default=None, type="float", help="""\ Repetition time of the 4d image (temporal difference of two successive volumes). This can be used to override the setting in the 4d image. The repetition time is necessary to convert onset times into volume numbers. If the '--times' option is not set this value has no effect. Please note that repetitions time and the supplied onsets have to be in the same unit. Please note, that if --times is given the tr has to be specified in the same unit as the read onset times. """ ) parser.add_option('--offset', dest='offset', action='store', default=0.0, type='float', help="""\ Constant offset applied to the onsets times when converting them to volume numbers. Without setting '--times' this option has no effect'. """ ) parser.add_option('-p', '--percsigchg', action='store_true', dest='perc_sig_chg', default=False, help="""\ Convert the computed timecourse to percent signal change relative to the first (onset) volume. This might not be meaningful when --operation is set to something different than 'mean'. Please note, that the shape of the computes timeseries heavily depends on the first average volume. It might be more meaningful to use a real baseline condition as origin. However, this is not supported yet. Default: False """ ) parser.add_option('--printvoxel', action='store', dest='printvoxel', default=None, help="""\ Print the peristimulus timeseries of a single voxel for all onsets separately. This will print a matrix (onsets x time), where the number of columns is identical to the value of --nvols and the number of rows corresponds to the number of specified onsets. (e.g. 'z,y,x') """ ) parser.add_option('--operation', action='store', dest='operation', default='mean', help="""\ Choose the math operation that is performed to compute the peristimulus timeseries. By default this is the mean across all stimulations ('mean'). Other possibilities are the standard deviation ('std') and standard error ('sde'). """ ) # parse options (opts, args) = parser.parse_args() # read sys.argv[1:] by default try: checkCmdLine( args, opts, 3 ) except: print sys.exc_info()[1] sys.exit( 1 ) if opts.verbose: print "Read 4d image '%s'" % args[0] nimg = nifti.NiftiImage( args[0] ) if not nimg.timepoints > 1: print "%s: error: Need 4d image as input. " \ "Supplied image only has one volume." \ % sys.argv[0] sys.exit( 1 ) # determine the requested function for timeseries calculation if opts.operation == 'mean': pst_fx = N.mean elif opts.operation == 'std' or opts.operation == 'sde': pst_fx = N.std else: print "'%s' is not a supported operation." % opts.operation sys.exit(1) outfilename = args[1] if opts.verbose: print "Output will be written to '%s'" % outfilename if opts.tr: tr = opts.tr if opts.verbose: print "Using provide repetition time: %f" % tr else: tr = nimg.rtime if opts.verbose: print "Using repetition from 4d image: %f" % tr onsets = [] for src in args[2:]: if os.path.isfile( src ): if opts.verbose: print "Reading values from '%s'" % src onsets += loadEVFile( src ) else: try: onsets.append( float( src ) ) except ValueError: print "%s: error: '%s' cannot be converted into a " \ "floating-point value" % (sys.argv[0], src) sys.exit( 1 ) if opts.times: if opts.verbose: print "Convert supplied onset times into volumes " \ "(tr: %f, offset: %f)" % (tr, opts.offset) onsetvols = nifti.utils.time2vol( onsets, tr, opts.offset, decimals = 0 ).astype('int') else: if opts.verbose: print "Verify onset volume numbers" onsetvols = [ int(i) for i in onsets ] if opts.verbose: print "Selected volumes (index starts at zero!):\n" + ', '.join([ str(o) for o in onsetvols]) if opts.verbose: print "Compute mean peristimulus signal timecourse " \ "(length: %i volumes)" % opts.nvols if opts.printvoxel: # get timeseries for each onset pst = nifti.utils.getPeristimulusTimeseries( nimg, onsetvols, opts.nvols, tuple ).copy() # make matrix ( onset x time ) voxel_pst = eval('pst[:,:,' + opts.printvoxel +'].T') for onset in voxel_pst: for t in onset: print t, print '' if opts.verbose: print "Compute peristimulus timeseries" pst = nifti.utils.getPeristimulusTimeseries( nimg, onsetvols, opts.nvols, pst_fx ).copy() # divide by srqt of number of stimulations if standard error is requested if opts.operation == 'sde': pst /= N.sqrt( len(onsetvols) ) if opts.perc_sig_chg: if opts.verbose: print "Convert to percent signal change" baseline = nifti.utils.getPeristimulusTimeseries( nimg, onsetvols, 1, N.mean )[0].copy() if opts.operation == 'mean': pst -= baseline # only divide if baseline is different from zero pst[:,baseline != 0] /= baseline[baseline != 0] pst *= 100.0 if opts.verbose: print "Write output" onimg = nifti.NiftiImage(pst,nimg.header) onimg.save( outfilename ) if opts.verbose: print "Done" if __name__ == "__main__": main() pynifti-0.20100607.1/3rd/0000775000175000017500000000000011414646040014212 5ustar michaelmichaelpynifti-0.20100607.1/3rd/nifticlibs/0000775000175000017500000000000011414646040016340 5ustar michaelmichaelpynifti-0.20100607.1/3rd/nifticlibs/Makefile0000664000175000017500000000103111414645202017772 0ustar michaelmichael# Minimalistic makefile for libnifti LIB=libniftiio.a libznz.a MISC=nifti1_io.c znzlib.c LIBFLAGS=-fPIC CFLAGS=-Wall -O2 -I. -DHAVE_ZLIB # Use the below CFLAGS on OSX # CFLAGS=-Wall -O2 -I. -DHAVE_ZLIB -arch i386 -arch ppc TDIR=../../build/nifticlibs all: prep $(LIB) prep: prep-stamp prep-stamp: mkdir -p $(TDIR) touch $@ .c.o: gcc $(CFLAGS) $(LIBFLAGS) -c $^ -o $(TDIR)/$(^:.c=.o) libniftiio.a: nifti1_io.o ar curs $(TDIR)/$@ $(TDIR)/$^ libznz.a: znzlib.o ar curs $(TDIR)/$@ $(TDIR)/$^ clean: rm -rf $(TDIR) rm *-stamp pynifti-0.20100607.1/3rd/nifticlibs/README0000664000175000017500000000442411414645202017223 0ustar michaelmichael Nifti-1 C libraries ------------------- Version 1.1.0 beta release Aug 2008 Version 1.0.0 beta release Dec 2007 Version 0.6 beta release Aug 2007 Version 0.5 beta release May 2007 Version 0.4 beta release Sept. 2006 Version 0.3 beta release April 2006 Version 0.2 beta release August 12, 2005 Version 0.1 beta release March 11, 2005 niftilib code is released into the public domain. Library directories ------------------- znzlib -- low level library for handling read/write of compressed files. niftilib -- core i/o routines for reading and writing nifti-1 format files. Primarily routines to read/write and manipulate the header field information, including orientation matrices. Volume-wise, timecourse-wise, access to image data. nifticdf -- functions to compute cumulative distributions and their inverses fsliolib -- i/o routines for reading and writing nifti-1 format files, higher level than niftilib, includes routines for reading the data blob by volume, timecourse, etc., and, addresses image orientation issues. *** work in progress, subject to significant revision..... utils -- directory containing library utility programs (nifti_tool) Destination directories ----------------------- bin -- destination directory for installed programs include -- destination directory for library header files lib -- destination directory for compiled libraries docs -- destination directory Doxygen html (created via "make doc") Example directories ------------------- examples -- directory containing sample code using nifti reference library real_easy -- code snippets to read nifti-1 files, not using nifti ref. lib. Other directories ----------------- Testing -- directory containing code to test the libraries packaging -- spec file for building RPMs, and template package description for Dev-Cpp (http://www.bloodshed.net/devcpp.html) Instructions to build --------------------- command -- "make all" results will be left in the directories: bin/ include/ lib/ command -- "make help" will show more build options For more information -------------------- See the niftilib webpage at http://niftilib.sourceforge.net/ See the NIFTI webpage at http://nifti.nimh.nih.gov/ pynifti-0.20100607.1/3rd/nifticlibs/nifti1_io.h0000664000175000017500000006011211414645202020371 0ustar michaelmichael/** \file nifti1_io.h \brief Data structures for using nifti1_io API. - Written by Bob Cox, SSCC NIMH - Revisions by Rick Reynolds, SSCC NIMH */ #ifndef _NIFTI_IO_HEADER_ #define _NIFTI_IO_HEADER_ #include #include #include #include #include #ifndef DONT_INCLUDE_ANALYZE_STRUCT #define DONT_INCLUDE_ANALYZE_STRUCT /*** not needed herein ***/ #endif #include "nifti1.h" /*** NIFTI-1 header specification ***/ #include /*=================*/ #ifdef __cplusplus extern "C" { #endif /*=================*/ /*****===================================================================*****/ /***** File nifti1_io.h == Declarations for nifti1_io.c *****/ /*****...................................................................*****/ /***** This code is released to the public domain. *****/ /*****...................................................................*****/ /***** Author: Robert W Cox, SSCC/DIRP/NIMH/NIH/DHHS/USA/EARTH *****/ /***** Date: August 2003 *****/ /*****...................................................................*****/ /***** Neither the National Institutes of Health (NIH), nor any of its *****/ /***** employees imply any warranty of usefulness of this software for *****/ /***** any purpose, and do not assume any liability for damages, *****/ /***** incidental or otherwise, caused by any use of this document. *****/ /*****===================================================================*****/ /* Modified by: Mark Jenkinson (FMRIB Centre, University of Oxford, UK) Date: July/August 2004 Mainly adding low-level IO and changing things to allow gzipped files to be read and written Full backwards compatability should have been maintained Modified by: Rick Reynolds (SSCC/DIRP/NIMH, National Institutes of Health) Date: December 2004 Modified and added many routines for I/O. */ /********************** Some sample data structures **************************/ typedef struct { /** 4x4 matrix struct **/ float m[4][4] ; } mat44 ; typedef struct { /** 3x3 matrix struct **/ float m[3][3] ; } mat33 ; /*...........................................................................*/ /*! \enum analyze_75_orient_code * \brief Old-style analyze75 orientation * codes. */ typedef enum _analyze75_orient_code { a75_transverse_unflipped = 0, a75_coronal_unflipped = 1, a75_sagittal_unflipped = 2, a75_transverse_flipped = 3, a75_coronal_flipped = 4, a75_sagittal_flipped = 5, a75_orient_unknown = 6 } analyze_75_orient_code; /*! \struct nifti_image \brief High level data structure for open nifti datasets in the nifti1_io API. Note that this structure is not part of the nifti1 format definition; it is used to implement one API for reading/writing formats in the nifti1 format. */ typedef struct { /*!< Image storage struct **/ int ndim ; /*!< last dimension greater than 1 (1..7) */ int nx ; /*!< dimensions of grid array */ int ny ; /*!< dimensions of grid array */ int nz ; /*!< dimensions of grid array */ int nt ; /*!< dimensions of grid array */ int nu ; /*!< dimensions of grid array */ int nv ; /*!< dimensions of grid array */ int nw ; /*!< dimensions of grid array */ int dim[8] ; /*!< dim[0]=ndim, dim[1]=nx, etc. */ size_t nvox ; /*!< number of voxels = nx*ny*nz*...*nw */ int nbyper ; /*!< bytes per voxel, matches datatype */ int datatype ; /*!< type of data in voxels: DT_* code */ float dx ; /*!< grid spacings */ float dy ; /*!< grid spacings */ float dz ; /*!< grid spacings */ float dt ; /*!< grid spacings */ float du ; /*!< grid spacings */ float dv ; /*!< grid spacings */ float dw ; /*!< grid spacings */ float pixdim[8] ; /*!< pixdim[1]=dx, etc. */ float scl_slope ; /*!< scaling parameter - slope */ float scl_inter ; /*!< scaling parameter - intercept */ float cal_min ; /*!< calibration parameter, minimum */ float cal_max ; /*!< calibration parameter, maximum */ int qform_code ; /*!< codes for (x,y,z) space meaning */ int sform_code ; /*!< codes for (x,y,z) space meaning */ int freq_dim ; /*!< indexes (1,2,3, or 0) for MRI */ int phase_dim ; /*!< directions in dim[]/pixdim[] */ int slice_dim ; /*!< directions in dim[]/pixdim[] */ int slice_code ; /*!< code for slice timing pattern */ int slice_start ; /*!< index for start of slices */ int slice_end ; /*!< index for end of slices */ float slice_duration ; /*!< time between individual slices */ /*! quaternion transform parameters [when writing a dataset, these are used for qform, NOT qto_xyz] */ float quatern_b , quatern_c , quatern_d , qoffset_x , qoffset_y , qoffset_z , qfac ; mat44 qto_xyz ; /*!< qform: transform (i,j,k) to (x,y,z) */ mat44 qto_ijk ; /*!< qform: transform (x,y,z) to (i,j,k) */ mat44 sto_xyz ; /*!< sform: transform (i,j,k) to (x,y,z) */ mat44 sto_ijk ; /*!< sform: transform (x,y,z) to (i,j,k) */ float toffset ; /*!< time coordinate offset */ int xyz_units ; /*!< dx,dy,dz units: NIFTI_UNITS_* code */ int time_units ; /*!< dt units: NIFTI_UNITS_* code */ int nifti_type ; /*!< 0==ANALYZE, 1==NIFTI-1 (1 file), 2==NIFTI-1 (2 files), 3==NIFTI-ASCII (1 file) */ int intent_code ; /*!< statistic type (or something) */ float intent_p1 ; /*!< intent parameters */ float intent_p2 ; /*!< intent parameters */ float intent_p3 ; /*!< intent parameters */ char intent_name[16] ; /*!< optional description of intent data */ char descrip[80] ; /*!< optional text to describe dataset */ char aux_file[24] ; /*!< auxiliary filename */ char *fname ; /*!< header filename (.hdr or .nii) */ char *iname ; /*!< image filename (.img or .nii) */ int iname_offset ; /*!< offset into iname where data starts */ int swapsize ; /*!< swap unit in image data (might be 0) */ int byteorder ; /*!< byte order on disk (MSB_ or LSB_FIRST) */ void *data ; /*!< pointer to data: nbyper*nvox bytes */ int num_ext ; /*!< number of extensions in ext_list */ nifti1_extension * ext_list ; /*!< array of extension structs (with data) */ analyze_75_orient_code analyze75_orient; /*!< for old analyze files, orient */ } nifti_image ; /* struct for return from nifti_image_read_bricks() */ typedef struct { int nbricks; /* the number of allocated pointers in 'bricks' */ size_t bsize; /* the length of each data block, in bytes */ void ** bricks; /* array of pointers to data blocks */ } nifti_brick_list; /*****************************************************************************/ /*------------------ NIfTI version of ANALYZE 7.5 structure -----------------*/ /* (based on fsliolib/dbh.h, but updated for version 7.5) */ typedef struct { /* header info fields - describes the header overlap with NIfTI */ /* ------------------ */ int sizeof_hdr; /* 0 + 4 same */ char data_type[10]; /* 4 + 10 same */ char db_name[18]; /* 14 + 18 same */ int extents; /* 32 + 4 same */ short int session_error; /* 36 + 2 same */ char regular; /* 38 + 1 same */ char hkey_un0; /* 39 + 1 40 bytes */ /* image dimension fields - describes image sizes */ short int dim[8]; /* 0 + 16 same */ short int unused8; /* 16 + 2 intent_p1... */ short int unused9; /* 18 + 2 ... */ short int unused10; /* 20 + 2 intent_p2... */ short int unused11; /* 22 + 2 ... */ short int unused12; /* 24 + 2 intent_p3... */ short int unused13; /* 26 + 2 ... */ short int unused14; /* 28 + 2 intent_code */ short int datatype; /* 30 + 2 same */ short int bitpix; /* 32 + 2 same */ short int dim_un0; /* 34 + 2 slice_start */ float pixdim[8]; /* 36 + 32 same */ float vox_offset; /* 68 + 4 same */ float funused1; /* 72 + 4 scl_slope */ float funused2; /* 76 + 4 scl_inter */ float funused3; /* 80 + 4 slice_end, */ /* slice_code, */ /* xyzt_units */ float cal_max; /* 84 + 4 same */ float cal_min; /* 88 + 4 same */ float compressed; /* 92 + 4 slice_duration */ float verified; /* 96 + 4 toffset */ int glmax,glmin; /* 100 + 8 108 bytes */ /* data history fields - optional */ char descrip[80]; /* 0 + 80 same */ char aux_file[24]; /* 80 + 24 same */ char orient; /* 104 + 1 NO GOOD OVERLAP */ char originator[10]; /* 105 + 10 FROM HERE DOWN... */ char generated[10]; /* 115 + 10 */ char scannum[10]; /* 125 + 10 */ char patient_id[10]; /* 135 + 10 */ char exp_date[10]; /* 145 + 10 */ char exp_time[10]; /* 155 + 10 */ char hist_un0[3]; /* 165 + 3 */ int views; /* 168 + 4 */ int vols_added; /* 172 + 4 */ int start_field; /* 176 + 4 */ int field_skip; /* 180 + 4 */ int omax, omin; /* 184 + 8 */ int smax, smin; /* 192 + 8 200 bytes */ } nifti_analyze75; /* total: 348 bytes */ /*****************************************************************************/ /*--------------- Prototypes of functions defined in this file --------------*/ char *nifti_datatype_string ( int dt ) ; char *nifti_units_string ( int uu ) ; char *nifti_intent_string ( int ii ) ; char *nifti_xform_string ( int xx ) ; char *nifti_slice_string ( int ss ) ; char *nifti_orientation_string( int ii ) ; int nifti_is_inttype( int dt ) ; mat44 nifti_mat44_inverse( mat44 R ) ; mat33 nifti_mat33_inverse( mat33 R ) ; mat33 nifti_mat33_polar ( mat33 A ) ; float nifti_mat33_rownorm( mat33 A ) ; float nifti_mat33_colnorm( mat33 A ) ; float nifti_mat33_determ ( mat33 R ) ; mat33 nifti_mat33_mul ( mat33 A , mat33 B ) ; void nifti_swap_2bytes ( int n , void *ar ) ; void nifti_swap_4bytes ( int n , void *ar ) ; void nifti_swap_8bytes ( int n , void *ar ) ; void nifti_swap_16bytes( int n , void *ar ) ; void nifti_swap_Nbytes ( int n , int siz , void *ar ) ; int nifti_datatype_is_valid (int dtype, int for_nifti); int nifti_datatype_from_string(const char * name); char * nifti_datatype_to_string (int dtype); int nifti_get_filesize( const char *pathname ) ; void swap_nifti_header ( struct nifti_1_header *h , int is_nifti ) ; void old_swap_nifti_header( struct nifti_1_header *h , int is_nifti ); int nifti_swap_as_analyze( nifti_analyze75 *h ); /* main read/write routines */ nifti_image *nifti_image_read_bricks(const char *hname , int nbricks, const int *blist, nifti_brick_list * NBL); int nifti_image_load_bricks(nifti_image *nim , int nbricks, const int *blist, nifti_brick_list * NBL); void nifti_free_NBL( nifti_brick_list * NBL ); nifti_image *nifti_image_read ( const char *hname , int read_data ) ; int nifti_image_load ( nifti_image *nim ) ; void nifti_image_unload ( nifti_image *nim ) ; void nifti_image_free ( nifti_image *nim ) ; int nifti_read_collapsed_image( nifti_image * nim, const int dims [8], void ** data ); int nifti_read_subregion_image( nifti_image * nim, int *start_index, int *region_size, void ** data ); void nifti_image_write ( nifti_image * nim ) ; void nifti_image_write_bricks(nifti_image * nim, const nifti_brick_list * NBL); void nifti_image_infodump( const nifti_image * nim ) ; void nifti_disp_lib_hist( void ) ; /* to display library history */ void nifti_disp_lib_version( void ) ; /* to display library version */ int nifti_disp_matrix_orient( const char * mesg, mat44 mat ); int nifti_disp_type_list( int which ); char * nifti_image_to_ascii ( const nifti_image * nim ) ; nifti_image *nifti_image_from_ascii( const char * str, int * bytes_read ) ; size_t nifti_get_volsize(const nifti_image *nim) ; /* basic file operations */ int nifti_set_filenames(nifti_image * nim, const char * prefix, int check, int set_byte_order); char * nifti_makehdrname (const char * prefix, int nifti_type, int check, int comp); char * nifti_makeimgname (const char * prefix, int nifti_type, int check, int comp); int is_nifti_file (const char *hname); char * nifti_find_file_extension(const char * name); int nifti_is_complete_filename(const char* fname); int nifti_validfilename(const char* fname); int disp_nifti_1_header(const char * info, const nifti_1_header * hp ) ; void nifti_set_debug_level( int level ) ; void nifti_set_skip_blank_ext( int skip ) ; int valid_nifti_brick_list(nifti_image * nim , int nbricks, const int * blist, int disp_error); /* znzFile operations */ znzFile nifti_image_open(const char * hname, char * opts, nifti_image ** nim); znzFile nifti_image_write_hdr_img(nifti_image *nim, int write_data, const char* opts); znzFile nifti_image_write_hdr_img2( nifti_image *nim , int write_opts , const char* opts, znzFile imgfile, const nifti_brick_list * NBL); size_t nifti_read_buffer(znzFile fp, void* datatptr, size_t ntot, nifti_image *nim); int nifti_write_all_data(znzFile fp, nifti_image * nim, const nifti_brick_list * NBL); size_t nifti_write_buffer(znzFile fp, const void * buffer, size_t numbytes); nifti_image *nifti_read_ascii_image(znzFile fp, char *fname, int flen, int read_data); znzFile nifti_write_ascii_image(nifti_image *nim, const nifti_brick_list * NBL, const char * opts, int write_data, int leave_open); void nifti_datatype_sizes( int datatype , int *nbyper, int *swapsize ) ; void nifti_mat44_to_quatern( mat44 R , float *qb, float *qc, float *qd, float *qx, float *qy, float *qz, float *dx, float *dy, float *dz, float *qfac ) ; mat44 nifti_quatern_to_mat44( float qb, float qc, float qd, float qx, float qy, float qz, float dx, float dy, float dz, float qfac ); mat44 nifti_make_orthog_mat44( float r11, float r12, float r13 , float r21, float r22, float r23 , float r31, float r32, float r33 ) ; int nifti_short_order(void) ; /* CPU byte order */ /* Orientation codes that might be returned from nifti_mat44_to_orientation().*/ #define NIFTI_L2R 1 /* Left to Right */ #define NIFTI_R2L 2 /* Right to Left */ #define NIFTI_P2A 3 /* Posterior to Anterior */ #define NIFTI_A2P 4 /* Anterior to Posterior */ #define NIFTI_I2S 5 /* Inferior to Superior */ #define NIFTI_S2I 6 /* Superior to Inferior */ void nifti_mat44_to_orientation( mat44 R , int *icod, int *jcod, int *kcod ) ; /*--------------------- Low level IO routines ------------------------------*/ char * nifti_findhdrname (const char* fname); char * nifti_findimgname (const char* fname , int nifti_type); int nifti_is_gzfile (const char* fname); char * nifti_makebasename(const char* fname); /* other routines */ struct nifti_1_header nifti_convert_nim2nhdr(const nifti_image* nim); nifti_1_header * nifti_make_new_header(const int arg_dims[], int arg_dtype); nifti_1_header * nifti_read_header(const char *hname, int *swapped, int check); nifti_image * nifti_copy_nim_info(const nifti_image * src); nifti_image * nifti_make_new_nim(const int dims[], int datatype, int data_fill); nifti_image * nifti_simple_init_nim(void); nifti_image * nifti_convert_nhdr2nim(struct nifti_1_header nhdr, const char * fname); int nifti_hdr_looks_good (const nifti_1_header * hdr); int nifti_is_valid_datatype (int dtype); int nifti_is_valid_ecode (int ecode); int nifti_nim_is_valid (nifti_image * nim, int complain); int nifti_nim_has_valid_dims (nifti_image * nim, int complain); int is_valid_nifti_type (int nifti_type); int nifti_test_datatype_sizes (int verb); int nifti_type_and_names_match (nifti_image * nim, int show_warn); int nifti_update_dims_from_array(nifti_image * nim); void nifti_set_iname_offset (nifti_image *nim); int nifti_set_type_from_names (nifti_image * nim); int nifti_add_extension(nifti_image * nim, const char * data, int len, int ecode ); int nifti_compiled_with_zlib (void); int nifti_copy_extensions (nifti_image *nim_dest,const nifti_image *nim_src); int nifti_free_extensions (nifti_image *nim); int * nifti_get_intlist (int nvals , const char *str); char * nifti_strdup (const char *str); int valid_nifti_extensions(const nifti_image *nim); /*-------------------- Some C convenience macros ----------------------------*/ /* NIfTI-1.1 extension codes: see http://nifti.nimh.nih.gov/nifti-1/documentation/faq#Q21 */ #define NIFTI_ECODE_IGNORE 0 /* changed from UNKNOWN, 29 June 2005 */ #define NIFTI_ECODE_DICOM 2 /* intended for raw DICOM attributes */ #define NIFTI_ECODE_AFNI 4 /* Robert W Cox: rwcox@nih.gov http://afni.nimh.nih.gov/afni */ #define NIFTI_ECODE_COMMENT 6 /* plain ASCII text only */ #define NIFTI_ECODE_XCEDE 8 /* David B Keator: dbkeator@uci.edu http://www.nbirn.net/Resources /Users/Applications/ /xcede/index.htm */ #define NIFTI_ECODE_JIMDIMINFO 10 /* Mark A Horsfield: mah5@leicester.ac.uk http://someplace/something */ #define NIFTI_ECODE_WORKFLOW_FWDS 12 /* Kate Fissell: fissell@pitt.edu http://kraepelin.wpic.pitt.edu /~fissell/NIFTI_ECODE_WORKFLOW_FWDS /NIFTI_ECODE_WORKFLOW_FWDS.html */ #define NIFTI_ECODE_FREESURFER 14 /* http://surfer.nmr.mgh.harvard.edu */ #define NIFTI_ECODE_PYPICKLE 16 /* Embedded Python objects http://niftilib.sourceforge.net/pynifti */ #define NIFTI_MAX_ECODE 16 /******* maximum extension code *******/ /* nifti_type file codes */ #define NIFTI_FTYPE_ANALYZE 0 #define NIFTI_FTYPE_NIFTI1_1 1 #define NIFTI_FTYPE_NIFTI1_2 2 #define NIFTI_FTYPE_ASCII 3 #define NIFTI_MAX_FTYPE 3 /* this should match the maximum code */ /*------------------------------------------------------------------------*/ /*-- the rest of these apply only to nifti1_io.c, check for _NIFTI1_IO_C_ */ /* Feb 9, 2005 [rickr] */ #ifdef _NIFTI1_IO_C_ typedef struct { int debug; /*!< debug level for status reports */ int skip_blank_ext; /*!< skip extender if no extensions */ } nifti_global_options; typedef struct { int type; /* should match the NIFTI_TYPE_ #define */ int nbyper; /* bytes per value, matches nifti_image */ int swapsize; /* bytes per swap piece, matches nifti_image */ char * name; /* text string to match #define */ } nifti_type_ele; #undef LNI_FERR /* local nifti file error, to be compact and repetative */ #define LNI_FERR(func,msg,file) \ fprintf(stderr,"** ERROR (%s): %s '%s'\n",func,msg,file) #undef swap_2 #undef swap_4 #define swap_2(s) nifti_swap_2bytes(1,&(s)) /* s: 2-byte short; swap in place */ #define swap_4(v) nifti_swap_4bytes(1,&(v)) /* v: 4-byte value; swap in place */ /***** isfinite() is a C99 macro, which is present in many C implementations already *****/ #undef IS_GOOD_FLOAT #undef FIXED_FLOAT #ifdef isfinite /* use isfinite() to check floats/doubles for goodness */ # define IS_GOOD_FLOAT(x) isfinite(x) /* check if x is a "good" float */ # define FIXED_FLOAT(x) (isfinite(x) ? (x) : 0) /* fixed if bad */ #else # define IS_GOOD_FLOAT(x) 1 /* don't check it */ # define FIXED_FLOAT(x) (x) /* don't fix it */ #endif #undef ASSIF /* assign v to *p, if possible */ #define ASSIF(p,v) if( (p)!=NULL ) *(p) = (v) #undef MSB_FIRST #undef LSB_FIRST #undef REVERSE_ORDER #define LSB_FIRST 1 #define MSB_FIRST 2 #define REVERSE_ORDER(x) (3-(x)) /* convert MSB_FIRST <--> LSB_FIRST */ #define LNI_MAX_NIA_EXT_LEN 100000 /* consider a longer extension invalid */ #endif /* _NIFTI1_IO_C_ section */ /*------------------------------------------------------------------------*/ /*=================*/ #ifdef __cplusplus } #endif /*=================*/ #endif /* _NIFTI_IO_HEADER_ */ pynifti-0.20100607.1/3rd/nifticlibs/nifti1.h0000664000175000017500000020716411414645202017714 0ustar michaelmichael/** \file nifti1.h \brief Official definition of the nifti1 header. Written by Bob Cox, SSCC, NIMH. HISTORY: 29 Nov 2007 [rickr] - added DT_RGBA32 and NIFTI_TYPE_RGBA32 - added NIFTI_INTENT codes: TIME_SERIES, NODE_INDEX, RGB_VECTOR, RGBA_VECTOR, SHAPE */ #ifndef _NIFTI_HEADER_ #define _NIFTI_HEADER_ /***************************************************************************** ** This file defines the "NIFTI-1" header format. ** ** It is derived from 2 meetings at the NIH (31 Mar 2003 and ** ** 02 Sep 2003) of the Data Format Working Group (DFWG), ** ** chartered by the NIfTI (Neuroimaging Informatics Technology ** ** Initiative) at the National Institutes of Health (NIH). ** **--------------------------------------------------------------** ** Neither the National Institutes of Health (NIH), the DFWG, ** ** nor any of the members or employees of these institutions ** ** imply any warranty of usefulness of this material for any ** ** purpose, and do not assume any liability for damages, ** ** incidental or otherwise, caused by any use of this document. ** ** If these conditions are not acceptable, do not use this! ** **--------------------------------------------------------------** ** Author: Robert W Cox (NIMH, Bethesda) ** ** Advisors: John Ashburner (FIL, London), ** ** Stephen Smith (FMRIB, Oxford), ** ** Mark Jenkinson (FMRIB, Oxford) ** ******************************************************************************/ /*---------------------------------------------------------------------------*/ /* Note that the ANALYZE 7.5 file header (dbh.h) is (c) Copyright 1986-1995 Biomedical Imaging Resource Mayo Foundation Incorporation of components of dbh.h are by permission of the Mayo Foundation. Changes from the ANALYZE 7.5 file header in this file are released to the public domain, including the functional comments and any amusing asides. -----------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ /*! INTRODUCTION TO NIFTI-1: ------------------------ The twin (and somewhat conflicting) goals of this modified ANALYZE 7.5 format are: (a) To add information to the header that will be useful for functional neuroimaging data analysis and display. These additions include: - More basic data types. - Two affine transformations to specify voxel coordinates. - "Intent" codes and parameters to describe the meaning of the data. - Affine scaling of the stored data values to their "true" values. - Optional storage of the header and image data in one file (.nii). (b) To maintain compatibility with non-NIFTI-aware ANALYZE 7.5 compatible software (i.e., such a program should be able to do something useful with a NIFTI-1 dataset -- at least, with one stored in a traditional .img/.hdr file pair). Most of the unused fields in the ANALYZE 7.5 header have been taken, and some of the lesser-used fields have been co-opted for other purposes. Notably, most of the data_history substructure has been co-opted for other purposes, since the ANALYZE 7.5 format describes this substructure as "not required". NIFTI-1 FLAG (MAGIC STRINGS): ---------------------------- To flag such a struct as being conformant to the NIFTI-1 spec, the last 4 bytes of the header must be either the C String "ni1" or "n+1"; in hexadecimal, the 4 bytes 6E 69 31 00 or 6E 2B 31 00 (in any future version of this format, the '1' will be upgraded to '2', etc.). Normally, such a "magic number" or flag goes at the start of the file, but trying to avoid clobbering widely-used ANALYZE 7.5 fields led to putting this marker last. However, recall that "the last shall be first" (Matthew 20:16). If a NIFTI-aware program reads a header file that is NOT marked with a NIFTI magic string, then it should treat the header as an ANALYZE 7.5 structure. NIFTI-1 FILE STORAGE: -------------------- "ni1" means that the image data is stored in the ".img" file corresponding to the header file (starting at file offset 0). "n+1" means that the image data is stored in the same file as the header information. We recommend that the combined header+data filename suffix be ".nii". When the dataset is stored in one file, the first byte of image data is stored at byte location (int)vox_offset in this combined file. The minimum allowed value of vox_offset is 352; for compatibility with some software, vox_offset should be an integral multiple of 16. GRACE UNDER FIRE: ---------------- Most NIFTI-aware programs will only be able to handle a subset of the full range of datasets possible with this format. All NIFTI-aware programs should take care to check if an input dataset conforms to the program's needs and expectations (e.g., check datatype, intent_code, etc.). If the input dataset can't be handled by the program, the program should fail gracefully (e.g., print a useful warning; not crash). SAMPLE CODES: ------------ The associated files nifti1_io.h and nifti1_io.c provide a sample implementation in C of a set of functions to read, write, and manipulate NIFTI-1 files. The file nifti1_test.c is a sample program that uses the nifti1_io.c functions. -----------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ /* HEADER STRUCT DECLARATION: ------------------------- In the comments below for each field, only NIFTI-1 specific requirements or changes from the ANALYZE 7.5 format are described. For convenience, the 348 byte header is described as a single struct, rather than as the ANALYZE 7.5 group of 3 substructs. Further comments about the interpretation of various elements of this header are after the data type definition itself. Fields that are marked as ++UNUSED++ have no particular interpretation in this standard. (Also see the UNUSED FIELDS comment section, far below.) The presumption below is that the various C types have particular sizes: sizeof(int) = sizeof(float) = 4 ; sizeof(short) = 2 -----------------------------------------------------------------------------*/ /*=================*/ #ifdef __cplusplus extern "C" { #endif /*=================*/ /*! \struct nifti_1_header \brief Data structure defining the fields in the nifti1 header. This binary header should be found at the beginning of a valid NIFTI-1 header file. */ /*************************/ /************************/ struct nifti_1_header { /* NIFTI-1 usage */ /* ANALYZE 7.5 field(s) */ /*************************/ /************************/ /*--- was header_key substruct ---*/ int sizeof_hdr; /*!< MUST be 348 */ /* int sizeof_hdr; */ char data_type[10]; /*!< ++UNUSED++ */ /* char data_type[10]; */ char db_name[18]; /*!< ++UNUSED++ */ /* char db_name[18]; */ int extents; /*!< ++UNUSED++ */ /* int extents; */ short session_error; /*!< ++UNUSED++ */ /* short session_error; */ char regular; /*!< ++UNUSED++ */ /* char regular; */ char dim_info; /*!< MRI slice ordering. */ /* char hkey_un0; */ /*--- was image_dimension substruct ---*/ short dim[8]; /*!< Data array dimensions.*/ /* short dim[8]; */ float intent_p1 ; /*!< 1st intent parameter. */ /* short unused8; */ /* short unused9; */ float intent_p2 ; /*!< 2nd intent parameter. */ /* short unused10; */ /* short unused11; */ float intent_p3 ; /*!< 3rd intent parameter. */ /* short unused12; */ /* short unused13; */ short intent_code ; /*!< NIFTI_INTENT_* code. */ /* short unused14; */ short datatype; /*!< Defines data type! */ /* short datatype; */ short bitpix; /*!< Number bits/voxel. */ /* short bitpix; */ short slice_start; /*!< First slice index. */ /* short dim_un0; */ float pixdim[8]; /*!< Grid spacings. */ /* float pixdim[8]; */ float vox_offset; /*!< Offset into .nii file */ /* float vox_offset; */ float scl_slope ; /*!< Data scaling: slope. */ /* float funused1; */ float scl_inter ; /*!< Data scaling: offset. */ /* float funused2; */ short slice_end; /*!< Last slice index. */ /* float funused3; */ char slice_code ; /*!< Slice timing order. */ char xyzt_units ; /*!< Units of pixdim[1..4] */ float cal_max; /*!< Max display intensity */ /* float cal_max; */ float cal_min; /*!< Min display intensity */ /* float cal_min; */ float slice_duration;/*!< Time for 1 slice. */ /* float compressed; */ float toffset; /*!< Time axis shift. */ /* float verified; */ int glmax; /*!< ++UNUSED++ */ /* int glmax; */ int glmin; /*!< ++UNUSED++ */ /* int glmin; */ /*--- was data_history substruct ---*/ char descrip[80]; /*!< any text you like. */ /* char descrip[80]; */ char aux_file[24]; /*!< auxiliary filename. */ /* char aux_file[24]; */ short qform_code ; /*!< NIFTI_XFORM_* code. */ /*-- all ANALYZE 7.5 ---*/ short sform_code ; /*!< NIFTI_XFORM_* code. */ /* fields below here */ /* are replaced */ float quatern_b ; /*!< Quaternion b param. */ float quatern_c ; /*!< Quaternion c param. */ float quatern_d ; /*!< Quaternion d param. */ float qoffset_x ; /*!< Quaternion x shift. */ float qoffset_y ; /*!< Quaternion y shift. */ float qoffset_z ; /*!< Quaternion z shift. */ float srow_x[4] ; /*!< 1st row affine transform. */ float srow_y[4] ; /*!< 2nd row affine transform. */ float srow_z[4] ; /*!< 3rd row affine transform. */ char intent_name[16];/*!< 'name' or meaning of data. */ char magic[4] ; /*!< MUST be "ni1\0" or "n+1\0". */ } ; /**** 348 bytes total ****/ typedef struct nifti_1_header nifti_1_header ; /*---------------------------------------------------------------------------*/ /* HEADER EXTENSIONS: ----------------- After the end of the 348 byte header (e.g., after the magic field), the next 4 bytes are a char array field named "extension". By default, all 4 bytes of this array should be set to zero. In a .nii file, these 4 bytes will always be present, since the earliest start point for the image data is byte #352. In a separate .hdr file, these bytes may or may not be present. If not present (i.e., if the length of the .hdr file is 348 bytes), then a NIfTI-1 compliant program should use the default value of extension={0,0,0,0}. The first byte (extension[0]) is the only value of this array that is specified at present. The other 3 bytes are reserved for future use. If extension[0] is nonzero, it indicates that extended header information is present in the bytes following the extension array. In a .nii file, this extended header data is before the image data (and vox_offset must be set correctly to allow for this). In a .hdr file, this extended data follows extension and proceeds (potentially) to the end of the file. The format of extended header data is weakly specified. Each extension must be an integer multiple of 16 bytes long. The first 8 bytes of each extension comprise 2 integers: int esize , ecode ; These values may need to be byte-swapped, as indicated by dim[0] for the rest of the header. * esize is the number of bytes that form the extended header data + esize must be a positive integral multiple of 16 + this length includes the 8 bytes of esize and ecode themselves * ecode is a non-negative integer that indicates the format of the extended header data that follows + different ecode values are assigned to different developer groups + at present, the "registered" values for code are = 0 = unknown private format (not recommended!) = 2 = DICOM format (i.e., attribute tags and values) = 4 = AFNI group (i.e., ASCII XML-ish elements) In the interests of interoperability (a primary rationale for NIfTI), groups developing software that uses this extension mechanism are encouraged to document and publicize the format of their extensions. To this end, the NIfTI DFWG will assign even numbered codes upon request to groups submitting at least rudimentary documentation for the format of their extension; at present, the contact is mailto:rwcox@nih.gov. The assigned codes and documentation will be posted on the NIfTI website. All odd values of ecode (and 0) will remain unassigned; at least, until the even ones are used up, when we get to 2,147,483,646. Note that the other contents of the extended header data section are totally unspecified by the NIfTI-1 standard. In particular, if binary data is stored in such a section, its byte order is not necessarily the same as that given by examining dim[0]; it is incumbent on the programs dealing with such data to determine the byte order of binary extended header data. Multiple extended header sections are allowed, each starting with an esize,ecode value pair. The first esize value, as described above, is at bytes #352-355 in the .hdr or .nii file (files start at byte #0). If this value is positive, then the second (esize2) will be found starting at byte #352+esize1 , the third (esize3) at byte #352+esize1+esize2, et cetera. Of course, in a .nii file, the value of vox_offset must be compatible with these extensions. If a malformed file indicates that an extended header data section would run past vox_offset, then the entire extended header section should be ignored. In a .hdr file, if an extended header data section would run past the end-of-file, that extended header data should also be ignored. With the above scheme, a program can successively examine the esize and ecode values, and skip over each extended header section if the program doesn't know how to interpret the data within. Of course, any program can simply ignore all extended header sections simply by jumping straight to the image data using vox_offset. -----------------------------------------------------------------------------*/ /*! \struct nifti1_extender \brief This structure represents a 4-byte string that should follow the binary nifti_1_header data in a NIFTI-1 header file. If the char values are {1,0,0,0}, the file is expected to contain extensions, values of {0,0,0,0} imply the file does not contain extensions. Other sequences of values are not currently defined. */ struct nifti1_extender { char extension[4] ; } ; typedef struct nifti1_extender nifti1_extender ; /*! \struct nifti1_extension \brief Data structure defining the fields of a header extension. */ struct nifti1_extension { int esize ; /*!< size of extension, in bytes (must be multiple of 16) */ int ecode ; /*!< extension code, one of the NIFTI_ECODE_ values */ char * edata ; /*!< raw data, with no byte swapping (length is esize-8) */ } ; typedef struct nifti1_extension nifti1_extension ; /*---------------------------------------------------------------------------*/ /* DATA DIMENSIONALITY (as in ANALYZE 7.5): --------------------------------------- dim[0] = number of dimensions; - if dim[0] is outside range 1..7, then the header information needs to be byte swapped appropriately - ANALYZE supports dim[0] up to 7, but NIFTI-1 reserves dimensions 1,2,3 for space (x,y,z), 4 for time (t), and 5,6,7 for anything else needed. dim[i] = length of dimension #i, for i=1..dim[0] (must be positive) - also see the discussion of intent_code, far below pixdim[i] = voxel width along dimension #i, i=1..dim[0] (positive) - cf. ORIENTATION section below for use of pixdim[0] - the units of pixdim can be specified with the xyzt_units field (also described far below). Number of bits per voxel value is in bitpix, which MUST correspond with the datatype field. The total number of bytes in the image data is dim[1] * ... * dim[dim[0]] * bitpix / 8 In NIFTI-1 files, dimensions 1,2,3 are for space, dimension 4 is for time, and dimension 5 is for storing multiple values at each spatiotemporal voxel. Some examples: - A typical whole-brain FMRI experiment's time series: - dim[0] = 4 - dim[1] = 64 pixdim[1] = 3.75 xyzt_units = NIFTI_UNITS_MM - dim[2] = 64 pixdim[2] = 3.75 | NIFTI_UNITS_SEC - dim[3] = 20 pixdim[3] = 5.0 - dim[4] = 120 pixdim[4] = 2.0 - A typical T1-weighted anatomical volume: - dim[0] = 3 - dim[1] = 256 pixdim[1] = 1.0 xyzt_units = NIFTI_UNITS_MM - dim[2] = 256 pixdim[2] = 1.0 - dim[3] = 128 pixdim[3] = 1.1 - A single slice EPI time series: - dim[0] = 4 - dim[1] = 64 pixdim[1] = 3.75 xyzt_units = NIFTI_UNITS_MM - dim[2] = 64 pixdim[2] = 3.75 | NIFTI_UNITS_SEC - dim[3] = 1 pixdim[3] = 5.0 - dim[4] = 1200 pixdim[4] = 0.2 - A 3-vector stored at each point in a 3D volume: - dim[0] = 5 - dim[1] = 256 pixdim[1] = 1.0 xyzt_units = NIFTI_UNITS_MM - dim[2] = 256 pixdim[2] = 1.0 - dim[3] = 128 pixdim[3] = 1.1 - dim[4] = 1 pixdim[4] = 0.0 - dim[5] = 3 intent_code = NIFTI_INTENT_VECTOR - A single time series with a 3x3 matrix at each point: - dim[0] = 5 - dim[1] = 1 xyzt_units = NIFTI_UNITS_SEC - dim[2] = 1 - dim[3] = 1 - dim[4] = 1200 pixdim[4] = 0.2 - dim[5] = 9 intent_code = NIFTI_INTENT_GENMATRIX - intent_p1 = intent_p2 = 3.0 (indicates matrix dimensions) -----------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ /* DATA STORAGE: ------------ If the magic field is "n+1", then the voxel data is stored in the same file as the header. In this case, the voxel data starts at offset (int)vox_offset into the header file. Thus, vox_offset=352.0 means that the data starts immediately after the NIFTI-1 header. If vox_offset is greater than 352, the NIFTI-1 format does not say much about the contents of the dataset file between the end of the header and the start of the data. FILES: ----- If the magic field is "ni1", then the voxel data is stored in the associated ".img" file, starting at offset 0 (i.e., vox_offset is not used in this case, and should be set to 0.0). When storing NIFTI-1 datasets in pairs of files, it is customary to name the files in the pattern "name.hdr" and "name.img", as in ANALYZE 7.5. When storing in a single file ("n+1"), the file name should be in the form "name.nii" (the ".nft" and ".nif" suffixes are already taken; cf. http://www.icdatamaster.com/n.html ). BYTE ORDERING: ------------- The byte order of the data arrays is presumed to be the same as the byte order of the header (which is determined by examining dim[0]). Floating point types are presumed to be stored in IEEE-754 format. -----------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ /* DETAILS ABOUT vox_offset: ------------------------ In a .nii file, the vox_offset field value is interpreted as the start location of the image data bytes in that file. In a .hdr/.img file pair, the vox_offset field value is the start location of the image data bytes in the .img file. * If vox_offset is less than 352 in a .nii file, it is equivalent to 352 (i.e., image data never starts before byte #352 in a .nii file). * The default value for vox_offset in a .nii file is 352. * In a .hdr file, the default value for vox_offset is 0. * vox_offset should be an integer multiple of 16; otherwise, some programs may not work properly (e.g., SPM). This is to allow memory-mapped input to be properly byte-aligned. Note that since vox_offset is an IEEE-754 32 bit float (for compatibility with the ANALYZE-7.5 format), it effectively has a 24 bit mantissa. All integers from 0 to 2^24 can be represented exactly in this format, but not all larger integers are exactly storable as IEEE-754 32 bit floats. However, unless you plan to have vox_offset be potentially larger than 16 MB, this should not be an issue. (Actually, any integral multiple of 16 up to 2^27 can be represented exactly in this format, which allows for up to 128 MB of random information before the image data. If that isn't enough, then perhaps this format isn't right for you.) In a .img file (i.e., image data stored separately from the NIfTI-1 header), data bytes between #0 and #vox_offset-1 (inclusive) are completely undefined and unregulated by the NIfTI-1 standard. One potential use of having vox_offset > 0 in the .hdr/.img file pair storage method is to make the .img file be a copy of (or link to) a pre-existing image file in some other format, such as DICOM; then vox_offset would be set to the offset of the image data in this file. (It may not be possible to follow the "multiple-of-16 rule" with an arbitrary external file; using the NIfTI-1 format in such a case may lead to a file that is incompatible with software that relies on vox_offset being a multiple of 16.) In a .nii file, data bytes between #348 and #vox_offset-1 (inclusive) may be used to store user-defined extra information; similarly, in a .hdr file, any data bytes after byte #347 are available for user-defined extra information. The (very weak) regulation of this extra header data is described elsewhere. -----------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ /* DATA SCALING: ------------ If the scl_slope field is nonzero, then each voxel value in the dataset should be scaled as y = scl_slope * x + scl_inter where x = voxel value stored y = "true" voxel value Normally, we would expect this scaling to be used to store "true" floating values in a smaller integer datatype, but that is not required. That is, it is legal to use scaling even if the datatype is a float type (crazy, perhaps, but legal). - However, the scaling is to be ignored if datatype is DT_RGB24. - If datatype is a complex type, then the scaling is to be applied to both the real and imaginary parts. The cal_min and cal_max fields (if nonzero) are used for mapping (possibly scaled) dataset values to display colors: - Minimum display intensity (black) corresponds to dataset value cal_min. - Maximum display intensity (white) corresponds to dataset value cal_max. - Dataset values below cal_min should display as black also, and values above cal_max as white. - Colors "black" and "white", of course, may refer to any scalar display scheme (e.g., a color lookup table specified via aux_file). - cal_min and cal_max only make sense when applied to scalar-valued datasets (i.e., dim[0] < 5 or dim[5] = 1). -----------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ /* TYPE OF DATA (acceptable values for datatype field): --------------------------------------------------- Values of datatype smaller than 256 are ANALYZE 7.5 compatible. Larger values are NIFTI-1 additions. These are all multiples of 256, so that no bits below position 8 are set in datatype. But there is no need to use only powers-of-2, as the original ANALYZE 7.5 datatype codes do. The additional codes are intended to include a complete list of basic scalar types, including signed and unsigned integers from 8 to 64 bits, floats from 32 to 128 bits, and complex (float pairs) from 64 to 256 bits. Note that most programs will support only a few of these datatypes! A NIFTI-1 program should fail gracefully (e.g., print a warning message) when it encounters a dataset with a type it doesn't like. -----------------------------------------------------------------------------*/ #undef DT_UNKNOWN /* defined in dirent.h on some Unix systems */ /*! \defgroup NIFTI1_DATATYPES \brief nifti1 datatype codes @{ */ /*--- the original ANALYZE 7.5 type codes ---*/ #define DT_NONE 0 #define DT_UNKNOWN 0 /* what it says, dude */ #define DT_BINARY 1 /* binary (1 bit/voxel) */ #define DT_UNSIGNED_CHAR 2 /* unsigned char (8 bits/voxel) */ #define DT_SIGNED_SHORT 4 /* signed short (16 bits/voxel) */ #define DT_SIGNED_INT 8 /* signed int (32 bits/voxel) */ #define DT_FLOAT 16 /* float (32 bits/voxel) */ #define DT_COMPLEX 32 /* complex (64 bits/voxel) */ #define DT_DOUBLE 64 /* double (64 bits/voxel) */ #define DT_RGB 128 /* RGB triple (24 bits/voxel) */ #define DT_ALL 255 /* not very useful (?) */ /*----- another set of names for the same ---*/ #define DT_UINT8 2 #define DT_INT16 4 #define DT_INT32 8 #define DT_FLOAT32 16 #define DT_COMPLEX64 32 #define DT_FLOAT64 64 #define DT_RGB24 128 /*------------------- new codes for NIFTI ---*/ #define DT_INT8 256 /* signed char (8 bits) */ #define DT_UINT16 512 /* unsigned short (16 bits) */ #define DT_UINT32 768 /* unsigned int (32 bits) */ #define DT_INT64 1024 /* long long (64 bits) */ #define DT_UINT64 1280 /* unsigned long long (64 bits) */ #define DT_FLOAT128 1536 /* long double (128 bits) */ #define DT_COMPLEX128 1792 /* double pair (128 bits) */ #define DT_COMPLEX256 2048 /* long double pair (256 bits) */ #define DT_RGBA32 2304 /* 4 byte RGBA (32 bits/voxel) */ /* @} */ /*------- aliases for all the above codes ---*/ /*! \defgroup NIFTI1_DATATYPE_ALIASES \brief aliases for the nifti1 datatype codes @{ */ /*! unsigned char. */ #define NIFTI_TYPE_UINT8 2 /*! signed short. */ #define NIFTI_TYPE_INT16 4 /*! signed int. */ #define NIFTI_TYPE_INT32 8 /*! 32 bit float. */ #define NIFTI_TYPE_FLOAT32 16 /*! 64 bit complex = 2 32 bit floats. */ #define NIFTI_TYPE_COMPLEX64 32 /*! 64 bit float = double. */ #define NIFTI_TYPE_FLOAT64 64 /*! 3 8 bit bytes. */ #define NIFTI_TYPE_RGB24 128 /*! signed char. */ #define NIFTI_TYPE_INT8 256 /*! unsigned short. */ #define NIFTI_TYPE_UINT16 512 /*! unsigned int. */ #define NIFTI_TYPE_UINT32 768 /*! signed long long. */ #define NIFTI_TYPE_INT64 1024 /*! unsigned long long. */ #define NIFTI_TYPE_UINT64 1280 /*! 128 bit float = long double. */ #define NIFTI_TYPE_FLOAT128 1536 /*! 128 bit complex = 2 64 bit floats. */ #define NIFTI_TYPE_COMPLEX128 1792 /*! 256 bit complex = 2 128 bit floats */ #define NIFTI_TYPE_COMPLEX256 2048 /*! 4 8 bit bytes. */ #define NIFTI_TYPE_RGBA32 2304 /* @} */ /*-------- sample typedefs for complicated types ---*/ #if 0 typedef struct { float r,i; } complex_float ; typedef struct { double r,i; } complex_double ; typedef struct { long double r,i; } complex_longdouble ; typedef struct { unsigned char r,g,b; } rgb_byte ; #endif /*---------------------------------------------------------------------------*/ /* INTERPRETATION OF VOXEL DATA: ---------------------------- The intent_code field can be used to indicate that the voxel data has some particular meaning. In particular, a large number of codes is given to indicate that the the voxel data should be interpreted as being drawn from a given probability distribution. VECTOR-VALUED DATASETS: ---------------------- The 5th dimension of the dataset, if present (i.e., dim[0]=5 and dim[5] > 1), contains multiple values (e.g., a vector) to be stored at each spatiotemporal location. For example, the header values - dim[0] = 5 - dim[1] = 64 - dim[2] = 64 - dim[3] = 20 - dim[4] = 1 (indicates no time axis) - dim[5] = 3 - datatype = DT_FLOAT - intent_code = NIFTI_INTENT_VECTOR mean that this dataset should be interpreted as a 3D volume (64x64x20), with a 3-vector of floats defined at each point in the 3D grid. A program reading a dataset with a 5th dimension may want to reformat the image data to store each voxels' set of values together in a struct or array. This programming detail, however, is beyond the scope of the NIFTI-1 file specification! Uses of dimensions 6 and 7 are also not specified here. STATISTICAL PARAMETRIC DATASETS (i.e., SPMs): -------------------------------------------- Values of intent_code from NIFTI_FIRST_STATCODE to NIFTI_LAST_STATCODE (inclusive) indicate that the numbers in the dataset should be interpreted as being drawn from a given distribution. Most such distributions have auxiliary parameters (e.g., NIFTI_INTENT_TTEST has 1 DOF parameter). If the dataset DOES NOT have a 5th dimension, then the auxiliary parameters are the same for each voxel, and are given in header fields intent_p1, intent_p2, and intent_p3. If the dataset DOES have a 5th dimension, then the auxiliary parameters are different for each voxel. For example, the header values - dim[0] = 5 - dim[1] = 128 - dim[2] = 128 - dim[3] = 1 (indicates a single slice) - dim[4] = 1 (indicates no time axis) - dim[5] = 2 - datatype = DT_FLOAT - intent_code = NIFTI_INTENT_TTEST mean that this is a 2D dataset (128x128) of t-statistics, with the t-statistic being in the first "plane" of data and the degrees-of-freedom parameter being in the second "plane" of data. If the dataset 5th dimension is used to store the voxel-wise statistical parameters, then dim[5] must be 1 plus the number of parameters required by that distribution (e.g., intent_code=NIFTI_INTENT_TTEST implies dim[5] must be 2, as in the example just above). Note: intent_code values 2..10 are compatible with AFNI 1.5x (which is why there is no code with value=1, which is obsolescent in AFNI). OTHER INTENTIONS: ---------------- The purpose of the intent_* fields is to help interpret the values stored in the dataset. Some non-statistical values for intent_code and conventions are provided for storing other complex data types. The intent_name field provides space for a 15 character (plus 0 byte) 'name' string for the type of data stored. Examples: - intent_code = NIFTI_INTENT_ESTIMATE; intent_name = "T1"; could be used to signify that the voxel values are estimates of the NMR parameter T1. - intent_code = NIFTI_INTENT_TTEST; intent_name = "House"; could be used to signify that the voxel values are t-statistics for the significance of 'activation' response to a House stimulus. - intent_code = NIFTI_INTENT_DISPVECT; intent_name = "ToMNI152"; could be used to signify that the voxel values are a displacement vector that transforms each voxel (x,y,z) location to the corresponding location in the MNI152 standard brain. - intent_code = NIFTI_INTENT_SYMMATRIX; intent_name = "DTI"; could be used to signify that the voxel values comprise a diffusion tensor image. If no data name is implied or needed, intent_name[0] should be set to 0. -----------------------------------------------------------------------------*/ /*! default: no intention is indicated in the header. */ #define NIFTI_INTENT_NONE 0 /*-------- These codes are for probability distributions ---------------*/ /* Most distributions have a number of parameters, below denoted by p1, p2, and p3, and stored in - intent_p1, intent_p2, intent_p3 if dataset doesn't have 5th dimension - image data array if dataset does have 5th dimension Functions to compute with many of the distributions below can be found in the CDF library from U Texas. Formulas for and discussions of these distributions can be found in the following books: [U] Univariate Discrete Distributions, NL Johnson, S Kotz, AW Kemp. [C1] Continuous Univariate Distributions, vol. 1, NL Johnson, S Kotz, N Balakrishnan. [C2] Continuous Univariate Distributions, vol. 2, NL Johnson, S Kotz, N Balakrishnan. */ /*----------------------------------------------------------------------*/ /*! [C2, chap 32] Correlation coefficient R (1 param): p1 = degrees of freedom R/sqrt(1-R*R) is t-distributed with p1 DOF. */ /*! \defgroup NIFTI1_INTENT_CODES \brief nifti1 intent codes, to describe intended meaning of dataset contents @{ */ #define NIFTI_INTENT_CORREL 2 /*! [C2, chap 28] Student t statistic (1 param): p1 = DOF. */ #define NIFTI_INTENT_TTEST 3 /*! [C2, chap 27] Fisher F statistic (2 params): p1 = numerator DOF, p2 = denominator DOF. */ #define NIFTI_INTENT_FTEST 4 /*! [C1, chap 13] Standard normal (0 params): Density = N(0,1). */ #define NIFTI_INTENT_ZSCORE 5 /*! [C1, chap 18] Chi-squared (1 param): p1 = DOF. Density(x) proportional to exp(-x/2) * x^(p1/2-1). */ #define NIFTI_INTENT_CHISQ 6 /*! [C2, chap 25] Beta distribution (2 params): p1=a, p2=b. Density(x) proportional to x^(a-1) * (1-x)^(b-1). */ #define NIFTI_INTENT_BETA 7 /*! [U, chap 3] Binomial distribution (2 params): p1 = number of trials, p2 = probability per trial. Prob(x) = (p1 choose x) * p2^x * (1-p2)^(p1-x), for x=0,1,...,p1. */ #define NIFTI_INTENT_BINOM 8 /*! [C1, chap 17] Gamma distribution (2 params): p1 = shape, p2 = scale. Density(x) proportional to x^(p1-1) * exp(-p2*x). */ #define NIFTI_INTENT_GAMMA 9 /*! [U, chap 4] Poisson distribution (1 param): p1 = mean. Prob(x) = exp(-p1) * p1^x / x! , for x=0,1,2,.... */ #define NIFTI_INTENT_POISSON 10 /*! [C1, chap 13] Normal distribution (2 params): p1 = mean, p2 = standard deviation. */ #define NIFTI_INTENT_NORMAL 11 /*! [C2, chap 30] Noncentral F statistic (3 params): p1 = numerator DOF, p2 = denominator DOF, p3 = numerator noncentrality parameter. */ #define NIFTI_INTENT_FTEST_NONC 12 /*! [C2, chap 29] Noncentral chi-squared statistic (2 params): p1 = DOF, p2 = noncentrality parameter. */ #define NIFTI_INTENT_CHISQ_NONC 13 /*! [C2, chap 23] Logistic distribution (2 params): p1 = location, p2 = scale. Density(x) proportional to sech^2((x-p1)/(2*p2)). */ #define NIFTI_INTENT_LOGISTIC 14 /*! [C2, chap 24] Laplace distribution (2 params): p1 = location, p2 = scale. Density(x) proportional to exp(-abs(x-p1)/p2). */ #define NIFTI_INTENT_LAPLACE 15 /*! [C2, chap 26] Uniform distribution: p1 = lower end, p2 = upper end. */ #define NIFTI_INTENT_UNIFORM 16 /*! [C2, chap 31] Noncentral t statistic (2 params): p1 = DOF, p2 = noncentrality parameter. */ #define NIFTI_INTENT_TTEST_NONC 17 /*! [C1, chap 21] Weibull distribution (3 params): p1 = location, p2 = scale, p3 = power. Density(x) proportional to ((x-p1)/p2)^(p3-1) * exp(-((x-p1)/p2)^p3) for x > p1. */ #define NIFTI_INTENT_WEIBULL 18 /*! [C1, chap 18] Chi distribution (1 param): p1 = DOF. Density(x) proportional to x^(p1-1) * exp(-x^2/2) for x > 0. p1 = 1 = 'half normal' distribution p1 = 2 = Rayleigh distribution p1 = 3 = Maxwell-Boltzmann distribution. */ #define NIFTI_INTENT_CHI 19 /*! [C1, chap 15] Inverse Gaussian (2 params): p1 = mu, p2 = lambda Density(x) proportional to exp(-p2*(x-p1)^2/(2*p1^2*x)) / x^3 for x > 0. */ #define NIFTI_INTENT_INVGAUSS 20 /*! [C2, chap 22] Extreme value type I (2 params): p1 = location, p2 = scale cdf(x) = exp(-exp(-(x-p1)/p2)). */ #define NIFTI_INTENT_EXTVAL 21 /*! Data is a 'p-value' (no params). */ #define NIFTI_INTENT_PVAL 22 /*! Data is ln(p-value) (no params). To be safe, a program should compute p = exp(-abs(this_value)). The nifti_stats.c library returns this_value as positive, so that this_value = -log(p). */ #define NIFTI_INTENT_LOGPVAL 23 /*! Data is log10(p-value) (no params). To be safe, a program should compute p = pow(10.,-abs(this_value)). The nifti_stats.c library returns this_value as positive, so that this_value = -log10(p). */ #define NIFTI_INTENT_LOG10PVAL 24 /*! Smallest intent_code that indicates a statistic. */ #define NIFTI_FIRST_STATCODE 2 /*! Largest intent_code that indicates a statistic. */ #define NIFTI_LAST_STATCODE 24 /*---------- these values for intent_code aren't for statistics ----------*/ /*! To signify that the value at each voxel is an estimate of some parameter, set intent_code = NIFTI_INTENT_ESTIMATE. The name of the parameter may be stored in intent_name. */ #define NIFTI_INTENT_ESTIMATE 1001 /*! To signify that the value at each voxel is an index into some set of labels, set intent_code = NIFTI_INTENT_LABEL. The filename with the labels may stored in aux_file. */ #define NIFTI_INTENT_LABEL 1002 /*! To signify that the value at each voxel is an index into the NeuroNames labels set, set intent_code = NIFTI_INTENT_NEURONAME. */ #define NIFTI_INTENT_NEURONAME 1003 /*! To store an M x N matrix at each voxel: - dataset must have a 5th dimension (dim[0]=5 and dim[5]>1) - intent_code must be NIFTI_INTENT_GENMATRIX - dim[5] must be M*N - intent_p1 must be M (in float format) - intent_p2 must be N (ditto) - the matrix values A[i][[j] are stored in row-order: - A[0][0] A[0][1] ... A[0][N-1] - A[1][0] A[1][1] ... A[1][N-1] - etc., until - A[M-1][0] A[M-1][1] ... A[M-1][N-1] */ #define NIFTI_INTENT_GENMATRIX 1004 /*! To store an NxN symmetric matrix at each voxel: - dataset must have a 5th dimension - intent_code must be NIFTI_INTENT_SYMMATRIX - dim[5] must be N*(N+1)/2 - intent_p1 must be N (in float format) - the matrix values A[i][[j] are stored in row-order: - A[0][0] - A[1][0] A[1][1] - A[2][0] A[2][1] A[2][2] - etc.: row-by-row */ #define NIFTI_INTENT_SYMMATRIX 1005 /*! To signify that the vector value at each voxel is to be taken as a displacement field or vector: - dataset must have a 5th dimension - intent_code must be NIFTI_INTENT_DISPVECT - dim[5] must be the dimensionality of the displacment vector (e.g., 3 for spatial displacement, 2 for in-plane) */ #define NIFTI_INTENT_DISPVECT 1006 /* specifically for displacements */ #define NIFTI_INTENT_VECTOR 1007 /* for any other type of vector */ /*! To signify that the vector value at each voxel is really a spatial coordinate (e.g., the vertices or nodes of a surface mesh): - dataset must have a 5th dimension - intent_code must be NIFTI_INTENT_POINTSET - dim[0] = 5 - dim[1] = number of points - dim[2] = dim[3] = dim[4] = 1 - dim[5] must be the dimensionality of space (e.g., 3 => 3D space). - intent_name may describe the object these points come from (e.g., "pial", "gray/white" , "EEG", "MEG"). */ #define NIFTI_INTENT_POINTSET 1008 /*! To signify that the vector value at each voxel is really a triple of indexes (e.g., forming a triangle) from a pointset dataset: - dataset must have a 5th dimension - intent_code must be NIFTI_INTENT_TRIANGLE - dim[0] = 5 - dim[1] = number of triangles - dim[2] = dim[3] = dim[4] = 1 - dim[5] = 3 - datatype should be an integer type (preferably DT_INT32) - the data values are indexes (0,1,...) into a pointset dataset. */ #define NIFTI_INTENT_TRIANGLE 1009 /*! To signify that the vector value at each voxel is a quaternion: - dataset must have a 5th dimension - intent_code must be NIFTI_INTENT_QUATERNION - dim[0] = 5 - dim[5] = 4 - datatype should be a floating point type */ #define NIFTI_INTENT_QUATERNION 1010 /*! Dimensionless value - no params - although, as in _ESTIMATE the name of the parameter may be stored in intent_name. */ #define NIFTI_INTENT_DIMLESS 1011 /*---------- these values apply to GIFTI datasets ----------*/ /*! To signify that the value at each location is from a time series. */ #define NIFTI_INTENT_TIME_SERIES 2001 /*! To signify that the value at each location is a node index, from a complete surface dataset. */ #define NIFTI_INTENT_NODE_INDEX 2002 /*! To signify that the vector value at each location is an RGB triplet, of whatever type. - dataset must have a 5th dimension - dim[0] = 5 - dim[1] = number of nodes - dim[2] = dim[3] = dim[4] = 1 - dim[5] = 3 */ #define NIFTI_INTENT_RGB_VECTOR 2003 /*! To signify that the vector value at each location is a 4 valued RGBA vector, of whatever type. - dataset must have a 5th dimension - dim[0] = 5 - dim[1] = number of nodes - dim[2] = dim[3] = dim[4] = 1 - dim[5] = 4 */ #define NIFTI_INTENT_RGBA_VECTOR 2004 /*! To signify that the value at each location is a shape value, such as the curvature. */ #define NIFTI_INTENT_SHAPE 2005 /* @} */ /*---------------------------------------------------------------------------*/ /* 3D IMAGE (VOLUME) ORIENTATION AND LOCATION IN SPACE: --------------------------------------------------- There are 3 different methods by which continuous coordinates can attached to voxels. The discussion below emphasizes 3D volumes, and the continuous coordinates are referred to as (x,y,z). The voxel index coordinates (i.e., the array indexes) are referred to as (i,j,k), with valid ranges: i = 0 .. dim[1]-1 j = 0 .. dim[2]-1 (if dim[0] >= 2) k = 0 .. dim[3]-1 (if dim[0] >= 3) The (x,y,z) coordinates refer to the CENTER of a voxel. In methods 2 and 3, the (x,y,z) axes refer to a subject-based coordinate system, with +x = Right +y = Anterior +z = Superior. This is a right-handed coordinate system. However, the exact direction these axes point with respect to the subject depends on qform_code (Method 2) and sform_code (Method 3). N.B.: The i index varies most rapidly, j index next, k index slowest. Thus, voxel (i,j,k) is stored starting at location (i + j*dim[1] + k*dim[1]*dim[2]) * (bitpix/8) into the dataset array. N.B.: The ANALYZE 7.5 coordinate system is +x = Left +y = Anterior +z = Superior which is a left-handed coordinate system. This backwardness is too difficult to tolerate, so this NIFTI-1 standard specifies the coordinate order which is most common in functional neuroimaging. N.B.: The 3 methods below all give the locations of the voxel centers in the (x,y,z) coordinate system. In many cases, programs will wish to display image data on some other grid. In such a case, the program will need to convert its desired (x,y,z) values into (i,j,k) values in order to extract (or interpolate) the image data. This operation would be done with the inverse transformation to those described below. N.B.: Method 2 uses a factor 'qfac' which is either -1 or 1; qfac is stored in the otherwise unused pixdim[0]. If pixdim[0]=0.0 (which should not occur), we take qfac=1. Of course, pixdim[0] is only used when reading a NIFTI-1 header, not when reading an ANALYZE 7.5 header. N.B.: The units of (x,y,z) can be specified using the xyzt_units field. METHOD 1 (the "old" way, used only when qform_code = 0): ------------------------------------------------------- The coordinate mapping from (i,j,k) to (x,y,z) is the ANALYZE 7.5 way. This is a simple scaling relationship: x = pixdim[1] * i y = pixdim[2] * j z = pixdim[3] * k No particular spatial orientation is attached to these (x,y,z) coordinates. (NIFTI-1 does not have the ANALYZE 7.5 orient field, which is not general and is often not set properly.) This method is not recommended, and is present mainly for compatibility with ANALYZE 7.5 files. METHOD 2 (used when qform_code > 0, which should be the "normal" case): --------------------------------------------------------------------- The (x,y,z) coordinates are given by the pixdim[] scales, a rotation matrix, and a shift. This method is intended to represent "scanner-anatomical" coordinates, which are often embedded in the image header (e.g., DICOM fields (0020,0032), (0020,0037), (0028,0030), and (0018,0050)), and represent the nominal orientation and location of the data. This method can also be used to represent "aligned" coordinates, which would typically result from some post-acquisition alignment of the volume to a standard orientation (e.g., the same subject on another day, or a rigid rotation to true anatomical orientation from the tilted position of the subject in the scanner). The formula for (x,y,z) in terms of header parameters and (i,j,k) is: [ x ] [ R11 R12 R13 ] [ pixdim[1] * i ] [ qoffset_x ] [ y ] = [ R21 R22 R23 ] [ pixdim[2] * j ] + [ qoffset_y ] [ z ] [ R31 R32 R33 ] [ qfac * pixdim[3] * k ] [ qoffset_z ] The qoffset_* shifts are in the NIFTI-1 header. Note that the center of the (i,j,k)=(0,0,0) voxel (first value in the dataset array) is just (x,y,z)=(qoffset_x,qoffset_y,qoffset_z). The rotation matrix R is calculated from the quatern_* parameters. This calculation is described below. The scaling factor qfac is either 1 or -1. The rotation matrix R defined by the quaternion parameters is "proper" (has determinant 1). This may not fit the needs of the data; for example, if the image grid is i increases from Left-to-Right j increases from Anterior-to-Posterior k increases from Inferior-to-Superior Then (i,j,k) is a left-handed triple. In this example, if qfac=1, the R matrix would have to be [ 1 0 0 ] [ 0 -1 0 ] which is "improper" (determinant = -1). [ 0 0 1 ] If we set qfac=-1, then the R matrix would be [ 1 0 0 ] [ 0 -1 0 ] which is proper. [ 0 0 -1 ] This R matrix is represented by quaternion [a,b,c,d] = [0,1,0,0] (which encodes a 180 degree rotation about the x-axis). METHOD 3 (used when sform_code > 0): ----------------------------------- The (x,y,z) coordinates are given by a general affine transformation of the (i,j,k) indexes: x = srow_x[0] * i + srow_x[1] * j + srow_x[2] * k + srow_x[3] y = srow_y[0] * i + srow_y[1] * j + srow_y[2] * k + srow_y[3] z = srow_z[0] * i + srow_z[1] * j + srow_z[2] * k + srow_z[3] The srow_* vectors are in the NIFTI_1 header. Note that no use is made of pixdim[] in this method. WHY 3 METHODS? -------------- Method 1 is provided only for backwards compatibility. The intention is that Method 2 (qform_code > 0) represents the nominal voxel locations as reported by the scanner, or as rotated to some fiducial orientation and location. Method 3, if present (sform_code > 0), is to be used to give the location of the voxels in some standard space. The sform_code indicates which standard space is present. Both methods 2 and 3 can be present, and be useful in different contexts (method 2 for displaying the data on its original grid; method 3 for displaying it on a standard grid). In this scheme, a dataset would originally be set up so that the Method 2 coordinates represent what the scanner reported. Later, a registration to some standard space can be computed and inserted in the header. Image display software can use either transform, depending on its purposes and needs. In Method 2, the origin of coordinates would generally be whatever the scanner origin is; for example, in MRI, (0,0,0) is the center of the gradient coil. In Method 3, the origin of coordinates would depend on the value of sform_code; for example, for the Talairach coordinate system, (0,0,0) corresponds to the Anterior Commissure. QUATERNION REPRESENTATION OF ROTATION MATRIX (METHOD 2) ------------------------------------------------------- The orientation of the (x,y,z) axes relative to the (i,j,k) axes in 3D space is specified using a unit quaternion [a,b,c,d], where a*a+b*b+c*c+d*d=1. The (b,c,d) values are all that is needed, since we require that a = sqrt(1.0-(b*b+c*c+d*d)) be nonnegative. The (b,c,d) values are stored in the (quatern_b,quatern_c,quatern_d) fields. The quaternion representation is chosen for its compactness in representing rotations. The (proper) 3x3 rotation matrix that corresponds to [a,b,c,d] is [ a*a+b*b-c*c-d*d 2*b*c-2*a*d 2*b*d+2*a*c ] R = [ 2*b*c+2*a*d a*a+c*c-b*b-d*d 2*c*d-2*a*b ] [ 2*b*d-2*a*c 2*c*d+2*a*b a*a+d*d-c*c-b*b ] [ R11 R12 R13 ] = [ R21 R22 R23 ] [ R31 R32 R33 ] If (p,q,r) is a unit 3-vector, then rotation of angle h about that direction is represented by the quaternion [a,b,c,d] = [cos(h/2), p*sin(h/2), q*sin(h/2), r*sin(h/2)]. Requiring a >= 0 is equivalent to requiring -Pi <= h <= Pi. (Note that [-a,-b,-c,-d] represents the same rotation as [a,b,c,d]; there are 2 quaternions that can be used to represent a given rotation matrix R.) To rotate a 3-vector (x,y,z) using quaternions, we compute the quaternion product [0,x',y',z'] = [a,b,c,d] * [0,x,y,z] * [a,-b,-c,-d] which is equivalent to the matrix-vector multiply [ x' ] [ x ] [ y' ] = R [ y ] (equivalence depends on a*a+b*b+c*c+d*d=1) [ z' ] [ z ] Multiplication of 2 quaternions is defined by the following: [a,b,c,d] = a*1 + b*I + c*J + d*K where I*I = J*J = K*K = -1 (I,J,K are square roots of -1) I*J = K J*K = I K*I = J J*I = -K K*J = -I I*K = -J (not commutative!) For example [a,b,0,0] * [0,0,0,1] = [0,0,-b,a] since this expands to (a+b*I)*(K) = (a*K+b*I*K) = (a*K-b*J). The above formula shows how to go from quaternion (b,c,d) to rotation matrix and direction cosines. Conversely, given R, we can compute the fields for the NIFTI-1 header by a = 0.5 * sqrt(1+R11+R22+R33) (not stored) b = 0.25 * (R32-R23) / a => quatern_b c = 0.25 * (R13-R31) / a => quatern_c d = 0.25 * (R21-R12) / a => quatern_d If a=0 (a 180 degree rotation), alternative formulas are needed. See the nifti1_io.c function mat44_to_quatern() for an implementation of the various cases in converting R to [a,b,c,d]. Note that R-transpose (= R-inverse) would lead to the quaternion [a,-b,-c,-d]. The choice to specify the qoffset_x (etc.) values in the final coordinate system is partly to make it easy to convert DICOM images to this format. The DICOM attribute "Image Position (Patient)" (0020,0032) stores the (Xd,Yd,Zd) coordinates of the center of the first voxel. Here, (Xd,Yd,Zd) refer to DICOM coordinates, and Xd=-x, Yd=-y, Zd=z, where (x,y,z) refers to the NIFTI coordinate system discussed above. (i.e., DICOM +Xd is Left, +Yd is Posterior, +Zd is Superior, whereas +x is Right, +y is Anterior , +z is Superior. ) Thus, if the (0020,0032) DICOM attribute is extracted into (px,py,pz), then qoffset_x = -px qoffset_y = -py qoffset_z = pz is a reasonable setting when qform_code=NIFTI_XFORM_SCANNER_ANAT. That is, DICOM's coordinate system is 180 degrees rotated about the z-axis from the neuroscience/NIFTI coordinate system. To transform between DICOM and NIFTI, you just have to negate the x- and y-coordinates. The DICOM attribute (0020,0037) "Image Orientation (Patient)" gives the orientation of the x- and y-axes of the image data in terms of 2 3-vectors. The first vector is a unit vector along the x-axis, and the second is along the y-axis. If the (0020,0037) attribute is extracted into the value (xa,xb,xc,ya,yb,yc), then the first two columns of the R matrix would be [ -xa -ya ] [ -xb -yb ] [ xc yc ] The negations are because DICOM's x- and y-axes are reversed relative to NIFTI's. The third column of the R matrix gives the direction of displacement (relative to the subject) along the slice-wise direction. This orientation is not encoded in the DICOM standard in a simple way; DICOM is mostly concerned with 2D images. The third column of R will be either the cross-product of the first 2 columns or its negative. It is possible to infer the sign of the 3rd column by examining the coordinates in DICOM attribute (0020,0032) "Image Position (Patient)" for successive slices. However, this method occasionally fails for reasons that I (RW Cox) do not understand. -----------------------------------------------------------------------------*/ /* [qs]form_code value: */ /* x,y,z coordinate system refers to: */ /*-----------------------*/ /*---------------------------------------*/ /*! \defgroup NIFTI1_XFORM_CODES \brief nifti1 xform codes to describe the "standard" coordinate system @{ */ /*! Arbitrary coordinates (Method 1). */ #define NIFTI_XFORM_UNKNOWN 0 /*! Scanner-based anatomical coordinates */ #define NIFTI_XFORM_SCANNER_ANAT 1 /*! Coordinates aligned to another file's, or to anatomical "truth". */ #define NIFTI_XFORM_ALIGNED_ANAT 2 /*! Coordinates aligned to Talairach- Tournoux Atlas; (0,0,0)=AC, etc. */ #define NIFTI_XFORM_TALAIRACH 3 /*! MNI 152 normalized coordinates. */ #define NIFTI_XFORM_MNI_152 4 /* @} */ /*---------------------------------------------------------------------------*/ /* UNITS OF SPATIAL AND TEMPORAL DIMENSIONS: ---------------------------------------- The codes below can be used in xyzt_units to indicate the units of pixdim. As noted earlier, dimensions 1,2,3 are for x,y,z; dimension 4 is for time (t). - If dim[4]=1 or dim[0] < 4, there is no time axis. - A single time series (no space) would be specified with - dim[0] = 4 (for scalar data) or dim[0] = 5 (for vector data) - dim[1] = dim[2] = dim[3] = 1 - dim[4] = number of time points - pixdim[4] = time step - xyzt_units indicates units of pixdim[4] - dim[5] = number of values stored at each time point Bits 0..2 of xyzt_units specify the units of pixdim[1..3] (e.g., spatial units are values 1..7). Bits 3..5 of xyzt_units specify the units of pixdim[4] (e.g., temporal units are multiples of 8). This compression of 2 distinct concepts into 1 byte is due to the limited space available in the 348 byte ANALYZE 7.5 header. The macros XYZT_TO_SPACE and XYZT_TO_TIME can be used to mask off the undesired bits from the xyzt_units fields, leaving "pure" space and time codes. Inversely, the macro SPACE_TIME_TO_XYZT can be used to assemble a space code (0,1,2,...,7) with a time code (0,8,16,32,...,56) into the combined value for xyzt_units. Note that codes are provided to indicate the "time" axis units are actually frequency in Hertz (_HZ), in part-per-million (_PPM) or in radians-per-second (_RADS). The toffset field can be used to indicate a nonzero start point for the time axis. That is, time point #m is at t=toffset+m*pixdim[4] for m=0..dim[4]-1. -----------------------------------------------------------------------------*/ /*! \defgroup NIFTI1_UNITS \brief nifti1 units codes to describe the unit of measurement for each dimension of the dataset @{ */ /*! NIFTI code for unspecified units. */ #define NIFTI_UNITS_UNKNOWN 0 /** Space codes are multiples of 1. **/ /*! NIFTI code for meters. */ #define NIFTI_UNITS_METER 1 /*! NIFTI code for millimeters. */ #define NIFTI_UNITS_MM 2 /*! NIFTI code for micrometers. */ #define NIFTI_UNITS_MICRON 3 /** Time codes are multiples of 8. **/ /*! NIFTI code for seconds. */ #define NIFTI_UNITS_SEC 8 /*! NIFTI code for milliseconds. */ #define NIFTI_UNITS_MSEC 16 /*! NIFTI code for microseconds. */ #define NIFTI_UNITS_USEC 24 /*** These units are for spectral data: ***/ /*! NIFTI code for Hertz. */ #define NIFTI_UNITS_HZ 32 /*! NIFTI code for ppm. */ #define NIFTI_UNITS_PPM 40 /*! NIFTI code for radians per second. */ #define NIFTI_UNITS_RADS 48 /* @} */ #undef XYZT_TO_SPACE #undef XYZT_TO_TIME #define XYZT_TO_SPACE(xyzt) ( (xyzt) & 0x07 ) #define XYZT_TO_TIME(xyzt) ( (xyzt) & 0x38 ) #undef SPACE_TIME_TO_XYZT #define SPACE_TIME_TO_XYZT(ss,tt) ( (((char)(ss)) & 0x07) \ | (((char)(tt)) & 0x38) ) /*---------------------------------------------------------------------------*/ /* MRI-SPECIFIC SPATIAL AND TEMPORAL INFORMATION: --------------------------------------------- A few fields are provided to store some extra information that is sometimes important when storing the image data from an FMRI time series experiment. (After processing such data into statistical images, these fields are not likely to be useful.) { freq_dim } = These fields encode which spatial dimension (1,2, or 3) { phase_dim } = corresponds to which acquisition dimension for MRI data. { slice_dim } = Examples: Rectangular scan multi-slice EPI: freq_dim = 1 phase_dim = 2 slice_dim = 3 (or some permutation) Spiral scan multi-slice EPI: freq_dim = phase_dim = 0 slice_dim = 3 since the concepts of frequency- and phase-encoding directions don't apply to spiral scan slice_duration = If this is positive, AND if slice_dim is nonzero, indicates the amount of time used to acquire 1 slice. slice_duration*dim[slice_dim] can be less than pixdim[4] with a clustered acquisition method, for example. slice_code = If this is nonzero, AND if slice_dim is nonzero, AND if slice_duration is positive, indicates the timing pattern of the slice acquisition. The following codes are defined: NIFTI_SLICE_SEQ_INC == sequential increasing NIFTI_SLICE_SEQ_DEC == sequential decreasing NIFTI_SLICE_ALT_INC == alternating increasing NIFTI_SLICE_ALT_DEC == alternating decreasing NIFTI_SLICE_ALT_INC2 == alternating increasing #2 NIFTI_SLICE_ALT_DEC2 == alternating decreasing #2 { slice_start } = Indicates the start and end of the slice acquisition { slice_end } = pattern, when slice_code is nonzero. These values are present to allow for the possible addition of "padded" slices at either end of the volume, which don't fit into the slice timing pattern. If there are no padding slices, then slice_start=0 and slice_end=dim[slice_dim]-1 are the correct values. For these values to be meaningful, slice_start must be non-negative and slice_end must be greater than slice_start. Otherwise, they should be ignored. The following table indicates the slice timing pattern, relative to time=0 for the first slice acquired, for some sample cases. Here, dim[slice_dim]=7 (there are 7 slices, labeled 0..6), slice_duration=0.1, and slice_start=1, slice_end=5 (1 padded slice on each end). slice index SEQ_INC SEQ_DEC ALT_INC ALT_DEC ALT_INC2 ALT_DEC2 6 : n/a n/a n/a n/a n/a n/a n/a = not applicable 5 : 0.4 0.0 0.2 0.0 0.4 0.2 (slice time offset 4 : 0.3 0.1 0.4 0.3 0.1 0.0 doesn't apply to 3 : 0.2 0.2 0.1 0.1 0.3 0.3 slices outside 2 : 0.1 0.3 0.3 0.4 0.0 0.1 the range 1 : 0.0 0.4 0.0 0.2 0.2 0.4 slice_start .. 0 : n/a n/a n/a n/a n/a n/a slice_end) The SEQ slice_codes are sequential ordering (uncommon but not unknown), either increasing in slice number or decreasing (INC or DEC), as illustrated above. The ALT slice codes are alternating ordering. The 'standard' way for these to operate (without the '2' on the end) is for the slice timing to start at the edge of the slice_start .. slice_end group (at slice_start for INC and at slice_end for DEC). For the 'ALT_*2' slice_codes, the slice timing instead starts at the first slice in from the edge (at slice_start+1 for INC2 and at slice_end-1 for DEC2). This latter acquisition scheme is found on some Siemens scanners. The fields freq_dim, phase_dim, slice_dim are all squished into the single byte field dim_info (2 bits each, since the values for each field are limited to the range 0..3). This unpleasantness is due to lack of space in the 348 byte allowance. The macros DIM_INFO_TO_FREQ_DIM, DIM_INFO_TO_PHASE_DIM, and DIM_INFO_TO_SLICE_DIM can be used to extract these values from the dim_info byte. The macro FPS_INTO_DIM_INFO can be used to put these 3 values into the dim_info byte. -----------------------------------------------------------------------------*/ #undef DIM_INFO_TO_FREQ_DIM #undef DIM_INFO_TO_PHASE_DIM #undef DIM_INFO_TO_SLICE_DIM #define DIM_INFO_TO_FREQ_DIM(di) ( ((di) ) & 0x03 ) #define DIM_INFO_TO_PHASE_DIM(di) ( ((di) >> 2) & 0x03 ) #define DIM_INFO_TO_SLICE_DIM(di) ( ((di) >> 4) & 0x03 ) #undef FPS_INTO_DIM_INFO #define FPS_INTO_DIM_INFO(fd,pd,sd) ( ( ( ((char)(fd)) & 0x03) ) | \ ( ( ((char)(pd)) & 0x03) << 2 ) | \ ( ( ((char)(sd)) & 0x03) << 4 ) ) /*! \defgroup NIFTI1_SLICE_ORDER \brief nifti1 slice order codes, describing the acquisition order of the slices @{ */ #define NIFTI_SLICE_UNKNOWN 0 #define NIFTI_SLICE_SEQ_INC 1 #define NIFTI_SLICE_SEQ_DEC 2 #define NIFTI_SLICE_ALT_INC 3 #define NIFTI_SLICE_ALT_DEC 4 #define NIFTI_SLICE_ALT_INC2 5 /* 05 May 2005: RWCox */ #define NIFTI_SLICE_ALT_DEC2 6 /* 05 May 2005: RWCox */ /* @} */ /*---------------------------------------------------------------------------*/ /* UNUSED FIELDS: ------------- Some of the ANALYZE 7.5 fields marked as ++UNUSED++ may need to be set to particular values for compatibility with other programs. The issue of interoperability of ANALYZE 7.5 files is a murky one -- not all programs require exactly the same set of fields. (Unobscuring this murkiness is a principal motivation behind NIFTI-1.) Some of the fields that may need to be set for other (non-NIFTI aware) software to be happy are: extents dbh.h says this should be 16384 regular dbh.h says this should be the character 'r' glmin, } dbh.h says these values should be the min and max voxel glmax } values for the entire dataset It is best to initialize ALL fields in the NIFTI-1 header to 0 (e.g., with calloc()), then fill in what is needed. -----------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ /* MISCELLANEOUS C MACROS -----------------------------------------------------------------------------*/ /*.................*/ /*! Given a nifti_1_header struct, check if it has a good magic number. Returns NIFTI version number (1..9) if magic is good, 0 if it is not. */ #define NIFTI_VERSION(h) \ ( ( (h).magic[0]=='n' && (h).magic[3]=='\0' && \ ( (h).magic[1]=='i' || (h).magic[1]=='+' ) && \ ( (h).magic[2]>='1' && (h).magic[2]<='9' ) ) \ ? (h).magic[2]-'0' : 0 ) /*.................*/ /*! Check if a nifti_1_header struct says if the data is stored in the same file or in a separate file. Returns 1 if the data is in the same file as the header, 0 if it is not. */ #define NIFTI_ONEFILE(h) ( (h).magic[1] == '+' ) /*.................*/ /*! Check if a nifti_1_header struct needs to be byte swapped. Returns 1 if it needs to be swapped, 0 if it does not. */ #define NIFTI_NEEDS_SWAP(h) ( (h).dim[0] < 0 || (h).dim[0] > 7 ) /*.................*/ /*! Check if a nifti_1_header struct contains a 5th (vector) dimension. Returns size of 5th dimension if > 1, returns 0 otherwise. */ #define NIFTI_5TH_DIM(h) ( ((h).dim[0]>4 && (h).dim[5]>1) ? (h).dim[5] : 0 ) /*****************************************************************************/ /*=================*/ #ifdef __cplusplus } #endif /*=================*/ #endif /* _NIFTI_HEADER_ */ pynifti-0.20100607.1/3rd/nifticlibs/nifti1_io.c0000664000175000017500000076775011414645202020412 0ustar michaelmichael#define _NIFTI1_IO_C_ #include "nifti1_io.h" /* typedefs, prototypes, macros, etc. */ /*****===================================================================*****/ /***** Sample functions to deal with NIFTI-1 and ANALYZE files *****/ /*****...................................................................*****/ /***** This code is released to the public domain. *****/ /*****...................................................................*****/ /***** Author: Robert W Cox, SSCC/DIRP/NIMH/NIH/DHHS/USA/EARTH *****/ /***** Date: August 2003 *****/ /*****...................................................................*****/ /***** Neither the National Institutes of Health (NIH), nor any of its *****/ /***** employees imply any warranty of usefulness of this software for *****/ /***** any purpose, and do not assume any liability for damages, *****/ /***** incidental or otherwise, caused by any use of this document. *****/ /*****===================================================================*****/ /** \file nifti1_io.c \brief main collection of nifti1 i/o routines - written by Bob Cox, SSCC NIMH - revised by Mark Jenkinson, FMRIB - revised by Rick Reynolds, SSCC, NIMH - revised by Kate Fissell, University of Pittsburgh The library history can be viewed via "nifti_tool -nifti_hist".
    The library version can be viewed via "nifti_tool -nifti_ver". */ /*! global history and version strings, for printing */ static char * gni_history[] = { "----------------------------------------------------------------------\n" "history (of nifti library changes):\n" "\n", "0.0 August, 2003 [rwcox]\n" " (Robert W Cox of the National Institutes of Health, SSCC/DIRP/NIMH)\n" " - initial version\n" "\n", "0.1 July/August, 2004 [Mark Jenkinson]\n" " (FMRIB Centre, University of Oxford, UK)\n" " - Mainly adding low-level IO and changing things to allow gzipped\n" " files to be read and written\n" " - Full backwards compatability should have been maintained\n" "\n", "0.2 16 Nov 2004 [rickr]\n" " (Rick Reynolds of the National Institutes of Health, SSCC/DIRP/NIMH)\n" " - included Mark's changes in the AFNI distribution (including znzlib/)\n" " (HAVE_ZLIB is commented out for the standard distribution)\n" " - modified nifti_validfilename() and nifti_makebasename()\n" " - added nifti_find_file_extension()\n" "\n", "0.3 3 Dec 2004 [rickr]\n" " - note: header extensions are not yet checked for\n" " - added formatted history as global string, for printing\n" " - added nifti_disp_lib_hist(), to display the nifti library history\n" " - added nifti_disp_lib_version(), to display the nifti library history\n", " - re-wrote nifti_findhdrname()\n" " o used nifti_find_file_extension()\n" " o changed order of file tests (default is .nii, depends on input)\n" " o free hdrname on failure\n" " - made similar changes to nifti_findimgname()\n" " - check for NULL return from nifti_findhdrname() calls\n", " - removed most of ERREX() macros\n" " - modified nifti_image_read()\n" " o added debug info and error checking (on gni_debug > 0, only)\n" " o fail if workingname is NULL\n" " o check for failure to open header file\n" " o free workingname on failure\n" " o check for failure of nifti_image_load()\n" " o check for failure of nifti_convert_nhdr2nim()\n", " - changed nifti_image_load() to int, and check nifti_read_buffer return\n" " - changed nifti_read_buffer() to fail on short read, and to count float\n" " fixes (to print on debug)\n" " - changed nifti_image_infodump to print to stderr\n" " - updated function header comments, or moved comments above header\n" " - removed const keyword\n" " - added LNI_FERR() macro for error reporting on input files\n" "\n", "0.4 10 Dec 2004 [rickr] - added header extensions\n" " - in nifti1_io.h:\n" " o added num_ext and ext_list to the definition of nifti_image\n" " o made many functions static (more to follow)\n" " o added LNI_MAX_NIA_EXT_LEN, for max nifti_type 3 extension length\n", " - added __DATE__ to version output in nifti_disp_lib_version()\n" " - added nifti_disp_matrix_orient() to print orientation information\n" " - added '.nia' as a valid file extension in nifti_find_file_extension()\n" " - added much more debug output\n" " - in nifti_image_read(), in the case of an ASCII header, check for\n" " extensions after the end of the header\n", " - added nifti_read_extensions() function\n" " - added nifti_read_next_extension() function\n" " - added nifti_add_exten_to_list() function\n" " - added nifti_check_extension() function\n" " - added nifti_write_extensions() function\n" " - added nifti_extension_size() function\n" " - in nifti_set_iname_offest():\n" " o adjust offset by the extension size and the extender size\n", " o fixed the 'ceiling modulo 16' computation\n" " - in nifti_image_write_hdr_img2(): \n" " o added extension writing\n" " o check for NULL return from nifti_findimgname()\n" " - include number of extensions in nifti_image_to_ascii() output\n" " - in nifti_image_from_ascii():\n" " o return bytes_read as a parameter, computed from the final spos\n" " o extract num_ext from ASCII header\n" "\n", "0.5 14 Dec 2004 [rickr] - added sub-brick reading functions\n" " - added nifti_brick_list type to nifti1_io.h, along with new prototypes\n" " - added main nifti_image_read_bricks() function, with description\n" " - added nifti_image_load_bricks() - library function (requires nim)\n" " - added valid_nifti_brick_list() - library function\n" " - added free_NBL() - library function\n", " - added update_nifti_image_for_brick_list() for dimension update\n" " - added nifti_load_NBL_bricks(), nifti_alloc_NBL_mem(),\n" " nifti_copynsort() and force_positive() (static functions)\n" " - in nifti_image_read(), check for failed load only if read_data is set\n" " - broke most of nifti_image_load() into nifti_image_load_prep()\n" "\n", "0.6 15 Dec 2004 [rickr] - added sub-brick writing functionality\n" " - in nifti1_io.h, removed znzlib directory from include - all nifti\n" " library files are now under the nifti directory\n" " - nifti_read_extensions(): print no offset warning for nifti_type 3\n" " - nifti_write_all_data():\n" " o pass nifti_brick_list * NBL, for optional writing\n" " o if NBL, write each sub-brick, sequentially\n", " - nifti_set_iname_offset(): case 1 must have sizeof() cast to int\n" " - pass NBL to nifti_image_write_hdr_img2(), and allow NBL or data\n" " - added nifti_image_write_bricks() wrapper for ...write_hdr_img2()\n" " - included compression abilities\n" "\n", "0.7 16 Dec 2004 [rickr] - minor changes to extension reading\n" "\n", "0.8 21 Dec 2004 [rickr] - restrict extension reading, and minor changes\n" " - in nifti_image_read(), compute bytes for extensions (see remaining)\n" " - in nifti_read_extensions(), pass 'remain' as space for extensions,\n" " pass it to nifti_read_next_ext(), and update for each one read \n" " - in nifti_check_extension(), require (size <= remain)\n", " - in update_nifti_image_brick_list(), update nvox\n" " - in nifti_image_load_bricks(), make explicit check for nbricks <= 0\n" " - in int_force_positive(), check for (!list)\n" " - in swap_nifti_header(), swap sizeof_hdr, and reorder to struct order\n" " - change get_filesize functions to signed ( < 0 is no file or error )\n", " - in nifti_validfilename(), lose redundant (len < 0) check\n" " - make print_hex_vals() static\n" " - in disp_nifti_1_header, restrict string field widths\n" "\n", "0.9 23 Dec 2004 [rickr] - minor changes\n" " - broke ASCII header reading out of nifti_image_read(), into new\n" " functions has_ascii_header() and read_ascii_image()\n", " - check image_read failure and znzseek failure\n" " - altered some debug output\n" " - nifti_write_all_data() now returns an int\n" "\n", "0.10 29 Dec 2004 [rickr]\n" " - renamed nifti_valid_extension() to nifti_check_extension()\n" " - added functions nifti_makehdrname() and nifti_makeimgname()\n" " - added function valid_nifti_extensions()\n" " - in nifti_write_extensions(), check for validity before writing\n", " - rewrote nifti_image_write_hdr_img2():\n" " o set write_data and leave_open flags from write_opts\n" " o add debug print statements\n" " o use nifti_write_ascii_image() for the ascii case\n" " o rewrote the logic of all cases to be easier to follow\n", " - broke out code as nifti_write_ascii_image() function\n" " - added debug to top-level write functions, and free the znzFile\n" " - removed unused internal function nifti_image_open()\n" "\n", "0.11 30 Dec 2004 [rickr] - small mods\n" " - moved static function prototypes from header to C file\n" " - free extensions in nifti_image_free()\n" "\n", "1.0 07 Jan 2005 [rickr] - INITIAL RELEASE VERSION\n" " - added function nifti_set_filenames()\n" " - added function nifti_read_header()\n" " - added static function nhdr_looks_good()\n" " - added static function need_nhdr_swap()\n" " - exported nifti_add_exten_to_list symbol\n", " - fixed #bytes written in nifti_write_extensions()\n" " - only modify offset if it is too small (nifti_set_iname_offset)\n" " - added nifti_type 3 to nifti_makehdrname and nifti_makeimgname\n" " - added function nifti_set_filenames()\n" "\n", "1.1 07 Jan 2005 [rickr]\n" " - in nifti_read_header(), swap if needed\n" "\n", "1.2 07 Feb 2005 [kate fissell c/o rickr] \n" " - nifti1.h: added doxygen comments for main struct and #define groups\n" " - nifti1_io.h: added doxygen comments for file and nifti_image struct\n" " - nifti1_io.h: added doxygen comments for file and some functions\n" " - nifti1_io.c: changed nifti_copy_nim_info to use memcpy\n" "\n", "1.3 09 Feb 2005 [rickr]\n" " - nifti1.h: added doxygen comments for extension structs\n" " - nifti1_io.h: put most #defines in #ifdef _NIFTI1_IO_C_ block\n" " - added a doxygen-style description to every exported function\n" " - added doxygen-style comments within some functions\n" " - re-exported many znzFile functions that I had made static\n" " - re-added nifti_image_open (sorry, Mark)\n" " - every exported function now has 'nifti' in the name (19 functions)\n", " - made sure every alloc() has a failure test\n" " - added nifti_copy_extensions function, for use in nifti_copy_nim_info\n" " - nifti_is_gzfile: added initial strlen test\n" " - nifti_set_filenames: added set_byte_order parameter option\n" " (it seems appropriate to set the BO when new files are associated)\n" " - disp_nifti_1_header: prints to stdout (a.o.t. stderr), with fflush\n" "\n", "1.4 23 Feb 2005 [rickr] - sourceforge merge\n" " - merged into the nifti_io CVS directory structure at sourceforge.net\n" " - merged in 4 changes by Mark, and re-added his const keywords\n" " - cast some pointers to (void *) for -pedantic compile option\n" " - added nifti_free_extensions()\n" "\n", "1.5 02 Mar 2005 [rickr] - started nifti global options\n" " - gni_debug is now g_opts.debug\n" " - added validity check parameter to nifti_read_header\n" " - need_nhdr_swap no longer does test swaps on the stack\n" "\n", "1.6 05 April 2005 [rickr] - validation and collapsed_image_read\n" " - added nifti_read_collapsed_image(), an interface for reading partial\n" " datasets, specifying a subset of array indices\n" " - for read_collapsed_image, added static functions: rci_read_data(),\n" " rci_alloc_mem(), and make_pivot_list()\n", " - added nifti_nim_is_valid() to check for consistency (more to do)\n" " - added nifti_nim_has_valid_dims() to do many dimensions tests\n" "\n", "1.7 08 April 2005 [rickr]\n" " - added nifti_update_dims_from_array() - to update dimensions\n" " - modified nifti_makehdrname() and nifti_makeimgname():\n" " if prefix has a valid extension, use it (else make one up)\n" " - added nifti_get_intlist - for making an array of ints\n" " - fixed init of NBL->bsize in nifti_alloc_NBL_mem() {thanks, Bob}\n" "\n", "1.8 14 April 2005 [rickr]\n" " - added nifti_set_type_from_names(), for nifti_set_filenames()\n" " (only updates type if number of files does not match it)\n" " - added is_valid_nifti_type(), just to be sure\n" " - updated description of nifti_read_collapsed_image() for *data change\n" " (if *data is already set, assume memory exists for results)\n" " - modified rci_alloc_mem() to allocate only if *data is NULL\n" "\n", "1.9 19 April 2005 [rickr]\n" " - added extension codes NIFTI_ECODE_COMMENT and NIFTI_ECODE_XCEDE\n" " - added nifti_type codes NIFTI_MAX_ECODE and NIFTI_MAX_FTYPE\n" " - added nifti_add_extension() {exported}\n" " - added nifti_fill_extension() as a static function\n" " - added nifti_is_valid_ecode() {exported}\n", " - nifti_type values are now NIFTI_FTYPE_* file codes\n" " - in nifti_read_extensions(), decrement 'remain' by extender size, 4\n" " - in nifti_set_iname_offset(), case 1, update if offset differs\n" " - only output '-d writing nifti file' if debug > 1\n" "\n", "1.10 10 May 2005 [rickr]\n" " - files are read using ZLIB only if they end in '.gz'\n" "\n", "1.11 12 August 2005 [kate fissell]\n" " - Kate's 0.2 release packaging, for sourceforge\n" "\n", "1.12 17 August 2005 [rickr] - comment (doxygen) updates\n" " - updated comments for most functions (2 updates from Cinly Ooi)\n" " - added nifti_type_and_names_match()\n" "\n", "1.12a 24 August 2005 [rickr] - remove all tabs from Clibs/*/*.[ch]\n", "1.12b 25 August 2005 [rickr] - changes by Hans Johnson\n", "1.13 25 August 2005 [rickr]\n", " - finished changes by Hans for Insight\n" " - added const in all appropraite parameter locations (30-40)\n" " (any pointer referencing data that will not change)\n" " - shortened all string constants below 509 character limit\n" "1.14 28 October 2005 [HJohnson]\n", " - use nifti_set_filenames() in nifti_convert_nhdr2nim()\n" "1.15 02 November 2005 [rickr]\n", " - added skip_blank_ext to nifti_global_options\n" " - added nifti_set_skip_blank_ext(), to set option\n" " - if skip_blank_ext and no extensions, do not read/write extender\n" "1.16 18 November 2005 [rickr]\n", " - removed any test or access of dim[i], i>dim[0]\n" " - do not set pixdim for collapsed dims to 1.0, leave them as they are\n" " - added magic and dim[i] tests in nifti_hdr_looks_good()\n" " - added 2 size_t casts\n" "1.17 22 November 2005 [rickr]\n", " - in hdr->nim, for i > dim[0], pass 0 or 1, else set to 1\n" "1.18 02 March 2006 [rickr]\n", " - in nifti_alloc_NBL_mem(), fixed nt=0 case from 1.17 change\n" "1.19 23 May 2006 [HJohnson,rickr]\n", " - nifti_write_ascii_image(): free(hstr)\n" " - nifti_copy_extensions(): clear num_ext and ext_list\n" "1.20 27 Jun 2006 [rickr]\n", " - nifti_findhdrname(): fixed assign of efirst to match stated logic\n" " (problem found by Atle Bjørnerud)\n" "1.21 05 Sep 2006 [rickr] update for nifticlib-0.4 release\n", " - was reminded to actually add nifti_set_skip_blank_ext()\n" " - init g_opts.skip_blank_ext to 0\n" "1.22 01 Jun 2007 nifticlib-0.5 release\n", "1.23 05 Jun 2007 nifti_add_exten_to_list: revert on failure, free old list\n" "1.24 07 Jun 2007 nifti_copy_extensions: use esize-8 for data size\n" "1.25 12 Jun 2007 [rickr] EMPTY_IMAGE creation\n", " - added nifti_make_new_header() - to create from dims/dtype\n" " - added nifti_make_new_nim() - to create from dims/dtype/fill\n" " - added nifti_is_valid_datatype(), and more debug info\n", "1.26 27 Jul 2007 [rickr] handle single volumes > 2^31 bytes (but < 2^32)\n", "1.27 28 Jul 2007 [rickr] nim->nvox, NBL-bsize are now type size_t\n" "1.28 30 Jul 2007 [rickr] size_t updates\n", "1.29 08 Aug 2007 [rickr] for list, valid_nifti_brick_list requires 3 dims\n" "1.30 08 Nov 2007 [Yaroslav/rickr]\n" " - fix ARM struct alignment problem in byte-swapping routines\n", "1.31 29 Nov 2007 [rickr] for nifticlib-1.0.0\n" " - added nifti_datatype_to/from_string routines\n" " - added DT_RGBA32/NIFTI_TYPE_RGBA32 datatype macros (2304)\n" " - added NIFTI_ECODE_FREESURFER (14)\n", "1.32 08 Dec 2007 [rickr]\n" " - nifti_hdr_looks_good() allows ANALYZE headers (req. by V. Luccio)\n" " - added nifti_datatype_is_valid()\n", "1.33 05 Feb 2008 [hansj,rickr] - block nia.gz use\n" "1.34 13 Jun 2008 [rickr] - added nifti_compiled_with_zlib()\n" "1.35 03 Aug 2008 [rickr]\n", " - deal with swapping, so that CPU type does not affect output\n" " (motivated by C Burns)\n" " - added nifti_analyze75 structure and nifti_swap_as_analyze()\n" " - previous swap_nifti_header is saved as old_swap_nifti_header\n" " - also swap UNUSED fields in nifti_1_header struct\n", "----------------------------------------------------------------------\n" }; static char gni_version[] = "nifti library version 1.35 (3 Aug, 2008)"; /*! global nifti options structure */ static nifti_global_options g_opts = { 1, 0 }; /*! global nifti types structure list (per type, ordered oldest to newest) */ static nifti_type_ele nifti_type_list[] = { /* type nbyper swapsize name */ { 0, 0, 0, "DT_UNKNOWN" }, { 0, 0, 0, "DT_NONE" }, { 1, 0, 0, "DT_BINARY" }, /* not usable */ { 2, 1, 0, "DT_UNSIGNED_CHAR" }, { 2, 1, 0, "DT_UINT8" }, { 2, 1, 0, "NIFTI_TYPE_UINT8" }, { 4, 2, 2, "DT_SIGNED_SHORT" }, { 4, 2, 2, "DT_INT16" }, { 4, 2, 2, "NIFTI_TYPE_INT16" }, { 8, 4, 4, "DT_SIGNED_INT" }, { 8, 4, 4, "DT_INT32" }, { 8, 4, 4, "NIFTI_TYPE_INT32" }, { 16, 4, 4, "DT_FLOAT" }, { 16, 4, 4, "DT_FLOAT32" }, { 16, 4, 4, "NIFTI_TYPE_FLOAT32" }, { 32, 8, 4, "DT_COMPLEX" }, { 32, 8, 4, "DT_COMPLEX64" }, { 32, 8, 4, "NIFTI_TYPE_COMPLEX64" }, { 64, 8, 8, "DT_DOUBLE" }, { 64, 8, 8, "DT_FLOAT64" }, { 64, 8, 8, "NIFTI_TYPE_FLOAT64" }, { 128, 3, 0, "DT_RGB" }, { 128, 3, 0, "DT_RGB24" }, { 128, 3, 0, "NIFTI_TYPE_RGB24" }, { 255, 0, 0, "DT_ALL" }, { 256, 1, 0, "DT_INT8" }, { 256, 1, 0, "NIFTI_TYPE_INT8" }, { 512, 2, 2, "DT_UINT16" }, { 512, 2, 2, "NIFTI_TYPE_UINT16" }, { 768, 4, 4, "DT_UINT32" }, { 768, 4, 4, "NIFTI_TYPE_UINT32" }, { 1024, 8, 8, "DT_INT64" }, { 1024, 8, 8, "NIFTI_TYPE_INT64" }, { 1280, 8, 8, "DT_UINT64" }, { 1280, 8, 8, "NIFTI_TYPE_UINT64" }, { 1536, 16, 16, "DT_FLOAT128" }, { 1536, 16, 16, "NIFTI_TYPE_FLOAT128" }, { 1792, 16, 8, "DT_COMPLEX128" }, { 1792, 16, 8, "NIFTI_TYPE_COMPLEX128" }, { 2048, 32, 16, "DT_COMPLEX256" }, { 2048, 32, 16, "NIFTI_TYPE_COMPLEX256" }, { 2304, 4, 0, "DT_RGBA32" }, { 2304, 4, 0, "NIFTI_TYPE_RGBA32" }, }; /*---------------------------------------------------------------------------*/ /* prototypes for internal functions - not part of exported library */ /* extension routines */ static int nifti_read_extensions( nifti_image *nim, znzFile fp, int remain ); static int nifti_read_next_extension( nifti1_extension * nex, nifti_image *nim, int remain, znzFile fp ); static int nifti_check_extension(nifti_image *nim, int size,int code, int rem); static void update_nifti_image_for_brick_list(nifti_image * nim , int nbricks); static int nifti_add_exten_to_list(nifti1_extension * new_ext, nifti1_extension ** list, int new_length); static int nifti_fill_extension(nifti1_extension * ext, const char * data, int len, int ecode); /* NBL routines */ static int nifti_load_NBL_bricks(nifti_image * nim , int * slist, int * sindex, nifti_brick_list * NBL, znzFile fp ); static int nifti_alloc_NBL_mem( nifti_image * nim, int nbricks, nifti_brick_list * nbl); static int nifti_copynsort(int nbricks, const int *blist, int **slist, int **sindex); /* for nifti_read_collapsed_image: */ static int rci_read_data(nifti_image *nim, int *pivots, int *prods, int nprods, const int dims[], char *data, znzFile fp, size_t base_offset); static int rci_alloc_mem(void ** data, int prods[8], int nprods, int nbyper ); static int make_pivot_list(nifti_image * nim, const int dims[], int pivots[], int prods[], int * nprods ); /* misc */ static int need_nhdr_swap (short dim0, int hdrsize); static int print_hex_vals (const char * data, int nbytes, FILE * fp); static int unescape_string (char *str); /* string utility functions */ static char *escapize_string (const char *str); /* internal I/O routines */ static znzFile nifti_image_load_prep( nifti_image *nim ); static int has_ascii_header(znzFile fp); /*---------------------------------------------------------------------------*/ /* for calling from some main program */ /*----------------------------------------------------------------------*/ /*! display the nifti library module history (via stdout) *//*--------------------------------------------------------------------*/ void nifti_disp_lib_hist( void ) { int c, len = sizeof(gni_history)/sizeof(char *); for( c = 0; c < len; c++ ) fputs(gni_history[c], stdout); } /*----------------------------------------------------------------------*/ /*! display the nifti library version (via stdout) *//*--------------------------------------------------------------------*/ void nifti_disp_lib_version( void ) { printf("%s, compiled %s\n", gni_version, __DATE__); } /*----------------------------------------------------------------------*/ /*! nifti_image_read_bricks - read nifti data as array of bricks * * 13 Dec 2004 [rickr] * * \param hname - filename of dataset to read (must be valid) * \param nbricks - number of sub-bricks to read * (if blist is valid, nbricks must be > 0) * \param blist - list of sub-bricks to read * (can be NULL; if NULL, read complete dataset) * \param NBL - pointer to empty nifti_brick_list struct * (must be a valid pointer) * * \return *
    nim - same as nifti_image_read, but nim->data will be NULL *
    NBL - filled with data * * By default, this function will read the nifti dataset and break the data * into a list of nt*nu*nv*nw sub-bricks, each having size nx*ny*nz elements. * That is to say, instead of reading the entire dataset as a single array, * break it up into sub-bricks, each of size nx*ny*nz elements. * * If 'blist' is valid, it is taken to be a list of sub-bricks, of length * 'nbricks'. The data will still be separated into sub-bricks of size * nx*ny*nz elements, but now 'nbricks' sub-bricks will be returned, of the * caller's choosing via 'blist'. * * E.g. consider a dataset with 12 sub-bricks (numbered 0..11), and the * following code: * *

     * { nifti_brick_list   NB_orig, NB_select;
     *   nifti_image      * nim_orig, * nim_select;
     *   int                blist[5] = { 7, 0, 5, 5, 9 };
     *
     *   nim_orig   = nifti_image_read_bricks("myfile.nii", 0, NULL,  &NB_orig);
     *   nim_select = nifti_image_read_bricks("myfile.nii", 5, blist, &NB_select);
     * }
     * 
    * * Here, nim_orig gets the entire dataset, where NB_orig.nbricks = 11. But * nim_select has NB_select.nbricks = 5. * * Note that the first case is not quite the same as just calling the * nifti_image_read function, as here the data is separated into sub-bricks. * * Note that valid blist elements are in [0..nt*nu*nv*nw-1], * or written [ 0 .. (dim[4]*dim[5]*dim[6]*dim[7] - 1) ]. * * Note that, as is the case with all of the reading functions, the * data will be allocated, read in, and properly byte-swapped, if * necessary. * * \sa nifti_image_load_bricks, nifti_free_NBL, valid_nifti_brick_list, nifti_image_read *//*----------------------------------------------------------------------*/ nifti_image *nifti_image_read_bricks(const char * hname, int nbricks, const int * blist, nifti_brick_list * NBL) { nifti_image * nim; if( !hname || !NBL ){ fprintf(stderr,"** nifti_image_read_bricks: bad params (%p,%p)\n", hname, (void *)NBL); return NULL; } if( blist && nbricks <= 0 ){ fprintf(stderr,"** nifti_image_read_bricks: bad nbricks, %d\n", nbricks); return NULL; } nim = nifti_image_read(hname, 0); /* read header, but not data */ if( !nim ) return NULL; /* errors were already printed */ /* if we fail, free image and return */ if( nifti_image_load_bricks(nim, nbricks, blist, NBL) <= 0 ){ nifti_image_free(nim); return NULL; } if( blist ) update_nifti_image_for_brick_list(nim, nbricks); return nim; } /*---------------------------------------------------------------------- * update_nifti_image_for_brick_list - update nifti_image * * When loading a specific brick list, the distinction between * nt, nu, nv and nw is lost. So put everything in t, and set * dim[0] = 4. *----------------------------------------------------------------------*/ static void update_nifti_image_for_brick_list( nifti_image * nim , int nbricks ) { int ndim; if( g_opts.debug > 2 ){ fprintf(stderr,"+d updating image dimensions for %d bricks in list\n", nbricks); fprintf(stderr," ndim = %d\n",nim->ndim); fprintf(stderr," nx,ny,nz,nt,nu,nv,nw: (%d,%d,%d,%d,%d,%d,%d)\n", nim->nx, nim->ny, nim->nz, nim->nt, nim->nu, nim->nv, nim->nw); } nim->nt = nbricks; nim->nu = nim->nv = nim->nw = 1; nim->dim[4] = nbricks; nim->dim[5] = nim->dim[6] = nim->dim[7] = 1; /* compute nvox */ /* do not rely on dimensions above dim[0] 16 Nov 2005 [rickr] */ for( nim->nvox = 1, ndim = 1; ndim <= nim->dim[0]; ndim++ ) nim->nvox *= nim->dim[ndim]; /* update the dimensions to 4 or lower */ for( ndim = 4; (ndim > 1) && (nim->dim[ndim] <= 1); ndim-- ) ; if( g_opts.debug > 2 ){ fprintf(stderr,"+d ndim = %d -> %d\n",nim->ndim, ndim); fprintf(stderr," --> (%d,%d,%d,%d,%d,%d,%d)\n", nim->nx, nim->ny, nim->nz, nim->nt, nim->nu, nim->nv, nim->nw); } nim->dim[0] = nim->ndim = ndim; } /*----------------------------------------------------------------------*/ /*! nifti_update_dims_from_array - update nx, ny, ... from nim->dim[] Fix all the dimension information, based on a new nim->dim[]. Note: we assume that dim[0] will not increase. Check for updates to pixdim[], dx,..., nx,..., nvox, ndim, dim[0]. *//*--------------------------------------------------------------------*/ int nifti_update_dims_from_array( nifti_image * nim ) { int c, ndim; if( !nim ){ fprintf(stderr,"** update_dims: missing nim\n"); return 1; } if( g_opts.debug > 2 ){ fprintf(stderr,"+d updating image dimensions given nim->dim:"); for( c = 0; c < 8; c++ ) fprintf(stderr," %d", nim->dim[c]); fputc('\n',stderr); } /* verify dim[0] first */ if(nim->dim[0] < 1 || nim->dim[0] > 7){ fprintf(stderr,"** invalid dim[0], dim[] = "); for( c = 0; c < 8; c++ ) fprintf(stderr," %d", nim->dim[c]); fputc('\n',stderr); return 1; } /* set nx, ny ..., dx, dy, ..., one by one */ /* less than 1, set to 1, else copy */ if(nim->dim[1] < 1) nim->nx = nim->dim[1] = 1; else nim->nx = nim->dim[1]; nim->dx = nim->pixdim[1]; /* if undefined, or less than 1, set to 1 */ if(nim->dim[0] < 2 || (nim->dim[0] >= 2 && nim->dim[2] < 1)) nim->ny = nim->dim[2] = 1; else nim->ny = nim->dim[2]; /* copy delta values, in any case */ nim->dy = nim->pixdim[2]; if(nim->dim[0] < 3 || (nim->dim[0] >= 3 && nim->dim[3] < 1)) nim->nz = nim->dim[3] = 1; else /* just copy vals from arrays */ nim->nz = nim->dim[3]; nim->dz = nim->pixdim[3]; if(nim->dim[0] < 4 || (nim->dim[0] >= 4 && nim->dim[4] < 1)) nim->nt = nim->dim[4] = 1; else /* just copy vals from arrays */ nim->nt = nim->dim[4]; nim->dt = nim->pixdim[4]; if(nim->dim[0] < 5 || (nim->dim[0] >= 5 && nim->dim[5] < 1)) nim->nu = nim->dim[5] = 1; else /* just copy vals from arrays */ nim->nu = nim->dim[5]; nim->du = nim->pixdim[5]; if(nim->dim[0] < 6 || (nim->dim[0] >= 6 && nim->dim[6] < 1)) nim->nv = nim->dim[6] = 1; else /* just copy vals from arrays */ nim->nv = nim->dim[6]; nim->dv = nim->pixdim[6]; if(nim->dim[0] < 7 || (nim->dim[0] >= 7 && nim->dim[7] < 1)) nim->nw = nim->dim[7] = 1; else /* just copy vals from arrays */ nim->nw = nim->dim[7]; nim->dw = nim->pixdim[7]; for( c = 1, nim->nvox = 1; c <= nim->dim[0]; c++ ) nim->nvox *= nim->dim[c]; /* compute ndim, assuming it can be no larger than the old one */ for( ndim = nim->dim[0]; (ndim > 1) && (nim->dim[ndim] <= 1); ndim-- ) ; if( g_opts.debug > 2 ){ fprintf(stderr,"+d ndim = %d -> %d\n",nim->ndim, ndim); fprintf(stderr," --> (%d,%d,%d,%d,%d,%d,%d)\n", nim->nx, nim->ny, nim->nz, nim->nt, nim->nu, nim->nv, nim->nw); } nim->dim[0] = nim->ndim = ndim; return 0; } /*----------------------------------------------------------------------*/ /*! Load the image data from disk into an already-prepared image struct. * * \param nim - initialized nifti_image, without data * \param nbricks - the length of blist (must be 0 if blist is NULL) * \param blist - an array of xyz volume indices to read (can be NULL) * \param NBL - pointer to struct where resulting data will be stored * * If blist is NULL, read all sub-bricks. * * \return the number of loaded bricks (NBL->nbricks), * 0 on failure, < 0 on error * * NOTE: it is likely that another function will copy the data pointers * out of NBL, in which case the only pointer the calling function * will want to free is NBL->bricks (not each NBL->bricks[i]). *//*--------------------------------------------------------------------*/ int nifti_image_load_bricks( nifti_image * nim , int nbricks, const int * blist, nifti_brick_list * NBL ) { int * slist = NULL, * sindex = NULL, rv; znzFile fp; /* we can have blist == NULL */ if( !nim || !NBL ){ fprintf(stderr,"** nifti_image_load_bricks, bad params (%p,%p)\n", (void *)nim, (void *)NBL); return -1; } if( blist && nbricks <= 0 ){ if( g_opts.debug > 1 ) fprintf(stderr,"-d load_bricks: received blist with nbricks = %d," "ignoring blist\n", nbricks); blist = NULL; /* pretend nothing was passed */ } if( blist && ! valid_nifti_brick_list(nim, nbricks, blist, g_opts.debug>0) ) return -1; /* for efficiency, let's read the file in order */ if( blist && nifti_copynsort( nbricks, blist, &slist, &sindex ) != 0 ) return -1; /* open the file and position the FILE pointer */ fp = nifti_image_load_prep( nim ); if( !fp ){ if( g_opts.debug > 0 ) fprintf(stderr,"** nifti_image_load_bricks, failed load_prep\n"); if( blist ){ free(slist); free(sindex); } return -1; } /* this will flag to allocate defaults */ if( !blist ) nbricks = 0; if( nifti_alloc_NBL_mem( nim, nbricks, NBL ) != 0 ){ if( blist ){ free(slist); free(sindex); } znzclose(fp); return -1; } rv = nifti_load_NBL_bricks(nim, slist, sindex, NBL, fp); if( rv != 0 ){ nifti_free_NBL( NBL ); /* failure! */ NBL->nbricks = 0; /* repetative, but clear */ } if( slist ){ free(slist); free(sindex); } znzclose(fp); return NBL->nbricks; } /*----------------------------------------------------------------------*/ /*! nifti_free_NBL - free all pointers and clear structure * * note: this does not presume to free the structure pointer *//*--------------------------------------------------------------------*/ void nifti_free_NBL( nifti_brick_list * NBL ) { int c; if( NBL->bricks ){ for( c = 0; c < NBL->nbricks; c++ ) if( NBL->bricks[c] ) free(NBL->bricks[c]); free(NBL->bricks); NBL->bricks = NULL; } NBL->bsize = NBL->nbricks = 0; } /*---------------------------------------------------------------------- * nifti_load_NBL_bricks - read the file data into the NBL struct * * return 0 on success, -1 on failure *----------------------------------------------------------------------*/ static int nifti_load_NBL_bricks( nifti_image * nim , int * slist, int * sindex, nifti_brick_list * NBL, znzFile fp ) { size_t oposn, fposn; /* orig and current file positions */ size_t rv; long test; int c; int prev, isrc, idest; /* previous and current sub-brick, and new index */ test = znztell(fp); /* store current file position */ if( test < 0 ){ fprintf(stderr,"** load bricks: ztell failed??\n"); return -1; } fposn = oposn = test; /* first, handle the default case, no passed blist */ if( !slist ){ for( c = 0; c < NBL->nbricks; c++ ) { rv = nifti_read_buffer(fp, NBL->bricks[c], NBL->bsize, nim); if( rv != NBL->bsize ){ fprintf(stderr,"** load bricks: cannot read brick %d from '%s'\n", c, nim->iname ? nim->iname : nim->fname); return -1; } } if( g_opts.debug > 1 ) fprintf(stderr,"+d read %d default %u-byte bricks from file %s\n", NBL->nbricks, (unsigned int)NBL->bsize, nim->iname ? nim->iname:nim->fname ); return 0; } if( !sindex ){ fprintf(stderr,"** load_NBL_bricks: missing index list\n"); return -1; } prev = -1; /* use prev for previous sub-brick */ for( c = 0; c < NBL->nbricks; c++ ){ isrc = slist[c]; /* this is original brick index (c is new one) */ idest = sindex[c]; /* this is the destination index for this data */ /* if this sub-brick is not the previous, we must read from disk */ if( isrc != prev ){ /* if we are not looking at the correct sub-brick, scan forward */ if( fposn != (oposn + isrc*NBL->bsize) ){ fposn = oposn + isrc*NBL->bsize; if( znzseek(fp, fposn, SEEK_SET) < 0 ){ fprintf(stderr,"** failed to locate brick %d in file '%s'\n", isrc, nim->iname ? nim->iname : nim->fname); return -1; } } /* only 10,000 lines later and we're actually reading something! */ rv = nifti_read_buffer(fp, NBL->bricks[idest], NBL->bsize, nim); if( rv != NBL->bsize ){ fprintf(stderr,"** failed to read brick %d from file '%s'\n", isrc, nim->iname ? nim->iname : nim->fname); return -1; } fposn += NBL->bsize; } else { /* we have already read this sub-brick, just copy the previous one */ /* note that this works because they are sorted */ memcpy(NBL->bricks[idest], NBL->bricks[sindex[c-1]], NBL->bsize); } prev = isrc; /* in any case, note the now previous sub-brick */ } return 0; } /*---------------------------------------------------------------------- * nifti_alloc_NBL_mem - allocate memory for bricks * * return 0 on success, -1 on failure *----------------------------------------------------------------------*/ static int nifti_alloc_NBL_mem(nifti_image * nim, int nbricks, nifti_brick_list * nbl) { int c; /* if nbricks is not specified, use the default */ if( nbricks > 0 ) nbl->nbricks = nbricks; else { /* I missed this one with the 1.17 change 02 Mar 2006 [rickr] */ nbl->nbricks = 1; for( c = 4; c <= nim->ndim; c++ ) nbl->nbricks *= nim->dim[c]; } nbl->bsize = (size_t)nim->nx * nim->ny * nim->nz * nim->nbyper;/* bytes */ nbl->bricks = (void **)malloc(nbl->nbricks * sizeof(void *)); if( ! nbl->bricks ){ fprintf(stderr,"** NANM: failed to alloc %d void ptrs\n",nbricks); return -1; } for( c = 0; c < nbl->nbricks; c++ ){ nbl->bricks[c] = (void *)malloc(nbl->bsize); if( ! nbl->bricks[c] ){ fprintf(stderr,"** NANM: failed to alloc %u bytes for brick %d\n", (unsigned int)nbl->bsize, c); /* so free and clear everything before returning */ while( c > 0 ){ c--; free(nbl->bricks[c]); } free(nbl->bricks); nbl->bricks = NULL; nbl->bsize = nbl->nbricks = 0; return -1; } } if( g_opts.debug > 2 ) fprintf(stderr,"+d NANM: alloc'd %d bricks of %u bytes for NBL\n", nbl->nbricks, (unsigned int)nbl->bsize); return 0; } /*---------------------------------------------------------------------- * nifti_copynsort - copy int list, and sort with indices * * 1. duplicate the incoming list * 2. create an sindex list, and init with 0..nbricks-1 * 3. do a slow insertion sort on the small slist, along with sindex list * 4. check results, just to be positive * * So slist is sorted, and sindex hold original positions. * * return 0 on success, -1 on failure *----------------------------------------------------------------------*/ static int nifti_copynsort(int nbricks, const int * blist, int ** slist, int ** sindex) { int * stmp, * itmp; /* for ease of typing/reading */ int c1, c2, spos, tmp; *slist = (int *)malloc(nbricks * sizeof(int)); *sindex = (int *)malloc(nbricks * sizeof(int)); if( !*slist || !*sindex ){ fprintf(stderr,"** NCS: failed to alloc %d ints for sorting\n",nbricks); if(*slist) free(*slist); /* maybe one succeeded */ if(*sindex) free(*sindex); return -1; } /* init the lists */ memcpy(*slist, blist, nbricks*sizeof(int)); for( c1 = 0; c1 < nbricks; c1++ ) (*sindex)[c1] = c1; /* now actually sort slist */ stmp = *slist; itmp = *sindex; for( c1 = 0; c1 < nbricks-1; c1++ ) { /* find smallest value, init to current */ spos = c1; for( c2 = c1+1; c2 < nbricks; c2++ ) if( stmp[c2] < stmp[spos] ) spos = c2; if( spos != c1 ) /* swap: fine, don't maintain sub-order, see if I care */ { tmp = stmp[c1]; /* first swap the sorting values */ stmp[c1] = stmp[spos]; stmp[spos] = tmp; tmp = itmp[c1]; /* then swap the index values */ itmp[c1] = itmp[spos]; itmp[spos] = tmp; } } if( g_opts.debug > 2 ){ fprintf(stderr, "+d sorted indexing list:\n"); fprintf(stderr, " orig : "); for( c1 = 0; c1 < nbricks; c1++ ) fprintf(stderr," %d",blist[c1]); fprintf(stderr,"\n new : "); for( c1 = 0; c1 < nbricks; c1++ ) fprintf(stderr," %d",stmp[c1]); fprintf(stderr,"\n indices: "); for( c1 = 0; c1 < nbricks; c1++ ) fprintf(stderr," %d",itmp[c1]); fputc('\n', stderr); } /* check the sort (why not? I've got time...) */ for( c1 = 0; c1 < nbricks-1; c1++ ){ if( (stmp[c1] > stmp[c1+1]) || (blist[itmp[c1]] != stmp[c1]) ){ fprintf(stderr,"** sorting screw-up, way to go, rick!\n"); free(stmp); free(itmp); *slist = NULL; *sindex = NULL; return -1; } } if( g_opts.debug > 2 ) fprintf(stderr,"-d sorting is okay\n"); return 0; } /*----------------------------------------------------------------------*/ /*! valid_nifti_brick_list - check sub-brick list for image * * This function verifies that nbricks and blist are appropriate * for use with this nim, based on the dimensions. * * \param nim nifti_image to check against * \param nbricks number of brick indices in blist * \param blist list of brick indices to check in nim * \param disp_error if this flag is set, report errors to user * * \return 1 if valid, 0 if not *//*--------------------------------------------------------------------*/ int valid_nifti_brick_list(nifti_image * nim , int nbricks, const int * blist, int disp_error) { int c, nsubs; if( !nim ){ if( disp_error || g_opts.debug > 0 ) fprintf(stderr,"** valid_nifti_brick_list: missing nifti image\n"); return 0; } if( nbricks <= 0 || !blist ){ if( disp_error || g_opts.debug > 1 ) fprintf(stderr,"** valid_nifti_brick_list: no brick list to check\n"); return 0; } if( nim->dim[0] < 3 ){ if( disp_error || g_opts.debug > 1 ) fprintf(stderr,"** cannot read explict brick list from %d-D dataset\n", nim->dim[0]); return 0; } /* nsubs sub-brick is nt*nu*nv*nw */ for( c = 4, nsubs = 1; c <= nim->dim[0]; c++ ) nsubs *= nim->dim[c]; if( nsubs <= 0 ){ fprintf(stderr,"** VNBL warning: bad dim list (%d,%d,%d,%d)\n", nim->dim[4], nim->dim[5], nim->dim[6], nim->dim[7]); return 0; } for( c = 0; c < nbricks; c++ ) if( (blist[c] < 0) || (blist[c] >= nsubs) ){ if( disp_error || g_opts.debug > 1 ) fprintf(stderr, "-d ** bad sub-brick chooser %d (#%d), valid range is [0,%d]\n", blist[c], c, nsubs-1); return 0; } return 1; /* all is well */ } #if 0 /* set any non-positive values to 1 */ static int int_force_positive( int * list, int nel ) { int c; if( !list || nel < 0 ){ if( g_opts.debug > 0 ) fprintf(stderr,"** int_force_positive: bad params (%p,%d)\n", (void *)list,nel); return -1; } for( c = 0; c < nel; c++ ) if( list[c] <= 0 ) list[c] = 1; return 0; } #endif /* end of new nifti_image_read_bricks() functionality */ /*----------------------------------------------------------------------*/ /*! display the orientation from the quaternian fields * * \param mesg if non-NULL, display this message first * \param mat the matrix to convert to "nearest" orientation * * \return -1 if results cannot be determined, 0 if okay *//*--------------------------------------------------------------------*/ int nifti_disp_matrix_orient( const char * mesg, mat44 mat ) { int i, j, k; if ( mesg ) fputs( mesg, stderr ); /* use stdout? */ nifti_mat44_to_orientation( mat, &i,&j,&k ); if ( i <= 0 || j <= 0 || k <= 0 ) return -1; /* so we have good codes */ fprintf(stderr, " i orientation = '%s'\n" " j orientation = '%s'\n" " k orientation = '%s'\n", nifti_orientation_string(i), nifti_orientation_string(j), nifti_orientation_string(k) ); return 0; } /*----------------------------------------------------------------------*/ /*! duplicate the given string (alloc length+1) * * \return allocated pointer (or NULL on failure) *//*--------------------------------------------------------------------*/ char *nifti_strdup(const char *str) { char *dup= (char *)malloc( strlen(str)+1 ); if (dup) strcpy(dup,str); return dup; } /*---------------------------------------------------------------------------*/ /*! Return a pointer to a string holding the name of a NIFTI datatype. \param dt NIfTI-1 datatype \return pointer to static string holding the datatype name \warning Do not free() or modify this string! It points to static storage. \sa NIFTI1_DATATYPES group in nifti1.h *//*-------------------------------------------------------------------------*/ char *nifti_datatype_string( int dt ) { switch( dt ){ case DT_UNKNOWN: return "UNKNOWN" ; case DT_BINARY: return "BINARY" ; case DT_INT8: return "INT8" ; case DT_UINT8: return "UINT8" ; case DT_INT16: return "INT16" ; case DT_UINT16: return "UINT16" ; case DT_INT32: return "INT32" ; case DT_UINT32: return "UINT32" ; case DT_INT64: return "INT64" ; case DT_UINT64: return "UINT64" ; case DT_FLOAT32: return "FLOAT32" ; case DT_FLOAT64: return "FLOAT64" ; case DT_FLOAT128: return "FLOAT128" ; case DT_COMPLEX64: return "COMPLEX64" ; case DT_COMPLEX128: return "COMPLEX128" ; case DT_COMPLEX256: return "COMPLEX256" ; case DT_RGB24: return "RGB24" ; case DT_RGBA32: return "RGBA32" ; } return "**ILLEGAL**" ; } /*----------------------------------------------------------------------*/ /*! Determine if the datatype code dt is an integer type (1=YES, 0=NO). \return whether the given NIfTI-1 datatype code is valid \sa NIFTI1_DATATYPES group in nifti1.h *//*--------------------------------------------------------------------*/ int nifti_is_inttype( int dt ) { switch( dt ){ case DT_UNKNOWN: return 0 ; case DT_BINARY: return 0 ; case DT_INT8: return 1 ; case DT_UINT8: return 1 ; case DT_INT16: return 1 ; case DT_UINT16: return 1 ; case DT_INT32: return 1 ; case DT_UINT32: return 1 ; case DT_INT64: return 1 ; case DT_UINT64: return 1 ; case DT_FLOAT32: return 0 ; case DT_FLOAT64: return 0 ; case DT_FLOAT128: return 0 ; case DT_COMPLEX64: return 0 ; case DT_COMPLEX128: return 0 ; case DT_COMPLEX256: return 0 ; case DT_RGB24: return 1 ; case DT_RGBA32: return 1 ; } return 0 ; } /*---------------------------------------------------------------------------*/ /*! Return a pointer to a string holding the name of a NIFTI units type. \param uu NIfTI-1 unit code \return pointer to static string for the given unit type \warning Do not free() or modify this string! It points to static storage. \sa NIFTI1_UNITS group in nifti1.h *//*-------------------------------------------------------------------------*/ char *nifti_units_string( int uu ) { switch( uu ){ case NIFTI_UNITS_METER: return "m" ; case NIFTI_UNITS_MM: return "mm" ; case NIFTI_UNITS_MICRON: return "um" ; case NIFTI_UNITS_SEC: return "s" ; case NIFTI_UNITS_MSEC: return "ms" ; case NIFTI_UNITS_USEC: return "us" ; case NIFTI_UNITS_HZ: return "Hz" ; case NIFTI_UNITS_PPM: return "ppm" ; case NIFTI_UNITS_RADS: return "rad/s" ; } return "Unknown" ; } /*---------------------------------------------------------------------------*/ /*! Return a pointer to a string holding the name of a NIFTI transform type. \param xx NIfTI-1 xform code \return pointer to static string describing xform code \warning Do not free() or modify this string! It points to static storage. \sa NIFTI1_XFORM_CODES group in nifti1.h *//*-------------------------------------------------------------------------*/ char *nifti_xform_string( int xx ) { switch( xx ){ case NIFTI_XFORM_SCANNER_ANAT: return "Scanner Anat" ; case NIFTI_XFORM_ALIGNED_ANAT: return "Aligned Anat" ; case NIFTI_XFORM_TALAIRACH: return "Talairach" ; case NIFTI_XFORM_MNI_152: return "MNI_152" ; } return "Unknown" ; } /*---------------------------------------------------------------------------*/ /*! Return a pointer to a string holding the name of a NIFTI intent type. \param ii NIfTI-1 intent code \return pointer to static string describing code \warning Do not free() or modify this string! It points to static storage. \sa NIFTI1_INTENT_CODES group in nifti1.h *//*-------------------------------------------------------------------------*/ char *nifti_intent_string( int ii ) { switch( ii ){ case NIFTI_INTENT_CORREL: return "Correlation statistic" ; case NIFTI_INTENT_TTEST: return "T-statistic" ; case NIFTI_INTENT_FTEST: return "F-statistic" ; case NIFTI_INTENT_ZSCORE: return "Z-score" ; case NIFTI_INTENT_CHISQ: return "Chi-squared distribution" ; case NIFTI_INTENT_BETA: return "Beta distribution" ; case NIFTI_INTENT_BINOM: return "Binomial distribution" ; case NIFTI_INTENT_GAMMA: return "Gamma distribution" ; case NIFTI_INTENT_POISSON: return "Poisson distribution" ; case NIFTI_INTENT_NORMAL: return "Normal distribution" ; case NIFTI_INTENT_FTEST_NONC: return "F-statistic noncentral" ; case NIFTI_INTENT_CHISQ_NONC: return "Chi-squared noncentral" ; case NIFTI_INTENT_LOGISTIC: return "Logistic distribution" ; case NIFTI_INTENT_LAPLACE: return "Laplace distribution" ; case NIFTI_INTENT_UNIFORM: return "Uniform distribition" ; case NIFTI_INTENT_TTEST_NONC: return "T-statistic noncentral" ; case NIFTI_INTENT_WEIBULL: return "Weibull distribution" ; case NIFTI_INTENT_CHI: return "Chi distribution" ; case NIFTI_INTENT_INVGAUSS: return "Inverse Gaussian distribution" ; case NIFTI_INTENT_EXTVAL: return "Extreme Value distribution" ; case NIFTI_INTENT_PVAL: return "P-value" ; case NIFTI_INTENT_LOGPVAL: return "Log P-value" ; case NIFTI_INTENT_LOG10PVAL: return "Log10 P-value" ; case NIFTI_INTENT_ESTIMATE: return "Estimate" ; case NIFTI_INTENT_LABEL: return "Label index" ; case NIFTI_INTENT_NEURONAME: return "NeuroNames index" ; case NIFTI_INTENT_GENMATRIX: return "General matrix" ; case NIFTI_INTENT_SYMMATRIX: return "Symmetric matrix" ; case NIFTI_INTENT_DISPVECT: return "Displacement vector" ; case NIFTI_INTENT_VECTOR: return "Vector" ; case NIFTI_INTENT_POINTSET: return "Pointset" ; case NIFTI_INTENT_TRIANGLE: return "Triangle" ; case NIFTI_INTENT_QUATERNION: return "Quaternion" ; case NIFTI_INTENT_DIMLESS: return "Dimensionless number" ; } return "Unknown" ; } /*---------------------------------------------------------------------------*/ /*! Return a pointer to a string holding the name of a NIFTI slice_code. \param ss NIfTI-1 slice order code \return pointer to static string describing code \warning Do not free() or modify this string! It points to static storage. \sa NIFTI1_SLICE_ORDER group in nifti1.h *//*-------------------------------------------------------------------------*/ char *nifti_slice_string( int ss ) { switch( ss ){ case NIFTI_SLICE_SEQ_INC: return "sequential_increasing" ; case NIFTI_SLICE_SEQ_DEC: return "sequential_decreasing" ; case NIFTI_SLICE_ALT_INC: return "alternating_increasing" ; case NIFTI_SLICE_ALT_DEC: return "alternating_decreasing" ; case NIFTI_SLICE_ALT_INC2: return "alternating_increasing_2" ; case NIFTI_SLICE_ALT_DEC2: return "alternating_decreasing_2" ; } return "Unknown" ; } /*---------------------------------------------------------------------------*/ /*! Return a pointer to a string holding the name of a NIFTI orientation. \param ii orientation code \return pointer to static string holding the orientation information \warning Do not free() or modify the return string! It points to static storage. \sa NIFTI_L2R in nifti1_io.h *//*-------------------------------------------------------------------------*/ char *nifti_orientation_string( int ii ) { switch( ii ){ case NIFTI_L2R: return "Left-to-Right" ; case NIFTI_R2L: return "Right-to-Left" ; case NIFTI_P2A: return "Posterior-to-Anterior" ; case NIFTI_A2P: return "Anterior-to-Posterior" ; case NIFTI_I2S: return "Inferior-to-Superior" ; case NIFTI_S2I: return "Superior-to-Inferior" ; } return "Unknown" ; } /*--------------------------------------------------------------------------*/ /*! Given a datatype code, set number of bytes per voxel and the swapsize. \param datatype nifti1 datatype code \param nbyper pointer to return value: number of bytes per voxel \param swapsize pointer to return value: size of swap blocks \return appropriate values at nbyper and swapsize The swapsize is set to 0 if this datatype doesn't ever need swapping. \sa NIFTI1_DATATYPES in nifti1.h *//*------------------------------------------------------------------------*/ void nifti_datatype_sizes( int datatype , int *nbyper, int *swapsize ) { int nb=0, ss=0 ; switch( datatype ){ case DT_INT8: case DT_UINT8: nb = 1 ; ss = 0 ; break ; case DT_INT16: case DT_UINT16: nb = 2 ; ss = 2 ; break ; case DT_RGB24: nb = 3 ; ss = 0 ; break ; case DT_RGBA32: nb = 4 ; ss = 0 ; break ; case DT_INT32: case DT_UINT32: case DT_FLOAT32: nb = 4 ; ss = 4 ; break ; case DT_COMPLEX64: nb = 8 ; ss = 4 ; break ; case DT_FLOAT64: case DT_INT64: case DT_UINT64: nb = 8 ; ss = 8 ; break ; case DT_FLOAT128: nb = 16 ; ss = 16 ; break ; case DT_COMPLEX128: nb = 16 ; ss = 8 ; break ; case DT_COMPLEX256: nb = 32 ; ss = 16 ; break ; } ASSIF(nbyper,nb) ; ASSIF(swapsize,ss) ; return ; } /*---------------------------------------------------------------------------*/ /*! Given the quaternion parameters (etc.), compute a transformation matrix. See comments in nifti1.h for details. - qb,qc,qd = quaternion parameters - qx,qy,qz = offset parameters - dx,dy,dz = grid stepsizes (non-negative inputs are set to 1.0) - qfac = sign of dz step (< 0 is negative; >= 0 is positive)
       If qx=qy=qz=0, dx=dy=dz=1, then the output is a rotation matrix.
       For qfac >= 0, the rotation is proper.
       For qfac <  0, the rotation is improper.
       
    \see "QUATERNION REPRESENTATION OF ROTATION MATRIX" in nifti1.h \see nifti_mat44_to_quatern, nifti_make_orthog_mat44, nifti_mat44_to_orientation *//*-------------------------------------------------------------------------*/ mat44 nifti_quatern_to_mat44( float qb, float qc, float qd, float qx, float qy, float qz, float dx, float dy, float dz, float qfac ) { mat44 R ; double a,b=qb,c=qc,d=qd , xd,yd,zd ; /* last row is always [ 0 0 0 1 ] */ R.m[3][0]=R.m[3][1]=R.m[3][2] = 0.0 ; R.m[3][3]= 1.0 ; /* compute a parameter from b,c,d */ a = 1.0l - (b*b + c*c + d*d) ; if( a < 1.e-7l ){ /* special case */ a = 1.0l / sqrt(b*b+c*c+d*d) ; b *= a ; c *= a ; d *= a ; /* normalize (b,c,d) vector */ a = 0.0l ; /* a = 0 ==> 180 degree rotation */ } else{ a = sqrt(a) ; /* angle = 2*arccos(a) */ } /* load rotation matrix, including scaling factors for voxel sizes */ xd = (dx > 0.0) ? dx : 1.0l ; /* make sure are positive */ yd = (dy > 0.0) ? dy : 1.0l ; zd = (dz > 0.0) ? dz : 1.0l ; if( qfac < 0.0 ) zd = -zd ; /* left handedness? */ R.m[0][0] = (a*a+b*b-c*c-d*d) * xd ; R.m[0][1] = 2.0l * (b*c-a*d ) * yd ; R.m[0][2] = 2.0l * (b*d+a*c ) * zd ; R.m[1][0] = 2.0l * (b*c+a*d ) * xd ; R.m[1][1] = (a*a+c*c-b*b-d*d) * yd ; R.m[1][2] = 2.0l * (c*d-a*b ) * zd ; R.m[2][0] = 2.0l * (b*d-a*c ) * xd ; R.m[2][1] = 2.0l * (c*d+a*b ) * yd ; R.m[2][2] = (a*a+d*d-c*c-b*b) * zd ; /* load offsets */ R.m[0][3] = qx ; R.m[1][3] = qy ; R.m[2][3] = qz ; return R ; } /*---------------------------------------------------------------------------*/ /*! Given the 3x4 upper corner of the matrix R, compute the quaternion parameters that fit it. - Any NULL pointer on input won't get assigned (e.g., if you don't want dx,dy,dz, just pass NULL in for those pointers). - If the 3 input matrix columns are NOT orthogonal, they will be orthogonalized prior to calculating the parameters, using the polar decomposition to find the orthogonal matrix closest to the column-normalized input matrix. - However, if the 3 input matrix columns are NOT orthogonal, then the matrix produced by nifti_quatern_to_mat44 WILL have orthogonal columns, so it won't be the same as the matrix input here. This "feature" is because the NIFTI 'qform' transform is deliberately not fully general -- it is intended to model a volume with perpendicular axes. - If the 3 input matrix columns are not even linearly independent, you'll just have to take your luck, won't you? \see "QUATERNION REPRESENTATION OF ROTATION MATRIX" in nifti1.h \see nifti_quatern_to_mat44, nifti_make_orthog_mat44, nifti_mat44_to_orientation *//*-------------------------------------------------------------------------*/ void nifti_mat44_to_quatern( mat44 R , float *qb, float *qc, float *qd, float *qx, float *qy, float *qz, float *dx, float *dy, float *dz, float *qfac ) { double r11,r12,r13 , r21,r22,r23 , r31,r32,r33 ; double xd,yd,zd , a,b,c,d ; mat33 P,Q ; /* offset outputs are read write out of input matrix */ ASSIF(qx,R.m[0][3]) ; ASSIF(qy,R.m[1][3]) ; ASSIF(qz,R.m[2][3]) ; /* load 3x3 matrix into local variables */ r11 = R.m[0][0] ; r12 = R.m[0][1] ; r13 = R.m[0][2] ; r21 = R.m[1][0] ; r22 = R.m[1][1] ; r23 = R.m[1][2] ; r31 = R.m[2][0] ; r32 = R.m[2][1] ; r33 = R.m[2][2] ; /* compute lengths of each column; these determine grid spacings */ xd = sqrt( r11*r11 + r21*r21 + r31*r31 ) ; yd = sqrt( r12*r12 + r22*r22 + r32*r32 ) ; zd = sqrt( r13*r13 + r23*r23 + r33*r33 ) ; /* if a column length is zero, patch the trouble */ if( xd == 0.0l ){ r11 = 1.0l ; r21 = r31 = 0.0l ; xd = 1.0l ; } if( yd == 0.0l ){ r22 = 1.0l ; r12 = r32 = 0.0l ; yd = 1.0l ; } if( zd == 0.0l ){ r33 = 1.0l ; r13 = r23 = 0.0l ; zd = 1.0l ; } /* assign the output lengths */ ASSIF(dx,xd) ; ASSIF(dy,yd) ; ASSIF(dz,zd) ; /* normalize the columns */ r11 /= xd ; r21 /= xd ; r31 /= xd ; r12 /= yd ; r22 /= yd ; r32 /= yd ; r13 /= zd ; r23 /= zd ; r33 /= zd ; /* At this point, the matrix has normal columns, but we have to allow for the fact that the hideous user may not have given us a matrix with orthogonal columns. So, now find the orthogonal matrix closest to the current matrix. One reason for using the polar decomposition to get this orthogonal matrix, rather than just directly orthogonalizing the columns, is so that inputting the inverse matrix to R will result in the inverse orthogonal matrix at this point. If we just orthogonalized the columns, this wouldn't necessarily hold. */ Q.m[0][0] = r11 ; Q.m[0][1] = r12 ; Q.m[0][2] = r13 ; /* load Q */ Q.m[1][0] = r21 ; Q.m[1][1] = r22 ; Q.m[1][2] = r23 ; Q.m[2][0] = r31 ; Q.m[2][1] = r32 ; Q.m[2][2] = r33 ; P = nifti_mat33_polar(Q) ; /* P is orthog matrix closest to Q */ r11 = P.m[0][0] ; r12 = P.m[0][1] ; r13 = P.m[0][2] ; /* unload */ r21 = P.m[1][0] ; r22 = P.m[1][1] ; r23 = P.m[1][2] ; r31 = P.m[2][0] ; r32 = P.m[2][1] ; r33 = P.m[2][2] ; /* [ r11 r12 r13 ] */ /* at this point, the matrix [ r21 r22 r23 ] is orthogonal */ /* [ r31 r32 r33 ] */ /* compute the determinant to determine if it is proper */ zd = r11*r22*r33-r11*r32*r23-r21*r12*r33 +r21*r32*r13+r31*r12*r23-r31*r22*r13 ; /* should be -1 or 1 */ if( zd > 0 ){ /* proper */ ASSIF(qfac,1.0) ; } else { /* improper ==> flip 3rd column */ ASSIF(qfac,-1.0) ; r13 = -r13 ; r23 = -r23 ; r33 = -r33 ; } /* now, compute quaternion parameters */ a = r11 + r22 + r33 + 1.0l ; if( a > 0.5l ){ /* simplest case */ a = 0.5l * sqrt(a) ; b = 0.25l * (r32-r23) / a ; c = 0.25l * (r13-r31) / a ; d = 0.25l * (r21-r12) / a ; } else { /* trickier case */ xd = 1.0 + r11 - (r22+r33) ; /* 4*b*b */ yd = 1.0 + r22 - (r11+r33) ; /* 4*c*c */ zd = 1.0 + r33 - (r11+r22) ; /* 4*d*d */ if( xd > 1.0 ){ b = 0.5l * sqrt(xd) ; c = 0.25l* (r12+r21) / b ; d = 0.25l* (r13+r31) / b ; a = 0.25l* (r32-r23) / b ; } else if( yd > 1.0 ){ c = 0.5l * sqrt(yd) ; b = 0.25l* (r12+r21) / c ; d = 0.25l* (r23+r32) / c ; a = 0.25l* (r13-r31) / c ; } else { d = 0.5l * sqrt(zd) ; b = 0.25l* (r13+r31) / d ; c = 0.25l* (r23+r32) / d ; a = 0.25l* (r21-r12) / d ; } if( a < 0.0l ){ b=-b ; c=-c ; d=-d; a=-a; } } ASSIF(qb,b) ; ASSIF(qc,c) ; ASSIF(qd,d) ; return ; } /*---------------------------------------------------------------------------*/ /*! Compute the inverse of a bordered 4x4 matrix.
       - Some numerical code fragments were generated by Maple 8.
       - If a singular matrix is input, the output matrix will be all zero.
       - You can check for this by examining the [3][3] element, which will
         be 1.0 for the normal case and 0.0 for the bad case.
    
         The input matrix should have the form:
            [ r11 r12 r13 v1 ]
            [ r21 r22 r23 v2 ]
            [ r31 r32 r33 v3 ]
            [  0   0   0   1 ]
         
    *//*-------------------------------------------------------------------------*/ mat44 nifti_mat44_inverse( mat44 R ) { double r11,r12,r13,r21,r22,r23,r31,r32,r33,v1,v2,v3 , deti ; mat44 Q ; /* INPUT MATRIX IS: */ r11 = R.m[0][0]; r12 = R.m[0][1]; r13 = R.m[0][2]; /* [ r11 r12 r13 v1 ] */ r21 = R.m[1][0]; r22 = R.m[1][1]; r23 = R.m[1][2]; /* [ r21 r22 r23 v2 ] */ r31 = R.m[2][0]; r32 = R.m[2][1]; r33 = R.m[2][2]; /* [ r31 r32 r33 v3 ] */ v1 = R.m[0][3]; v2 = R.m[1][3]; v3 = R.m[2][3]; /* [ 0 0 0 1 ] */ deti = r11*r22*r33-r11*r32*r23-r21*r12*r33 +r21*r32*r13+r31*r12*r23-r31*r22*r13 ; if( deti != 0.0l ) deti = 1.0l / deti ; Q.m[0][0] = deti*( r22*r33-r32*r23) ; Q.m[0][1] = deti*(-r12*r33+r32*r13) ; Q.m[0][2] = deti*( r12*r23-r22*r13) ; Q.m[0][3] = deti*(-r12*r23*v3+r12*v2*r33+r22*r13*v3 -r22*v1*r33-r32*r13*v2+r32*v1*r23) ; Q.m[1][0] = deti*(-r21*r33+r31*r23) ; Q.m[1][1] = deti*( r11*r33-r31*r13) ; Q.m[1][2] = deti*(-r11*r23+r21*r13) ; Q.m[1][3] = deti*( r11*r23*v3-r11*v2*r33-r21*r13*v3 +r21*v1*r33+r31*r13*v2-r31*v1*r23) ; Q.m[2][0] = deti*( r21*r32-r31*r22) ; Q.m[2][1] = deti*(-r11*r32+r31*r12) ; Q.m[2][2] = deti*( r11*r22-r21*r12) ; Q.m[2][3] = deti*(-r11*r22*v3+r11*r32*v2+r21*r12*v3 -r21*r32*v1-r31*r12*v2+r31*r22*v1) ; Q.m[3][0] = Q.m[3][1] = Q.m[3][2] = 0.0l ; Q.m[3][3] = (deti == 0.0l) ? 0.0l : 1.0l ; /* failure flag if deti == 0 */ return Q ; } /*---------------------------------------------------------------------------*/ /*! Input 9 floats and make an orthgonal mat44 out of them. Each row is normalized, then nifti_mat33_polar() is used to orthogonalize them. If row #3 (r31,r32,r33) is input as zero, then it will be taken to be the cross product of rows #1 and #2. This function can be used to create a rotation matrix for transforming an oblique volume to anatomical coordinates. For this application: - row #1 (r11,r12,r13) is the direction vector along the image i-axis - row #2 (r21,r22,r23) is the direction vector along the image j-axis - row #3 (r31,r32,r33) is the direction vector along the slice direction (if available; otherwise enter it as 0's) The first 2 rows can be taken from the DICOM attribute (0020,0037) "Image Orientation (Patient)". After forming the rotation matrix, the complete affine transformation from (i,j,k) grid indexes to (x,y,z) spatial coordinates can be computed by multiplying each column by the appropriate grid spacing: - column #1 (R.m[0][0],R.m[1][0],R.m[2][0]) by delta-x - column #2 (R.m[0][1],R.m[1][1],R.m[2][1]) by delta-y - column #3 (R.m[0][2],R.m[1][2],R.m[2][2]) by delta-z and by then placing the center (x,y,z) coordinates of voxel (0,0,0) into the column #4 (R.m[0][3],R.m[1][3],R.m[2][3]). \sa nifti_quatern_to_mat44, nifti_mat44_to_quatern, nifti_mat44_to_orientation *//*-------------------------------------------------------------------------*/ mat44 nifti_make_orthog_mat44( float r11, float r12, float r13 , float r21, float r22, float r23 , float r31, float r32, float r33 ) { mat44 R ; mat33 Q , P ; double val ; R.m[3][0] = R.m[3][1] = R.m[3][2] = 0.0l ; R.m[3][3] = 1.0l ; Q.m[0][0] = r11 ; Q.m[0][1] = r12 ; Q.m[0][2] = r13 ; /* load Q */ Q.m[1][0] = r21 ; Q.m[1][1] = r22 ; Q.m[1][2] = r23 ; Q.m[2][0] = r31 ; Q.m[2][1] = r32 ; Q.m[2][2] = r33 ; /* normalize row 1 */ val = Q.m[0][0]*Q.m[0][0] + Q.m[0][1]*Q.m[0][1] + Q.m[0][2]*Q.m[0][2] ; if( val > 0.0l ){ val = 1.0l / sqrt(val) ; Q.m[0][0] *= val ; Q.m[0][1] *= val ; Q.m[0][2] *= val ; } else { Q.m[0][0] = 1.0l ; Q.m[0][1] = 0.0l ; Q.m[0][2] = 0.0l ; } /* normalize row 2 */ val = Q.m[1][0]*Q.m[1][0] + Q.m[1][1]*Q.m[1][1] + Q.m[1][2]*Q.m[1][2] ; if( val > 0.0l ){ val = 1.0l / sqrt(val) ; Q.m[1][0] *= val ; Q.m[1][1] *= val ; Q.m[1][2] *= val ; } else { Q.m[1][0] = 0.0l ; Q.m[1][1] = 1.0l ; Q.m[1][2] = 0.0l ; } /* normalize row 3 */ val = Q.m[2][0]*Q.m[2][0] + Q.m[2][1]*Q.m[2][1] + Q.m[2][2]*Q.m[2][2] ; if( val > 0.0l ){ val = 1.0l / sqrt(val) ; Q.m[2][0] *= val ; Q.m[2][1] *= val ; Q.m[2][2] *= val ; } else { Q.m[2][0] = Q.m[0][1]*Q.m[1][2] - Q.m[0][2]*Q.m[1][1] ; /* cross */ Q.m[2][1] = Q.m[0][2]*Q.m[1][0] - Q.m[0][0]*Q.m[1][2] ; /* product */ Q.m[2][2] = Q.m[0][0]*Q.m[1][1] - Q.m[0][1]*Q.m[1][0] ; } P = nifti_mat33_polar(Q) ; /* P is orthog matrix closest to Q */ R.m[0][0] = P.m[0][0] ; R.m[0][1] = P.m[0][1] ; R.m[0][2] = P.m[0][2] ; R.m[1][0] = P.m[1][0] ; R.m[1][1] = P.m[1][1] ; R.m[1][2] = P.m[1][2] ; R.m[2][0] = P.m[2][0] ; R.m[2][1] = P.m[2][1] ; R.m[2][2] = P.m[2][2] ; R.m[0][3] = R.m[1][3] = R.m[2][3] = 0.0 ; return R ; } /*----------------------------------------------------------------------*/ /*! compute the inverse of a 3x3 matrix *//*--------------------------------------------------------------------*/ mat33 nifti_mat33_inverse( mat33 R ) /* inverse of 3x3 matrix */ { double r11,r12,r13,r21,r22,r23,r31,r32,r33 , deti ; mat33 Q ; /* INPUT MATRIX: */ r11 = R.m[0][0]; r12 = R.m[0][1]; r13 = R.m[0][2]; /* [ r11 r12 r13 ] */ r21 = R.m[1][0]; r22 = R.m[1][1]; r23 = R.m[1][2]; /* [ r21 r22 r23 ] */ r31 = R.m[2][0]; r32 = R.m[2][1]; r33 = R.m[2][2]; /* [ r31 r32 r33 ] */ deti = r11*r22*r33-r11*r32*r23-r21*r12*r33 +r21*r32*r13+r31*r12*r23-r31*r22*r13 ; if( deti != 0.0l ) deti = 1.0l / deti ; Q.m[0][0] = deti*( r22*r33-r32*r23) ; Q.m[0][1] = deti*(-r12*r33+r32*r13) ; Q.m[0][2] = deti*( r12*r23-r22*r13) ; Q.m[1][0] = deti*(-r21*r33+r31*r23) ; Q.m[1][1] = deti*( r11*r33-r31*r13) ; Q.m[1][2] = deti*(-r11*r23+r21*r13) ; Q.m[2][0] = deti*( r21*r32-r31*r22) ; Q.m[2][1] = deti*(-r11*r32+r31*r12) ; Q.m[2][2] = deti*( r11*r22-r21*r12) ; return Q ; } /*----------------------------------------------------------------------*/ /*! compute the determinant of a 3x3 matrix *//*--------------------------------------------------------------------*/ float nifti_mat33_determ( mat33 R ) /* determinant of 3x3 matrix */ { double r11,r12,r13,r21,r22,r23,r31,r32,r33 ; /* INPUT MATRIX: */ r11 = R.m[0][0]; r12 = R.m[0][1]; r13 = R.m[0][2]; /* [ r11 r12 r13 ] */ r21 = R.m[1][0]; r22 = R.m[1][1]; r23 = R.m[1][2]; /* [ r21 r22 r23 ] */ r31 = R.m[2][0]; r32 = R.m[2][1]; r33 = R.m[2][2]; /* [ r31 r32 r33 ] */ return r11*r22*r33-r11*r32*r23-r21*r12*r33 +r21*r32*r13+r31*r12*r23-r31*r22*r13 ; } /*----------------------------------------------------------------------*/ /*! compute the max row norm of a 3x3 matrix *//*--------------------------------------------------------------------*/ float nifti_mat33_rownorm( mat33 A ) /* max row norm of 3x3 matrix */ { float r1,r2,r3 ; r1 = fabs(A.m[0][0])+fabs(A.m[0][1])+fabs(A.m[0][2]) ; r2 = fabs(A.m[1][0])+fabs(A.m[1][1])+fabs(A.m[1][2]) ; r3 = fabs(A.m[2][0])+fabs(A.m[2][1])+fabs(A.m[2][2]) ; if( r1 < r2 ) r1 = r2 ; if( r1 < r3 ) r1 = r3 ; return r1 ; } /*----------------------------------------------------------------------*/ /*! compute the max column norm of a 3x3 matrix *//*--------------------------------------------------------------------*/ float nifti_mat33_colnorm( mat33 A ) /* max column norm of 3x3 matrix */ { float r1,r2,r3 ; r1 = fabs(A.m[0][0])+fabs(A.m[1][0])+fabs(A.m[2][0]) ; r2 = fabs(A.m[0][1])+fabs(A.m[1][1])+fabs(A.m[2][1]) ; r3 = fabs(A.m[0][2])+fabs(A.m[1][2])+fabs(A.m[2][2]) ; if( r1 < r2 ) r1 = r2 ; if( r1 < r3 ) r1 = r3 ; return r1 ; } /*----------------------------------------------------------------------*/ /*! multiply 2 3x3 matrices *//*--------------------------------------------------------------------*/ mat33 nifti_mat33_mul( mat33 A , mat33 B ) /* multiply 2 3x3 matrices */ { mat33 C ; int i,j ; for( i=0 ; i < 3 ; i++ ) for( j=0 ; j < 3 ; j++ ) C.m[i][j] = A.m[i][0] * B.m[0][j] + A.m[i][1] * B.m[1][j] + A.m[i][2] * B.m[2][j] ; return C ; } /*---------------------------------------------------------------------------*/ /*! polar decomposition of a 3x3 matrix This finds the closest orthogonal matrix to input A (in both the Frobenius and L2 norms). Algorithm is that from NJ Higham, SIAM J Sci Stat Comput, 7:1160-1174. *//*-------------------------------------------------------------------------*/ mat33 nifti_mat33_polar( mat33 A ) { mat33 X , Y , Z ; float alp,bet,gam,gmi , dif=1.0 ; int k=0 ; X = A ; /* force matrix to be nonsingular */ gam = nifti_mat33_determ(X) ; while( gam == 0.0 ){ /* perturb matrix */ gam = 0.00001 * ( 0.001 + nifti_mat33_rownorm(X) ) ; X.m[0][0] += gam ; X.m[1][1] += gam ; X.m[2][2] += gam ; gam = nifti_mat33_determ(X) ; } while(1){ Y = nifti_mat33_inverse(X) ; if( dif > 0.3 ){ /* far from convergence */ alp = sqrt( nifti_mat33_rownorm(X) * nifti_mat33_colnorm(X) ) ; bet = sqrt( nifti_mat33_rownorm(Y) * nifti_mat33_colnorm(Y) ) ; gam = sqrt( bet / alp ) ; gmi = 1.0 / gam ; } else { gam = gmi = 1.0 ; /* close to convergence */ } Z.m[0][0] = 0.5 * ( gam*X.m[0][0] + gmi*Y.m[0][0] ) ; Z.m[0][1] = 0.5 * ( gam*X.m[0][1] + gmi*Y.m[1][0] ) ; Z.m[0][2] = 0.5 * ( gam*X.m[0][2] + gmi*Y.m[2][0] ) ; Z.m[1][0] = 0.5 * ( gam*X.m[1][0] + gmi*Y.m[0][1] ) ; Z.m[1][1] = 0.5 * ( gam*X.m[1][1] + gmi*Y.m[1][1] ) ; Z.m[1][2] = 0.5 * ( gam*X.m[1][2] + gmi*Y.m[2][1] ) ; Z.m[2][0] = 0.5 * ( gam*X.m[2][0] + gmi*Y.m[0][2] ) ; Z.m[2][1] = 0.5 * ( gam*X.m[2][1] + gmi*Y.m[1][2] ) ; Z.m[2][2] = 0.5 * ( gam*X.m[2][2] + gmi*Y.m[2][2] ) ; dif = fabs(Z.m[0][0]-X.m[0][0])+fabs(Z.m[0][1]-X.m[0][1]) +fabs(Z.m[0][2]-X.m[0][2])+fabs(Z.m[1][0]-X.m[1][0]) +fabs(Z.m[1][1]-X.m[1][1])+fabs(Z.m[1][2]-X.m[1][2]) +fabs(Z.m[2][0]-X.m[2][0])+fabs(Z.m[2][1]-X.m[2][1]) +fabs(Z.m[2][2]-X.m[2][2]) ; k = k+1 ; if( k > 100 || dif < 3.e-6 ) break ; /* convergence or exhaustion */ X = Z ; } return Z ; } /*---------------------------------------------------------------------------*/ /*! compute the (closest) orientation from a 4x4 ijk->xyz tranformation matrix
       Input:  4x4 matrix that transforms (i,j,k) indexes to (x,y,z) coordinates,
               where +x=Right, +y=Anterior, +z=Superior.
               (Only the upper-left 3x3 corner of R is used herein.)
       Output: 3 orientation codes that correspond to the closest "standard"
               anatomical orientation of the (i,j,k) axes.
       Method: Find which permutation of (x,y,z) has the smallest angle to the
               (i,j,k) axes directions, which are the columns of the R matrix.
       Errors: The codes returned will be zero.
    
       For example, an axial volume might get return values of
         *icod = NIFTI_R2L   (i axis is mostly Right to Left)
         *jcod = NIFTI_P2A   (j axis is mostly Posterior to Anterior)
         *kcod = NIFTI_I2S   (k axis is mostly Inferior to Superior)
       
    \see "QUATERNION REPRESENTATION OF ROTATION MATRIX" in nifti1.h \see nifti_quatern_to_mat44, nifti_mat44_to_quatern, nifti_make_orthog_mat44 *//*-------------------------------------------------------------------------*/ void nifti_mat44_to_orientation( mat44 R , int *icod, int *jcod, int *kcod ) { float xi,xj,xk , yi,yj,yk , zi,zj,zk , val,detQ,detP ; mat33 P , Q , M ; int i,j,k=0,p,q,r , ibest,jbest,kbest,pbest,qbest,rbest ; float vbest ; if( icod == NULL || jcod == NULL || kcod == NULL ) return ; /* bad */ *icod = *jcod = *kcod = 0 ; /* error returns, if sh*t happens */ /* load column vectors for each (i,j,k) direction from matrix */ /*-- i axis --*/ /*-- j axis --*/ /*-- k axis --*/ xi = R.m[0][0] ; xj = R.m[0][1] ; xk = R.m[0][2] ; yi = R.m[1][0] ; yj = R.m[1][1] ; yk = R.m[1][2] ; zi = R.m[2][0] ; zj = R.m[2][1] ; zk = R.m[2][2] ; /* normalize column vectors to get unit vectors along each ijk-axis */ /* normalize i axis */ val = sqrt( xi*xi + yi*yi + zi*zi ) ; if( val == 0.0 ) return ; /* stupid input */ xi /= val ; yi /= val ; zi /= val ; /* normalize j axis */ val = sqrt( xj*xj + yj*yj + zj*zj ) ; if( val == 0.0 ) return ; /* stupid input */ xj /= val ; yj /= val ; zj /= val ; /* orthogonalize j axis to i axis, if needed */ val = xi*xj + yi*yj + zi*zj ; /* dot product between i and j */ if( fabs(val) > 1.e-4 ){ xj -= val*xi ; yj -= val*yi ; zj -= val*zi ; val = sqrt( xj*xj + yj*yj + zj*zj ) ; /* must renormalize */ if( val == 0.0 ) return ; /* j was parallel to i? */ xj /= val ; yj /= val ; zj /= val ; } /* normalize k axis; if it is zero, make it the cross product i x j */ val = sqrt( xk*xk + yk*yk + zk*zk ) ; if( val == 0.0 ){ xk = yi*zj-zi*yj; yk = zi*xj-zj*xi ; zk=xi*yj-yi*xj ; } else { xk /= val ; yk /= val ; zk /= val ; } /* orthogonalize k to i */ val = xi*xk + yi*yk + zi*zk ; /* dot product between i and k */ if( fabs(val) > 1.e-4 ){ xk -= val*xi ; yk -= val*yi ; zk -= val*zi ; val = sqrt( xk*xk + yk*yk + zk*zk ) ; if( val == 0.0 ) return ; /* bad */ xk /= val ; yk /= val ; zk /= val ; } /* orthogonalize k to j */ val = xj*xk + yj*yk + zj*zk ; /* dot product between j and k */ if( fabs(val) > 1.e-4 ){ xk -= val*xj ; yk -= val*yj ; zk -= val*zj ; val = sqrt( xk*xk + yk*yk + zk*zk ) ; if( val == 0.0 ) return ; /* bad */ xk /= val ; yk /= val ; zk /= val ; } Q.m[0][0] = xi ; Q.m[0][1] = xj ; Q.m[0][2] = xk ; Q.m[1][0] = yi ; Q.m[1][1] = yj ; Q.m[1][2] = yk ; Q.m[2][0] = zi ; Q.m[2][1] = zj ; Q.m[2][2] = zk ; /* at this point, Q is the rotation matrix from the (i,j,k) to (x,y,z) axes */ detQ = nifti_mat33_determ( Q ) ; if( detQ == 0.0 ) return ; /* shouldn't happen unless user is a DUFIS */ /* Build and test all possible +1/-1 coordinate permutation matrices P; then find the P such that the rotation matrix M=PQ is closest to the identity, in the sense of M having the smallest total rotation angle. */ /* Despite the formidable looking 6 nested loops, there are only 3*3*3*2*2*2 = 216 passes, which will run very quickly. */ vbest = -666.0 ; ibest=pbest=qbest=rbest=1 ; jbest=2 ; kbest=3 ; for( i=1 ; i <= 3 ; i++ ){ /* i = column number to use for row #1 */ for( j=1 ; j <= 3 ; j++ ){ /* j = column number to use for row #2 */ if( i == j ) continue ; for( k=1 ; k <= 3 ; k++ ){ /* k = column number to use for row #3 */ if( i == k || j == k ) continue ; P.m[0][0] = P.m[0][1] = P.m[0][2] = P.m[1][0] = P.m[1][1] = P.m[1][2] = P.m[2][0] = P.m[2][1] = P.m[2][2] = 0.0 ; for( p=-1 ; p <= 1 ; p+=2 ){ /* p,q,r are -1 or +1 */ for( q=-1 ; q <= 1 ; q+=2 ){ /* and go into rows #1,2,3 */ for( r=-1 ; r <= 1 ; r+=2 ){ P.m[0][i-1] = p ; P.m[1][j-1] = q ; P.m[2][k-1] = r ; detP = nifti_mat33_determ(P) ; /* sign of permutation */ if( detP * detQ <= 0.0 ) continue ; /* doesn't match sign of Q */ M = nifti_mat33_mul(P,Q) ; /* angle of M rotation = 2.0*acos(0.5*sqrt(1.0+trace(M))) */ /* we want largest trace(M) == smallest angle == M nearest to I */ val = M.m[0][0] + M.m[1][1] + M.m[2][2] ; /* trace */ if( val > vbest ){ vbest = val ; ibest = i ; jbest = j ; kbest = k ; pbest = p ; qbest = q ; rbest = r ; } }}}}}} /* At this point ibest is 1 or 2 or 3; pbest is -1 or +1; etc. The matrix P that corresponds is the best permutation approximation to Q-inverse; that is, P (approximately) takes (x,y,z) coordinates to the (i,j,k) axes. For example, the first row of P (which contains pbest in column ibest) determines the way the i axis points relative to the anatomical (x,y,z) axes. If ibest is 2, then the i axis is along the y axis, which is direction P2A (if pbest > 0) or A2P (if pbest < 0). So, using ibest and pbest, we can assign the output code for the i axis. Mutatis mutandis for the j and k axes, of course. */ switch( ibest*pbest ){ case 1: i = NIFTI_L2R ; break ; case -1: i = NIFTI_R2L ; break ; case 2: i = NIFTI_P2A ; break ; case -2: i = NIFTI_A2P ; break ; case 3: i = NIFTI_I2S ; break ; case -3: i = NIFTI_S2I ; break ; } switch( jbest*qbest ){ case 1: j = NIFTI_L2R ; break ; case -1: j = NIFTI_R2L ; break ; case 2: j = NIFTI_P2A ; break ; case -2: j = NIFTI_A2P ; break ; case 3: j = NIFTI_I2S ; break ; case -3: j = NIFTI_S2I ; break ; } switch( kbest*rbest ){ case 1: k = NIFTI_L2R ; break ; case -1: k = NIFTI_R2L ; break ; case 2: k = NIFTI_P2A ; break ; case -2: k = NIFTI_A2P ; break ; case 3: k = NIFTI_I2S ; break ; case -3: k = NIFTI_S2I ; break ; } *icod = i ; *jcod = j ; *kcod = k ; return ; } /*---------------------------------------------------------------------------*/ /* Routines to swap byte arrays in various ways: - 2 at a time: ab -> ba [short] - 4 at a time: abcd -> dcba [int, float] - 8 at a time: abcdDCBA -> ABCDdcba [long long, double] - 16 at a time: abcdefghHGFEDCBA -> ABCDEFGHhgfedcba [long double] -----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------*/ /*! swap each byte pair from the given list of n pairs * * Due to alignment of structures at some architectures (e.g. on ARM), * stick to char varaibles. * Fixes http://bugs.debian.org/446893 Yaroslav * *//*--------------------------------------------------------------------*/ void nifti_swap_2bytes( int n , void *ar ) /* 2 bytes at a time */ { register int ii ; unsigned char * cp1 = (unsigned char *)ar, * cp2 ; unsigned char tval; for( ii=0 ; ii < n ; ii++ ){ cp2 = cp1 + 1; tval = *cp1; *cp1 = *cp2; *cp2 = tval; cp1 += 2; } return ; } /*----------------------------------------------------------------------*/ /*! swap 4 bytes at a time from the given list of n sets of 4 bytes *//*--------------------------------------------------------------------*/ void nifti_swap_4bytes( int n , void *ar ) /* 4 bytes at a time */ { register int ii ; unsigned char * cp0 = (unsigned char *)ar, * cp1, * cp2 ; register unsigned char tval ; for( ii=0 ; ii < n ; ii++ ){ cp1 = cp0; cp2 = cp0+3; tval = *cp1; *cp1 = *cp2; *cp2 = tval; cp1++; cp2--; tval = *cp1; *cp1 = *cp2; *cp2 = tval; cp0 += 4; } return ; } /*----------------------------------------------------------------------*/ /*! swap 8 bytes at a time from the given list of n sets of 8 bytes * * perhaps use this style for the general Nbytes, as Yaroslav suggests *//*--------------------------------------------------------------------*/ void nifti_swap_8bytes( int n , void *ar ) /* 8 bytes at a time */ { register int ii ; unsigned char * cp0 = (unsigned char *)ar, * cp1, * cp2 ; register unsigned char tval ; for( ii=0 ; ii < n ; ii++ ){ cp1 = cp0; cp2 = cp0+7; while ( cp2 > cp1 ) /* unroll? */ { tval = *cp1 ; *cp1 = *cp2 ; *cp2 = tval ; cp1++; cp2--; } cp0 += 8; } return ; } /*----------------------------------------------------------------------*/ /*! swap 16 bytes at a time from the given list of n sets of 16 bytes *//*--------------------------------------------------------------------*/ void nifti_swap_16bytes( int n , void *ar ) /* 16 bytes at a time */ { register int ii ; unsigned char * cp0 = (unsigned char *)ar, * cp1, * cp2 ; register unsigned char tval ; for( ii=0 ; ii < n ; ii++ ){ cp1 = cp0; cp2 = cp0+15; while ( cp2 > cp1 ) { tval = *cp1 ; *cp1 = *cp2 ; *cp2 = tval ; cp1++; cp2--; } cp0 += 16; } return ; } /*---------------------------------------------------------------------------*/ /*----------------------------------------------------------------------*/ /*! based on siz, call the appropriate nifti_swap_Nbytes() function *//*--------------------------------------------------------------------*/ void nifti_swap_Nbytes( int n , int siz , void *ar ) /* subsuming case */ { switch( siz ){ case 2: nifti_swap_2bytes ( n , ar ) ; break ; case 4: nifti_swap_4bytes ( n , ar ) ; break ; case 8: nifti_swap_8bytes ( n , ar ) ; break ; case 16: nifti_swap_16bytes( n , ar ) ; break ; } return ; } /*-------------------------------------------------------------------------*/ /*! Byte swap NIFTI-1 file header in various places and ways. If is_nifti, swap all (even UNUSED) fields of NIfTI header. Else, swap as a nifti_analyze75 struct. *//*---------------------------------------------------------------------- */ void swap_nifti_header( struct nifti_1_header *h , int is_nifti ) { /* if ANALYZE, swap as such and return */ if( ! is_nifti ) { nifti_swap_as_analyze((nifti_analyze75 *)h); return; } /* otherwise, swap all NIFTI fields */ nifti_swap_4bytes(1, &h->sizeof_hdr); nifti_swap_4bytes(1, &h->extents); nifti_swap_2bytes(1, &h->session_error); nifti_swap_2bytes(8, h->dim); nifti_swap_4bytes(1, &h->intent_p1); nifti_swap_4bytes(1, &h->intent_p2); nifti_swap_4bytes(1, &h->intent_p3); nifti_swap_2bytes(1, &h->intent_code); nifti_swap_2bytes(1, &h->datatype); nifti_swap_2bytes(1, &h->bitpix); nifti_swap_2bytes(1, &h->slice_start); nifti_swap_4bytes(8, h->pixdim); nifti_swap_4bytes(1, &h->vox_offset); nifti_swap_4bytes(1, &h->scl_slope); nifti_swap_4bytes(1, &h->scl_inter); nifti_swap_2bytes(1, &h->slice_end); nifti_swap_4bytes(1, &h->cal_max); nifti_swap_4bytes(1, &h->cal_min); nifti_swap_4bytes(1, &h->slice_duration); nifti_swap_4bytes(1, &h->toffset); nifti_swap_4bytes(1, &h->glmax); nifti_swap_4bytes(1, &h->glmin); nifti_swap_2bytes(1, &h->qform_code); nifti_swap_2bytes(1, &h->sform_code); nifti_swap_4bytes(1, &h->quatern_b); nifti_swap_4bytes(1, &h->quatern_c); nifti_swap_4bytes(1, &h->quatern_d); nifti_swap_4bytes(1, &h->qoffset_x); nifti_swap_4bytes(1, &h->qoffset_y); nifti_swap_4bytes(1, &h->qoffset_z); nifti_swap_4bytes(4, h->srow_x); nifti_swap_4bytes(4, h->srow_y); nifti_swap_4bytes(4, h->srow_z); return ; } /*-------------------------------------------------------------------------*/ /*! Byte swap as an ANALYZE 7.5 header * * return non-zero on failure *//*---------------------------------------------------------------------- */ int nifti_swap_as_analyze( nifti_analyze75 * h ) { if( !h ) return 1; nifti_swap_4bytes(1, &h->sizeof_hdr); nifti_swap_4bytes(1, &h->extents); nifti_swap_2bytes(1, &h->session_error); nifti_swap_2bytes(8, h->dim); nifti_swap_2bytes(1, &h->unused8); nifti_swap_2bytes(1, &h->unused9); nifti_swap_2bytes(1, &h->unused10); nifti_swap_2bytes(1, &h->unused11); nifti_swap_2bytes(1, &h->unused12); nifti_swap_2bytes(1, &h->unused13); nifti_swap_2bytes(1, &h->unused14); nifti_swap_2bytes(1, &h->datatype); nifti_swap_2bytes(1, &h->bitpix); nifti_swap_2bytes(1, &h->dim_un0); nifti_swap_4bytes(8, h->pixdim); nifti_swap_4bytes(1, &h->vox_offset); nifti_swap_4bytes(1, &h->funused1); nifti_swap_4bytes(1, &h->funused2); nifti_swap_4bytes(1, &h->funused3); nifti_swap_4bytes(1, &h->cal_max); nifti_swap_4bytes(1, &h->cal_min); nifti_swap_4bytes(1, &h->compressed); nifti_swap_4bytes(1, &h->verified); nifti_swap_4bytes(1, &h->glmax); nifti_swap_4bytes(1, &h->glmin); nifti_swap_4bytes(1, &h->views); nifti_swap_4bytes(1, &h->vols_added); nifti_swap_4bytes(1, &h->start_field); nifti_swap_4bytes(1, &h->field_skip); nifti_swap_4bytes(1, &h->omax); nifti_swap_4bytes(1, &h->omin); nifti_swap_4bytes(1, &h->smax); nifti_swap_4bytes(1, &h->smin); return 0; } /*-------------------------------------------------------------------------*/ /*! OLD VERSION of swap_nifti_header (left for undo/compare operations) Byte swap NIFTI-1 file header in various places and ways. If is_nifti is nonzero, will also swap the NIFTI-specific components of the header; otherwise, only the components common to NIFTI and ANALYZE will be swapped. *//*---------------------------------------------------------------------- */ void old_swap_nifti_header( struct nifti_1_header *h , int is_nifti ) { /* this stuff is always present, for ANALYZE and NIFTI */ swap_4(h->sizeof_hdr) ; nifti_swap_2bytes( 8 , h->dim ) ; nifti_swap_4bytes( 8 , h->pixdim ) ; swap_2(h->datatype) ; swap_2(h->bitpix) ; swap_4(h->vox_offset); swap_4(h->cal_max); swap_4(h->cal_min); /* this stuff is NIFTI specific */ if( is_nifti ){ swap_4(h->intent_p1); swap_4(h->intent_p2); swap_4(h->intent_p3); swap_2(h->intent_code); swap_2(h->slice_start); swap_2(h->slice_end); swap_4(h->scl_slope); swap_4(h->scl_inter); swap_4(h->slice_duration); swap_4(h->toffset); swap_2(h->qform_code); swap_2(h->sform_code); swap_4(h->quatern_b); swap_4(h->quatern_c); swap_4(h->quatern_d); swap_4(h->qoffset_x); swap_4(h->qoffset_y); swap_4(h->qoffset_z); nifti_swap_4bytes(4,h->srow_x); nifti_swap_4bytes(4,h->srow_y); nifti_swap_4bytes(4,h->srow_z); } return ; } #define USE_STAT #ifdef USE_STAT /*---------------------------------------------------------------------------*/ /* Return the file length (0 if file not found or has no contents). This is a Unix-specific function, since it uses stat(). -----------------------------------------------------------------------------*/ #include #include /*---------------------------------------------------------------------------*/ /*! return the size of a file, in bytes \return size of file on success, -1 on error or no file changed to return int, -1 means no file or error 20 Dec 2004 [rickr] *//*-------------------------------------------------------------------------*/ int nifti_get_filesize( const char *pathname ) { struct stat buf ; int ii ; if( pathname == NULL || *pathname == '\0' ) return -1 ; ii = stat( pathname , &buf ); if( ii != 0 ) return -1 ; return (unsigned int)buf.st_size ; } #else /*---------- non-Unix version of the above, less efficient -----------*/ int nifti_get_filesize( const char *pathname ) { znzFile fp ; int len ; if( pathname == NULL || *pathname == '\0' ) return -1 ; fp = znzopen(pathname,"rb",0); if( znz_isnull(fp) ) return -1 ; znzseek(fp,0L,SEEK_END) ; len = znztell(fp) ; znzclose(fp) ; return len ; } #endif /* USE_STAT */ /*----------------------------------------------------------------------*/ /*! return the total volume size, in bytes This is computed as nvox * nbyper. *//*--------------------------------------------------------------------*/ size_t nifti_get_volsize(const nifti_image *nim) { return (size_t)(nim->nbyper) * (size_t)(nim->nvox) ; /* total bytes */ } /*--------------------------------------------------------------------------*/ /* Support functions for filenames in read and write - allows for gzipped files */ /*----------------------------------------------------------------------*/ /*! simple check for file existence \return 1 on existence, 0 otherwise *//*--------------------------------------------------------------------*/ int nifti_fileexists(const char* fname) { znzFile fp; fp = znzopen( fname , "rb" , 1 ) ; if( !znz_isnull(fp) ) { znzclose(fp); return 1; } return 0; /* fp is NULL */ } /*----------------------------------------------------------------------*/ /*! return whether the filename is valid The name is considered valid if the file basename has length greater than zero, AND one of the valid nifti extensions is provided. fname input | return | =============================== "myimage" | 0 | "myimage.tif" | 0 | "myimage.tif.gz" | 0 | "myimage.nii" | 1 | ".nii" | 0 | ".myhiddenimage" | 0 | ".myhiddenimage.nii" | 1 | *//*--------------------------------------------------------------------*/ int nifti_is_complete_filename(const char* fname) { char * ext; /* check input file(s) for sanity */ if( fname == NULL || *fname == '\0' ){ if ( g_opts.debug > 1 ) fprintf(stderr,"-- empty filename in nifti_validfilename()\n"); return 0; } ext = nifti_find_file_extension(fname); if ( ext == NULL ) { /*Invalid extension given */ if ( g_opts.debug > 0 ) fprintf(stderr,"-- no nifti valid extension for filename '%s'\n", fname); return 0; } if ( ext && ext == fname ) { /* then no filename prefix */ if ( g_opts.debug > 0 ) fprintf(stderr,"-- no prefix for filename '%s'\n", fname); return 0; } return 1; } /*----------------------------------------------------------------------*/ /*! return whether the filename is valid The name is considered valid if its length is positive, excluding any nifti filename extension. fname input | return | result of nifti_makebasename ==================================================================== "myimage" | 1 | "myimage" "myimage.tif" | 1 | "myimage.tif" "myimage.tif.gz" | 1 | "myimage.tif" "myimage.nii" | 1 | "myimage" ".nii" | 0 | ".myhiddenimage" | 1 | ".myhiddenimage" ".myhiddenimage.nii | 1 | ".myhiddenimage" *//*--------------------------------------------------------------------*/ int nifti_validfilename(const char* fname) { char * ext; /* check input file(s) for sanity */ if( fname == NULL || *fname == '\0' ){ if ( g_opts.debug > 1 ) fprintf(stderr,"-- empty filename in nifti_validfilename()\n"); return 0; } ext = nifti_find_file_extension(fname); if ( ext && ext == fname ) { /* then no filename prefix */ if ( g_opts.debug > 0 ) fprintf(stderr,"-- no prefix for filename '%s'\n", fname); return 0; } return 1; } /*----------------------------------------------------------------------*/ /*! check the end of the filename for a valid nifti extension Valid extensions are currently .nii, .hdr, .img, .nia, or any of them followed by .gz. Note that '.' is part of the extension. \return a pointer to the extension (within the filename), or NULL *//*--------------------------------------------------------------------*/ char * nifti_find_file_extension( const char * name ) { char * ext; int len; if ( ! name ) return NULL; len = strlen(name); if ( len < 4 ) return NULL; ext = (char *)name + len - 4; if ( (strcmp(ext, ".hdr") == 0) || (strcmp(ext, ".img") == 0) || (strcmp(ext, ".nia") == 0) || (strcmp(ext, ".nii") == 0) ) return ext; #ifdef HAVE_ZLIB if ( len < 7 ) return NULL; ext = (char *)name + len - 7; if ( (strcmp(ext, ".hdr.gz") == 0) || (strcmp(ext, ".img.gz") == 0) || (strcmp(ext, ".nii.gz") == 0) ) return ext; #endif if( g_opts.debug > 1 ) fprintf(stderr,"** find_file_ext: failed for name '%s'\n", name); return NULL; } /*----------------------------------------------------------------------*/ /*! return whether the filename ends in ".gz" *//*--------------------------------------------------------------------*/ int nifti_is_gzfile(const char* fname) { /* return true if the filename ends with .gz */ if (fname == NULL) { return 0; } #ifdef HAVE_ZLIB { /* just so len doesn't generate compile warning */ int len; len = strlen(fname); if (len < 3) return 0; /* so we don't search before the name */ if (strcmp(fname + strlen(fname) - 3,".gz")==0) { return 1; } } #endif return 0; } /*----------------------------------------------------------------------*/ /*! return whether the given library was compiled with HAVE_ZLIB set *//*--------------------------------------------------------------------*/ int nifti_compiled_with_zlib(void) { #ifdef HAVE_ZLIB return 1; #else return 0; #endif } /*----------------------------------------------------------------------*/ /*! duplicate the filename, while clearing any extension This allocates memory for basename which should eventually be freed. *//*--------------------------------------------------------------------*/ char * nifti_makebasename(const char* fname) { char *basename, *ext; basename=nifti_strdup(fname); ext = nifti_find_file_extension(basename); if ( ext ) *ext = '\0'; /* clear out extension */ return basename; /* in either case */ } /*----------------------------------------------------------------------*/ /*! set nifti's global debug level, for status reporting - 0 : quiet, nothing is printed to the terminal, but errors - 1 : normal execution (the default) - 2, 3 : more details *//*--------------------------------------------------------------------*/ void nifti_set_debug_level( int level ) { g_opts.debug = level; } /*----------------------------------------------------------------------*/ /*! set nifti's global skip_blank_ext flag 5 Sep 2006 [rickr] explicitly set to 0 or 1 *//*--------------------------------------------------------------------*/ void nifti_set_skip_blank_ext( int skip ) { g_opts.skip_blank_ext = skip ? 1 : 0; } /*----------------------------------------------------------------------*/ /*! check current directory for existing header file \return filename of header on success and NULL if no appropriate file could be found NB: it allocates memory for hdrname which should be freed when no longer required *//*-------------------------------------------------------------------*/ char * nifti_findhdrname(const char* fname) { char *basename, *hdrname, *ext; char elist[2][5] = { ".hdr", ".nii" }; int efirst; /**- check input file(s) for sanity */ if( !nifti_validfilename(fname) ) return NULL; basename = nifti_makebasename(fname); if( !basename ) return NULL; /* only on string alloc failure */ /**- return filename if it has a valid extension and exists (except if it is an .img file (and maybe .gz)) */ ext = nifti_find_file_extension(fname); if ( ext && nifti_fileexists(fname) ) { if ( strncmp(ext,".img",4) != 0 ){ hdrname = nifti_strdup(fname); free(basename); return hdrname; } } /* So the requested name is a basename, contains .img, or does not exist. */ /* In any case, use basename. */ /**- if .img, look for .hdr, .hdr.gz, .nii, .nii.gz, in that order */ /**- else, look for .nii, .nii.gz, .hdr, .hdr.gz, in that order */ /* if we get more extension choices, this could be a loop */ if ( ext && strncmp(ext,".img",4) == 0 ) efirst = 0; else efirst = 1; hdrname = (char *)calloc(sizeof(char),strlen(basename)+8); if( !hdrname ){ fprintf(stderr,"** nifti_findhdrname: failed to alloc hdrname\n"); free(basename); return NULL; } strcpy(hdrname,basename); strcat(hdrname,elist[efirst]); if (nifti_fileexists(hdrname)) { free(basename); return hdrname; } #ifdef HAVE_ZLIB strcat(hdrname,".gz"); if (nifti_fileexists(hdrname)) { free(basename); return hdrname; } #endif /* okay, try the other possibility */ efirst = 1 - efirst; strcpy(hdrname,basename); strcat(hdrname,elist[efirst]); if (nifti_fileexists(hdrname)) { free(basename); return hdrname; } #ifdef HAVE_ZLIB strcat(hdrname,".gz"); if (nifti_fileexists(hdrname)) { free(basename); return hdrname; } #endif /**- if nothing has been found, return NULL */ free(basename); free(hdrname); return NULL; } /*------------------------------------------------------------------------*/ /*! check current directory for existing image file \param fname filename to check for \nifti_type nifti_type for dataset - this determines whether to first check for ".nii" or ".img" (since both may exist) \return filename of data/img file on success and NULL if no appropriate file could be found NB: it allocates memory for the image filename, which should be freed when no longer required *//*---------------------------------------------------------------------*/ char * nifti_findimgname(const char* fname , int nifti_type) { char *basename, *imgname, ext[2][5] = { ".nii", ".img" }; int first; /* first extension to use */ /* check input file(s) for sanity */ if( !nifti_validfilename(fname) ) return NULL; basename = nifti_makebasename(fname); imgname = (char *)calloc(sizeof(char),strlen(basename)+8); if( !imgname ){ fprintf(stderr,"** nifti_findimgname: failed to alloc imgname\n"); free(basename); return NULL; } /* only valid extension for ASCII type is .nia, handle first */ if( nifti_type == NIFTI_FTYPE_ASCII ){ strcpy(imgname,basename); strcat(imgname,".nia"); if (nifti_fileexists(imgname)) { free(basename); return imgname; } } else { /**- test for .nii and .img (don't assume input type from image type) */ /**- if nifti_type = 1, check for .nii first, else .img first */ /* if we get 3 or more extensions, can make a loop here... */ if (nifti_type == NIFTI_FTYPE_NIFTI1_1) first = 0; /* should match .nii */ else first = 1; /* should match .img */ strcpy(imgname,basename); strcat(imgname,ext[first]); if (nifti_fileexists(imgname)) { free(basename); return imgname; } #ifdef HAVE_ZLIB /* then also check for .gz */ strcat(imgname,".gz"); if (nifti_fileexists(imgname)) { free(basename); return imgname; } #endif /* failed to find image file with expected extension, try the other */ strcpy(imgname,basename); strcat(imgname,ext[1-first]); /* can do this with only 2 choices */ if (nifti_fileexists(imgname)) { free(basename); return imgname; } #ifdef HAVE_ZLIB /* then also check for .gz */ strcat(imgname,".gz"); if (nifti_fileexists(imgname)) { free(basename); return imgname; } #endif } /**- if nothing has been found, return NULL */ free(basename); free(imgname); return NULL; } /*----------------------------------------------------------------------*/ /*! creates a filename for storing the header, based on nifti_type \param prefix - this will be copied before the suffix is added \param nifti_type - determines the extension, unless one is in prefix \param check - check for existence (fail condition) \param comp - add .gz for compressed name Note that if prefix provides a file suffix, nifti_type is not used. NB: this allocates memory which should be freed \sa nifti_set_filenames *//*-------------------------------------------------------------------*/ char * nifti_makehdrname(const char * prefix, int nifti_type, int check, int comp) { char * iname, * ext; if( !nifti_validfilename(prefix) ) return NULL; /* add space for extension, optional ".gz", and null char */ iname = (char *)calloc(sizeof(char),strlen(prefix)+8); if( !iname ){ fprintf(stderr,"** small malloc failure!\n"); return NULL; } strcpy(iname, prefix); /* use any valid extension */ if( (ext = nifti_find_file_extension(iname)) != NULL ){ if( strncmp(ext,".img",4) == 0 ) memcpy(ext,".hdr",4); /* then convert img name to hdr */ } /* otherwise, make one up an */ else if( nifti_type == NIFTI_FTYPE_NIFTI1_1 ) strcat(iname, ".nii"); else if( nifti_type == NIFTI_FTYPE_ASCII ) strcat(iname, ".nia"); else strcat(iname, ".hdr"); #ifdef HAVE_ZLIB /* then also check for .gz */ if( comp && (!ext || !strstr(iname,".gz")) ) strcat(iname,".gz"); #endif /* check for existence failure */ if( check && nifti_fileexists(iname) ){ fprintf(stderr,"** failure: header file '%s' already exists\n",iname); free(iname); return NULL; } if(g_opts.debug > 2) fprintf(stderr,"+d made header filename '%s'\n", iname); return iname; } /*----------------------------------------------------------------------*/ /*! creates a filename for storing the image, based on nifti_type \param prefix - this will be copied before the suffix is added \param nifti_type - determines the extension, unless provided by prefix \param check - check for existence (fail condition) \param comp - add .gz for compressed name Note that if prefix provides a file suffix, nifti_type is not used. NB: it allocates memory which should be freed \sa nifti_set_filenames *//*-------------------------------------------------------------------*/ char * nifti_makeimgname(const char * prefix, int nifti_type, int check, int comp) { char * iname, * ext; if( !nifti_validfilename(prefix) ) return NULL; /* add space for extension, optional ".gz", and null char */ iname = (char *)calloc(sizeof(char),strlen(prefix)+8); if( !iname ){ fprintf(stderr,"** small malloc failure!\n"); return NULL; } strcpy(iname, prefix); /* use any valid extension */ if( (ext = nifti_find_file_extension(iname)) != NULL ){ if( strncmp(ext,".hdr",4) == 0 ) memcpy(ext,".img",4); /* then convert hdr name to img */ } /* otherwise, make one up */ else if( nifti_type == NIFTI_FTYPE_NIFTI1_1 ) strcat(iname, ".nii"); else if( nifti_type == NIFTI_FTYPE_ASCII ) strcat(iname, ".nia"); else strcat(iname, ".img"); #ifdef HAVE_ZLIB /* then also check for .gz */ if( comp && (!ext || !strstr(iname,".gz")) ) strcat(iname,".gz"); #endif /* check for existence failure */ if( check && nifti_fileexists(iname) ){ fprintf(stderr,"** failure: image file '%s' already exists\n",iname); free(iname); return NULL; } if( g_opts.debug > 2 ) fprintf(stderr,"+d made image filename '%s'\n",iname); return iname; } /*----------------------------------------------------------------------*/ /*! create and set new filenames, based on prefix and image type \param nim pointer to nifti_image in which to set filenames \param prefix (required) prefix for output filenames \param check check for previous existence of filename (existence is an error condition) \param set_byte_order flag to set nim->byteorder here (this is probably a logical place to do so) \return 0 on successful update \warning this will free() any existing names and create new ones \sa nifti_makeimgname, nifti_makehdrname, nifti_type_and_names_match *//*--------------------------------------------------------------------*/ int nifti_set_filenames( nifti_image * nim, const char * prefix, int check, int set_byte_order ) { int comp = nifti_is_gzfile(prefix); if( !nim || !prefix ){ fprintf(stderr,"** nifti_set_filenames, bad params %p, %p\n", (void *)nim,prefix); return -1; } if( g_opts.debug > 1 ) fprintf(stderr,"+d modifying output filenames using prefix %s\n", prefix); if( nim->fname ) free(nim->fname); if( nim->iname ) free(nim->iname); nim->fname = nifti_makehdrname(prefix, nim->nifti_type, check, comp); nim->iname = nifti_makeimgname(prefix, nim->nifti_type, check, comp); if( !nim->fname || !nim->iname ){ LNI_FERR("nifti_set_filename","failed to set prefix for",prefix); return -1; } if( set_byte_order ) nim->byteorder = nifti_short_order() ; if( nifti_set_type_from_names(nim) < 0 ) return -1; if( g_opts.debug > 2 ) fprintf(stderr,"+d have new filenames %s and %s\n",nim->fname,nim->iname); return 0; } /*--------------------------------------------------------------------------*/ /*! check whether nifti_type matches fname and iname for the nifti_image - if type 0 or 2, expect .hdr/.img pair - if type 1, expect .nii (and names must match) \param nim given nifti_image \param show_warn if set, print a warning message for any mis-match \return - 1 if the values seem to match - 0 if there is a mis-match - -1 if there is not sufficient information to create file(s) \sa NIFTI_FTYPE_* codes in nifti1_io.h \sa nifti_set_type_from_names, is_valid_nifti_type *//*------------------------------------------------------------------------*/ int nifti_type_and_names_match( nifti_image * nim, int show_warn ) { char func[] = "nifti_type_and_names_match"; char * ext_h, * ext_i; /* header and image filename extensions */ int errs = 0; /* error counter */ /* sanity checks */ if( !nim ){ if( show_warn ) fprintf(stderr,"** %s: missing nifti_image\n", func); return -1; } if( !nim->fname ){ if( show_warn ) fprintf(stderr,"** %s: missing header filename\n", func); errs++; } if( !nim->iname ){ if( show_warn ) fprintf(stderr,"** %s: missing image filename\n", func); errs++; } if( !is_valid_nifti_type(nim->nifti_type) ){ if( show_warn ) fprintf(stderr,"** %s: bad nifti_type %d\n", func, nim->nifti_type); errs++; } if( errs ) return -1; /* then do not proceed */ /* get pointers to extensions */ ext_h = nifti_find_file_extension( nim->fname ); ext_i = nifti_find_file_extension( nim->iname ); /* check for filename extensions */ if( !ext_h ){ if( show_warn ) fprintf(stderr,"-d missing NIFTI extension in header filename, %s\n", nim->fname); errs++; } if( !ext_i ){ if( show_warn ) fprintf(stderr,"-d missing NIFTI extension in image filename, %s\n", nim->iname); errs++; } if( errs ) return 0; /* do not proceed, but this is just a mis-match */ /* general tests */ if( nim->nifti_type == NIFTI_FTYPE_NIFTI1_1 ){ /* .nii */ if( strncmp(ext_h,".nii",4) ) { if( show_warn ) fprintf(stderr, "-d NIFTI_FTYPE 1, but no .nii extension in header filename, %s\n", nim->fname); errs++; } if( strncmp(ext_i,".nii",4) ) { if( show_warn ) fprintf(stderr, "-d NIFTI_FTYPE 1, but no .nii extension in image filename, %s\n", nim->iname); errs++; } if( strcmp(nim->fname, nim->iname) != 0 ){ if( show_warn ) fprintf(stderr, "-d NIFTI_FTYPE 1, but header and image filenames differ: %s, %s\n", nim->fname, nim->iname); errs++; } } else if( (nim->nifti_type == NIFTI_FTYPE_NIFTI1_2) || /* .hdr/.img */ (nim->nifti_type == NIFTI_FTYPE_ANALYZE) ) { if( strncmp(ext_h,".hdr",4) != 0 ){ if( show_warn ) fprintf(stderr,"-d no '.hdr' extension, but NIFTI type is %d, %s\n", nim->nifti_type, nim->fname); errs++; } if( strncmp(ext_i,".img",4) != 0 ){ if( show_warn ) fprintf(stderr,"-d no '.img' extension, but NIFTI type is %d, %s\n", nim->nifti_type, nim->iname); errs++; } } /* ignore any other nifti_type */ return 1; } /*--------------------------------------------------------------------------*/ /*! check whether the given type is on the "approved" list The code is valid if it is non-negative, and does not exceed NIFTI_MAX_FTYPE. \return 1 if nifti_type is valid, 0 otherwise \sa NIFTI_FTYPE_* codes in nifti1_io.h *//*------------------------------------------------------------------------*/ int is_valid_nifti_type( int nifti_type ) { if( nifti_type >= NIFTI_FTYPE_ANALYZE && /* smallest type, 0 */ nifti_type <= NIFTI_MAX_FTYPE ) return 1; return 0; } /*--------------------------------------------------------------------------*/ /*! check whether the given type is on the "approved" list The type is explicitly checked against the NIFTI_TYPE_* list in nifti1.h. \return 1 if dtype is valid, 0 otherwise \sa NIFTI_TYPE_* codes in nifti1.h *//*------------------------------------------------------------------------*/ int nifti_is_valid_datatype( int dtype ) { if( dtype == NIFTI_TYPE_UINT8 || dtype == NIFTI_TYPE_INT16 || dtype == NIFTI_TYPE_INT32 || dtype == NIFTI_TYPE_FLOAT32 || dtype == NIFTI_TYPE_COMPLEX64 || dtype == NIFTI_TYPE_FLOAT64 || dtype == NIFTI_TYPE_RGB24 || dtype == NIFTI_TYPE_RGBA32 || dtype == NIFTI_TYPE_INT8 || dtype == NIFTI_TYPE_UINT16 || dtype == NIFTI_TYPE_UINT32 || dtype == NIFTI_TYPE_INT64 || dtype == NIFTI_TYPE_UINT64 || dtype == NIFTI_TYPE_FLOAT128 || dtype == NIFTI_TYPE_COMPLEX128 || dtype == NIFTI_TYPE_COMPLEX256 ) return 1; return 0; } /*--------------------------------------------------------------------------*/ /*! set the nifti_type field based on fname and iname Note that nifti_type is changed only when it does not match the filenames. \return 0 on success, -1 on error \sa is_valid_nifti_type, nifti_type_and_names_match *//*------------------------------------------------------------------------*/ int nifti_set_type_from_names( nifti_image * nim ) { /* error checking first */ if( !nim ){ fprintf(stderr,"** NSTFN: no nifti_image\n"); return -1; } if( !nim->fname || !nim->iname ){ fprintf(stderr,"** NSTFN: missing filename(s) fname @ %p, iname @ %p\n", nim->fname, nim->iname); return -1; } if( ! nifti_validfilename ( nim->fname ) || ! nifti_validfilename ( nim->iname ) || ! nifti_find_file_extension( nim->fname ) || ! nifti_find_file_extension( nim->iname ) ) { fprintf(stderr,"** NSTFN: invalid filename(s) fname='%s', iname='%s'\n", nim->fname, nim->iname); return -1; } if( g_opts.debug > 2 ) fprintf(stderr,"-d verify nifti_type from filenames: %d",nim->nifti_type); /* type should be NIFTI_FTYPE_ASCII if extension is .nia */ if( (strcmp(nifti_find_file_extension( nim->fname ),".nia")==0) ) { nim->nifti_type = NIFTI_FTYPE_ASCII; } else { /* not too picky here, do what must be done, and then verify */ if( strcmp(nim->fname, nim->iname) == 0 ) /* one file, type 1 */ nim->nifti_type = NIFTI_FTYPE_NIFTI1_1; else if( nim->nifti_type == NIFTI_FTYPE_NIFTI1_1 ) /* cannot be type 1 */ nim->nifti_type = NIFTI_FTYPE_NIFTI1_2; } if( g_opts.debug > 2 ) fprintf(stderr," -> %d\n",nim->nifti_type); if( g_opts.debug > 1 ) /* warn user about anything strange */ nifti_type_and_names_match(nim, 1); if( is_valid_nifti_type(nim->nifti_type) ) return 0; /* success! */ fprintf(stderr,"** NSTFN: bad nifti_type %d, for '%s' and '%s'\n", nim->nifti_type, nim->fname, nim->iname); return -1; } /*--------------------------------------------------------------------------*/ /*! Determine if this is a NIFTI-formatted file.
       \return  0 if file looks like ANALYZE 7.5 [checks sizeof_hdr field == 348]
                1 if file marked as NIFTI (header+data in 1 file)
                2 if file marked as NIFTI (header+data in 2 files)
               -1 if it can't tell, file doesn't exist, etc.
       
    *//*------------------------------------------------------------------------*/ int is_nifti_file( const char *hname ) { struct nifti_1_header nhdr ; znzFile fp ; int ii ; char *tmpname; /* bad input name? */ if( !nifti_validfilename(hname) ) return -1 ; /* open file */ tmpname = nifti_findhdrname(hname); if( tmpname == NULL ){ if( g_opts.debug > 0 ) fprintf(stderr,"** no header file found for '%s'\n",hname); return -1; } fp = znzopen( tmpname , "rb" , nifti_is_gzfile(tmpname) ) ; free(tmpname); if (znz_isnull(fp)) return -1 ; /* bad open? */ /* read header, close file */ ii = znzread( &nhdr , 1 , sizeof(nhdr) , fp ) ; znzclose( fp ) ; if( ii < (int) sizeof(nhdr) ) return -1 ; /* bad read? */ /* check for NIFTI-ness */ if( NIFTI_VERSION(nhdr) != 0 ){ return ( NIFTI_ONEFILE(nhdr) ) ? 1 : 2 ; } /* check for ANALYZE-ness (sizeof_hdr field == 348) */ ii = nhdr.sizeof_hdr ; if( ii == (int)sizeof(nhdr) ) return 0 ; /* matches */ /* try byte-swapping header */ swap_4(ii) ; if( ii == (int)sizeof(nhdr) ) return 0 ; /* matches */ return -1 ; /* not good */ } static int print_hex_vals( const char * data, int nbytes, FILE * fp ) { int c; if ( !data || nbytes < 1 || !fp ) return -1; fputs("0x", fp); for ( c = 0; c < nbytes; c++ ) fprintf(fp, " %x", data[c]); return 0; } /*----------------------------------------------------------------------*/ /*! display the contents of the nifti_1_header (send to stdout) \param info if non-NULL, print this character string \param hp pointer to nifti_1_header *//*--------------------------------------------------------------------*/ int disp_nifti_1_header( const char * info, const nifti_1_header * hp ) { int c; fputs( "-------------------------------------------------------\n", stdout ); if ( info ) fputs( info, stdout ); if ( !hp ){ fputs(" ** no nifti_1_header to display!\n",stdout); return 1; } fprintf(stdout," nifti_1_header :\n" " sizeof_hdr = %d\n" " data_type[10] = ", hp->sizeof_hdr); print_hex_vals(hp->data_type, 10, stdout); fprintf(stdout, "\n" " db_name[18] = "); print_hex_vals(hp->db_name, 18, stdout); fprintf(stdout, "\n" " extents = %d\n" " session_error = %d\n" " regular = 0x%x\n" " dim_info = 0x%x\n", hp->extents, hp->session_error, hp->regular, hp->dim_info ); fprintf(stdout, " dim[8] ="); for ( c = 0; c < 8; c++ ) fprintf(stdout," %d", hp->dim[c]); fprintf(stdout, "\n" " intent_p1 = %f\n" " intent_p2 = %f\n" " intent_p3 = %f\n" " intent_code = %d\n" " datatype = %d\n" " bitpix = %d\n" " slice_start = %d\n" " pixdim[8] =", hp->intent_p1, hp->intent_p2, hp->intent_p3, hp->intent_code, hp->datatype, hp->bitpix, hp->slice_start); /* break pixdim over 2 lines */ for ( c = 0; c < 4; c++ ) fprintf(stdout," %f", hp->pixdim[c]); fprintf(stdout, "\n "); for ( c = 4; c < 8; c++ ) fprintf(stdout," %f", hp->pixdim[c]); fprintf(stdout, "\n" " vox_offset = %f\n" " scl_slope = %f\n" " scl_inter = %f\n" " slice_end = %d\n" " slice_code = %d\n" " xyzt_units = 0x%x\n" " cal_max = %f\n" " cal_min = %f\n" " slice_duration = %f\n" " toffset = %f\n" " glmax = %d\n" " glmin = %d\n", hp->vox_offset, hp->scl_slope, hp->scl_inter, hp->slice_end, hp->slice_code, hp->xyzt_units, hp->cal_max, hp->cal_min, hp->slice_duration, hp->toffset, hp->glmax, hp->glmin); fprintf(stdout, " descrip = '%.80s'\n" " aux_file = '%.24s'\n" " qform_code = %d\n" " sform_code = %d\n" " quatern_b = %f\n" " quatern_c = %f\n" " quatern_d = %f\n" " qoffset_x = %f\n" " qoffset_y = %f\n" " qoffset_z = %f\n" " srow_x[4] = %f, %f, %f, %f\n" " srow_y[4] = %f, %f, %f, %f\n" " srow_z[4] = %f, %f, %f, %f\n" " intent_name = '%-.16s'\n" " magic = '%-.4s'\n", hp->descrip, hp->aux_file, hp->qform_code, hp->sform_code, hp->quatern_b, hp->quatern_c, hp->quatern_d, hp->qoffset_x, hp->qoffset_y, hp->qoffset_z, hp->srow_x[0], hp->srow_x[1], hp->srow_x[2], hp->srow_x[3], hp->srow_y[0], hp->srow_y[1], hp->srow_y[2], hp->srow_y[3], hp->srow_z[0], hp->srow_z[1], hp->srow_z[2], hp->srow_z[3], hp->intent_name, hp->magic); fputs( "-------------------------------------------------------\n", stdout ); fflush(stdout); return 0; } #undef ERREX #define ERREX(msg) \ do{ fprintf(stderr,"** ERROR: nifti_convert_nhdr2nim: %s\n", (msg) ) ; \ return NULL ; } while(0) /*----------------------------------------------------------------------*/ /*! convert a nifti_1_header into a nift1_image \return an allocated nifti_image, or NULL on failure *//*--------------------------------------------------------------------*/ nifti_image* nifti_convert_nhdr2nim(struct nifti_1_header nhdr, const char * fname) { int ii , doswap , ioff ; int is_nifti , is_onefile ; nifti_image *nim; nim = (nifti_image *) calloc( 1 , sizeof(nifti_image) ) ; if( !nim ) ERREX("failed to allocate nifti image"); /* be explicit with pointers */ nim->fname = NULL; nim->iname = NULL; nim->data = NULL; /**- check if we must swap bytes */ doswap = need_nhdr_swap(nhdr.dim[0], nhdr.sizeof_hdr); /* swap data flag */ if( doswap < 0 ){ if( doswap == -1 ) ERREX("bad dim[0]") ; ERREX("bad sizeof_hdr") ; /* else */ } /**- determine if this is a NIFTI-1 compliant header */ is_nifti = NIFTI_VERSION(nhdr) ; /* * before swapping header, record the Analyze75 orient code */ if(!is_nifti) { /**- in analyze75, the orient code is at the same address as * qform_code, but it's just one byte * the qform_code will be zero, at which point you can check * analyze75_orient if you care to. */ unsigned char c = *((char *)(&nhdr.qform_code)); nim->analyze75_orient = (analyze_75_orient_code)c; } if( doswap ) { if ( g_opts.debug > 3 ) disp_nifti_1_header("-d ni1 pre-swap: ", &nhdr); swap_nifti_header( &nhdr , is_nifti ) ; } if ( g_opts.debug > 2 ) disp_nifti_1_header("-d nhdr2nim : ", &nhdr); if( nhdr.datatype == DT_BINARY || nhdr.datatype == DT_UNKNOWN ) ERREX("bad datatype") ; if( nhdr.dim[1] <= 0 ) ERREX("bad dim[1]") ; /* fix bad dim[] values in the defined dimension range */ for( ii=2 ; ii <= nhdr.dim[0] ; ii++ ) if( nhdr.dim[ii] <= 0 ) nhdr.dim[ii] = 1 ; /* fix any remaining bad dim[] values, so garbage does not propagate */ /* (only values 0 or 1 seem rational, otherwise set to arbirary 1) */ for( ii=nhdr.dim[0]+1 ; ii <= 7 ; ii++ ) if( nhdr.dim[ii] != 1 && nhdr.dim[ii] != 0) nhdr.dim[ii] = 1 ; #if 0 /* rely on dim[0], do not attempt to modify it 16 Nov 2005 [rickr] */ /**- get number of dimensions (ignoring dim[0] now) */ for( ii=7 ; ii >= 2 ; ii-- ) /* loop backwards until we */ if( nhdr.dim[ii] > 1 ) break ; /* find a dim bigger than 1 */ ndim = ii ; #endif /**- set bad grid spacings to 1.0 */ for( ii=1 ; ii <= nhdr.dim[0] ; ii++ ){ if( nhdr.pixdim[ii] == 0.0 || !IS_GOOD_FLOAT(nhdr.pixdim[ii]) ) nhdr.pixdim[ii] = 1.0 ; } is_onefile = is_nifti && NIFTI_ONEFILE(nhdr) ; if( is_nifti ) nim->nifti_type = (is_onefile) ? NIFTI_FTYPE_NIFTI1_1 : NIFTI_FTYPE_NIFTI1_2 ; else nim->nifti_type = NIFTI_FTYPE_ANALYZE ; ii = nifti_short_order() ; if( doswap ) nim->byteorder = REVERSE_ORDER(ii) ; else nim->byteorder = ii ; /**- set dimensions of data array */ nim->ndim = nim->dim[0] = nhdr.dim[0]; nim->nx = nim->dim[1] = nhdr.dim[1]; nim->ny = nim->dim[2] = nhdr.dim[2]; nim->nz = nim->dim[3] = nhdr.dim[3]; nim->nt = nim->dim[4] = nhdr.dim[4]; nim->nu = nim->dim[5] = nhdr.dim[5]; nim->nv = nim->dim[6] = nhdr.dim[6]; nim->nw = nim->dim[7] = nhdr.dim[7]; for( ii=1, nim->nvox=1; ii <= nhdr.dim[0]; ii++ ) nim->nvox *= nhdr.dim[ii]; /**- set the type of data in voxels and how many bytes per voxel */ nim->datatype = nhdr.datatype ; nifti_datatype_sizes( nim->datatype , &(nim->nbyper) , &(nim->swapsize) ) ; if( nim->nbyper == 0 ){ free(nim); ERREX("bad datatype"); } /**- set the grid spacings */ nim->dx = nim->pixdim[1] = nhdr.pixdim[1] ; nim->dy = nim->pixdim[2] = nhdr.pixdim[2] ; nim->dz = nim->pixdim[3] = nhdr.pixdim[3] ; nim->dt = nim->pixdim[4] = nhdr.pixdim[4] ; nim->du = nim->pixdim[5] = nhdr.pixdim[5] ; nim->dv = nim->pixdim[6] = nhdr.pixdim[6] ; nim->dw = nim->pixdim[7] = nhdr.pixdim[7] ; /**- compute qto_xyz transformation from pixel indexes (i,j,k) to (x,y,z) */ if( !is_nifti || nhdr.qform_code <= 0 ){ /**- if not nifti or qform_code <= 0, use grid spacing for qto_xyz */ nim->qto_xyz.m[0][0] = nim->dx ; /* grid spacings */ nim->qto_xyz.m[1][1] = nim->dy ; /* along diagonal */ nim->qto_xyz.m[2][2] = nim->dz ; /* off diagonal is zero */ nim->qto_xyz.m[0][1]=nim->qto_xyz.m[0][2]=nim->qto_xyz.m[0][3] = 0.0; nim->qto_xyz.m[1][0]=nim->qto_xyz.m[1][2]=nim->qto_xyz.m[1][3] = 0.0; nim->qto_xyz.m[2][0]=nim->qto_xyz.m[2][1]=nim->qto_xyz.m[2][3] = 0.0; /* last row is always [ 0 0 0 1 ] */ nim->qto_xyz.m[3][0]=nim->qto_xyz.m[3][1]=nim->qto_xyz.m[3][2] = 0.0; nim->qto_xyz.m[3][3]= 1.0 ; nim->qform_code = NIFTI_XFORM_UNKNOWN ; if( g_opts.debug > 1 ) fprintf(stderr,"-d no qform provided\n"); } else { /**- else NIFTI: use the quaternion-specified transformation */ nim->quatern_b = FIXED_FLOAT( nhdr.quatern_b ) ; nim->quatern_c = FIXED_FLOAT( nhdr.quatern_c ) ; nim->quatern_d = FIXED_FLOAT( nhdr.quatern_d ) ; nim->qoffset_x = FIXED_FLOAT(nhdr.qoffset_x) ; nim->qoffset_y = FIXED_FLOAT(nhdr.qoffset_y) ; nim->qoffset_z = FIXED_FLOAT(nhdr.qoffset_z) ; nim->qfac = (nhdr.pixdim[0] < 0.0) ? -1.0 : 1.0 ; /* left-handedness? */ nim->qto_xyz = nifti_quatern_to_mat44( nim->quatern_b, nim->quatern_c, nim->quatern_d, nim->qoffset_x, nim->qoffset_y, nim->qoffset_z, nim->dx , nim->dy , nim->dz , nim->qfac ) ; nim->qform_code = nhdr.qform_code ; if( g_opts.debug > 1 ) nifti_disp_matrix_orient("-d qform orientations:\n", nim->qto_xyz); } /**- load inverse transformation (x,y,z) -> (i,j,k) */ nim->qto_ijk = nifti_mat44_inverse( nim->qto_xyz ) ; /**- load sto_xyz affine transformation, if present */ if( !is_nifti || nhdr.sform_code <= 0 ){ /**- if not nifti or sform_code <= 0, then no sto transformation */ nim->sform_code = NIFTI_XFORM_UNKNOWN ; if( g_opts.debug > 1 ) fprintf(stderr,"-d no sform provided\n"); } else { /**- else set the sto transformation from srow_*[] */ nim->sto_xyz.m[0][0] = nhdr.srow_x[0] ; nim->sto_xyz.m[0][1] = nhdr.srow_x[1] ; nim->sto_xyz.m[0][2] = nhdr.srow_x[2] ; nim->sto_xyz.m[0][3] = nhdr.srow_x[3] ; nim->sto_xyz.m[1][0] = nhdr.srow_y[0] ; nim->sto_xyz.m[1][1] = nhdr.srow_y[1] ; nim->sto_xyz.m[1][2] = nhdr.srow_y[2] ; nim->sto_xyz.m[1][3] = nhdr.srow_y[3] ; nim->sto_xyz.m[2][0] = nhdr.srow_z[0] ; nim->sto_xyz.m[2][1] = nhdr.srow_z[1] ; nim->sto_xyz.m[2][2] = nhdr.srow_z[2] ; nim->sto_xyz.m[2][3] = nhdr.srow_z[3] ; /* last row is always [ 0 0 0 1 ] */ nim->sto_xyz.m[3][0]=nim->sto_xyz.m[3][1]=nim->sto_xyz.m[3][2] = 0.0; nim->sto_xyz.m[3][3]= 1.0 ; nim->sto_ijk = nifti_mat44_inverse( nim->sto_xyz ) ; nim->sform_code = nhdr.sform_code ; if( g_opts.debug > 1 ) nifti_disp_matrix_orient("-d sform orientations:\n", nim->sto_xyz); } /**- set miscellaneous NIFTI stuff */ if( is_nifti ){ nim->scl_slope = FIXED_FLOAT( nhdr.scl_slope ) ; nim->scl_inter = FIXED_FLOAT( nhdr.scl_inter ) ; nim->intent_code = nhdr.intent_code ; nim->intent_p1 = FIXED_FLOAT( nhdr.intent_p1 ) ; nim->intent_p2 = FIXED_FLOAT( nhdr.intent_p2 ) ; nim->intent_p3 = FIXED_FLOAT( nhdr.intent_p3 ) ; nim->toffset = FIXED_FLOAT( nhdr.toffset ) ; memcpy(nim->intent_name,nhdr.intent_name,15); nim->intent_name[15] = '\0'; nim->xyz_units = XYZT_TO_SPACE(nhdr.xyzt_units) ; nim->time_units = XYZT_TO_TIME (nhdr.xyzt_units) ; nim->freq_dim = DIM_INFO_TO_FREQ_DIM ( nhdr.dim_info ) ; nim->phase_dim = DIM_INFO_TO_PHASE_DIM( nhdr.dim_info ) ; nim->slice_dim = DIM_INFO_TO_SLICE_DIM( nhdr.dim_info ) ; nim->slice_code = nhdr.slice_code ; nim->slice_start = nhdr.slice_start ; nim->slice_end = nhdr.slice_end ; nim->slice_duration = FIXED_FLOAT(nhdr.slice_duration) ; } /**- set Miscellaneous ANALYZE stuff */ nim->cal_min = FIXED_FLOAT(nhdr.cal_min) ; nim->cal_max = FIXED_FLOAT(nhdr.cal_max) ; memcpy(nim->descrip ,nhdr.descrip ,79) ; nim->descrip [79] = '\0' ; memcpy(nim->aux_file,nhdr.aux_file,23) ; nim->aux_file[23] = '\0' ; /**- set ioff from vox_offset (but at least sizeof(header)) */ is_onefile = is_nifti && NIFTI_ONEFILE(nhdr) ; if( is_onefile ){ ioff = (int)nhdr.vox_offset ; if( ioff < (int) sizeof(nhdr) ) ioff = (int) sizeof(nhdr) ; } else { ioff = (int)nhdr.vox_offset ; } nim->iname_offset = ioff ; /**- deal with file names if set */ if (fname!=NULL) { nifti_set_filenames(nim,fname,0,0); if (nim->iname==NULL) { ERREX("bad filename"); } } else { nim->fname = NULL; nim->iname = NULL; } /* clear extension fields */ nim->num_ext = 0; nim->ext_list = NULL; return nim; } #undef ERREX #define ERREX(msg) \ do{ fprintf(stderr,"** ERROR: nifti_image_open(%s): %s\n", \ (hname != NULL) ? hname : "(null)" , (msg) ) ; \ return fptr ; } while(0) /*************************************************************** * nifti_image_open ***************************************************************/ /*! znzFile nifti_image_open( char *hname, char *opts , nifti_image **nim) \brief Read in NIFTI-1 or ANALYZE-7.5 file (pair) header information into a nifti_image struct. - The image data is not read from disk (it may be read later using nifti_image_load(), for example). - The image data will be stored in whatever data format the input data is; no scaling will be applied. - DT_BINARY data is not supported. - nifti_image_free() can be used to delete the returned struct, when you are done with it. \param hname filename of dataset .hdr or .nii file \param opts options string for opening the header file \param nim pointer to pointer to nifti_image struct (this routine allocates the nifti_image struct) \return file pointer (gzippable) to the file with the image data, ready for reading.
    NULL if something fails badly. \sa nifti_image_load, nifti_image_free */ znzFile nifti_image_open(const char * hname, char * opts, nifti_image ** nim) { znzFile fptr=NULL; /* open the hdr and reading it in, but do not load the data */ *nim = nifti_image_read(hname,0); /* open the image file, ready for reading (compressed works for all reads) */ if( ((*nim) == NULL) || ((*nim)->iname == NULL) || ((*nim)->nbyper <= 0) || ((*nim)->nvox <= 0) ) ERREX("bad header info") ; /* open image data file */ fptr = znzopen( (*nim)->iname, opts, nifti_is_gzfile((*nim)->iname) ); if( znz_isnull(fptr) ) ERREX("Can't open data file") ; return fptr; } /*----------------------------------------------------------------------*/ /*! return an allocated and filled nifti_1_header struct Read the binary header from disk, and swap bytes if necessary. \return an allocated nifti_1_header struct, or NULL on failure \param hname name of file containing header \param swapped if not NULL, return whether header bytes were swapped \param check flag to check for invalid nifti_1_header \warning ASCII header type is not supported \sa nifti_image_read, nifti_image_free, nifti_image_read_bricks *//*--------------------------------------------------------------------*/ nifti_1_header * nifti_read_header(const char * hname, int * swapped, int check) { nifti_1_header nhdr, * hptr; znzFile fp; int bytes, lswap; char * hfile; char fname[] = { "nifti_read_header" }; /* determine file name to use for header */ hfile = nifti_findhdrname(hname); if( hfile == NULL ){ if( g_opts.debug > 0 ) LNI_FERR(fname,"failed to find header file for", hname); return NULL; } else if( g_opts.debug > 1 ) fprintf(stderr,"-d %s: found header filename '%s'\n",fname,hfile); fp = znzopen( hfile, "rb", nifti_is_gzfile(hfile) ); if( znz_isnull(fp) ){ if( g_opts.debug > 0 ) LNI_FERR(fname,"failed to open header file",hfile); free(hfile); return NULL; } free(hfile); /* done with filename */ if( has_ascii_header(fp) == 1 ){ znzclose( fp ); if( g_opts.debug > 0 ) LNI_FERR(fname,"ASCII header type not supported",hname); return NULL; } /* read the binary header */ bytes = znzread( &nhdr, 1, sizeof(nhdr), fp ); znzclose( fp ); /* we are done with the file now */ if( bytes < (int)sizeof(nhdr) ){ if( g_opts.debug > 0 ){ LNI_FERR(fname,"bad binary header read for file", hname); fprintf(stderr," - read %d of %d bytes\n",bytes, (int)sizeof(nhdr)); } return NULL; } /* now just decide on byte swapping */ lswap = need_nhdr_swap(nhdr.dim[0], nhdr.sizeof_hdr); /* swap data flag */ if( check && lswap < 0 ){ LNI_FERR(fname,"bad nifti_1_header for file", hname); return NULL; } else if ( lswap < 0 ) { lswap = 0; /* if swapping does not help, don't do it */ if(g_opts.debug > 1) fprintf(stderr,"-- swap failure, none applied\n"); } if( lswap ) { if ( g_opts.debug > 3 ) disp_nifti_1_header("-d nhdr pre-swap: ", &nhdr); swap_nifti_header( &nhdr , NIFTI_VERSION(nhdr) ) ; } if ( g_opts.debug > 2 ) disp_nifti_1_header("-d nhdr post-swap: ", &nhdr); if ( check && ! nifti_hdr_looks_good(&nhdr) ){ LNI_FERR(fname,"nifti_1_header looks bad for file", hname); return NULL; } /* all looks good, so allocate memory for and return the header */ hptr = (nifti_1_header *)malloc(sizeof(nifti_1_header)); if( ! hptr ){ fprintf(stderr,"** nifti_read_hdr: failed to alloc nifti_1_header\n"); return NULL; } if( swapped ) *swapped = lswap; /* only if they care */ memcpy(hptr, &nhdr, sizeof(nifti_1_header)); return hptr; } /*----------------------------------------------------------------------*/ /*! decide if this nifti_1_header structure looks reasonable Check dim[0], dim[1], sizeof_hdr, and datatype. Check magic string for "n+1". Maybe more tests will follow. \return 1 if the header seems valid, 0 otherwise \sa nifti_nim_is_valid, valid_nifti_extensions *//*--------------------------------------------------------------------*/ int nifti_hdr_looks_good(const nifti_1_header * hdr) { int is_nifti, c, errs = 0; /* check dim[0] and sizeof_hdr */ if( need_nhdr_swap(hdr->dim[0], hdr->sizeof_hdr) < 0 ){ if( g_opts.debug > 0 ) fprintf(stderr,"** bad nhdr fields: dim0, sizeof_hdr = %d, %d\n", hdr->dim[0], hdr->sizeof_hdr); errs++; } /* check the valid dimension sizes (maybe dim[0] is bad) */ for( c = 1; c <= hdr->dim[0] && c <= 7; c++ ) if( hdr->dim[c] <= 0 ){ if( g_opts.debug > 0 ) fprintf(stderr,"** bad nhdr field: dim[%d] = %d\n",c,hdr->dim[c]); errs++; } is_nifti = NIFTI_VERSION(*hdr); /* determine header type */ if( is_nifti ){ /* NIFTI */ if( ! nifti_datatype_is_valid(hdr->datatype, 1) ){ if( g_opts.debug > 0 ) fprintf(stderr,"** bad NIFTI datatype in hdr, %d\n",hdr->datatype); errs++; } } else { /* ANALYZE 7.5 */ if( g_opts.debug > 1 ) /* maybe tell user it's an ANALYZE hdr */ fprintf(stderr, "-- nhdr magic field implies ANALYZE: magic = '%.4s'\n",hdr->magic); if( ! nifti_datatype_is_valid(hdr->datatype, 0) ){ if( g_opts.debug > 0 ) fprintf(stderr,"** bad ANALYZE datatype in hdr, %d\n",hdr->datatype); errs++; } } if( errs ) return 0; /* problems */ if( g_opts.debug > 2 ) fprintf(stderr,"-d nifti header looks good\n"); return 1; /* looks good */ } /*---------------------------------------------------------------------- * check whether byte swapping is needed * * dim[0] should be in [0,7], and sizeof_hdr should be accurate * * \returns > 0 : needs swap * 0 : does not need swap * < 0 : error condition *----------------------------------------------------------------------*/ static int need_nhdr_swap( short dim0, int hdrsize ) { short d0 = dim0; /* so we won't have to swap them on the stack */ int hsize = hdrsize; if( d0 != 0 ){ /* then use it for the check */ if( d0 > 0 && d0 <= 7 ) return 0; nifti_swap_2bytes(1, &d0); /* swap? */ if( d0 > 0 && d0 <= 7 ) return 1; if( g_opts.debug > 1 ){ fprintf(stderr,"** NIFTI: bad swapped d0 = %d, unswapped = ", d0); nifti_swap_2bytes(1, &d0); /* swap? */ fprintf(stderr,"%d\n", d0); } return -1; /* bad, naughty d0 */ } /* dim[0] == 0 should not happen, but could, so try hdrsize */ if( hsize == sizeof(nifti_1_header) ) return 0; nifti_swap_4bytes(1, &hsize); /* swap? */ if( hsize == sizeof(nifti_1_header) ) return 1; if( g_opts.debug > 1 ){ fprintf(stderr,"** NIFTI: bad swapped hsize = %d, unswapped = ", hsize); nifti_swap_4bytes(1, &hsize); /* swap? */ fprintf(stderr,"%d\n", hsize); } return -2; /* bad, naughty hsize */ } /* use macro LNI_FILE_ERROR instead of ERREX() #undef ERREX #define ERREX(msg) \ do{ fprintf(stderr,"** ERROR: nifti_image_read(%s): %s\n", \ (hname != NULL) ? hname : "(null)" , (msg) ) ; \ return NULL ; } while(0) */ /*************************************************************** * nifti_image_read ***************************************************************/ /*! \brief Read a nifti header and optionally the data, creating a nifti_image. - The data buffer will be byteswapped if necessary. - The data buffer will not be scaled. - The data buffer is allocated with calloc(). \param hname filename of the nifti dataset \param read_data Flag, true=read data blob, false=don't read blob. \return A pointer to the nifti_image data structure. \sa nifti_image_free, nifti_free_extensions, nifti_image_read_bricks */ nifti_image *nifti_image_read( const char *hname , int read_data ) { struct nifti_1_header nhdr ; nifti_image *nim ; znzFile fp ; int rv, ii , filesize, remaining; char fname[] = { "nifti_image_read" }; char *hfile=NULL; if( g_opts.debug > 1 ){ fprintf(stderr,"-d image_read from '%s', read_data = %d",hname,read_data); #ifdef HAVE_ZLIB fprintf(stderr,", HAVE_ZLIB = 1\n"); #else fprintf(stderr,", HAVE_ZLIB = 0\n"); #endif } /**- determine filename to use for header */ hfile = nifti_findhdrname(hname); if( hfile == NULL ){ if(g_opts.debug > 0) LNI_FERR(fname,"failed to find header file for", hname); return NULL; /* check return */ } else if( g_opts.debug > 1 ) fprintf(stderr,"-d %s: found header filename '%s'\n",fname,hfile); if( nifti_is_gzfile(hfile) ) filesize = -1; /* unknown */ else filesize = nifti_get_filesize(hfile); fp = znzopen(hfile, "rb", nifti_is_gzfile(hfile)); if( znz_isnull(fp) ){ if( g_opts.debug > 0 ) LNI_FERR(fname,"failed to open header file",hfile); free(hfile); return NULL; } rv = has_ascii_header( fp ); if( rv < 0 ){ if( g_opts.debug > 0 ) LNI_FERR(fname,"short header read",hfile); znzclose( fp ); free(hfile); return NULL; } else if ( rv == 1 ) /* process special file type */ return nifti_read_ascii_image( fp, hfile, filesize, read_data ); /* else, just process normally */ /**- read binary header */ ii = znzread( &nhdr , 1 , sizeof(nhdr) , fp ) ; /* read the thing */ /* keep file open so we can check for exts. after nifti_convert_nhdr2nim() */ if( ii < (unsigned int) sizeof(nhdr) ){ if( g_opts.debug > 0 ){ LNI_FERR(fname,"bad binary header read for file", hfile); fprintf(stderr," - read %d of %d bytes\n",ii, (int)sizeof(nhdr)); } znzclose(fp) ; free(hfile); return NULL; } /* create output image struct and set it up */ /**- convert all nhdr fields to nifti_image fields */ nim = nifti_convert_nhdr2nim(nhdr,hfile); if( nim == NULL ){ znzclose( fp ) ; /* close the file */ if( g_opts.debug > 0 ) LNI_FERR(fname,"cannot create nifti image from header",hfile); free(hfile); /* had to save this for debug message */ return NULL; } if( g_opts.debug > 3 ){ fprintf(stderr,"+d nifti_image_read(), have nifti image:\n"); if( g_opts.debug > 2 ) nifti_image_infodump(nim); } /**- check for extensions (any errors here means no extensions) */ if( NIFTI_ONEFILE(nhdr) ) remaining = nim->iname_offset - sizeof(nhdr); else remaining = filesize - sizeof(nhdr); (void)nifti_read_extensions(nim, fp, remaining); znzclose( fp ) ; /* close the file */ free(hfile); /**- read the data if desired, then bug out */ if( read_data ){ if( nifti_image_load( nim ) < 0 ){ nifti_image_free(nim); /* take ball, go home. */ return NULL; } } else nim->data = NULL ; return nim ; } /*---------------------------------------------------------------------- * has_ascii_header - see if the NIFTI header is an ASCII format * * If the file starts with the ASCII string " 1 ) fprintf(stderr,"-d %s: have ASCII NIFTI file of size %d\n",fname,slen); if( slen > 65530 ) slen = 65530 ; sbuf = (char *)calloc(sizeof(char),slen+1) ; if( !sbuf ){ fprintf(stderr,"** %s: failed to alloc %d bytes for sbuf",lfunc,65530); free(fname); znzclose(fp); return NULL; } znzread( sbuf , 1 , slen , fp ) ; nim = nifti_image_from_ascii( sbuf, &txt_size ) ; free( sbuf ) ; if( nim == NULL ){ LNI_FERR(lfunc,"failed nifti_image_from_ascii()",fname); free(fname); znzclose(fp); return NULL; } nim->nifti_type = NIFTI_FTYPE_ASCII ; /* compute remaining space for extensions */ remain = flen - txt_size - (int)nifti_get_volsize(nim); if( remain > 4 ){ /* read extensions (reposition file pointer, first) */ znzseek(fp, txt_size, SEEK_SET); (void) nifti_read_extensions(nim, fp, remain); } free(fname); znzclose( fp ) ; nim->iname_offset = -1 ; /* check from the end of the file */ if( read_data ) rv = nifti_image_load( nim ) ; else nim->data = NULL ; /* check for nifti_image_load() failure, maybe bail out */ if( read_data && rv != 0 ){ if( g_opts.debug > 1 ) fprintf(stderr,"-d failed image_load, free nifti image struct\n"); free(nim); return NULL; } return nim ; } /*---------------------------------------------------------------------- * Read the extensions into the nifti_image struct 08 Dec 2004 [rickr] * * This function is called just after the header struct is read in, and * it is assumed the file pointer has not moved. The value in remain * is assumed to be accurate, reflecting the bytes of space for potential * extensions. * * return the number of extensions read in, or < 0 on error *----------------------------------------------------------------------*/ static int nifti_read_extensions( nifti_image *nim, znzFile fp, int remain ) { nifti1_extender extdr; /* defines extension existence */ nifti1_extension extn; /* single extension to process */ nifti1_extension * Elist; /* list of processed extensions */ int posn, count; if( !nim || znz_isnull(fp) ) { if( g_opts.debug > 0 ) fprintf(stderr,"** nifti_read_extensions: bad inputs (%p,%p)\n", (void *)nim, (void *)fp); return -1; } posn = znztell(fp); if( (posn != sizeof(nifti_1_header)) && (nim->nifti_type != NIFTI_FTYPE_ASCII) ) fprintf(stderr,"** WARNING: posn not header size (%d, %d)\n", posn, (int)sizeof(nifti_1_header)); if( g_opts.debug > 2 ) fprintf(stderr,"-d nre: posn = %d, offset = %d, type = %d, remain = %d\n", posn, nim->iname_offset, nim->nifti_type, remain); if( remain < 16 ){ if( g_opts.debug > 2 ){ if( g_opts.skip_blank_ext ) fprintf(stderr,"-d no extender in '%s' is okay, as " "skip_blank_ext is set\n",nim->fname); else fprintf(stderr,"-d remain=%d, no space for extensions\n",remain); } return 0; } count = znzread( extdr.extension, 1, 4, fp ); /* get extender */ if( count < 4 ){ if( g_opts.debug > 1 ) fprintf(stderr,"-d file '%s' is too short for an extender\n", nim->fname); return 0; } if( extdr.extension[0] != 1 ){ if( g_opts.debug > 2 ) fprintf(stderr,"-d extender[0] (%d) shows no extensions for '%s'\n", extdr.extension[0], nim->fname); return 0; } remain -= 4; if( g_opts.debug > 2 ) fprintf(stderr,"-d found valid 4-byte extender, remain = %d\n", remain); /* so we expect extensions, but have no idea of how many there may be */ count = 0; Elist = NULL; while (nifti_read_next_extension(&extn, nim, remain, fp) > 0) { if( nifti_add_exten_to_list(&extn, &Elist, count+1) < 0 ){ if( g_opts.debug > 0 ) fprintf(stderr,"** failed adding ext %d to list\n", count); return -1; } /* we have a new extension */ if( g_opts.debug > 1 ){ fprintf(stderr,"+d found extension #%d, code = 0x%x, size = %d\n", count, extn.ecode, extn.esize); if( extn.ecode == NIFTI_ECODE_AFNI && g_opts.debug > 2 ) /* ~XML */ fprintf(stderr," AFNI extension: %.*s\n", extn.esize-8,extn.edata); else if( extn.ecode == NIFTI_ECODE_COMMENT && g_opts.debug > 2 ) fprintf(stderr," COMMENT extension: %.*s\n", /* TEXT */ extn.esize-8,extn.edata); } remain -= extn.esize; count++; } if( g_opts.debug > 2 ) fprintf(stderr,"+d found %d extension(s)\n", count); nim->num_ext = count; nim->ext_list = Elist; return count; } /*----------------------------------------------------------------------*/ /*! nifti_add_extension - add an extension, with a copy of the data Add an extension to the nim->ext_list array. Fill this extension with a copy of the data, noting the length and extension code. \param nim - nifti_image to add extension to \param data - raw extension data \param length - length of raw extension data \param ecode - extension code \sa extension codes NIFTI_ECODE_* in nifti1_io.h \sa nifti_free_extensions, valid_nifti_extensions, nifti_copy_extensions \return 0 on success, -1 on error (and free the entire list) *//*--------------------------------------------------------------------*/ int nifti_add_extension(nifti_image *nim, const char * data, int len, int ecode) { nifti1_extension ext; /* error are printed in functions */ if( nifti_fill_extension(&ext, data, len, ecode) ) return -1; if( nifti_add_exten_to_list(&ext, &nim->ext_list, nim->num_ext+1)) return -1; nim->num_ext++; /* success, so increment */ return 0; } /*----------------------------------------------------------------------*/ /* nifti_add_exten_to_list - add a new nifti1_extension to the list We will append via "malloc, copy and free", because on an error, the list will revert to the previous one (sorry realloc(), only quality dolphins get to become part of St@rk!st brand tunafish). return 0 on success, -1 on error (and free the entire list) *//*--------------------------------------------------------------------*/ static int nifti_add_exten_to_list( nifti1_extension * new_ext, nifti1_extension ** list, int new_length ) { nifti1_extension * tmplist; tmplist = *list; *list = (nifti1_extension *)malloc(new_length * sizeof(nifti1_extension)); /* check for failure first */ if( ! *list ){ fprintf(stderr,"** failed to alloc %d extension structs (%d bytes)\n", new_length, new_length*(int)sizeof(nifti1_extension)); if( !tmplist ) return -1; /* no old list to lose */ *list = tmplist; /* reset list to old one */ return -1; } /* if an old list exists, copy the pointers and free the list */ if( tmplist ){ memcpy(*list, tmplist, (new_length-1)*sizeof(nifti1_extension)); free(tmplist); } /* for some reason, I just don't like struct copy... */ (*list)[new_length-1].esize = new_ext->esize; (*list)[new_length-1].ecode = new_ext->ecode; (*list)[new_length-1].edata = new_ext->edata; if( g_opts.debug > 2 ) fprintf(stderr,"+d allocated and appended extension #%d to list\n", new_length); return 0; } /*----------------------------------------------------------------------*/ /* nifti_fill_extension - given data and length, fill an extension struct Allocate memory for data, copy data, set the size and code. return 0 on success, -1 on error (and free the entire list) *//*--------------------------------------------------------------------*/ static int nifti_fill_extension( nifti1_extension *ext, const char * data, int len, int ecode) { int esize; if( !ext || !data || len < 0 ){ fprintf(stderr,"** fill_ext: bad params (%p,%p,%d)\n", (void *)ext, data, len); return -1; } else if( ! nifti_is_valid_ecode(ecode) ){ fprintf(stderr,"** fill_ext: invalid ecode %d\n", ecode); return -1; } /* compute esize, first : len+8, and take ceiling up to a mult of 16 */ esize = len+8; if( esize & 0xf ) esize = (esize + 0xf) & ~0xf; ext->esize = esize; /* allocate esize-8 (maybe more than len), using calloc for fill */ ext->edata = (char *)calloc(esize-8, sizeof(char)); if( !ext->edata ){ fprintf(stderr,"** NFE: failed to alloc %d bytes for extension\n",len); return -1; } memcpy(ext->edata, data, len); /* copy the data, using len */ ext->ecode = ecode; /* set the ecode */ if( g_opts.debug > 2 ) fprintf(stderr,"+d alloc %d bytes for ext len %d, ecode %d, esize %d\n", esize-8, len, ecode, esize); return 0; } /*---------------------------------------------------------------------- * nifti_read_next_extension - read a single extension from the file * * return (>= 0 is okay): * * success : esize * no extension : 0 * error : -1 *----------------------------------------------------------------------*/ static int nifti_read_next_extension( nifti1_extension * nex, nifti_image *nim, int remain, znzFile fp ) { int swap = nim->byteorder != nifti_short_order(); int count, size, code; /* first clear nex */ nex->esize = nex->ecode = 0; nex->edata = NULL; if( remain < 16 ){ if( g_opts.debug > 2 ) fprintf(stderr,"-d only %d bytes remain, so no extension\n", remain); return 0; } /* must start with 4-byte size and code */ count = znzread( &size, 4, 1, fp ); if( count == 1 ) count += znzread( &code, 4, 1, fp ); if( count != 2 ){ if( g_opts.debug > 2 ) fprintf(stderr,"-d current extension read failed\n"); znzseek(fp, -4*count, SEEK_CUR); /* back up past any read */ return 0; /* no extension, no error condition */ } if( swap ){ if( g_opts.debug > 2 ) fprintf(stderr,"-d pre-swap exts: code %d, size %d\n", code, size); nifti_swap_4bytes(1, &size); nifti_swap_4bytes(1, &code); } if( g_opts.debug > 2 ) fprintf(stderr,"-d potential extension: code %d, size %d\n", code, size); if( !nifti_check_extension(nim, size, code, remain) ){ if( znzseek(fp, -8, SEEK_CUR) < 0 ){ /* back up past any read */ fprintf(stderr,"** failure to back out of extension read!\n"); return -1; } return 0; } /* now get the actual data */ nex->esize = size; nex->ecode = code; size -= 8; /* subtract space for size and code in extension */ nex->edata = (char *)malloc(size * sizeof(char)); if( !nex->edata ){ fprintf(stderr,"** failed to allocate %d bytes for extension\n",size); return -1; } count = znzread(nex->edata, 1, size, fp); if( count < size ){ if( g_opts.debug > 0 ) fprintf(stderr,"-d read only %d (of %d) bytes for extension\n", count, size); free(nex->edata); nex->edata = NULL; return -1; } /* success! */ if( g_opts.debug > 2 ) fprintf(stderr,"+d successfully read extension, code %d, size %d\n", nex->ecode, nex->esize); return nex->esize; } /*----------------------------------------------------------------------*/ /*! for each extension, check code, size and data pointer *//*--------------------------------------------------------------------*/ int valid_nifti_extensions(const nifti_image * nim) { nifti1_extension * ext; int c, errs; if( nim->num_ext <= 0 || nim->ext_list == NULL ){ if( g_opts.debug > 2 ) fprintf(stderr,"-d empty extension list\n"); return 0; } /* for each extension, check code, size and data pointer */ ext = nim->ext_list; errs = 0; for ( c = 0; c < nim->num_ext; c++ ){ if( ! nifti_is_valid_ecode(ext->ecode) ) { if( g_opts.debug > 1 ) fprintf(stderr,"-d ext %d, invalid code %d\n", c, ext->ecode); errs++; } if( ext->esize <= 0 ){ if( g_opts.debug > 1 ) fprintf(stderr,"-d ext %d, bad size = %d\n", c, ext->esize); errs++; } else if( ext->esize & 0xf ){ if( g_opts.debug > 1 ) fprintf(stderr,"-d ext %d, size %d not multiple of 16\n", c, ext->esize); errs++; } if( ext->edata == NULL ){ if( g_opts.debug > 1 ) fprintf(stderr,"-d ext %d, missing data\n", c); errs++; } ext++; } if( errs > 0 ){ if( g_opts.debug > 0 ) fprintf(stderr,"-d had %d extension errors, none will be written\n", errs); return 0; } /* if we're here, we're good */ return 1; } /*----------------------------------------------------------------------*/ /*! check whether the extension code is valid \return 1 if valid, 0 otherwise *//*--------------------------------------------------------------------*/ int nifti_is_valid_ecode( int ecode ) { if( ecode < NIFTI_ECODE_IGNORE || /* minimum code number (0) */ ecode > NIFTI_MAX_ECODE || /* maximum code number */ ecode & 1 ) /* cannot be odd */ return 0; return 1; } /*---------------------------------------------------------------------- * check for valid size and code, as well as can be done *----------------------------------------------------------------------*/ static int nifti_check_extension(nifti_image *nim, int size, int code, int rem) { /* check for bad code before bad size */ if( ! nifti_is_valid_ecode(code) ) { if( g_opts.debug > 2 ) fprintf(stderr,"-d invalid extension code %d\n",code); return 0; } if( size < 16 ){ if( g_opts.debug > 2 ) fprintf(stderr,"-d ext size %d, no extension\n",size); return 0; } if( size > rem ){ if( g_opts.debug > 2 ) fprintf(stderr,"-d ext size %d, space %d, no extension\n", size, rem); return 0; } if( size & 0xf ){ if( g_opts.debug > 2 ) fprintf(stderr,"-d nifti extension size %d not multiple of 16\n",size); return 0; } if( nim->nifti_type == NIFTI_FTYPE_ASCII && size > LNI_MAX_NIA_EXT_LEN ){ if( g_opts.debug > 2 ) fprintf(stderr,"-d NVE, bad nifti_type 3 size %d\n", size); return 0; } return 1; } /*---------------------------------------------------------------------- * nifti_image_load_prep - prepare to read data * * Check nifti_image fields, open the file and seek to the appropriate * offset for reading. * * return NULL on failure *----------------------------------------------------------------------*/ static znzFile nifti_image_load_prep( nifti_image *nim ) { /* set up data space, open data file and seek, then call nifti_read_buffer */ size_t ntot , ii , ioff; znzFile fp; char *tmpimgname; char fname[] = { "nifti_image_load_prep" }; /**- perform sanity checks */ if( nim == NULL || nim->iname == NULL || nim->nbyper <= 0 || nim->nvox <= 0 ) { if ( g_opts.debug > 0 ){ if( !nim ) fprintf(stderr,"** ERROR: N_image_load: no nifti image\n"); else fprintf(stderr,"** ERROR: N_image_load: bad params (%p,%d,%u)\n", nim->iname, nim->nbyper, (unsigned)nim->nvox); } return NULL; } ntot = nifti_get_volsize(nim) ; /* total bytes to read */ /**- open image data file */ tmpimgname = nifti_findimgname(nim->iname , nim->nifti_type); if( tmpimgname == NULL ){ if( g_opts.debug > 0 ) fprintf(stderr,"** no image file found for '%s'\n",nim->iname); return NULL; } fp = znzopen(tmpimgname, "rb", nifti_is_gzfile(tmpimgname)); if (znz_isnull(fp)){ if(g_opts.debug > 0) LNI_FERR(fname,"cannot open data file",tmpimgname); free(tmpimgname); return NULL; /* bad open? */ } free(tmpimgname); /**- get image offset: a negative offset means to figure from end of file */ if( nim->iname_offset < 0 ){ if( nifti_is_gzfile(nim->iname) ){ if( g_opts.debug > 0 ) LNI_FERR(fname,"negative offset for compressed file",nim->iname); znzclose(fp); return NULL; } ii = nifti_get_filesize( nim->iname ) ; if( ii <= 0 ){ if( g_opts.debug > 0 ) LNI_FERR(fname,"empty data file",nim->iname); znzclose(fp); return NULL; } ioff = (ii > ntot) ? ii-ntot : 0 ; } else { /* non-negative offset */ ioff = nim->iname_offset ; /* means use it directly */ } /**- seek to the appropriate read position */ if( znzseek(fp , ioff , SEEK_SET) < 0 ){ fprintf(stderr,"** could not seek to offset %u in file '%s'\n", (unsigned)ioff, nim->iname); znzclose(fp); return NULL; } /**- and return the File pointer */ return fp; } /*---------------------------------------------------------------------- * nifti_image_load *----------------------------------------------------------------------*/ /*! \fn int nifti_image_load( nifti_image *nim ) \brief Load the image blob into a previously initialized nifti_image. - If not yet set, the data buffer is allocated with calloc(). - The data buffer will be byteswapped if necessary. - The data buffer will not be scaled. This function is used to read the image from disk. It should be used after a function such as nifti_image_read(), so that the nifti_image structure is already initialized. \param nim pointer to a nifti_image (previously initialized) \return 0 on success, -1 on failure \sa nifti_image_read, nifti_image_free, nifti_image_unload */ int nifti_image_load( nifti_image *nim ) { /* set up data space, open data file and seek, then call nifti_read_buffer */ size_t ntot , ii ; znzFile fp ; /**- open the file and position the FILE pointer */ fp = nifti_image_load_prep( nim ); if( fp == NULL ){ if( g_opts.debug > 0 ) fprintf(stderr,"** nifti_image_load, failed load_prep\n"); return -1; } ntot = nifti_get_volsize(nim); /**- if the data pointer is not yet set, get memory space for the image */ if( nim->data == NULL ) { nim->data = (void *)calloc(1,ntot) ; /* create image memory */ if( nim->data == NULL ){ if( g_opts.debug > 0 ) fprintf(stderr,"** failed to alloc %d bytes for image data\n", (int)ntot); znzclose(fp); return -1; } } /**- now that everything is set up, do the reading */ ii = nifti_read_buffer(fp,nim->data,ntot,nim); if( ii < ntot ){ znzclose(fp) ; free(nim->data) ; nim->data = NULL ; return -1 ; /* errors were printed in nifti_read_buffer() */ } /**- close the file */ znzclose( fp ) ; return 0 ; } /* 30 Nov 2004 [rickr] #undef ERREX #define ERREX(msg) \ do{ fprintf(stderr,"** ERROR: nifti_read_buffer: %s\n",(msg)) ; \ return 0; } while(0) */ /*----------------------------------------------------------------------*/ /*! read ntot bytes of data from an open file and byte swaps if necessary note that nifti_image is required for information on datatype, bsize (for any needed byte swapping), etc. This function does not allocate memory, so dataptr must be valid. *//*--------------------------------------------------------------------*/ size_t nifti_read_buffer(znzFile fp, void* dataptr, size_t ntot, nifti_image *nim) { size_t ii; if( dataptr == NULL ){ if( g_opts.debug > 0 ) fprintf(stderr,"** ERROR: nifti_read_buffer: NULL dataptr\n"); return -1; } ii = znzread( dataptr , 1 , ntot , fp ) ; /* data input */ /* if read was short, fail */ if( ii < ntot ){ if( g_opts.debug > 0 ) fprintf(stderr,"++ WARNING: nifti_read_buffer(%s):\n" " data bytes needed = %u\n" " data bytes input = %u\n" " number missing = %u (set to 0)\n", nim->iname , (unsigned int)ntot , (unsigned int)ii , (unsigned int)(ntot-ii) ) ; /* memset( (char *)(dataptr)+ii , 0 , ntot-ii ) ; now failure [rickr] */ return -1 ; } if( g_opts.debug > 2 ) fprintf(stderr,"+d nifti_read_buffer: read %u bytes\n", (unsigned)ii); /* byte swap array if needed */ if( nim->swapsize > 1 && nim->byteorder != nifti_short_order() ) nifti_swap_Nbytes( ntot / nim->swapsize , nim->swapsize , dataptr ) ; #ifdef isfinite { /* check input float arrays for goodness, and fix bad floats */ int fix_count = 0 ; switch( nim->datatype ){ case NIFTI_TYPE_FLOAT32: case NIFTI_TYPE_COMPLEX64:{ register float *far = (float *)dataptr ; register size_t jj,nj ; nj = ntot / sizeof(float) ; for( jj=0 ; jj < nj ; jj++ ) /* count fixes 30 Nov 2004 [rickr] */ if( !IS_GOOD_FLOAT(far[jj]) ){ far[jj] = 0 ; fix_count++ ; } } break ; case NIFTI_TYPE_FLOAT64: case NIFTI_TYPE_COMPLEX128:{ register double *far = (double *)dataptr ; register size_t jj,nj ; nj = ntot / sizeof(double) ; for( jj=0 ; jj < nj ; jj++ ) /* count fixes 30 Nov 2004 [rickr] */ if( !IS_GOOD_FLOAT(far[jj]) ){ far[jj] = 0 ; fix_count++ ; } } break ; } if( g_opts.debug > 1 ) fprintf(stderr,"+d in image, %d bad floats were set to 0\n", fix_count); } #endif return ii; } /*--------------------------------------------------------------------------*/ /*! Unload the data in a nifti_image struct, but keep the metadata. *//*------------------------------------------------------------------------*/ void nifti_image_unload( nifti_image *nim ) { if( nim != NULL && nim->data != NULL ){ free(nim->data) ; nim->data = NULL ; } return ; } /*--------------------------------------------------------------------------*/ /*! free 'everything' about a nifti_image struct (including the passed struct) free (only fields which are not NULL): - fname and iname - data - any ext_list[i].edata - ext_list - nim *//*------------------------------------------------------------------------*/ void nifti_image_free( nifti_image *nim ) { if( nim == NULL ) return ; if( nim->fname != NULL ) free(nim->fname) ; if( nim->iname != NULL ) free(nim->iname) ; if( nim->data != NULL ) free(nim->data ) ; (void)nifti_free_extensions( nim ) ; free(nim) ; return ; } /*--------------------------------------------------------------------------*/ /*! free the nifti extensions - If any edata pointer is set in the extension list, free() it. - Free ext_list, if it is set. - Clear num_ext and ext_list from nim. \return 0 on success, -1 on error \sa nifti_add_extension, nifti_copy_extensions *//*------------------------------------------------------------------------*/ int nifti_free_extensions( nifti_image *nim ) { int c ; if( nim == NULL ) return -1; if( nim->num_ext > 0 && nim->ext_list ){ for( c = 0; c < nim->num_ext; c++ ) if ( nim->ext_list[c].edata ) free(nim->ext_list[c].edata); free(nim->ext_list); } /* or if it is inconsistent, warn the user (if we are not in quiet mode) */ else if ( (nim->num_ext > 0 || nim->ext_list != NULL) && (g_opts.debug > 0) ) fprintf(stderr,"** warning: nifti extension num/ptr mismatch (%d,%p)\n", nim->num_ext, (void *)nim->ext_list); if( g_opts.debug > 2 ) fprintf(stderr,"+d free'd %d extension(s)\n", nim->num_ext); nim->num_ext = 0; nim->ext_list = NULL; return 0; } /*--------------------------------------------------------------------------*/ /*! Print to stdout some info about a nifti_image struct. *//*------------------------------------------------------------------------*/ void nifti_image_infodump( const nifti_image *nim ) { char *str = nifti_image_to_ascii( nim ) ; /* stdout -> stderr 2 Dec 2004 [rickr] */ if( str != NULL ){ fputs(str,stderr) ; free(str) ; } return ; } /*-------------------------------------------------------------------------- * nifti_write_buffer just check for a null znzFile and call znzwrite *--------------------------------------------------------------------------*/ /*! \fn size_t nifti_write_buffer(znzFile fp, void *buffer, size_t numbytes) \brief write numbytes of buffer to file, fp \param fp File pointer (from znzopen) to gzippable nifti datafile \param buffer data buffer to be written \param numbytes number of bytes in buffer to write \return number of bytes successfully written */ size_t nifti_write_buffer(znzFile fp, const void *buffer, size_t numbytes) { /* Write all the image data at once (no swapping here) */ size_t ss; if (znz_isnull(fp)){ fprintf(stderr,"** ERROR: nifti_write_buffer: null file pointer\n"); return 0; } ss = znzwrite( (void*)buffer , 1 , numbytes , fp ) ; return ss; } /*----------------------------------------------------------------------*/ /*! write the nifti_image data to file (from nim->data or from NBL) If NBL is not NULL, write the data from that structure. Otherwise, write it out from nim->data. No swapping is done here. \param fp : File pointer \param nim : nifti_image corresponding to the data \param NBL : optional source of write data (if NULL use nim->data) \return 0 on success, -1 on failure Note: the nifti_image byte_order is set as that of the current CPU. This is because such a conversion was made to the data upon reading, while byte_order was not set (so the programs would know what format the data was on disk). Effectively, since byte_order should match what is on disk, it should bet set to that of the current CPU whenever new filenames are assigned. *//*--------------------------------------------------------------------*/ int nifti_write_all_data(znzFile fp, nifti_image * nim, const nifti_brick_list * NBL) { size_t ss; int bnum; if( !NBL ){ /* just write one buffer and get out of here */ if( nim->data == NULL ){ fprintf(stderr,"** NWAD: no image data to write\n"); return -1; } ss = nifti_write_buffer(fp,nim->data,nim->nbyper * nim->nvox); if (ss < nim->nbyper * nim->nvox){ fprintf(stderr, "** ERROR: NWAD: wrote only %u of %u bytes to file\n", (unsigned)ss, (unsigned)(nim->nbyper * nim->nvox)); return -1; } if( g_opts.debug > 1 ) fprintf(stderr,"+d wrote single image of %u bytes\n", (unsigned)ss); } else { if( ! NBL->bricks || NBL->nbricks <= 0 || NBL->bsize <= 0 ){ fprintf(stderr,"** NWAD: no brick data to write (%p,%d,%u)\n", (void *)NBL->bricks, NBL->nbricks, (unsigned)NBL->bsize); return -1; } for( bnum = 0; bnum < NBL->nbricks; bnum++ ){ ss = nifti_write_buffer(fp, NBL->bricks[bnum], NBL->bsize); if( ss < NBL->bsize ){ fprintf(stderr, "** NWAD ERROR: wrote %u of %u bytes of brick %d of %d to file", (unsigned)ss, (unsigned)NBL->bsize, bnum+1, NBL->nbricks); return -1; } } if( g_opts.debug > 1 ) fprintf(stderr,"+d wrote image of %d brick(s), each of %u bytes\n", NBL->nbricks, (unsigned int)NBL->bsize); } /* mark as being in this CPU byte order */ nim->byteorder = nifti_short_order() ; return 0; } /* return number of extensions written, or -1 on error */ static int nifti_write_extensions(znzFile fp, nifti_image *nim) { nifti1_extension * list; char extdr[4] = { 0, 0, 0, 0 }; int c, size, ok = 1; if( znz_isnull(fp) || !nim || nim->num_ext < 0 ){ if( g_opts.debug > 0 ) fprintf(stderr,"** nifti_write_extensions, bad params\n"); return -1; } /* if no extensions and user requests it, skip extender */ if( g_opts.skip_blank_ext && (nim->num_ext == 0 || ! nim->ext_list ) ){ if( g_opts.debug > 1 ) fprintf(stderr,"-d no exts and skip_blank_ext set, " "so skipping 4-byte extender\n"); return 0; } /* if invalid extension list, clear num_ext */ if( ! valid_nifti_extensions(nim) ) nim->num_ext = 0; /* write out extender block */ if( nim->num_ext > 0 ) extdr[0] = 1; if( nifti_write_buffer(fp, extdr, 4) != 4 ){ fprintf(stderr,"** failed to write extender\n"); return -1; } list = nim->ext_list; for ( c = 0; c < nim->num_ext; c++ ){ size = nifti_write_buffer(fp, &list->esize, sizeof(int)); ok = (size == (int)sizeof(int)); if( ok ){ size = nifti_write_buffer(fp, &list->ecode, sizeof(int)); ok = (size == (int)sizeof(int)); } if( ok ){ size = nifti_write_buffer(fp, list->edata, list->esize - 8); ok = (size == list->esize - 8); } if( !ok ){ fprintf(stderr,"** failed while writing extension #%d\n",c); return -1; } else if ( g_opts.debug > 2 ) fprintf(stderr,"+d wrote extension %d of %d bytes\n", c, size); list++; } if( g_opts.debug > 1 ) fprintf(stderr,"+d wrote out %d extension(s)\n", nim->num_ext); return nim->num_ext; } /*----------------------------------------------------------------------*/ /*! basic initialization of a nifti_image struct (to a 1x1x1 image) *//*--------------------------------------------------------------------*/ nifti_image* nifti_simple_init_nim(void) { nifti_image *nim; struct nifti_1_header nhdr; int nbyper, swapsize; memset(&nhdr,0,sizeof(nhdr)) ; /* zero out header, to be safe */ nhdr.sizeof_hdr = sizeof(nhdr) ; nhdr.regular = 'r' ; /* for some stupid reason */ nhdr.dim[0] = 3 ; nhdr.dim[1] = 1 ; nhdr.dim[2] = 1 ; nhdr.dim[3] = 1 ; nhdr.dim[4] = 0 ; nhdr.pixdim[0] = 0.0 ; nhdr.pixdim[1] = 1.0 ; nhdr.pixdim[2] = 1.0 ; nhdr.pixdim[3] = 1.0 ; nhdr.datatype = DT_FLOAT32 ; nifti_datatype_sizes( nhdr.datatype , &nbyper, &swapsize ); nhdr.bitpix = 8 * nbyper ; strcpy(nhdr.magic, "n+1"); /* init to single file */ nim = nifti_convert_nhdr2nim(nhdr,NULL); nim->fname = NULL; nim->iname = NULL; return nim; } /*----------------------------------------------------------------------*/ /*! basic initialization of a nifti_1_header struct (with given dimensions) Return an allocated nifti_1_header struct, based on the given dimensions and datatype. \param arg_dims : optional dim[8] array (default {3,1,1,1,0,0,0,0}) \param arg_dtype : optional datatype (default DT_FLOAT32) \return pointer to allocated nifti_1_header struct *//*--------------------------------------------------------------------*/ nifti_1_header * nifti_make_new_header(const int arg_dims[], int arg_dtype) { nifti_1_header * nhdr; const int default_dims[8] = { 3, 1, 1, 1, 0, 0, 0, 0 }; const int * dim; /* either passed or default dims */ int dtype; /* either passed or default dtype */ int c, nbyper, swapsize; /* if arg_dims is passed, apply it */ if( arg_dims ) dim = arg_dims; else dim = default_dims; /* validate dim: if there is any problem, apply default_dims */ if( dim[0] < 1 || dim[0] > 7 ) { fprintf(stderr,"** nifti_simple_hdr_with_dims: bad dim[0]=%d\n",dim[0]); dim = default_dims; } else { for( c = 1; c <= dim[0]; c++ ) if( dim[c] < 1 ) { fprintf(stderr, "** nifti_simple_hdr_with_dims: bad dim[%d]=%d\n",c,dim[c]); dim = default_dims; break; } } /* validate dtype, too */ dtype = arg_dtype; if( ! nifti_is_valid_datatype(dtype) ) { fprintf(stderr,"** nifti_simple_hdr_with_dims: bad dtype %d\n",dtype); dtype = DT_FLOAT32; } /* now populate the header struct */ if( g_opts.debug > 1 ) fprintf(stderr,"+d nifti_make_new_header, dim[0] = %d, datatype = %d\n", dim[0], dtype); nhdr = (nifti_1_header *)calloc(1,sizeof(nifti_1_header)); if( !nhdr ){ fprintf(stderr,"** nifti_make_new_header: failed to alloc hdr\n"); return NULL; } nhdr->sizeof_hdr = sizeof(nifti_1_header) ; nhdr->regular = 'r' ; /* for some stupid reason */ /* init dim and pixdim */ nhdr->dim[0] = dim[0] ; nhdr->pixdim[0] = 0.0; for( c = 1; c <= dim[0]; c++ ) { nhdr->dim[c] = dim[c]; nhdr->pixdim[c] = 1.0; } nhdr->datatype = dtype ; nifti_datatype_sizes( nhdr->datatype , &nbyper, &swapsize ); nhdr->bitpix = 8 * nbyper ; strcpy(nhdr->magic, "n+1"); /* init to single file */ return nhdr; } /*----------------------------------------------------------------------*/ /*! basic creation of a nifti_image struct Create a nifti_image from the given dimensions and data type. Optinally, allocate zero-filled data. \param dims : optional dim[8] (default {3,1,1,1,0,0,0,0}) \param datatype : optional datatype (default DT_FLOAT32) \param data_fill : if flag is set, allocate zero-filled data for image \return pointer to allocated nifti_image struct *//*--------------------------------------------------------------------*/ nifti_image * nifti_make_new_nim(const int dims[], int datatype, int data_fill) { nifti_image * nim; nifti_1_header * nhdr; nhdr = nifti_make_new_header(dims, datatype); if( !nhdr ) return NULL; /* error already printed */ nim = nifti_convert_nhdr2nim(*nhdr,NULL); free(nhdr); /* in any case, we are done with this */ if( !nim ){ fprintf(stderr,"** NMNN: nifti_convert_nhdr2nim failure\n"); return NULL; } if( g_opts.debug > 1 ) fprintf(stderr,"+d nifti_make_new_nim, data_fill = %d\n",data_fill); if( data_fill ) { nim->data = calloc(nim->nvox, nim->nbyper); /* if we cannot allocate data, take ball and go home */ if( !nim->data ) { fprintf(stderr,"** NMNN: failed to alloc %u bytes for data\n", (unsigned)nim->nvox); nifti_image_free(nim); nim = NULL; } } return nim; } /*----------------------------------------------------------------------*/ /*! convert a nifti_image structure to a nifti_1_header struct No allocation is done, this should be used via structure copy. As in:
        nifti_1_header my_header;
        my_header = nifti_convert_nim2nhdr(my_nim_pointer);
        
    *//*--------------------------------------------------------------------*/ struct nifti_1_header nifti_convert_nim2nhdr(const nifti_image * nim) { struct nifti_1_header nhdr; memset(&nhdr,0,sizeof(nhdr)) ; /* zero out header, to be safe */ /**- load the ANALYZE-7.5 generic parts of the header struct */ nhdr.sizeof_hdr = sizeof(nhdr) ; nhdr.regular = 'r' ; /* for some stupid reason */ nhdr.dim[0] = nim->ndim ; nhdr.dim[1] = nim->nx ; nhdr.dim[2] = nim->ny ; nhdr.dim[3] = nim->nz ; nhdr.dim[4] = nim->nt ; nhdr.dim[5] = nim->nu ; nhdr.dim[6] = nim->nv ; nhdr.dim[7] = nim->nw ; nhdr.pixdim[0] = 0.0 ; nhdr.pixdim[1] = nim->dx ; nhdr.pixdim[2] = nim->dy ; nhdr.pixdim[3] = nim->dz ; nhdr.pixdim[4] = nim->dt ; nhdr.pixdim[5] = nim->du ; nhdr.pixdim[6] = nim->dv ; nhdr.pixdim[7] = nim->dw ; nhdr.datatype = nim->datatype ; nhdr.bitpix = 8 * nim->nbyper ; if( nim->cal_max > nim->cal_min ){ nhdr.cal_max = nim->cal_max ; nhdr.cal_min = nim->cal_min ; } if( nim->scl_slope != 0.0 ){ nhdr.scl_slope = nim->scl_slope ; nhdr.scl_inter = nim->scl_inter ; } if( nim->descrip[0] != '\0' ){ memcpy(nhdr.descrip ,nim->descrip ,79) ; nhdr.descrip[79] = '\0' ; } if( nim->aux_file[0] != '\0' ){ memcpy(nhdr.aux_file ,nim->aux_file ,23) ; nhdr.aux_file[23] = '\0' ; } /**- Load NIFTI specific stuff into the header */ if( nim->nifti_type > NIFTI_FTYPE_ANALYZE ){ /* then not ANALYZE */ if( nim->nifti_type == NIFTI_FTYPE_NIFTI1_1 ) strcpy(nhdr.magic,"n+1") ; else strcpy(nhdr.magic,"ni1") ; nhdr.pixdim[1] = fabs(nhdr.pixdim[1]) ; nhdr.pixdim[2] = fabs(nhdr.pixdim[2]) ; nhdr.pixdim[3] = fabs(nhdr.pixdim[3]) ; nhdr.pixdim[4] = fabs(nhdr.pixdim[4]) ; nhdr.pixdim[5] = fabs(nhdr.pixdim[5]) ; nhdr.pixdim[6] = fabs(nhdr.pixdim[6]) ; nhdr.pixdim[7] = fabs(nhdr.pixdim[7]) ; nhdr.intent_code = nim->intent_code ; nhdr.intent_p1 = nim->intent_p1 ; nhdr.intent_p2 = nim->intent_p2 ; nhdr.intent_p3 = nim->intent_p3 ; if( nim->intent_name[0] != '\0' ){ memcpy(nhdr.intent_name,nim->intent_name,15) ; nhdr.intent_name[15] = '\0' ; } nhdr.vox_offset = (float) nim->iname_offset ; nhdr.xyzt_units = SPACE_TIME_TO_XYZT( nim->xyz_units, nim->time_units ) ; nhdr.toffset = nim->toffset ; if( nim->qform_code > 0 ){ nhdr.qform_code = nim->qform_code ; nhdr.quatern_b = nim->quatern_b ; nhdr.quatern_c = nim->quatern_c ; nhdr.quatern_d = nim->quatern_d ; nhdr.qoffset_x = nim->qoffset_x ; nhdr.qoffset_y = nim->qoffset_y ; nhdr.qoffset_z = nim->qoffset_z ; nhdr.pixdim[0] = (nim->qfac >= 0.0) ? 1.0 : -1.0 ; } if( nim->sform_code > 0 ){ nhdr.sform_code = nim->sform_code ; nhdr.srow_x[0] = nim->sto_xyz.m[0][0] ; nhdr.srow_x[1] = nim->sto_xyz.m[0][1] ; nhdr.srow_x[2] = nim->sto_xyz.m[0][2] ; nhdr.srow_x[3] = nim->sto_xyz.m[0][3] ; nhdr.srow_y[0] = nim->sto_xyz.m[1][0] ; nhdr.srow_y[1] = nim->sto_xyz.m[1][1] ; nhdr.srow_y[2] = nim->sto_xyz.m[1][2] ; nhdr.srow_y[3] = nim->sto_xyz.m[1][3] ; nhdr.srow_z[0] = nim->sto_xyz.m[2][0] ; nhdr.srow_z[1] = nim->sto_xyz.m[2][1] ; nhdr.srow_z[2] = nim->sto_xyz.m[2][2] ; nhdr.srow_z[3] = nim->sto_xyz.m[2][3] ; } nhdr.dim_info = FPS_INTO_DIM_INFO( nim->freq_dim , nim->phase_dim , nim->slice_dim ) ; nhdr.slice_code = nim->slice_code ; nhdr.slice_start = nim->slice_start ; nhdr.slice_end = nim->slice_end ; nhdr.slice_duration = nim->slice_duration ; } return nhdr; } /*----------------------------------------------------------------------*/ /*! \fn int nifti_copy_extensions(nifti_image * nim_dest, nifti_image * nim_src) \brief copy the nifti1_extension list from src to dest Duplicate the list of nifti1_extensions. The dest structure must be clear of extensions. \return 0 on success, -1 on failure \sa nifti_add_extension, nifti_free_extensions */ int nifti_copy_extensions(nifti_image * nim_dest, const nifti_image * nim_src) { char * data; size_t bytes; int c, size, old_size; if( nim_dest->num_ext > 0 || nim_dest->ext_list != NULL ){ fprintf(stderr,"** will not copy extensions over existing ones\n"); return -1; } if( g_opts.debug > 1 ) fprintf(stderr,"+d duplicating %d extension(s)\n", nim_src->num_ext); if( nim_src->num_ext <= 0 ) return 0; bytes = nim_src->num_ext * sizeof(nifti1_extension); /* I'm lazy */ nim_dest->ext_list = (nifti1_extension *)malloc(bytes); if( !nim_dest->ext_list ){ fprintf(stderr,"** failed to allocate %d nifti1_extension structs\n", nim_src->num_ext); return -1; } /* copy the extension data */ nim_dest->num_ext = 0; for( c = 0; c < nim_src->num_ext; c++ ){ size = old_size = nim_src->ext_list[c].esize; if( size & 0xf ) size = (size + 0xf) & ~0xf; /* make multiple of 16 */ if( g_opts.debug > 2 ) fprintf(stderr,"+d dup'ing ext #%d of size %d (from size %d)\n", c, size, old_size); /* data length is size-8, as esize includes space for esize and ecode */ data = (char *)calloc(size-8,sizeof(char)); /* maybe size > old */ if( !data ){ fprintf(stderr,"** failed to alloc %d bytes for extention\n", size); if( c == 0 ) { free(nim_dest->ext_list); nim_dest->ext_list = NULL; } /* otherwise, keep what we have (a.o.t. deleting them all) */ return -1; } /* finally, fill the new structure */ nim_dest->ext_list[c].esize = size; nim_dest->ext_list[c].ecode = nim_src->ext_list[c].ecode; nim_dest->ext_list[c].edata = data; memcpy(data, nim_src->ext_list[c].edata, old_size-8); nim_dest->num_ext++; } return 0; } /*----------------------------------------------------------------------*/ /*! compute the total size of all extensions \return the total of all esize fields Note that each esize includes 4 bytes for ecode, 4 bytes for esize, and the bytes used for the data. Each esize also needs to be a multiple of 16, so it may be greater than the sum of its 3 parts. *//*--------------------------------------------------------------------*/ int nifti_extension_size(nifti_image *nim) { int c, size = 0; if( !nim || nim->num_ext <= 0 ) return 0; if( g_opts.debug > 2 ) fprintf(stderr,"-d ext sizes:"); for ( c = 0; c < nim->num_ext; c++ ){ size += nim->ext_list[c].esize; if( g_opts.debug > 2 ) fprintf(stderr," %d",nim->ext_list[c].esize); } if( g_opts.debug > 2 ) fprintf(stderr," (total = %d)\n",size); return size; } /*----------------------------------------------------------------------*/ /*! set the nifti_image iname_offset field, based on nifti_type - if writing to 2 files, set offset to 0 - if writing to a single NIFTI-1 file, set the offset to 352 + total extension size, then align to 16-byte boundary - if writing an ASCII header, set offset to -1 *//*--------------------------------------------------------------------*/ void nifti_set_iname_offset(nifti_image *nim) { int offset; switch( nim->nifti_type ){ default: /* writing into 2 files */ /* we only write files with 0 offset in the 2 file format */ nim->iname_offset = 0 ; break ; /* NIFTI-1 single binary file - always update */ case NIFTI_FTYPE_NIFTI1_1: offset = nifti_extension_size(nim)+sizeof(struct nifti_1_header)+4; /* be sure offset is aligned to a 16 byte boundary */ if ( ( offset % 16 ) != 0 ) offset = ((offset + 0xf) & ~0xf); if( nim->iname_offset != offset ){ if( g_opts.debug > 1 ) fprintf(stderr,"+d changing offset from %d to %d\n", nim->iname_offset, offset); nim->iname_offset = offset; } break ; /* non-standard case: NIFTI-1 ASCII header + binary data (single file) */ case NIFTI_FTYPE_ASCII: nim->iname_offset = -1 ; /* compute offset from filesize */ break ; } } /*----------------------------------------------------------------------*/ /*! write the nifti_image dataset to disk, optionally including data This is just a front-end for nifti_image_write_hdr_img2. \param nim nifti_image to write to disk \param write_data write options (see nifti_image_write_hdr_img2) \param opts file open options ("wb" from nifti_image_write) \sa nifti_image_write, nifti_image_write_hdr_img2, nifti_image_free, nifti_set_filenames *//*--------------------------------------------------------------------*/ znzFile nifti_image_write_hdr_img( nifti_image *nim , int write_data , const char* opts ) { return nifti_image_write_hdr_img2(nim,write_data,opts,NULL,NULL); } #undef ERREX #define ERREX(msg) \ do{ fprintf(stderr,"** ERROR: nifti_image_write_hdr_img: %s\n",(msg)) ; \ return fp ; } while(0) /* ----------------------------------------------------------------------*/ /*! This writes the header (and optionally the image data) to file * * If the image data file is left open it returns a valid znzFile handle. * It also uses imgfile as the open image file is not null, and modifies * it inside. * * \param nim nifti_image to write to disk * \param write_opts flags whether to write data and/or close file (see below) * \param opts file-open options, probably "wb" from nifti_image_write() * \param imgfile optional open znzFile struct, for writing image data (may be NULL) * \param NBL optional nifti_brick_list, containing the image data (may be NULL) * * Values for write_opts mode are based on two binary flags * ( 0/1 for no-write/write data, and 0/2 for close/leave-open files ) : * - 0 = do not write data and close (do not open data file) * - 1 = write data and close * - 2 = do not write data and leave data file open * - 3 = write data and leave data file open * * \sa nifti_image_write, nifti_image_write_hdr_img, nifti_image_free, * nifti_set_filenames *//*---------------------------------------------------------------------*/ znzFile nifti_image_write_hdr_img2(nifti_image *nim, int write_opts, const char * opts, znzFile imgfile, const nifti_brick_list * NBL) { struct nifti_1_header nhdr ; znzFile fp=NULL; size_t ss ; int write_data, leave_open; char func[] = { "nifti_image_write_hdr_img2" }; write_data = write_opts & 1; /* just separate the bits now */ leave_open = write_opts & 2; if( ! nim ) ERREX("NULL input") ; if( ! nifti_validfilename(nim->fname) ) ERREX("bad fname input") ; if( write_data && ! nim->data && ! NBL ) ERREX("no image data") ; nifti_set_iname_offset(nim); if( g_opts.debug > 1 ){ fprintf(stderr,"-d writing nifti file '%s'...\n", nim->fname); if( g_opts.debug > 2 ) fprintf(stderr,"-d nifti type %d, offset %d\n", nim->nifti_type, nim->iname_offset); } if( nim->nifti_type == NIFTI_FTYPE_ASCII ) /* non-standard case */ return nifti_write_ascii_image(nim,NBL,opts,write_data,leave_open); nhdr = nifti_convert_nim2nhdr(nim); /* create the nifti1_header struct */ /* if writing to 2 files, make sure iname is set and different from fname */ if( nim->nifti_type != NIFTI_FTYPE_NIFTI1_1 ){ if( nim->iname && strcmp(nim->iname,nim->fname) == 0 ){ free(nim->iname) ; nim->iname = NULL ; } if( nim->iname == NULL ){ /* then make a new one */ nim->iname = nifti_makeimgname(nim->fname,nim->nifti_type,0,0); if( nim->iname == NULL ) return NULL; } } /* if we have an imgfile and will write the header there, use it */ if( ! znz_isnull(imgfile) && nim->nifti_type == NIFTI_FTYPE_NIFTI1_1 ){ if( g_opts.debug > 2 ) fprintf(stderr,"+d using passed file for hdr\n"); fp = imgfile; } else { if( g_opts.debug > 2 ) fprintf(stderr,"+d opening output file %s [%s]\n",nim->fname,opts); fp = znzopen( nim->fname , opts , nifti_is_gzfile(nim->fname) ) ; if( znz_isnull(fp) ){ LNI_FERR(func,"cannot open output file",nim->fname); return fp; } } /* write the header and extensions */ ss = znzwrite(&nhdr , 1 , sizeof(nhdr) , fp); /* write header */ if( ss < sizeof(nhdr) ){ LNI_FERR(func,"bad header write to output file",nim->fname); znzclose(fp); return fp; } /* partial file exists, and errors have been printed, so ignore return */ if( nim->nifti_type != NIFTI_FTYPE_ANALYZE ) (void)nifti_write_extensions(fp,nim); /* if the header is all we want, we are done */ if( ! write_data && ! leave_open ){ if( g_opts.debug > 2 ) fprintf(stderr,"-d header is all we want: done\n"); znzclose(fp); return(fp); } if( nim->nifti_type != NIFTI_FTYPE_NIFTI1_1 ){ /* get a new file pointer */ znzclose(fp); /* first, close header file */ if( ! znz_isnull(imgfile) ){ if(g_opts.debug > 2) fprintf(stderr,"+d using passed file for img\n"); fp = imgfile; } else { if( g_opts.debug > 2 ) fprintf(stderr,"+d opening img file '%s'\n", nim->iname); fp = znzopen( nim->iname , opts , nifti_is_gzfile(nim->iname) ) ; if( znz_isnull(fp) ) ERREX("cannot open image file") ; } } znzseek(fp, nim->iname_offset, SEEK_SET); /* in any case, seek to offset */ if( write_data ) nifti_write_all_data(fp,nim,NBL); if( ! leave_open ) znzclose(fp); return fp; } /*----------------------------------------------------------------------*/ /*! write a nifti_image to disk in ASCII format *//*--------------------------------------------------------------------*/ znzFile nifti_write_ascii_image(nifti_image *nim, const nifti_brick_list * NBL, const char *opts, int write_data, int leave_open) { znzFile fp; char * hstr; hstr = nifti_image_to_ascii( nim ) ; /* get header in ASCII form */ if( ! hstr ){ fprintf(stderr,"** failed image_to_ascii()\n"); return NULL; } fp = znzopen( nim->fname , opts , nifti_is_gzfile(nim->fname) ) ; if( znz_isnull(fp) ){ free(hstr); fprintf(stderr,"** failed to open '%s' for ascii write\n",nim->fname); return fp; } znzputs(hstr,fp); /* header */ nifti_write_extensions(fp,nim); /* extensions */ if ( write_data ) { nifti_write_all_data(fp,nim,NBL); } /* data */ if ( ! leave_open ) { znzclose(fp); } free(hstr); return fp; /* returned but may be closed */ } /*--------------------------------------------------------------------------*/ /*! Write a nifti_image to disk. Since data is properly byte-swapped upon reading, it is assumed to be in the byte-order of the current CPU at write time. Thus, nim->byte_order should match that of the current CPU. Note that the nifti_set_filenames() function takes the flag, set_byte_order. The following fields of nim affect how the output appears: - nifti_type = 0 ==> ANALYZE-7.5 format file pair will be written - nifti_type = 1 ==> NIFTI-1 format single file will be written (data offset will be 352+extensions) - nifti_type = 2 ==> NIFTI_1 format file pair will be written - nifti_type = 3 ==> NIFTI_1 ASCII single file will be written - fname is the name of the output file (header or header+data) - if a file pair is being written, iname is the name of the data file - existing files WILL be overwritten with extreme prejudice - if qform_code > 0, the quatern_*, qoffset_*, and qfac fields determine the qform output, NOT the qto_xyz matrix; if you want to compute these fields from the qto_xyz matrix, you can use the utility function nifti_mat44_to_quatern() \sa nifti_image_write_bricks, nifti_image_free, nifti_set_filenames, nifti_image_write_hdr_img *//*------------------------------------------------------------------------*/ void nifti_image_write( nifti_image *nim ) { znzFile fp = nifti_image_write_hdr_img(nim,1,"wb"); if( fp ){ if( g_opts.debug > 2 ) fprintf(stderr,"-d niw: done with znzFile\n"); free(fp); } if( g_opts.debug > 1 ) fprintf(stderr,"-d nifti_image_write: done\n"); } /*----------------------------------------------------------------------*/ /*! similar to nifti_image_write, but data is in NBL struct, not nim->data \sa nifti_image_write, nifti_image_free, nifti_set_filenames, nifti_free_NBL *//*--------------------------------------------------------------------*/ void nifti_image_write_bricks( nifti_image *nim, const nifti_brick_list * NBL ) { znzFile fp = nifti_image_write_hdr_img2(nim,1,"wb",NULL,NBL); if( fp ){ if( g_opts.debug > 2 ) fprintf(stderr,"-d niwb: done with znzFile\n"); free(fp); } if( g_opts.debug > 1 ) fprintf(stderr,"-d niwb: done writing bricks\n"); } /*----------------------------------------------------------------------*/ /*! copy the nifti_image structure, without data Duplicate the structure, including fname, iname and extensions. Leave the data pointer as NULL. *//*--------------------------------------------------------------------*/ nifti_image * nifti_copy_nim_info(const nifti_image * src) { nifti_image *dest; dest = (nifti_image *)calloc(1,sizeof(nifti_image)); if( !dest ){ fprintf(stderr,"** NCNI: failed to alloc nifti_image\n"); return NULL; } memcpy(dest, src, sizeof(nifti_image)); if( src->fname ) dest->fname = nifti_strdup(src->fname); if( src->iname ) dest->iname = nifti_strdup(src->iname); dest->num_ext = 0; dest->ext_list = NULL; /* errors will be printed in NCE(), continue in either case */ (void)nifti_copy_extensions(dest, src); dest->data = NULL; return dest; } /*------------------------------------------------------------------------*/ /* Un-escape a C string in place -- that is, convert XML escape sequences back into their characters. (This can be done in place since the replacement is always smaller than the input.) Escapes recognized are: - < -> < - > -> > - " -> " - ' -> ' - & -> & Also replace CR LF pair (Microsoft), or CR alone (Macintosh) with LF (Unix), per the XML standard. Return value is number of replacements made (if you care). --------------------------------------------------------------------------*/ #undef CR #undef LF #define CR 0x0D #define LF 0x0A static int unescape_string( char *str ) { int ii,jj , nn,ll ; if( str == NULL ) return 0 ; /* no string? */ ll = strlen(str) ; if( ll == 0 ) return 0 ; /* scan for escapes: &something; */ for( ii=jj=nn=0 ; ii': lout += 4 ; break ; /* replace '<' with "<" */ case '"' : case '\'': lout += 6 ; break ; /* replace '"' with """ */ case CR: case LF: lout += 6 ; break ; /* replace CR with " " LF with " " */ default: lout++ ; break ; /* copy all other chars */ } } out = (char *)calloc(1,lout) ; /* allocate output string */ if( !out ){ fprintf(stderr,"** escapize_string: failed to alloc %d bytes\n",lout); return NULL; } out[0] = '\'' ; /* opening quote mark */ for( ii=0,jj=1 ; ii < lstr ; ii++ ){ switch( str[ii] ){ default: out[jj++] = str[ii] ; break ; /* normal characters */ case '&': memcpy(out+jj,"&",5) ; jj+=5 ; break ; case '<': memcpy(out+jj,"<",4) ; jj+=4 ; break ; case '>': memcpy(out+jj,">",4) ; jj+=4 ; break ; case '"' : memcpy(out+jj,""",6) ; jj+=6 ; break ; case '\'': memcpy(out+jj,"'",6) ; jj+=6 ; break ; case CR: memcpy(out+jj," ",6) ; jj+=6 ; break ; case LF: memcpy(out+jj," ",6) ; jj+=6 ; break ; } } out[jj++] = '\'' ; /* closing quote mark */ out[jj] = '\0' ; /* terminate the string */ return out ; } /*---------------------------------------------------------------------------*/ /*! Dump the information in a NIFTI image header to an XML-ish ASCII string that can later be converted back into a NIFTI header in nifti_image_from_ascii(). The resulting string can be free()-ed when you are done with it. *//*-------------------------------------------------------------------------*/ char *nifti_image_to_ascii( const nifti_image *nim ) { char *buf , *ebuf ; int nbuf ; if( nim == NULL ) return NULL ; /* stupid caller */ buf = (char *)calloc(1,65534); nbuf = 0; /* longer than needed, to be safe */ if( !buf ){ fprintf(stderr,"** NITA: failed to alloc %d bytes\n",65534); return NULL; } sprintf( buf , "nifti_type == NIFTI_FTYPE_NIFTI1_1) ? "NIFTI-1+" :(nim->nifti_type == NIFTI_FTYPE_NIFTI1_2) ? "NIFTI-1" :(nim->nifti_type == NIFTI_FTYPE_ASCII ) ? "NIFTI-1A" : "ANALYZE-7.5" ) ; /** Strings that we don't control (filenames, etc.) that might contain "weird" characters (like quotes) are "escaped": - A few special characters are replaced by XML-style escapes, using the function escapize_string(). - On input, function unescape_string() reverses this process. - The result is that the NIFTI ASCII-format header is XML-compliant. */ ebuf = escapize_string(nim->fname) ; sprintf( buf+strlen(buf) , " header_filename = %s\n",ebuf); free(ebuf); ebuf = escapize_string(nim->iname) ; sprintf( buf+strlen(buf) , " image_filename = %s\n", ebuf); free(ebuf); sprintf( buf+strlen(buf) , " image_offset = '%d'\n" , nim->iname_offset ); sprintf( buf+strlen(buf), " ndim = '%d'\n", nim->ndim); sprintf( buf+strlen(buf), " nx = '%d'\n", nim->nx ); if( nim->ndim > 1 ) sprintf( buf+strlen(buf), " ny = '%d'\n", nim->ny ); if( nim->ndim > 2 ) sprintf( buf+strlen(buf), " nz = '%d'\n", nim->nz ); if( nim->ndim > 3 ) sprintf( buf+strlen(buf), " nt = '%d'\n", nim->nt ); if( nim->ndim > 4 ) sprintf( buf+strlen(buf), " nu = '%d'\n", nim->nu ); if( nim->ndim > 5 ) sprintf( buf+strlen(buf), " nv = '%d'\n", nim->nv ); if( nim->ndim > 6 ) sprintf( buf+strlen(buf), " nw = '%d'\n", nim->nw ); sprintf( buf+strlen(buf), " dx = '%g'\n", nim->dx ); if( nim->ndim > 1 ) sprintf( buf+strlen(buf), " dy = '%g'\n", nim->dy ); if( nim->ndim > 2 ) sprintf( buf+strlen(buf), " dz = '%g'\n", nim->dz ); if( nim->ndim > 3 ) sprintf( buf+strlen(buf), " dt = '%g'\n", nim->dt ); if( nim->ndim > 4 ) sprintf( buf+strlen(buf), " du = '%g'\n", nim->du ); if( nim->ndim > 5 ) sprintf( buf+strlen(buf), " dv = '%g'\n", nim->dv ); if( nim->ndim > 6 ) sprintf( buf+strlen(buf), " dw = '%g'\n", nim->dw ); sprintf( buf+strlen(buf) , " datatype = '%d'\n" , nim->datatype ) ; sprintf( buf+strlen(buf) , " datatype_name = '%s'\n" , nifti_datatype_string(nim->datatype) ) ; sprintf( buf+strlen(buf) , " nvox = '%u'\n" , (unsigned)nim->nvox ) ; sprintf( buf+strlen(buf) , " nbyper = '%d'\n" , nim->nbyper ) ; sprintf( buf+strlen(buf) , " byteorder = '%s'\n" , (nim->byteorder==MSB_FIRST) ? "MSB_FIRST" : "LSB_FIRST" ) ; if( nim->cal_min < nim->cal_max ){ sprintf( buf+strlen(buf) , " cal_min = '%g'\n", nim->cal_min ) ; sprintf( buf+strlen(buf) , " cal_max = '%g'\n", nim->cal_max ) ; } if( nim->scl_slope != 0.0 ){ sprintf( buf+strlen(buf) , " scl_slope = '%g'\n" , nim->scl_slope ) ; sprintf( buf+strlen(buf) , " scl_inter = '%g'\n" , nim->scl_inter ) ; } if( nim->intent_code > 0 ){ sprintf( buf+strlen(buf) , " intent_code = '%d'\n", nim->intent_code ) ; sprintf( buf+strlen(buf) , " intent_code_name = '%s'\n" , nifti_intent_string(nim->intent_code) ) ; sprintf( buf+strlen(buf) , " intent_p1 = '%g'\n" , nim->intent_p1 ) ; sprintf( buf+strlen(buf) , " intent_p2 = '%g'\n" , nim->intent_p2 ) ; sprintf( buf+strlen(buf) , " intent_p3 = '%g'\n" , nim->intent_p3 ) ; if( nim->intent_name[0] != '\0' ){ ebuf = escapize_string(nim->intent_name) ; sprintf( buf+strlen(buf) , " intent_name = %s\n",ebuf) ; free(ebuf) ; } } if( nim->toffset != 0.0 ) sprintf( buf+strlen(buf) , " toffset = '%g'\n",nim->toffset ) ; if( nim->xyz_units > 0 ) sprintf( buf+strlen(buf) , " xyz_units = '%d'\n" " xyz_units_name = '%s'\n" , nim->xyz_units , nifti_units_string(nim->xyz_units) ) ; if( nim->time_units > 0 ) sprintf( buf+strlen(buf) , " time_units = '%d'\n" " time_units_name = '%s'\n" , nim->time_units , nifti_units_string(nim->time_units) ) ; if( nim->freq_dim > 0 ) sprintf( buf+strlen(buf) , " freq_dim = '%d'\n",nim->freq_dim ) ; if( nim->phase_dim > 0 ) sprintf( buf+strlen(buf) , " phase_dim = '%d'\n",nim->phase_dim ) ; if( nim->slice_dim > 0 ) sprintf( buf+strlen(buf) , " slice_dim = '%d'\n",nim->slice_dim ) ; if( nim->slice_code > 0 ) sprintf( buf+strlen(buf) , " slice_code = '%d'\n" " slice_code_name = '%s'\n" , nim->slice_code , nifti_slice_string(nim->slice_code) ) ; if( nim->slice_start >= 0 && nim->slice_end > nim->slice_start ) sprintf( buf+strlen(buf) , " slice_start = '%d'\n" " slice_end = '%d'\n" , nim->slice_start , nim->slice_end ) ; if( nim->slice_duration != 0.0 ) sprintf( buf+strlen(buf) , " slice_duration = '%g'\n", nim->slice_duration ) ; if( nim->descrip[0] != '\0' ){ ebuf = escapize_string(nim->descrip) ; sprintf( buf+strlen(buf) , " descrip = %s\n",ebuf) ; free(ebuf) ; } if( nim->aux_file[0] != '\0' ){ ebuf = escapize_string(nim->aux_file) ; sprintf( buf+strlen(buf) , " aux_file = %s\n",ebuf) ; free(ebuf) ; } if( nim->qform_code > 0 ){ int i,j,k ; sprintf( buf+strlen(buf) , " qform_code = '%d'\n" " qform_code_name = '%s'\n" " qto_xyz_matrix = '%g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g'\n" , nim->qform_code , nifti_xform_string(nim->qform_code) , nim->qto_xyz.m[0][0] , nim->qto_xyz.m[0][1] , nim->qto_xyz.m[0][2] , nim->qto_xyz.m[0][3] , nim->qto_xyz.m[1][0] , nim->qto_xyz.m[1][1] , nim->qto_xyz.m[1][2] , nim->qto_xyz.m[1][3] , nim->qto_xyz.m[2][0] , nim->qto_xyz.m[2][1] , nim->qto_xyz.m[2][2] , nim->qto_xyz.m[2][3] , nim->qto_xyz.m[3][0] , nim->qto_xyz.m[3][1] , nim->qto_xyz.m[3][2] , nim->qto_xyz.m[3][3] ) ; sprintf( buf+strlen(buf) , " qto_ijk_matrix = '%g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g'\n" , nim->qto_ijk.m[0][0] , nim->qto_ijk.m[0][1] , nim->qto_ijk.m[0][2] , nim->qto_ijk.m[0][3] , nim->qto_ijk.m[1][0] , nim->qto_ijk.m[1][1] , nim->qto_ijk.m[1][2] , nim->qto_ijk.m[1][3] , nim->qto_ijk.m[2][0] , nim->qto_ijk.m[2][1] , nim->qto_ijk.m[2][2] , nim->qto_ijk.m[2][3] , nim->qto_ijk.m[3][0] , nim->qto_ijk.m[3][1] , nim->qto_ijk.m[3][2] , nim->qto_ijk.m[3][3] ) ; sprintf( buf+strlen(buf) , " quatern_b = '%g'\n" " quatern_c = '%g'\n" " quatern_d = '%g'\n" " qoffset_x = '%g'\n" " qoffset_y = '%g'\n" " qoffset_z = '%g'\n" " qfac = '%g'\n" , nim->quatern_b , nim->quatern_c , nim->quatern_d , nim->qoffset_x , nim->qoffset_y , nim->qoffset_z , nim->qfac ) ; nifti_mat44_to_orientation( nim->qto_xyz , &i,&j,&k ) ; if( i > 0 && j > 0 && k > 0 ) sprintf( buf+strlen(buf) , " qform_i_orientation = '%s'\n" " qform_j_orientation = '%s'\n" " qform_k_orientation = '%s'\n" , nifti_orientation_string(i) , nifti_orientation_string(j) , nifti_orientation_string(k) ) ; } if( nim->sform_code > 0 ){ int i,j,k ; sprintf( buf+strlen(buf) , " sform_code = '%d'\n" " sform_code_name = '%s'\n" " sto_xyz_matrix = '%g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g'\n" , nim->sform_code , nifti_xform_string(nim->sform_code) , nim->sto_xyz.m[0][0] , nim->sto_xyz.m[0][1] , nim->sto_xyz.m[0][2] , nim->sto_xyz.m[0][3] , nim->sto_xyz.m[1][0] , nim->sto_xyz.m[1][1] , nim->sto_xyz.m[1][2] , nim->sto_xyz.m[1][3] , nim->sto_xyz.m[2][0] , nim->sto_xyz.m[2][1] , nim->sto_xyz.m[2][2] , nim->sto_xyz.m[2][3] , nim->sto_xyz.m[3][0] , nim->sto_xyz.m[3][1] , nim->sto_xyz.m[3][2] , nim->sto_xyz.m[3][3] ) ; sprintf( buf+strlen(buf) , " sto_ijk matrix = '%g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g'\n" , nim->sto_ijk.m[0][0] , nim->sto_ijk.m[0][1] , nim->sto_ijk.m[0][2] , nim->sto_ijk.m[0][3] , nim->sto_ijk.m[1][0] , nim->sto_ijk.m[1][1] , nim->sto_ijk.m[1][2] , nim->sto_ijk.m[1][3] , nim->sto_ijk.m[2][0] , nim->sto_ijk.m[2][1] , nim->sto_ijk.m[2][2] , nim->sto_ijk.m[2][3] , nim->sto_ijk.m[3][0] , nim->sto_ijk.m[3][1] , nim->sto_ijk.m[3][2] , nim->sto_ijk.m[3][3] ) ; nifti_mat44_to_orientation( nim->sto_xyz , &i,&j,&k ) ; if( i > 0 && j > 0 && k > 0 ) sprintf( buf+strlen(buf) , " sform_i_orientation = '%s'\n" " sform_j_orientation = '%s'\n" " sform_k_orientation = '%s'\n" , nifti_orientation_string(i) , nifti_orientation_string(j) , nifti_orientation_string(k) ) ; } sprintf( buf+strlen(buf) , " num_ext = '%d'\n", nim->num_ext ) ; sprintf( buf+strlen(buf) , "/>\n" ) ; /* XML-ish closer */ nbuf = strlen(buf) ; buf = (char *)realloc((void *)buf, nbuf+1); /* cut back to proper length */ if( !buf ) fprintf(stderr,"** NITA: failed to realloc %d bytes\n",nbuf+1); return buf ; } /*---------------------------------------------------------------------------*/ /*----------------------------------------------------------------------*/ /*! get the byte order for this CPU - LSB_FIRST means least significant byte, first (little endian) - MSB_FIRST means most significant byte, first (big endian) *//*--------------------------------------------------------------------*/ int nifti_short_order(void) /* determine this CPU's byte order */ { union { unsigned char bb[2] ; short ss ; } fred ; fred.bb[0] = 1 ; fred.bb[1] = 0 ; return (fred.ss == 1) ? LSB_FIRST : MSB_FIRST ; } /*---------------------------------------------------------------------------*/ #undef QQNUM #undef QNUM #undef QSTR /* macro to check lhs string against "n1"; if it matches, interpret rhs string as a number, and put it into nim->"n2" */ #define QQNUM(n1,n2) if( strcmp(lhs,#n1)==0 ) nim->n2=strtod(rhs,NULL) /* same, but where "n1" == "n2" */ #define QNUM(nam) QQNUM(nam,nam) /* macro to check lhs string against "nam"; if it matches, put rhs string into nim->"nam" string, with max length = "ml" */ #define QSTR(nam,ml) if( strcmp(lhs,#nam) == 0 ) \ strncpy(nim->nam,rhs,ml), nim->nam[ml]='\0' /*---------------------------------------------------------------------------*/ /*! Take an XML-ish ASCII string and create a NIFTI image header to match. NULL is returned if enough information isn't present in the input string. - The image data can later be loaded with nifti_image_load(). - The struct returned here can be liberated with nifti_image_free(). - Not a lot of error checking is done here to make sure that the input values are reasonable! *//*-------------------------------------------------------------------------*/ nifti_image *nifti_image_from_ascii( const char *str, int * bytes_read ) { char lhs[1024] , rhs[1024] ; int ii , spos, nn , slen ; nifti_image *nim ; /* will be output */ if( str == NULL || *str == '\0' ) return NULL ; /* bad input!? */ /* scan for opening string */ spos = 0 ; slen = strlen(str) ; ii = sscanf( str+spos , "%1023s%n" , lhs , &nn ) ; spos += nn ; if( ii == 0 || strcmp(lhs,"nx = nim->ny = nim->nz = nim->nt = nim->nu = nim->nv = nim->nw = 1 ; nim->dx = nim->dy = nim->dz = nim->dt = nim->du = nim->dv = nim->dw = 0 ; nim->qfac = 1.0 ; nim->byteorder = nifti_short_order() ; /* starting at str[spos], scan for "equations" of the form lhs = 'rhs' and assign rhs values into the struct component named by lhs */ while(1){ while( isspace(str[spos]) ) spos++ ; /* skip whitespace */ if( str[spos] == '\0' ) break ; /* end of string? */ /* get lhs string */ ii = sscanf( str+spos , "%1023s%n" , lhs , &nn ) ; spos += nn ; if( ii == 0 || strcmp(lhs,"/>") == 0 ) break ; /* end of input? */ /* skip whitespace and the '=' marker */ while( isspace(str[spos]) || str[spos] == '=' ) spos++ ; if( str[spos] == '\0' ) break ; /* end of string? */ /* if next character is a quote ', copy everything up to next ' otherwise, copy everything up to next nonblank */ if( str[spos] == '\'' ){ ii = spos+1 ; while( str[ii] != '\0' && str[ii] != '\'' ) ii++ ; nn = ii-spos-1 ; if( nn > 1023 ) nn = 1023 ; memcpy(rhs,str+spos+1,nn) ; rhs[nn] = '\0' ; spos = (str[ii] == '\'') ? ii+1 : ii ; } else { ii = sscanf( str+spos , "%1023s%n" , rhs , &nn ) ; spos += nn ; if( ii == 0 ) break ; /* nothing found? */ } unescape_string(rhs) ; /* remove any XML escape sequences */ /* Now can do the assignment, based on lhs string. Start with special cases that don't fit the QNUM/QSTR macros. */ if( strcmp(lhs,"nifti_type") == 0 ){ if( strcmp(rhs,"ANALYZE-7.5") == 0 ) nim->nifti_type = NIFTI_FTYPE_ANALYZE ; else if( strcmp(rhs,"NIFTI-1+") == 0 ) nim->nifti_type = NIFTI_FTYPE_NIFTI1_1 ; else if( strcmp(rhs,"NIFTI-1") == 0 ) nim->nifti_type = NIFTI_FTYPE_NIFTI1_2 ; else if( strcmp(rhs,"NIFTI-1A") == 0 ) nim->nifti_type = NIFTI_FTYPE_ASCII ; } else if( strcmp(lhs,"header_filename") == 0 ){ nim->fname = nifti_strdup(rhs) ; } else if( strcmp(lhs,"image_filename") == 0 ){ nim->iname = nifti_strdup(rhs) ; } else if( strcmp(lhs,"sto_xyz_matrix") == 0 ){ sscanf( rhs , "%f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f" , &(nim->sto_xyz.m[0][0]) , &(nim->sto_xyz.m[0][1]) , &(nim->sto_xyz.m[0][2]) , &(nim->sto_xyz.m[0][3]) , &(nim->sto_xyz.m[1][0]) , &(nim->sto_xyz.m[1][1]) , &(nim->sto_xyz.m[1][2]) , &(nim->sto_xyz.m[1][3]) , &(nim->sto_xyz.m[2][0]) , &(nim->sto_xyz.m[2][1]) , &(nim->sto_xyz.m[2][2]) , &(nim->sto_xyz.m[2][3]) , &(nim->sto_xyz.m[3][0]) , &(nim->sto_xyz.m[3][1]) , &(nim->sto_xyz.m[3][2]) , &(nim->sto_xyz.m[3][3]) ) ; } else if( strcmp(lhs,"byteorder") == 0 ){ if( strcmp(rhs,"MSB_FIRST") == 0 ) nim->byteorder = MSB_FIRST ; if( strcmp(rhs,"LSB_FIRST") == 0 ) nim->byteorder = LSB_FIRST ; } else QQNUM(image_offset,iname_offset) ; else QNUM(datatype) ; else QNUM(ndim) ; else QNUM(nx) ; else QNUM(ny) ; else QNUM(nz) ; else QNUM(nt) ; else QNUM(nu) ; else QNUM(nv) ; else QNUM(nw) ; else QNUM(dx) ; else QNUM(dy) ; else QNUM(dz) ; else QNUM(dt) ; else QNUM(du) ; else QNUM(dv) ; else QNUM(dw) ; else QNUM(cal_min) ; else QNUM(cal_max) ; else QNUM(scl_slope) ; else QNUM(scl_inter) ; else QNUM(intent_code) ; else QNUM(intent_p1) ; else QNUM(intent_p2) ; else QNUM(intent_p3) ; else QSTR(intent_name,15) ; else QNUM(toffset) ; else QNUM(xyz_units) ; else QNUM(time_units) ; else QSTR(descrip,79) ; else QSTR(aux_file,23) ; else QNUM(qform_code) ; else QNUM(quatern_b) ; else QNUM(quatern_c) ; else QNUM(quatern_d) ; else QNUM(qoffset_x) ; else QNUM(qoffset_y) ; else QNUM(qoffset_z) ; else QNUM(qfac) ; else QNUM(sform_code) ; else QNUM(freq_dim) ; else QNUM(phase_dim) ; else QNUM(slice_dim) ; else QNUM(slice_code) ; else QNUM(slice_start) ; else QNUM(slice_end) ; else QNUM(slice_duration) ; else QNUM(num_ext) ; } /* end of while loop */ if( bytes_read ) *bytes_read = spos+1; /* "process" last '\n' */ /* do miscellaneous checking and cleanup */ if( nim->ndim <= 0 ){ nifti_image_free(nim); return NULL; } /* bad! */ nifti_datatype_sizes( nim->datatype, &(nim->nbyper), &(nim->swapsize) ); if( nim->nbyper == 0 ){ nifti_image_free(nim); return NULL; } /* bad! */ nim->dim[0] = nim->ndim ; nim->dim[1] = nim->nx ; nim->pixdim[1] = nim->dx ; nim->dim[2] = nim->ny ; nim->pixdim[2] = nim->dy ; nim->dim[3] = nim->nz ; nim->pixdim[3] = nim->dz ; nim->dim[4] = nim->nt ; nim->pixdim[4] = nim->dt ; nim->dim[5] = nim->nu ; nim->pixdim[5] = nim->du ; nim->dim[6] = nim->nv ; nim->pixdim[6] = nim->dv ; nim->dim[7] = nim->nw ; nim->pixdim[7] = nim->dw ; nim->nvox = (size_t)nim->nx * nim->ny * nim->nz * nim->nt * nim->nu * nim->nv * nim->nw ; if( nim->qform_code > 0 ) nim->qto_xyz = nifti_quatern_to_mat44( nim->quatern_b, nim->quatern_c, nim->quatern_d, nim->qoffset_x, nim->qoffset_y, nim->qoffset_z, nim->dx , nim->dy , nim->dz , nim->qfac ) ; else nim->qto_xyz = nifti_quatern_to_mat44( 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , nim->dx , nim->dy , nim->dz , 0.0 ) ; nim->qto_ijk = nifti_mat44_inverse( nim->qto_xyz ) ; if( nim->sform_code > 0 ) nim->sto_ijk = nifti_mat44_inverse( nim->sto_xyz ) ; return nim ; } /*---------------------------------------------------------------------------*/ /*! validate the nifti_image \return 1 if the structure seems valid, otherwise 0 \sa nifti_nim_has_valid_dims, nifti_hdr_looks_good *//*-------------------------------------------------------------------------*/ int nifti_nim_is_valid(nifti_image * nim, int complain) { int errs = 0; if( !nim ){ fprintf(stderr,"** is_valid_nim: nim is NULL\n"); return 0; } if( g_opts.debug > 2 ) fprintf(stderr,"-d nim_is_valid check...\n"); /**- check that dim[] matches the individual values ndim, nx, ny, ... */ if( ! nifti_nim_has_valid_dims(nim,complain) ){ if( !complain ) return 0; errs++; } /* might check nbyper, pixdim, q/sforms, swapsize, nifti_type, ... */ /**- be explicit in return of 0 or 1 */ if( errs > 0 ) return 0; else return 1; } /*---------------------------------------------------------------------------*/ /*! validate nifti dimensions \return 1 if valid, 0 if not \sa nifti_nim_is_valid, nifti_hdr_looks_good rely on dim[] as the master *//*-------------------------------------------------------------------------*/ int nifti_nim_has_valid_dims(nifti_image * nim, int complain) { size_t prod; int c, errs = 0; /**- start with dim[0]: failure here is considered terminal */ if( nim->dim[0] <= 0 || nim->dim[0] > 7 ){ errs++; if( complain ) fprintf(stderr,"** NVd: dim[0] (%d) out of range [1,7]\n",nim->dim[0]); return 0; } /**- check whether ndim equals dim[0] */ if( nim->ndim != nim->dim[0] ){ errs++; if( ! complain ) return 0; fprintf(stderr,"** NVd: ndim != dim[0] (%d,%d)\n",nim->ndim,nim->dim[0]); } /**- compare each dim[i] to the proper nx, ny, ... */ if( ( (nim->dim[0] >= 1) && (nim->dim[1] != nim->nx) ) || ( (nim->dim[0] >= 2) && (nim->dim[2] != nim->ny) ) || ( (nim->dim[0] >= 3) && (nim->dim[3] != nim->nz) ) || ( (nim->dim[0] >= 4) && (nim->dim[4] != nim->nt) ) || ( (nim->dim[0] >= 5) && (nim->dim[5] != nim->nu) ) || ( (nim->dim[0] >= 6) && (nim->dim[6] != nim->nv) ) || ( (nim->dim[0] >= 7) && (nim->dim[7] != nim->nw) ) ){ errs++; if( !complain ) return 0; fprintf(stderr,"** NVd mismatch: dims = %d,%d,%d,%d,%d,%d,%d\n" " nxyz... = %d,%d,%d,%d,%d,%d,%d\n", nim->dim[1], nim->dim[2], nim->dim[3], nim->dim[4], nim->dim[5], nim->dim[6], nim->dim[7], nim->nx, nim->ny, nim->nz, nim->nt, nim->nu, nim->nv, nim->nw ); } if( g_opts.debug > 2 ){ fprintf(stderr,"-d check dim[%d] =", nim->dim[0]); for( c = 0; c < 7; c++ ) fprintf(stderr," %d", nim->dim[c]); fputc('\n', stderr); } /**- check the dimensions, and that their product matches nvox */ prod = 1; for( c = 1; c <= nim->dim[0]; c++ ){ if( nim->dim[c] > 0) prod *= nim->dim[c]; else if( nim->dim[c] <= 0 ){ if( !complain ) return 0; fprintf(stderr,"** NVd: dim[%d] (=%d) <= 0\n",c, nim->dim[c]); errs++; } } if( prod != nim->nvox ){ if( ! complain ) return 0; fprintf(stderr,"** NVd: nvox does not match %d-dim product (%u, %u)\n", nim->dim[0], (unsigned)nim->nvox, (unsigned)prod); errs++; } /**- if debug, warn about any remaining dim that is neither 0, nor 1 */ /* (values in dims above dim[0] are undefined, as reminded by Cinly Ooi and Alle Meije Wink) 16 Nov 2005 [rickr] */ if( g_opts.debug > 1 ) for( c = nim->dim[0]+1; c <= 7; c++ ) if( nim->dim[c] != 0 && nim->dim[c] != 1 ) fprintf(stderr,"** NVd warning: dim[%d] = %d, but ndim = %d\n", c, nim->dim[c], nim->dim[0]); if( g_opts.debug > 2 ) fprintf(stderr,"-d nim_has_valid_dims check, errs = %d\n", errs); /**- return invalid or valid */ if( errs > 0 ) return 0; else return 1; } /*---------------------------------------------------------------------------*/ /*! read a nifti image, collapsed across dimensions according to dims[8]
    
        This function may be used to read parts of a nifti dataset, such as
        the time series for a single voxel, or perhaps a slice.  It is similar
        to nifti_image_load(), though the passed 'data' parameter is used for
        returning the image, not nim->data.
    
        \param nim  given nifti_image struct, corresponding to the data file
        \param dims given list of dimensions (see below)
        \param data pointer to data pointer (if *data is NULL, data will be
                    allocated, otherwise not)
    
        Here, dims is an array of 8 ints, similar to nim->dim[8].  While dims[0]
        is unused at this point, the other indices specify which dimensions to
        collapse (and at which index), and which not to collapse.  If dims[i] is
        set to -1, then that entire dimension will be read in, from index 0 to
        index (nim->dim[i] - 1).  If dims[i] >= 0, then only that index will be
        read in (so dims[i] must also be < nim->dim[i]).
    
        Example: given  nim->dim[8] = { 4, 64, 64, 21, 80, 1, 1, 1 } (4-D dataset)
    
          if dims[8] = { 0,  5,  4, 17, -1, -1, -1, -1 }
             -> read time series for voxel i,j,k = 5,4,17
    
          if dims[8] = { 0, -1, -1, -1, 17, -1, -1, -1 }
             -> read single volume at time point 17
    
        Example: given  nim->dim[8] = { 6, 64, 64, 21, 80, 4, 3, 1 } (6-D dataset)
    
          if dims[8] = { 0, 5, 4, 17, -1, 2, 1, 0 }
             -> read time series for the voxel i,j,k = 5,4,17, and dim 5,6 = 2,1
    
          if dims[8] = { 0, 5, 4, -1, -1, 0, 0, 0 }
             -> read time series for slice at i,j = 5,4, and dim 5,6,7 = 0,0,0
                (note that dims[7] is not relevant, but must be 0 or -1)
    
        If *data is NULL, then *data will be set as a pointer to new memory,
        allocated here for the resulting collapsed image data.
    
          e.g. { int    dims[8] = { 0,  5,  4, 17, -1, -1, -1, -1 };
                 void * data    = NULL;
                 ret_val = nifti_read_collapsed_image(nim, dims, &data);
                 if( ret_val > 0 ){
                    process_time_series(data);
                    if( data != NULL ) free(data);
                 }
               }
    
        NOTE: If *data is not NULL, then it will be assumed that it points to
              valid memory, sufficient to hold the results.  This is done for
              speed and possibly repeated calls to this function.
    
          e.g. { int    dims[8] = { 0,  -1, -1, -1, -1, -1, -1, -1 };
                 void * data    = NULL;
                 for( zslice = 0; zslice < nzslices; zslice++ ){
                    dims[3] = zslice;
                    ret_val = nifti_read_collapsed_image(nim, dims, &data);
                    if( ret_val > 0 ) process_slice(zslice, data);
                 }
                 if( data != NULL ) free(data);
               }
    
        \return
            -  the total number of bytes read, or < 0 on failure
            -  the read and byte-swapped data, in 'data'            
    \sa nifti_image_read, nifti_image_free, nifti_image_read_bricks nifti_image_load *//*-------------------------------------------------------------------------*/ int nifti_read_collapsed_image( nifti_image * nim, const int dims [8], void ** data ) { znzFile fp; int pivots[8], prods[8], nprods; /* sizes are bounded by dims[], so 8 */ int c, bytes; /** - check pointers for sanity */ if( !nim || !dims || !data ){ fprintf(stderr,"** nifti_RCI: bad params %p, %p, %p\n", (void *)nim, (void *)dims, (void *)data); return -1; } if( g_opts.debug > 2 ){ fprintf(stderr,"-d read_collapsed_image:\n dims ="); for(c = 0; c < 8; c++) fprintf(stderr," %3d", dims[c]); fprintf(stderr,"\n nim->dims ="); for(c = 0; c < 8; c++) fprintf(stderr," %3d", nim->dim[c]); fputc('\n', stderr); } /** - verify that dim[] makes sense */ if( ! nifti_nim_is_valid(nim, g_opts.debug > 0) ){ fprintf(stderr,"** invalid nim (file is '%s')\n", nim->fname ); return -1; } /** - verify that dims[] makes sense for this dataset */ for( c = 1; c <= nim->dim[0]; c++ ){ if( dims[c] >= nim->dim[c] ){ fprintf(stderr,"** nifti_RCI: dims[%d] >= nim->dim[%d] (%d,%d)\n", c, c, dims[c], nim->dim[c]); return -1; } } /** - prepare pivot list - pivots are fixed indices */ if( make_pivot_list(nim, dims, pivots, prods, &nprods) < 0 ) return -1; bytes = rci_alloc_mem(data, prods, nprods, nim->nbyper); if( bytes < 0 ) return -1; /** - open the image file for reading at the appropriate offset */ fp = nifti_image_load_prep( nim ); if( ! fp ){ free(*data); *data = NULL; return -1; } /* failure */ /** - call the recursive reading function, passing nim, the pivot info, location to store memory, and file pointer and position */ c = rci_read_data(nim, pivots,prods,nprods,dims, (char *)*data, fp, znztell(fp)); znzclose(fp); /* in any case, close the file */ if( c < 0 ){ free(*data); *data = NULL; return -1; } /* failure */ if( g_opts.debug > 1 ) fprintf(stderr,"+d read %d bytes of collapsed image from %s\n", bytes, nim->fname); return bytes; } /* local function to find strides per dimension. assumes 7D size and ** stride array. */ static void compute_strides(int *strides,const int *size,int nbyper) { int i; strides[0] = nbyper; for(i = 1; i < 7; i++) { strides[i] = size[i-1] * strides[i-1]; } } /*---------------------------------------------------------------------------*/ /*! read an arbitrary subregion from a nifti image This function may be used to read a single arbitary subregion of any rectangular size from a nifti dataset, such as a small 5x5x5 subregion around the center of a 3D image. \param nim given nifti_image struct, corresponding to the data file \param start_index the index location of the first voxel that will be returned \param region_size the size of the subregion to be returned \param data pointer to data pointer (if *data is NULL, data will be allocated, otherwise not) Example: given nim->dim[8] = {3, 64, 64, 64, 1, 1, 1, 1 } (3-D dataset) if start_index[7] = { 29, 29, 29, 0, 0, 0, 0 } and region_size[7] = { 5, 5, 5, 1, 1, 1, 1 } -> read 5x5x5 region starting with the first voxel location at (29,29,29) NOTE: If *data is not NULL, then it will be assumed that it points to valid memory, sufficient to hold the results. This is done for speed and possibly repeated calls to this function. \return - the total number of bytes read, or < 0 on failure - the read and byte-swapped data, in 'data' \sa nifti_image_read, nifti_image_free, nifti_image_read_bricks nifti_image_load, nifti_read_collapsed_image *//*-------------------------------------------------------------------------*/ int nifti_read_subregion_image( nifti_image * nim, int *start_index, int *region_size, void ** data ) { znzFile fp; /* file to read */ int i,j,k,l,m,n; /* indices for dims */ long int bytes = 0; /* total # bytes read */ int total_alloc_size; /* size of buffer allocation */ char *readptr; /* where in *data to read next */ int strides[7]; /* strides between dimensions */ int collapsed_dims[8]; /* for read_collapsed_image */ int *image_size; /* pointer to dimensions in header */ long int initial_offset; long int offset; /* seek offset for reading current row */ /* probably ignored, but set to ndim for consistency*/ collapsed_dims[0] = nim->ndim; /* build a dims array for collapsed image read */ for(i = 0; i < nim->ndim; i++) { /* if you take the whole extent in this dimension */ if(start_index[i] == 0 && region_size[i] == nim->dim[i+1]) { collapsed_dims[i+1] = -1; } /* if you specify a single element in this dimension */ else if(region_size[i] == 1) { collapsed_dims[i+1] = start_index[i]; } else { collapsed_dims[i+1] = -2; /* sentinel value */ } } /* fill out end of collapsed_dims */ for(i = nim->ndim ; i < 7; i++) { collapsed_dims[i+1] = -1; } /* check to see whether collapsed read is possible */ for(i = 1; i <= nim->ndim; i++) { if(collapsed_dims[i] == -2) { break; } } /* if you get through all the dimensions without hitting ** a subrange of size > 1, a collapsed read is possible */ if(i > nim->ndim) { return nifti_read_collapsed_image(nim, collapsed_dims, data); } /* point past first element of dim, which holds nim->ndim */ image_size = &(nim->dim[1]); /* check region sizes for sanity */ for(i = 0; i < nim->ndim; i++) { if(start_index[i] + region_size[i] > image_size[i]) { if(g_opts.debug > 1) { fprintf(stderr,"region doesn't fit within image size\n"); } return -1; } } /* get the file open */ fp = nifti_image_load_prep( nim ); /* the current offset is just past the nifti header, save * location so that SEEK_SET can be used below */ initial_offset = znztell(fp); /* get strides*/ compute_strides(strides,image_size,nim->nbyper); total_alloc_size = nim->nbyper; /* size of pixel */ /* find alloc size */ for(i = 0; i < nim->ndim; i++) { total_alloc_size *= region_size[i]; } /* allocate buffer, if necessary */ if(*data == 0) { *data = (void *)malloc(total_alloc_size); } if(*data == 0) { if(g_opts.debug > 1) { fprintf(stderr,"allocation of %d bytes failed\n",total_alloc_size); return -1; } } /* point to start of data buffer as char * */ readptr = *((char **)data); { /* can't assume that start_index and region_size have any more than ** nim->ndim elements so make local copies, filled out to seven elements */ int si[7], rs[7]; for(i = 0; i < nim->ndim; i++) { si[i] = start_index[i]; rs[i] = region_size[i]; } for(i = nim->ndim; i < 7; i++) { si[i] = 0; rs[i] = 1; } /* loop through subregion and read a row at a time */ for(i = si[6]; i < (si[6] + rs[6]); i++) { for(j = si[5]; j < (si[5] + rs[5]); j++) { for(k = si[4]; k < (si[4] + rs[4]); k++) { for(l = si[3]; l < (si[3] + rs[3]); l++) { for(m = si[2]; m < (si[2] + rs[2]); m++) { for(n = si[1]; n < (si[1] + rs[1]); n++) { int nread,read_amount; offset = initial_offset + (i * strides[6]) + (j * strides[5]) + (k * strides[4]) + (l * strides[3]) + (m * strides[2]) + (n * strides[1]) + (si[0] * strides[0]); znzseek(fp, offset, SEEK_SET); /* seek to current row */ read_amount = rs[0] * nim->nbyper; /* read a row of the subregion*/ nread = nifti_read_buffer(fp, readptr, read_amount, nim); if(nread != read_amount) { if(g_opts.debug > 1) { fprintf(stderr,"read of %d bytes failed\n",read_amount); return -1; } } bytes += nread; readptr += read_amount; } } } } } } } return bytes; } /* read the data from the file pointed to by fp - this a recursive function, so start with the base case - data is now (char *) for easy incrementing return 0 on success, < 0 on failure */ static int rci_read_data(nifti_image * nim, int * pivots, int * prods, int nprods, const int dims[], char * data, znzFile fp, size_t base_offset) { size_t sublen, offset, read_size; int c; /* bad check first - base_offset may not have been checked */ if( nprods <= 0 ){ fprintf(stderr,"** rci_read_data, bad prods, %d\n", nprods); return -1; } /* base case: actually read the data */ if( nprods == 1 ){ size_t nread, bytes; /* make sure things look good here */ if( *pivots != 0 ){ fprintf(stderr,"** rciRD: final pivot == %d!\n", *pivots); return -1; } /* so just seek and read (prods[0] * nbyper) bytes from the file */ znzseek(fp, base_offset, SEEK_SET); bytes = (size_t)prods[0] * nim->nbyper; nread = nifti_read_buffer(fp, data, bytes, nim); if( nread != bytes ){ fprintf(stderr,"** rciRD: read only %u of %u bytes from '%s'\n", (unsigned)nread, (unsigned)bytes, nim->fname); return -1; } else if( g_opts.debug > 3 ) fprintf(stderr,"+d successful read of %u bytes at offset %u\n", (unsigned)bytes, (unsigned)base_offset); return 0; /* done with base case - return success */ } /* not the base case, so do a set of reduced reads */ /* compute size of sub-brick: all dimensions below pivot */ for( c = 1, sublen = 1; c < *pivots; c++ ) sublen *= nim->dim[c]; /* compute number of values to read, i.e. remaining prods */ for( c = 1, read_size = 1; c < nprods; c++ ) read_size *= prods[c]; read_size *= nim->nbyper; /* and multiply by bytes per voxel */ /* now repeatedly compute offsets, and recursively read */ for( c = 0; c < prods[0]; c++ ){ /* offset is (c * sub-block size (including pivot dim)) */ /* + (dims[] index into pivot sub-block) */ /* the unneeded multiplication is to make this more clear */ offset = (size_t)c * sublen * nim->dim[*pivots] + (size_t)sublen * dims[*pivots]; offset *= nim->nbyper; if( g_opts.debug > 3 ) fprintf(stderr,"-d reading %u bytes, foff %u + %u, doff %u\n", (unsigned)read_size, (unsigned)base_offset, (unsigned)offset, (unsigned)(c*read_size)); /* now read the next level down, adding this offset */ if( rci_read_data(nim, pivots+1, prods+1, nprods-1, dims, data + c * read_size, fp, base_offset + offset) < 0 ) return -1; } return 0; } /* allocate memory for all collapsed image data If *data is already set, do not allocate, but still calculate size for debug report. return total size on success, and < 0 on failure */ static int rci_alloc_mem(void ** data, int prods[8], int nprods, int nbyper ) { int size, index; if( nbyper < 0 || nprods < 1 || nprods > 8 ){ fprintf(stderr,"** rci_am: bad params, %d, %d\n", nbyper, nprods); return -1; } for( index = 0, size = 1; index < nprods; index++ ) size *= prods[index]; size *= nbyper; if( ! *data ){ /* then allocate what is needed */ if( g_opts.debug > 1 ) fprintf(stderr,"+d alloc %d (= %d x %d) bytes for collapsed image\n", size, size/nbyper, nbyper); *data = malloc(size); /* actually allocate the memory */ if( ! *data ){ fprintf(stderr,"** rci_am: failed to alloc %d bytes for data\n", size); return -1; } } else if( g_opts.debug > 1 ) fprintf(stderr,"-d rci_am: *data already set, need %d (%d x %d) bytes\n", size, size/nbyper, nbyper); return size; } /* prepare a pivot list for reading The pivot points are the indices into dims where the calling function wants to collapse a dimension. The last pivot should always be zero (note that we have space for that in the lists). */ static int make_pivot_list(nifti_image * nim, const int dims[], int pivots[], int prods[], int * nprods ) { int len, index; len = 0; index = nim->dim[0]; while( index > 0 ){ prods[len] = 1; while( index > 0 && (nim->dim[index] == 1 || dims[index] == -1) ){ prods[len] *= nim->dim[index]; index--; } pivots[len] = index; len++; index--; /* fine, let it drop out at -1 */ } /* make sure to include 0 as a pivot (instead of just 1, if it is) */ if( pivots[len-1] != 0 ){ pivots[len] = 0; prods[len] = 1; len++; } *nprods = len; if( g_opts.debug > 2 ){ fprintf(stderr,"+d pivot list created, pivots :"); for(index = 0; index < len; index++) fprintf(stderr," %d", pivots[index]); fprintf(stderr,", prods :"); for(index = 0; index < len; index++) fprintf(stderr," %d", prods[index]); fputc('\n',stderr); } return 0; } #undef ISEND #define ISEND(c) ( (c)==']' || (c)=='}' || (c)=='\0' ) /*---------------------------------------------------------------------*/ /*! Get an integer list in the range 0..(nvals-1), from the character string str. If we call the output pointer fred, then fred[0] = number of integers in the list (> 0), and fred[i] = i-th integer in the list for i=1..fred[0]. If on return, fred == NULL or fred[0] == 0, then something is wrong, and the caller must deal with that. Syntax of input string: - initial '{' or '[' is skipped, if present - ends when '}' or ']' or end of string is found - contains entries separated by commas - entries have one of these forms: - a single number - a dollar sign '$', which means nvals-1 - a sequence of consecutive numbers in the form "a..b" or "a-b", where "a" and "b" are single numbers (or '$') - a sequence of evenly spaced numbers in the form "a..b(c)" or "a-b(c)", where "c" encodes the step - Example: "[2,7..4,3..9(2)]" decodes to the list 2 7 6 5 4 3 5 7 9 - entries should be in the range 0..nvals-1 (borrowed, with permission, from thd_intlist.c) *//*-------------------------------------------------------------------*/ int * nifti_get_intlist( int nvals , const char * str ) { int *subv = NULL ; int ii , ipos , nout , slen ; int ibot,itop,istep , nused ; char *cpt ; /* Meaningless input? */ if( nvals < 1 ) return NULL ; /* No selection list? */ if( str == NULL || str[0] == '\0' ) return NULL ; /* skip initial '[' or '{' */ subv = (int *) malloc( sizeof(int) * 2 ) ; subv[0] = nout = 0 ; ipos = 0 ; if( str[ipos] == '[' || str[ipos] == '{' ) ipos++ ; if( g_opts.debug > 1 ) fprintf(stderr,"-d making int_list (vals = %d) from '%s'\n", nvals, str); /**- for each sub-selector until end of input... */ slen = strlen(str) ; while( ipos < slen && !ISEND(str[ipos]) ){ while( isspace(str[ipos]) ) ipos++ ; /* skip blanks */ if( ISEND(str[ipos]) ) break ; /* done */ /**- get starting value */ if( str[ipos] == '$' ){ /* special case */ ibot = nvals-1 ; ipos++ ; } else { /* decode an integer */ ibot = strtol( str+ipos , &cpt , 10 ) ; if( ibot < 0 ){ fprintf(stderr,"** ERROR: list index %d is out of range 0..%d\n", ibot,nvals-1) ; free(subv) ; return NULL ; } if( ibot >= nvals ){ fprintf(stderr,"** ERROR: list index %d is out of range 0..%d\n", ibot,nvals-1) ; free(subv) ; return NULL ; } nused = (cpt-(str+ipos)) ; if( ibot == 0 && nused == 0 ){ fprintf(stderr,"** ERROR: list syntax error '%s'\n",str+ipos) ; free(subv) ; return NULL ; } ipos += nused ; } while( isspace(str[ipos]) ) ipos++ ; /* skip blanks */ /**- if that's it for this sub-selector, add one value to list */ if( str[ipos] == ',' || ISEND(str[ipos]) ){ nout++ ; subv = (int *) realloc( (char *)subv , sizeof(int) * (nout+1) ) ; subv[0] = nout ; subv[nout] = ibot ; if( ISEND(str[ipos]) ) break ; /* done */ ipos++ ; continue ; /* re-start loop at next sub-selector */ } /**- otherwise, must have '..' or '-' as next inputs */ if( str[ipos] == '-' ){ ipos++ ; } else if( str[ipos] == '.' && str[ipos+1] == '.' ){ ipos++ ; ipos++ ; } else { fprintf(stderr,"** ERROR: index list syntax is bad: '%s'\n", str+ipos) ; free(subv) ; return NULL ; } /**- get ending value for loop now */ if( str[ipos] == '$' ){ /* special case */ itop = nvals-1 ; ipos++ ; } else { /* decode an integer */ itop = strtol( str+ipos , &cpt , 10 ) ; if( itop < 0 ){ fprintf(stderr,"** ERROR: index %d is out of range 0..%d\n", itop,nvals-1) ; free(subv) ; return NULL ; } if( itop >= nvals ){ fprintf(stderr,"** ERROR: index %d is out of range 0..%d\n", itop,nvals-1) ; free(subv) ; return NULL ; } nused = (cpt-(str+ipos)) ; if( itop == 0 && nused == 0 ){ fprintf(stderr,"** ERROR: index list syntax error '%s'\n",str+ipos) ; free(subv) ; return NULL ; } ipos += nused ; } /**- set default loop step */ istep = (ibot <= itop) ? 1 : -1 ; while( isspace(str[ipos]) ) ipos++ ; /* skip blanks */ /**- check if we have a non-default loop step */ if( str[ipos] == '(' ){ /* decode an integer */ ipos++ ; istep = strtol( str+ipos , &cpt , 10 ) ; if( istep == 0 ){ fprintf(stderr,"** ERROR: index loop step is 0!\n") ; free(subv) ; return NULL ; } nused = (cpt-(str+ipos)) ; ipos += nused ; if( str[ipos] == ')' ) ipos++ ; if( (ibot-itop)*istep > 0 ){ fprintf(stderr,"** WARNING: index list '%d..%d(%d)' means nothing\n", ibot,itop,istep ) ; } } /**- add values to output */ for( ii=ibot ; (ii-itop)*istep <= 0 ; ii += istep ){ nout++ ; subv = (int *) realloc( (char *)subv , sizeof(int) * (nout+1) ) ; subv[0] = nout ; subv[nout] = ii ; } /**- check if we have a comma to skip over */ while( isspace(str[ipos]) ) ipos++ ; /* skip blanks */ if( str[ipos] == ',' ) ipos++ ; /* skip commas */ } /* end of loop through selector string */ if( g_opts.debug > 1 ) { fprintf(stderr,"+d int_list (vals = %d): ", subv[0]); for( ii = 1; ii <= subv[0]; ii++ ) fprintf(stderr,"%d ", subv[ii]); fputc('\n',stderr); } if( subv[0] == 0 ){ free(subv); subv = NULL; } return subv ; } /*---------------------------------------------------------------------*/ /*! Given a NIFTI_TYPE string, such as "NIFTI_TYPE_INT16", return the * corresponding integral type code. The type code is the macro * value defined in nifti1.h. *//*-------------------------------------------------------------------*/ int nifti_datatype_from_string( const char * name ) { int tablen = sizeof(nifti_type_list)/sizeof(nifti_type_ele); int c; if( !name ) return DT_UNKNOWN; for( c = tablen-1; c > 0; c-- ) if( !strcmp(name, nifti_type_list[c].name) ) break; return nifti_type_list[c].type; } /*---------------------------------------------------------------------*/ /*! Given a NIFTI_TYPE value, such as NIFTI_TYPE_INT16, return the * corresponding macro label as a string. The dtype code is the * macro value defined in nifti1.h. *//*-------------------------------------------------------------------*/ char * nifti_datatype_to_string( int dtype ) { int tablen = sizeof(nifti_type_list)/sizeof(nifti_type_ele); int c; for( c = tablen-1; c > 0; c-- ) if( nifti_type_list[c].type == dtype ) break; return nifti_type_list[c].name; } /*---------------------------------------------------------------------*/ /*! Determine whether dtype is a valid NIFTI_TYPE. * * DT_UNKNOWN is considered invalid * * The only difference 'for_nifti' makes is that DT_BINARY * should be invalid for a NIfTI dataset. *//*-------------------------------------------------------------------*/ int nifti_datatype_is_valid( int dtype, int for_nifti ) { int tablen = sizeof(nifti_type_list)/sizeof(nifti_type_ele); int c; /* special case */ if( for_nifti && dtype == DT_BINARY ) return 0; for( c = tablen-1; c > 0; c-- ) if( nifti_type_list[c].type == dtype ) return 1; return 0; } /*---------------------------------------------------------------------*/ /*! Only as a test, verify that the new nifti_type_list table matches * the the usage of nifti_datatype_sizes (which could be changed to * use the table, if there were interest). * * return the number of errors (so 0 is success, as usual) *//*-------------------------------------------------------------------*/ int nifti_test_datatype_sizes(int verb) { int tablen = sizeof(nifti_type_list)/sizeof(nifti_type_ele); int nbyper, ssize; int c, errs = 0; for( c = 0; c < tablen; c++ ) { nbyper = ssize = -1; nifti_datatype_sizes(nifti_type_list[c].type, &nbyper, &ssize); if( nbyper < 0 || ssize < 0 || nbyper != nifti_type_list[c].nbyper || ssize != nifti_type_list[c].swapsize ) { if( verb || g_opts.debug > 2 ) fprintf(stderr, "** type mismatch: %s, %d, %d, %d : %d, %d\n", nifti_type_list[c].name, nifti_type_list[c].type, nifti_type_list[c].nbyper, nifti_type_list[c].swapsize, nbyper, ssize); errs++; } } if( errs ) fprintf(stderr,"** nifti_test_datatype_sizes: found %d errors\n",errs); else if( verb || g_opts.debug > 1 ) fprintf(stderr,"-- nifti_test_datatype_sizes: all OK\n"); return errs; } /*---------------------------------------------------------------------*/ /*! Display the nifti_type_list table. * * if which == 1 : display DT_* * if which == 2 : display NIFTI_TYPE* * else : display all *//*-------------------------------------------------------------------*/ int nifti_disp_type_list( int which ) { char * style; int tablen = sizeof(nifti_type_list)/sizeof(nifti_type_ele); int lwhich, c; if ( which == 1 ){ lwhich = 1; style = "DT_"; } else if( which == 2 ){ lwhich = 2; style = "NIFTI_TYPE_"; } else { lwhich = 3; style = "ALL"; } printf("nifti_type_list entries (%s) :\n" " name type nbyper swapsize\n" " --------------------- ---- ------ --------\n", style); for( c = 0; c < tablen; c++ ) if( (lwhich & 1 && nifti_type_list[c].name[0] == 'D') || (lwhich & 2 && nifti_type_list[c].name[0] == 'N') ) printf(" %-22s %5d %3d %5d\n", nifti_type_list[c].name, nifti_type_list[c].type, nifti_type_list[c].nbyper, nifti_type_list[c].swapsize); return 0; } pynifti-0.20100607.1/3rd/nifticlibs/LICENSE0000664000175000017500000000060411414645202017344 0ustar michaelmichaelNiftilib has been developed by members of the NIFTI DFWG and volunteers in the neuroimaging community and serves as a reference implementation of the nifti-1 file format. http://nifti.nimh.nih.gov/ Nifticlib code is released into the public domain, developers are encouraged to incorporate niftilib code into their applications, and, to contribute changes and enhancements to niftilib. pynifti-0.20100607.1/3rd/nifticlibs/Makefile.win0000775000175000017500000000067011414645202020601 0ustar michaelmichael# Minimalistic makefile for libnifti LIB=libniftiio.a libznz.a MISC=nifti1_io.c znzlib.c LIBFLAGS= CFLAGS=-Wall -O2 -I. -DHAVE_ZLIB -DWIN32 TDIR=..\..\build\nifticlibs all: prep $(LIB) prep: -mkdir ..\..\build -mkdir $(TDIR) .c.o: gcc $(CFLAGS) $(LIBFLAGS) -c $^ -o $(TDIR)\$(^:.c=.o) libniftiio.a: nifti1_io.o ar curs $(TDIR)\$@ $(TDIR)\$^ libznz.a: znzlib.o ar curs $(TDIR)\$@ $(TDIR)\$^ clean: -rmdir $(TDIR) -del *-stamp pynifti-0.20100607.1/3rd/nifticlibs/znzlib.h0000664000175000017500000000572411414645202020030 0ustar michaelmichael#ifndef _ZNZLIB_H_ #define _ZNZLIB_H_ /* znzlib.h (zipped or non-zipped library) ***** This code is released to the public domain. ***** ***** Author: Mark Jenkinson, FMRIB Centre, University of Oxford ***** ***** Date: September 2004 ***** ***** Neither the FMRIB Centre, the University of Oxford, nor any of ***** ***** its employees imply any warranty of usefulness of this software ***** ***** for any purpose, and do not assume any liability for damages, ***** ***** incidental or otherwise, caused by any use of this document. ***** */ /* This library provides an interface to both compressed (gzip/zlib) and uncompressed (normal) file IO. The functions are written to have the same interface as the standard file IO functions. To use this library instead of normal file IO, the following changes are required: - replace all instances of FILE* with znzFile - change the name of all function calls, replacing the initial character f with the znz (e.g. fseek becomes znzseek) - add a third parameter to all calls to znzopen (previously fopen) that specifies whether to use compression (1) or not (0) - use znz_isnull rather than any (pointer == NULL) comparisons in the code NB: seeks for writable files with compression are quite restricted */ /*=================*/ #ifdef __cplusplus extern "C" { #endif /*=================*/ #include #include #include #include /* include optional check for HAVE_FDOPEN here, from deleted config.h: uncomment the following line if fdopen() exists for your compiler and compiler options */ /* #define HAVE_FDOPEN */ #ifdef HAVE_ZLIB #if defined(ITKZLIB) #include "itk_zlib.h" #else #include "zlib.h" #endif #endif struct znzptr { int withz; FILE* nzfptr; #ifdef HAVE_ZLIB gzFile zfptr; #endif } ; /* the type for all file pointers */ typedef struct znzptr * znzFile; /* int znz_isnull(znzFile f); */ /* int znzclose(znzFile f); */ #define znz_isnull(f) ((f) == NULL) #define znzclose(f) Xznzclose(&(f)) /* Note extra argument (use_compression) where use_compression==0 is no compression use_compression!=0 uses zlib (gzip) compression */ znzFile znzopen(const char *path, const char *mode, int use_compression); znzFile znzdopen(int fd, const char *mode, int use_compression); int Xznzclose(znzFile * file); size_t znzread(void* buf, size_t size, size_t nmemb, znzFile file); size_t znzwrite(const void* buf, size_t size, size_t nmemb, znzFile file); long znzseek(znzFile file, long offset, int whence); int znzrewind(znzFile stream); long znztell(znzFile file); int znzputs(const char *str, znzFile file); char * znzgets(char* str, int size, znzFile file); int znzputc(int c, znzFile file); int znzgetc(znzFile file); #if !defined(WIN32) int znzprintf(znzFile stream, const char *format, ...); #endif /*=================*/ #ifdef __cplusplus } #endif /*=================*/ #endif pynifti-0.20100607.1/3rd/nifticlibs/znzlib.c0000664000175000017500000001477411414645202020030 0ustar michaelmichael/** \file znzlib.c \brief Low level i/o interface to compressed and noncompressed files. Written by Mark Jenkinson, FMRIB This library provides an interface to both compressed (gzip/zlib) and uncompressed (normal) file IO. The functions are written to have the same interface as the standard file IO functions. To use this library instead of normal file IO, the following changes are required: - replace all instances of FILE* with znzFile - change the name of all function calls, replacing the initial character f with the znz (e.g. fseek becomes znzseek) one exception is rewind() -> znzrewind() - add a third parameter to all calls to znzopen (previously fopen) that specifies whether to use compression (1) or not (0) - use znz_isnull rather than any (pointer == NULL) comparisons in the code for znzfile types (normally done after a return from znzopen) NB: seeks for writable files with compression are quite restricted */ #include "znzlib.h" /* znzlib.c (zipped or non-zipped library) ***** This code is released to the public domain. ***** ***** Author: Mark Jenkinson, FMRIB Centre, University of Oxford ***** ***** Date: September 2004 ***** ***** Neither the FMRIB Centre, the University of Oxford, nor any of ***** ***** its employees imply any warranty of usefulness of this software ***** ***** for any purpose, and do not assume any liability for damages, ***** ***** incidental or otherwise, caused by any use of this document. ***** */ /* Note extra argument (use_compression) where use_compression==0 is no compression use_compression!=0 uses zlib (gzip) compression */ znzFile znzopen(const char *path, const char *mode, int use_compression) { znzFile file; file = (znzFile) calloc(1,sizeof(struct znzptr)); if( file == NULL ){ fprintf(stderr,"** ERROR: znzopen failed to alloc znzptr\n"); return NULL; } file->nzfptr = NULL; #ifdef HAVE_ZLIB file->zfptr = NULL; if (use_compression) { file->withz = 1; if((file->zfptr = gzopen(path,mode)) == NULL) { free(file); file = NULL; } } else { #endif file->withz = 0; if((file->nzfptr = fopen(path,mode)) == NULL) { free(file); file = NULL; } #ifdef HAVE_ZLIB } #endif return file; } znzFile znzdopen(int fd, const char *mode, int use_compression) { znzFile file; file = (znzFile) calloc(1,sizeof(struct znzptr)); if( file == NULL ){ fprintf(stderr,"** ERROR: znzdopen failed to alloc znzptr\n"); return NULL; } #ifdef HAVE_ZLIB if (use_compression) { file->withz = 1; file->zfptr = gzdopen(fd,mode); file->nzfptr = NULL; } else { #endif file->withz = 0; #ifdef HAVE_FDOPEN file->nzfptr = fdopen(fd,mode); #endif #ifdef HAVE_ZLIB file->zfptr = NULL; }; #endif return file; } int Xznzclose(znzFile * file) { int retval = 0; if (*file!=NULL) { #ifdef HAVE_ZLIB if ((*file)->zfptr!=NULL) { retval = gzclose((*file)->zfptr); } #endif if ((*file)->nzfptr!=NULL) { retval = fclose((*file)->nzfptr); } free(*file); *file = NULL; } return retval; } size_t znzread(void* buf, size_t size, size_t nmemb, znzFile file) { if (file==NULL) { return 0; } #ifdef HAVE_ZLIB if (file->zfptr!=NULL) return (size_t) (gzread(file->zfptr,buf,((int) size)*((int) nmemb)) / size); #endif return fread(buf,size,nmemb,file->nzfptr); } size_t znzwrite(const void* buf, size_t size, size_t nmemb, znzFile file) { if (file==NULL) { return 0; } #ifdef HAVE_ZLIB if (file->zfptr!=NULL) { /* NOTE: We must typecast const away from the buffer because gzwrite does not have complete const specification */ return (size_t) ( gzwrite(file->zfptr,(void *)buf,size*nmemb) / size ); } #endif return fwrite(buf,size,nmemb,file->nzfptr); } long znzseek(znzFile file, long offset, int whence) { if (file==NULL) { return 0; } #ifdef HAVE_ZLIB if (file->zfptr!=NULL) return (long) gzseek(file->zfptr,offset,whence); #endif return fseek(file->nzfptr,offset,whence); } int znzrewind(znzFile stream) { if (stream==NULL) { return 0; } #ifdef HAVE_ZLIB /* On some systems, gzrewind() fails for uncompressed files. Use gzseek(), instead. 10, May 2005 [rickr] if (stream->zfptr!=NULL) return gzrewind(stream->zfptr); */ if (stream->zfptr!=NULL) return (int)gzseek(stream->zfptr, 0L, SEEK_SET); #endif rewind(stream->nzfptr); return 0; } long znztell(znzFile file) { if (file==NULL) { return 0; } #ifdef HAVE_ZLIB if (file->zfptr!=NULL) return (long) gztell(file->zfptr); #endif return ftell(file->nzfptr); } int znzputs(const char * str, znzFile file) { if (file==NULL) { return 0; } #ifdef HAVE_ZLIB if (file->zfptr!=NULL) return gzputs(file->zfptr,str); #endif return fputs(str,file->nzfptr); } char * znzgets(char* str, int size, znzFile file) { if (file==NULL) { return NULL; } #ifdef HAVE_ZLIB if (file->zfptr!=NULL) return gzgets(file->zfptr,str,size); #endif return fgets(str,size,file->nzfptr); } int znzflush(znzFile file) { if (file==NULL) { return 0; } #ifdef HAVE_ZLIB if (file->zfptr!=NULL) return gzflush(file->zfptr,Z_SYNC_FLUSH); #endif return fflush(file->nzfptr); } int znzeof(znzFile file) { if (file==NULL) { return 0; } #ifdef HAVE_ZLIB if (file->zfptr!=NULL) return gzeof(file->zfptr); #endif return feof(file->nzfptr); } int znzputc(int c, znzFile file) { if (file==NULL) { return 0; } #ifdef HAVE_ZLIB if (file->zfptr!=NULL) return gzputc(file->zfptr,c); #endif return fputc(c,file->nzfptr); } int znzgetc(znzFile file) { if (file==NULL) { return 0; } #ifdef HAVE_ZLIB if (file->zfptr!=NULL) return gzgetc(file->zfptr); #endif return fgetc(file->nzfptr); } #if !defined (WIN32) int znzprintf(znzFile stream, const char *format, ...) { int retval=0; char *tmpstr; va_list va; if (stream==NULL) { return 0; } va_start(va, format); #ifdef HAVE_ZLIB if (stream->zfptr!=NULL) { int size; /* local to HAVE_ZLIB block */ size = strlen(format) + 1000000; /* overkill I hope */ tmpstr = (char *)calloc(1, size); if( tmpstr == NULL ){ fprintf(stderr,"** ERROR: znzprintf failed to alloc %d bytes\n", size); return retval; } vsprintf(tmpstr,format,va); retval=gzprintf(stream->zfptr,"%s",tmpstr); free(tmpstr); } else #endif { retval=vfprintf(stream->nzfptr,format,va); } va_end(va); return retval; } #endif pynifti-0.20100607.1/tests/0000775000175000017500000000000011414646040014664 5ustar michaelmichaelpynifti-0.20100607.1/tests/test_utils.py0000664000175000017500000000205311414645202017434 0ustar michaelmichael### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### # # Unit tests for PyNIfTI file io # # Copyright (C) 2007 by # Michael Hanke # # This is free software; you can redistribute it and/or # modify it under the terms of the MIT License. # # This package is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the COPYING # file that comes with this package for more details. # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### import nifti.utils import numpy as N import unittest class UtilsTests(unittest.TestCase): def testZScoring(self): # dataset: mean=2, std=1 data = N.array( (0,1,3,4,2,2,3,1,1,3,3,1,2,2,2,2) ) self.failUnlessEqual( data.mean(), 2.0 ) self.failUnlessEqual( data.std(), 1.0 ) def suite(): return unittest.makeSuite(UtilsTests) if __name__ == '__main__': unittest.main() pynifti-0.20100607.1/tests/test_format.py0000664000175000017500000000323511414645202017567 0ustar michaelmichael#emacs: -*- mode: python-mode; py-indent-offset: 4; indent-tabs-mode: nil -*- #ex: set sts=4 ts=4 sw=4 et: ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ## # # See COPYING file distributed along with the PyNIfTI package for the # copyright and license terms. # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ## """Unit tests for PyNIfTI header class""" __docformat__ = 'restructuredtext' from nifti.format import NiftiFormat import unittest import numpy as N class NiftiFormatTests(unittest.TestCase): def testLoadHdrFromFile(self): nhdr = NiftiFormat('data/example4d.nii.gz') # basic incomplete property check self.failUnlessEqual(nhdr.extent, (128, 96, 24, 2)) self.failUnlessEqual(nhdr.rtime, 2000) self.failUnlessEqual(nhdr.pixdim, (2.0, 2.0, 2.1999990940093994, 2000.0, 1.0, 1.0, 1.0)) self.failUnlessEqual(nhdr.extent, (128, 96, 24, 2)) self.failUnlessEqual(nhdr.voxdim, (2.0, 2.0, 2.1999990940093994)) self.failUnlessEqual(nhdr.extent, (128, 96, 24, 2)) self.failUnlessEqual(nhdr.header['datatype'], 4) self.failUnlessEqual(nhdr.header['bitpix'], 16) self.failUnlessEqual(nhdr.header['magic'], 'n+1') def testLoadHdrFromArray(self): nhdr = NiftiFormat(N.zeros((4,3,2))) # basic incomplete property check self.failUnlessEqual(nhdr.extent, (2, 3, 4)) self.failUnlessEqual(nhdr.rtime, 0) def suite(): return unittest.makeSuite(NiftiFormatTests) if __name__ == '__main__': unittest.main() pynifti-0.20100607.1/tests/test_misc.py0000664000175000017500000000600111414645202017224 0ustar michaelmichael#emacs: -*- mode: python-mode; py-indent-offset: 4; indent-tabs-mode: nil -*- #ex: set sts=4 ts=4 sw=4 et: ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ## # # See COPYING file distributed along with the PyNIfTI package for the # copyright and license terms. # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ## """Misc unit tests for PyNIfTI""" __docformat__ = 'restructuredtext' import os import numpy as N from nifti import * import nifti.clib as ncl from nifti.format import NiftiFormat import unittest import cPickle class MiscTests(unittest.TestCase): def testFilenameProps(self): def helper(obj, filename): obj.filename = filename nif = NiftiFormat(os.path.join('data', 'example4d')) self.failUnlessRaises(AttributeError, helper, nif, 'test.nii') nim = NiftiImage(os.path.join('data', 'example4d')) nim.filename = 'test.nii' self.failUnless(nim.filename == 'test.nii') def testArrayAssign(self): """Test whether the header is updated correctly when assigning a new data array""" orig_array = N.ones((2,3,4), dtype='float') nimg = NiftiImage(orig_array) self.failUnless(nimg.header['dim'] == [3, 4, 3, 2, 1, 1, 1, 1]) self.failUnless(nimg.raw_nimg.datatype == ncl.NIFTI_TYPE_FLOAT64) # now turn that image into 4d with ints alt_array = N.zeros((4,5,6,7), dtype='int32') nimg.data = alt_array self.failUnless(nimg.data.shape == alt_array.shape) self.failUnless(nimg.header['dim'] == [4, 7, 6, 5, 4, 1, 1, 1]) self.failUnless(nimg.raw_nimg.datatype == ncl.NIFTI_TYPE_INT32) def testCopying(self): nim = NiftiImage(os.path.join('data', 'example4d')) n2 = nim.copy() n2.voxdim = (2,3,4) n2.data[0,3,4,2] = 543 self.failUnless(n2.voxdim == (2,3,4)) self.failIf(nim.voxdim == n2.voxdim) self.failUnless(n2.data[0,3,4,2] == 543) self.failIf(nim.data[0,3,4,2] == n2.data[0,3,4,2]) # XXX Disabled since the corresponding method is temporally unavailable. # # def testVolumeIter(self): # nim = NiftiImage(os.path.join('data', 'example4d')) # # vols = [v for v in nim.iterVolumes()] # # self.failUnless(len(vols) == 2) # # for v in vols: # self.failUnless(v.extent == v.volextent == nim.volextent) # # # test if data is shared # vols[1].data[20,10,5] = 666 # # # check if copying works # print vols[1].data[20,10,5] # print nim.data[1,20,10,5] def testPickleCycle(self): nim = NiftiImage(os.path.join('data', 'example4d')) pickled = cPickle.dumps(nim) nim2 = cPickle.loads(pickled) self.failUnless((nim.data == nim2.data).all()) self.failUnless(N.all([N.all(nim2.header[k] == v) for k,v in nim.header.iteritems()])) def suite(): return unittest.makeSuite(MiscTests) if __name__ == '__main__': unittest.main() pynifti-0.20100607.1/tests/main.py0000664000175000017500000000225111414645202016161 0ustar michaelmichael### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### # # Main unit test interface for PyNIfTI # # Copyright (C) 2007 by # Michael Hanke # # This is free software; you can redistribute it and/or # modify it under the terms of the MIT License. # # This package is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the COPYING # file that comes with this package for more details. # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### import unittest # list all test modules (without .py extension) tests = [ 'test_fileio', 'test_utils', 'test_format', 'test_extensions', 'test_misc', ] # import all test modules for t in tests: exec 'import ' + t def main(): # load all tests suites suites = [ eval(t + '.suite()') for t in tests ] # and make global test suite ts = unittest.TestSuite( suites ) # finally run it unittest.TextTestRunner().run( ts ) if __name__ == '__main__': main() pynifti-0.20100607.1/tests/test_fileio.py0000664000175000017500000002752211414645202017553 0ustar michaelmichael#vim:fileencoding=utf-8 #emacs: -*- mode: python-mode; py-indent-offset: 4; indent-tabs-mode: nil -*- #ex: set sts=4 ts=4 sw=4 et: ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ## # # See COPYING file distributed along with the PyNIfTI package for the # copyright and license terms. # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ## """Unit tests for PyNIfTI file io""" __docformat__ = 'restructuredtext' from nifti.image import NiftiImage, MemMappedNiftiImage from nifti.format import NiftiFormat import nifti.clib as ncl import unittest import md5 import tempfile import shutil import os import numpy as N def md5sum(filename): """ Generate MD5 hash string. """ file = open( filename ) sum = md5.new() while True: data = file.read() if not data: break sum.update(data) return sum.hexdigest() class FileIOTests(unittest.TestCase): def setUp(self): self.workdir = tempfile.mkdtemp('pynifti_test') self.nimg = NiftiImage(os.path.join('data', 'example4d.nii.gz')) self.fp = tempfile.NamedTemporaryFile(suffix='.nii.gz') def tearDown(self): shutil.rmtree(self.workdir) del self.nimg self.fp.close() def testIdempotentLoadSaveCycle(self): """ check if file is unchanged by load/save cycle. """ md5_orig = md5sum(os.path.join('data', 'example4d.nii.gz')) self.nimg.save( os.path.join( self.workdir, 'iotest.nii.gz') ) nimg2 = NiftiImage( os.path.join( self.workdir, 'iotest.nii.gz')) md5_io = md5sum( os.path.join( self.workdir, 'iotest.nii.gz') ) self.failUnlessEqual(md5_orig, md5_io) def testUnicodeLoadSaveCycle(self): """ check load/save cycle for unicode filenames. """ md5_orig = md5sum(os.path.join('data', 'example4d.nii.gz')) self.nimg.save( os.path.join( self.workdir, 'üöä.nii.gz') ) md5_io = md5sum( os.path.join( self.workdir, 'üöä.nii.gz') ) self.failUnlessEqual(md5_orig, md5_io) def testDataAccess(self): # test two points self.failUnlessEqual(self.nimg.data[1,12,59,49], 509) self.failUnlessEqual(self.nimg.data[0,4,17,42], 435) def testDataOwnership(self): # assign data, but no copying data = self.nimg.data # data is a view of the array data buffer assert data.flags.owndata == False # get copy data_copy = self.nimg.asarray() # data_copy is a copy of the array data buffer, it own's the buffer assert data_copy.flags.owndata == True # test two points self.failUnlessEqual(data[1,12,59,49], 509) self.failUnlessEqual(data[0,4,17,42], 435) # now remove image and try again #del nimg # next section would cause segfault as the #self.failUnlessEqual(data[1,12,59,49], 509) #self.failUnlessEqual(data[0,4,17,42], 435) self.failUnlessEqual(data_copy[1,12,59,49], 509) self.failUnlessEqual(data_copy[0,4,17,42], 435) def testFromScratch(self): data = N.arange(24).reshape(2,3,4) n = NiftiImage(data) n.save(os.path.join(self.workdir, 'scratch.nii')) n2 = NiftiImage(os.path.join(self.workdir, 'scratch.nii')) self.failUnless((n2.data == data).all()) # now modify data and store again n2.data[:] = n2.data * 2 n2.save(os.path.join(self.workdir, 'scratch.nii')) # reopen and check data n3 = NiftiImage(os.path.join(self.workdir, 'scratch.nii')) self.failUnless((n3.data == data * 2).all()) # def testLeak(self): # for i in xrange(100000): # nimg = NiftiImage('data/example4d.nii.gz') # nimg = NiftiImage(N.arange(1)) def testMemoryMapping(self): # save as uncompressed file self.nimg.save(os.path.join(self.workdir, 'mmap.nii')) nimg_mm = MemMappedNiftiImage(os.path.join(self.workdir, 'mmap.nii')) # make sure we have the same self.failUnlessEqual(self.nimg.data[1,12,39,46], nimg_mm.data[1,12,39,46]) orig = nimg_mm.data[0,12,30,23] nimg_mm.data[0,12,30,23] = 999 # make sure data is written to disk nimg_mm.save() self.failUnlessEqual(nimg_mm.data[0,12,30,23], 999) # now reopen non-mapped and confirm operation nimg_mod = NiftiImage(os.path.join(self.workdir, 'mmap.nii')) self.failUnlessEqual(nimg_mod.data[0,12,30,23], 999) self.failUnlessRaises(RuntimeError, nimg_mm.setFilename, 'someother') def testQFormSetting(self): # 4x4 identity matrix ident = N.identity(4) self.failIf( (self.nimg.qform == ident).all() ) # assign new qform self.nimg.qform = ident self.failUnless( (self.nimg.qform == ident).all() ) # test save/load cycle self.nimg.save( os.path.join( self.workdir, 'qformtest.nii.gz') ) nimg2 = NiftiImage( os.path.join( self.workdir, 'qformtest.nii.gz') ) self.failUnless( (self.nimg.qform == nimg2.qform).all() ) def testQFormSetting_fromFile(self): # test setting qoffset new_qoffset = (10.0, 20.0, 30.0) self.nimg.qoffset = new_qoffset fname = os.path.join(self.workdir, 'test-qoffset-file.nii.gz') self.nimg.save(fname) nimg2 = NiftiImage(fname) self.failUnless((self.nimg.qform == nimg2.qform).all()) # now test setting full qform nimg3 = NiftiImage(os.path.join('data', 'example4d.nii.gz')) # build custom qform matrix qform = N.identity(4) # give 2mm pixdim qform.ravel()[0:11:5] = 2 # give some qoffset qform[0:3, 3] = [10.0, 20.0, 30.0] nimg3.qform = qform self.failUnless( (nimg3.qform == qform).all() ) # see whether it survives save/load cycle fname = os.path.join(self.workdir, 'qform_fromfile_test.nii.gz') nimg3.save(fname) nimg4 = NiftiImage(fname) # test rotation portion of qform, pixdims appear to be ok self.failUnless( (nimg4.qform[:3, :3] == qform[:3, :3]).all() ) # test full qform self.failUnless( (nimg4.qform == qform).all() ) def testQFormSetting_fromArray(self): data = N.zeros((4,3,2)) ident = N.identity(4) # give 2mm pixdim ident.ravel()[0:11:5] = 2 # give some qoffset ident[0:3, 3] = [10.0, 20.0, 30.0] nimg = NiftiImage(data) nimg.qform = ident self.failUnless( (nimg.qform == ident).all() ) fname = os.path.join(self.workdir, 'qform_fromarray_test.nii.gz') nimg.save(fname) nimg2 = NiftiImage(fname) # test rotation portion of qform, pixdims appear to be ok self.failUnless( (nimg.qform[:3, :3] == nimg2.qform[:3, :3]).all() ) # test full qform self.failUnless( (nimg.qform == nimg2.qform).all() ) def test_setPixDims(self): pdims = (20.0, 30.0, 40.0, 2000.0, 1.0, 1.0, 1.0) # test setPixDims func self.nimg.setPixDims(pdims) self.failUnless(self.nimg.getPixDims() == pdims) self.nimg.save(self.fp.name) nimg2 = NiftiImage(self.fp.name) self.failUnless(nimg2.getPixDims() == pdims) # test assignment pdims = [x*2 for x in pdims] pdims = tuple(pdims) self.nimg.pixdim = pdims self.failUnless(self.nimg.pixdim == pdims) self.nimg.save(self.fp.name) nimg2 = NiftiImage(self.fp.name) self.failUnless(nimg2.pixdim == pdims) def test_setVoxDims(self): vdims = (2.0, 3.0, 4.0) # test setVoxDims func self.nimg.setVoxDims(vdims) self.failUnless(self.nimg.getVoxDims() == vdims) self.nimg.save(self.fp.name) nimg2 = NiftiImage(self.fp.name) self.failUnless(nimg2.getVoxDims() == vdims) # test assignment vdims = [x*2 for x in vdims] vdims = tuple(vdims) self.nimg.voxdim = vdims self.failUnless(self.nimg.voxdim == vdims) self.nimg.save(self.fp.name) nimg2 = NiftiImage(self.fp.name) self.failUnless(self.nimg.voxdim == nimg2.voxdim) def testExtensionsSurvive(self): """ check if extensions actually get safed to the file. """ self.nimg.extensions += ('comment', 'fileio') self.nimg.save(os.path.join( self.workdir, 'extensions.nii.gz')) nimg2 = NiftiImage(os.path.join(self.workdir, 'extensions.nii.gz')) # should be the last one added self.failUnless(nimg2.extensions[-1] == 'fileio') def testPristineExtensions(self): """See whether extensions of variable length are loaded properly. """ ext = self.nimg.extensions # tabula rasa ext.clear() self.failIf(len(ext)) chunks = 100 teststr = chunks * '0123456789' for el in xrange(10 * chunks): ext += ('comment', teststr[:el]) # check whether all went well for el in xrange(10 * chunks): self.failUnless(ext[el] == teststr[:el]) # save/load cycle self.nimg.save(os.path.join( self.workdir, 'ext2.nii.gz')) nimg2 = NiftiImage(os.path.join(self.workdir, 'ext2.nii.gz')) # see what came out of it ext2 = nimg2.extensions for el in xrange(10 * chunks): if not ext2[el] == teststr[:el]: print 'extension of length %i is broken' % el self.failUnless(ext2[el] == teststr[:el]) def testMetaReconstruction(self): """Check if the meta data gets properly reconstructed during save/load cycle. """ self.nimg.meta['something'] = 'Gmork' self.nimg.save(os.path.join( self.workdir, 'meta.nii.gz')) nimg2 = NiftiImage(os.path.join(self.workdir, 'meta.nii.gz'), loadmeta=True) self.failUnless(nimg2.meta['something'] == 'Gmork') # test whether the meta extensions is preserved during a load/safe cycle # even when it is not unpickled intermediately # by default nothing is unpickled nimg_packed = NiftiImage(os.path.join(self.workdir, 'meta.nii.gz')) self.failUnless(len(nimg_packed.meta) == 0) nimg_packed.save(os.path.join( self.workdir, 'packed.nii.gz')) nimg_unpacked = NiftiImage(os.path.join(self.workdir, 'packed.nii.gz')) self.failUnless(nimg2.meta['something'] == 'Gmork') def testArrayAssign(self): alt_array = N.zeros((3,4,5,6,7), dtype='int32') self.nimg.data = alt_array self.nimg.save(os.path.join( self.workdir, 'assign.nii')) nimg2 = NiftiImage(os.path.join(self.workdir, 'assign.nii')) self.failUnless(nimg2.header['dim'] == [5, 7, 6, 5, 4, 3, 1, 1]) self.failUnless(nimg2.raw_nimg.datatype == ncl.NIFTI_TYPE_INT32) def testUnicodeHandling(self): fn = os.path.join(u'data', u'example4d.nii.gz') fn_pureuni = fn + u'łđ€æßđ¢»«' # should both be unicode self.failUnless(isinstance(fn, unicode)) self.failUnless(isinstance(fn_pureuni, unicode)) # nifti should be able to deal with ascii encodable unicode string self.failUnless(NiftiImage(fn)) # and it should raise an exception if that is not possible self.failUnlessRaises(UnicodeError, NiftiImage, fn_pureuni) # same for calling 'save' outpath = os.path.join( self.workdir, u'assign.nii') self.failUnless(isinstance(outpath, unicode)) nim = NiftiImage(N.ones((2,3,4))) nim.save(outpath) self.failUnless(os.path.exists(outpath)) self.failUnlessRaises(UnicodeError, nim.save, fn_pureuni) def suite(): return unittest.makeSuite(FileIOTests) if __name__ == '__main__': unittest.main() pynifti-0.20100607.1/tests/data/0000775000175000017500000000000011414646040015575 5ustar michaelmichaelpynifti-0.20100607.1/tests/data/example4d.nii.gz0000664000175000017500000124452311414645202020612 0ustar michaelmichaelTW Bp`5X܂ww5$3s>s_VOfU_}Ue**h9tUL?rw?Zs,ϟ~D #9-_"RmӦL!nL&n7^COVMkg m %akPs6[ wᛟH62exz&N^Q38jMQ4;b4K[).?!۾uMm:_lg7iެۤBcRRJ^I&$dC#$4.&Y$%?xJc]#$`?RI!ǫJ6%CY Hq)(d\ƻ e $ն2ĕoH| g%>{3',ĐMCZ^M\<H.ޭ_{d$ @~Y}Y$9 me,zQe%ctR% ӣƓ%qChB$\iS=e,%FVf:t2]K@C(i)#`t[=mmeuVLRZ:?itQsXu+al崯 \HJu/uגOz9,S?1č.L6I@5zTi$jo5pBw]55V/-jPBR?9HBa(Yu^SvK&Ŵ>uN6-]zHO5Ln}+]=(DKŨ@]^b`Nѥ^GxC4:Bς!x[| ^1Gt zHhI=!{ T&LN&?zI_ӵzE7kEgfom{({5l8'oclتΔNiP1_kN>V(}}'N`V]įuQdڗ8Pcǰ1iyXXrG72t2A%"+c!ݑZtYc"?gXk`,tmpF2ژFt41E×h Meߺz!YmVG_%{+- ǻ25,[e&/}UBx{Ymj5 ),@܁+I*e~NoݰЗ-&6Lm6j,ќ , (Fd,s'Vc>Z`/Ze' ȭ}9 $F2Aꑯ3нd" ePT { "9|/U"FZ"KE=nЃDILߌHm.>%M/{lx֣j5Ψ)ކw۽'|9Q 82EH?nuAgtdݟOW,cp% GW)ʷ <. p u8Op*`]@r\pڹ Jki,(a@цG^($ '꽀n'&R%j?`첃6}G5}C}x ]2[ ey7F||g<@ ~@F I݄wsQ9(_N'[P5h>x|*[ ;'/bX-͢Kz@#Z][H#9 בHz)%н0{:V8r#`mDj0z Atz v{Ÿ m0]au0WZ%6ydr.ͧu|z .<~ZܑM|3~nY5Zi ^?G`%ʨw!KJ$,쨶'JJ * 8JH ]v4n: s|0Oƻx^_{P#O6El3|:=pOBNȡ;}-2aPz2,y)s</.pm@ _Œa8~0k+ 3ƾN-Y, Pڙ P+?cuxz L 3gs{֖,Lv{B=x{^am&%h.8'Y맪5[<#Y?yN>NXR[5@+Ip6[{@b,m0tC- |ЅHc- W)Ah2A]QFGe4{ЭAwk9wP ^LAGÓ1p~193 S9FV;}nmmRGSȁ/ bKi5~_1nr ; ?.yQ2QX`gx}K<& .|]'|{mZ֕<ܐ+[hJE/ \"@QtVL;8{$>n#bкx[FlA:'367ÎyPծد 4|zh@'yٟ=hUW|LnHz|xX֭h\ >"*8V3xL_4 D! aӰnk4d. Hn2Q%9,F0Gשhx͉[HlY-q ɫAWP ơ"T!!h%nc+W1~񯤞4bԩ} ۉ p~%Z֌_~"КDL?֏WhB|W?xv虈%v krt 0K&(i&wQ[sx65R?œCT%ɁYB<+Ej3|bwg2u2i8q-h%c<PH7y/^N4^KwG 9|_ڭ8Xe"0j[`ɼ3 ө\n+]ؗi,=$%So18/h qpw Zvl$,̟FX&?ܝɩyV}A4ǡ [zMMFo5VJ(URWdūEɉh9WwaXx֩ 4@%5?-XFVR ̄MSb}.=L "ʋJZ'syѺվ˨};|<-šUSi>۴% Ko"n";X"B~}[Ա&66=#1) _-4DK)M}ܮ b6.W]ka Q3tVjQ|v?yn \1{Z’ؠ`z#N@&ٿvhRXCSt ` ?.o!g-mgRLXw񕉃g2w%˵B)v/z-D@A?i42`IP5̑|7Ҹ*X|@O{V_J>|6[x*M覱с~xy1M?WQL1x҂OV%ʑ (!iN?5xp k y[רkxMMEӍ0 nV]N5g3E-i Z*vcmj7E{ Uċs՞2}{S_맶|YLЂ[@O|ΩC-nDU xB?+9Iof_|="ba^ ǨQү,\݀ kp6 Q@'^m[KJ?L?Tj܎dxf0s}|U20wc7aX`% vbq>AFw0k ZXs(M4, (~Ҏo($/vu`B'|VZ{ٲZqa\v$U ЎuTk. '>wUoKtr `:ԚFSw=UOPv`xH aD8#菉ضFO{`Qa3x͝ΥDySMds D:u ,x?2v zWbG1g`,-WI#}P3h/"^D,lسCQd_|GJ J",R/L> POFSx? 4tiH"AŊ%"N#e!ғFQId>Jx<͑Dx>|&L#zMq tdVqfSͣS6Nqf$ҌWB D m5;j9Q=@ êHK@F2HRQTN[㩃Dnp؇:<^wS3#k$c&s/d2WΖn1[(hSF!J uP[I ~/R".D?^h<4YFvtP: |z[I?$#u:-mnl>vzv ؾmI)e@C nR>b JR҈Zk$' z]Kg٢S[Nz,kmoy[0j$iG< Tr"<7\~-A_OF lEA !5iMA#TddTv[o+a!-Rmhd56IR;~ї}@v%pW-bVDnQ; c< ]WJ&kWp MBo_ObHZ,{RHpџlL:MObkgo+0e=߄"97=j[N:QDے@q/ɩ1 ;t,@ <" ?4&=C,F쭏96GW|3/Eul|( nbЂ j揄"'l%M{N"9ya;OVG)n-e7뺂G&skd޿5:HTT0\PH?DO5 cIIORR<<&*O>?/$wҵuP( 0Ɵ1 bÐX$*?ȩS%6$Gƃe 7FD݊wSezrZ 摞+]`"WP6f.;ƃ~59#DA7*Ş@ cg.'$?[ǿr(U@<> "FF3@5栜϶ѿgz.U{ ܊F>G}v#>塚OOжcv~ <tC:Ak<;dB~,O0wj'*ݚع+P0fޟh1gNRAJt;u&??xSâh^l3[ MLƳOg>XkKȮ] 7FBQBRf=0*U;r[WY 2NVo|mWP!]nԷz 4іƦ2k+&df"-_ -"B"kn۪= #euE²\Sg6dցTli}΋tKj]% d&3oj=%tecֲU~Lr[ttt4 6>uMD.NS/d$R/j ~aurT?=FdN5OӳtӰv:[F䯓IU/V/CdRFj`lS; $*Tj86/а|#耳hGekuB|-IKלHK\!%r,:Kˡw#t'S< +ޑx 'R[v}$iZդmO^x%4R U|Jd?_QfGLG'v?c1ؒT P0f+("ե]B#7]_|w$z#obwGVY;tgfn_ ēZкʎypXKbg kYհI-+1 J#%7Jm@|:_qP/ s>oTKrG15A{;:M!zETݤ KV.Ey@;>  E'[d\ﻫAuXw.O%4AHg쮿^>GӖAНF*嶬qa] ` ;Pfd6ODDD&ZMJA{GJS+^[WYl(%ZR 47NQ/kb27oxtUkZ2@C#MN>OwMӎ _rN٠@80+٤\ħ{֨NT߻93m=AKx^j_>F3Y_-3yW2i'i#d0__hd[6֏z *ޞ G2 )BΈwk]C`D!yN{5AS[!]fzr~ _oa^җ\Ff›з! Znmk*sn$C,=Z[Xپ1RH vߟF|s> t7E Wx$f>twRPE>-QEǟvn+$:8sHGV@K>jdmGr7yf*o>&ꯃ? /@ 7vn`x&x_zRRm>P ͇^󧀺%/"  nGQ$ G3yn;VTzKjc>MF%7H R|;z y=]W'ZlR!_Q0"M |\ fOD6~Gi=7&h}9Ew%а}ā vu|~*{*-?Fj 9bzu FCϢNSYp"%"F+k kIA7t3{m%,JyPO ]F?S5a5:AH?Q -mQ<ޟns_v(.%X>Jlt7׈d.[u;gI^@t_Z!˄*$_u x;Ln„ڨ p_k'<7y@Gb?b,tsg"H%R &4tFJI"2jon=A~ֆyZ 5g:Elztہ=" I?3s2) 1(\~V |s2_=Z - XIXh)UsX;,8q$衴ǟ`7*l>(7r X/@\Ͱ:atfȚow^8Zp0 :J-IP1~t]?[aqV2%l2%dz7WXK$lh:Q5~+CqF 2iIȑwd7 p><]B3b[hi"?=x̭"8QQ^Q3}f}UߑP p CP#<A8 [>iP-ӝ?" Ƭ} 9Ļ{"x?|zx'{Jf8 jώmLT,zGݜ|C7?BD XB,pÕl} ^cdw 8 kB_)][N[͈o XEzj>^ÿn`7p#-'ݗ-QG?%ԋ~j )ϕ߃\(~} Be sΗc,=zV{*`Ov(Lx6uўB'=x}LUu\5-%usKYDzjG{[>5|Z>VgG?lʬGa.*33V˲Oͨtkxy{'@;Vbh&͍jwEl7p9?N O$/Ƞ=:kA9uy؟%=Ţ ʟ]F5?Яe1̯orX3"&ђEɈx+N.C FuZv-Ǝ-;9B=rѡp~Yo}6?ٝ{RScSU[~~:Ћ;:h//F4O%#.ga׳)Wg6c[/u(RXA],~j8vg܊Eorpk|CAN+ ߯hs7!?*ѿ`/J>{C>~Ðfj/oO8Cj3(20w1JЃ7wۭfRUEJ9Cc2^[d?߱ ίLK.LV滹bx_?x15Wlc96 (迲'kvRX,1[pV ΃,A2}DskT|O] Xk4o< cZT`d<؞ x@]_P`aQ) Z[l 6xm ({O*{7?[vįrTOFYZ{wݵgv؎[UvX$"­Zؠ%~߇N c[^ˀI K5\fm͊.~8w{ނfNzj&kl-aVv!URW7m*6B|̧ڈ.6ת2.oEfTw;s/+eӢYesL 7SnmeAu(8Sk _+Ult"C4&g(/dloȳ^"؝942vY(_>֑#Us)L+ނy?{:[aW~ԒX~$Ϙ/I̐h_/<9 z^G+PJH^d0|+`ܕa!ώuC,F٧(dJS^!D4<"ޅ{dܔmX,QwKy)(U%m+S;S錣[ Vwń;Ϝ{W46/FK s=hg<񵴁nՊz ƥ"dT,ed'tNHG>f>9$ БOZuscLU \-vS8B f6 qʒ0~4݀; tK +kS~,B${m\%x.ťnmv̕9BiI'e/I*40^@0L#JpU&~~ێ(6QCAaj}CEI$I 7FGCJj^0#!n>|;nA|ߓgsviV_hX&66ƈ[) џDaU=Isw}4mK&}_-vD{_ ݅53cq(Bh]$S_r06g нu:OkzN 8 ܺ7X.-@~]m *N@Oeh9z|\G;{?krWAjb kd6Ǯߌԕ2K?.2s7$N'*WCx0p+ %Z ۑše'sVKb`f~Ԃ!Gz$ճҏ~[jO]/yv.,Xo]kbEndVۚ4zT'فl6V3_~e_g}CP?NvWILSZ5Au/K/(VĊỂx3"7.p ru1 "ݯvf.Y@]}JϮ]*z <=:X%NVĝBmW2|жi ik@q- MrJQ1R,!y[8UēE-<995,z~D?DK2sWF1ձ nNd.XˡQۜvA3BskATÑJ6Vײ9CBt0h5d˩:;׻1Q:II Tl_/:tb8+gʠ{~ JgFAo7[,}Q\Yҿ_i1 slMK=j"|+ EgBL<:Ts6ú@_F#4Z^50WB~񒘨k(FR!{*RTd2@R |$=@-$ ?0J~)CKDZ`3rV@ZJͦWI"I%%A6:`=e)hHᑛzuvء5RQ Ii%<HzI j1^?# =h0-~.Y$=+H 0&"W ,TbUfU]MT)`a*$) .%d3#:qlz ?c1VJ+vH/)NP:;?4KHSP$/E4>%Z/ )m Ĥ+|.rN'V)jT-)%swe$h|/1JUzYV^)<)獩y/=g:GE"DI.)q),eԃ:NY_[e˴ΐ|hCnX~#-\OkIwbIBJU,5%YDQtRvHA',rERZl+ ͝Xrm$nZXhguE} d)F|dG!| aLwsvϵp>ҊVֲ[ k`xmR9䌷?Jl_濗P2[>'oz=jNyVX|&N6`6ZsI&O@;U&>s<7gtN~}֝u_ۺ b_9>ubl}a4#O sۈ w]>;rJ[B fa}LcwŀOKgլ5Q-RCe& ༥t<> bs> & ߅FUuFC+))Dv$V6RjZ)hpp䢞-$.֋ 񲻳};\8ğalnÈMX<*@-1VP3sn),Au7|>[t h/H.6z4\bnLVN?Ӊu*bʁwF:I%rKt2x~zAgYܜȃc5}x͈0 <nFPO8b*V\~c?XBwTeC J}ϓǃq?{lnbaޕ2鈴ae};4];uy?68n%%(~;WDU}zsn}RCj;X!{ mK`kj+d䆸lDN" 0ߎ4seE]J;l`"ۏWv?EG?cr1]HxQlHDͭKǠ6DfkgQ`O,D!b㤎7MK?mb.yP:GxGk$#Qߌhte(9m=*NDt#:ap+ cx0eU p5wZV&S =9&hhG$ټwR{F{y~E|2u /u_ v u8y=ۊWCCÅ"t_Z?F-FI U ťӉ!Y뷽C|/Ϸ;~_7r3*~9WT ZGnӪpw"3~ŗ \HV__ޣ&keQ k P '58JVs3=-,|553i:n탐vk/TQ#[P΋j09 uv $=~-I0yvX/`ܩ]wv ȧ~`7!a 9dBs[i{[g@N\«5"~t~Nωa;W&1BU2kp08wOj'Z㜿s5"Y6kT#nrZz®dUA}. Z"WurR/O{Z;|*F767[奦>l4+po%f}wF.r!us^t G_t_@gB %?k 뽔"#lt|5ی7(Ni˓>1mzi$MBr"[w}V^{2^&M-dA:Jh͡9aH}#Y~GE/"DÏP?oGQ-0f pG.p\ 'Zh У e@~:_2T[ԭz9Q抏qQ5RaKl5.oJC<4"&ë.<Ű``ki3A=o5y)5+Fbd۟g4_x)|nՁ+94?Zi=nAEUP7'\6aub"|^ ]~kzZ)aksѶq}?|f7Lq+)d7cY]j~WԬp< Ok_s>+4'C @Gt);+v>ov}لZL'&qK@ߓ>]jDdv 5fL肟fٌ@ߟ p5M:}]mGNt9NwkD._Vf_)eV@>?{Wb{Z @ɫiZl69ﷄ+Vy .J>:4x q߁oAXX+yXg͎%"}l4ZD˭0j`}߸On=[9p/WW l{PRK6Tj׀907L~aSRO9{h ǂf|v|Gw-n5pݭd#,eԿq7) Ub5p|S`t \=Nh~w+*eAZ.눷kmiGib{s/QH{Q {M|NR^LCQ.Cea@د0߆E/Z_Xrlm$h(wЯy] wO^J"I"_4# NoY枸o]<{a`|ѯ \IV 2RAs>oeW3ϱuWΠ lw&ٟ)r@%-Kڲ#^IjzL]IFF&hM>S ׆X-xzOD|fL_H $= Zx<< _?rBBV,[%C[h2C_+뤪Dׅ-=w;7sO,޾F4eW< 4xF-*9%F6P|:_ ugvؽW`q'%*5%JqD#[x;+ǢkvGG=O9. ݏO&% |:LK<3-nnmޚURN/>@`jdAOPY54Awh)%]":h2w=ˆ=a_#P v, v,`~w,Aa:\ TGMy#w T&Kg‡&V\k<Ŋeou:BhDfj) c~wE h =FSSh}ys,?H~!ŰRv:q"z>X8а}|P ͸XY,w-{/#'&"U8 {;|(@_SV5֌K̟K51D6}#$+܌DW">|^"[bݝgz-FcVZ 66&9v`u{rib#F%ah_PYÍot%PEʑ#n稶?W/wk~uMn]!~.h7?Bb*(*ksMg>O`M6I% /i( \~Q> l8د%y'5og:pV3^_оh IK 57R8--q[)M7OMG y| ; .A6pe ?qD}#:-(jۢt2?9R0'|.Z?ʟ qku=h}~V3p"bqߜamg<߭x\OVOJA_X:*(tO~j|US$uІbgs{ 3_+1)ul%G0 )$_)$ԭ٨QTx,> Bp8*j;cdx[5rfUƓwh!-%/G<]!1~zN۲сsg@; & xgp3%2%X~ kfk>}p.߅Ka2r& zRK1)u!+YBg#(Cj7x _~:/V++ѻ pi+|~Q丈@XsB ĴJ{tFßRK#>Akחvz]m Eet {E_%6#΂ڇXupKE*fk=0}ßl-j-W/'?P!a]_[%l4r5u[?kpKi,3-3[AX1΃N'kEbv5, <߇ pgxqXqM֦nھ+Gm--Rߌ[ILoRO:>. T:jt}_)>ώXyg_k>kխ= nlH\j\2UiuP%seI0 4*/;1 nP0]RCU,w6ж7v遆㲴TjwGFzmuїQn4T.:N JIݱw_h|g<i( wD"}e\h@SMиU}?`~)q>rc`U5y!1c-U30wLrw;ѿ%P[=NtC+W2LNlk^ K׋, z6 kC+9 ҁGQmrY{ ^I@4W&&^RZ3WL3iU5h 'H-X ,sogϞӓk쩧>c&A;m}!fniza]hunн/[W\in_zdcV~BvYvJkU_PATk]刑Nٷ1_Vp3-ڭD?^n\d\+|&deEwx@?1* ?-"TDq4tccםlWD&fN=WSLV>@{r]*kY$#%3t'Т+-vgdVF%9pPwc ?$'K_ :/Q䕺2&^CӜ*#a5ŖvzޯzޯrWog>@7S?Xevs! rкPJ9yvE?IRj~]D:g@\)9T2IhsjR!лXI%6m1Y"wr5x}<ҧd}}nAWU^k/S3@2EK:joکd UOBO;nlvޔb DdPh3kjy,մ(>\Vʆ]%^h>ϗ;}#ݰn&$Xԯͭf~ B t\;P?UÿMugp2 A} 5{ʎea#-EF;eVfXA+l sBXK~1k><-h`^T|+V)56Xcb/~dCUO%DZjJ O?S~nοg՝ G{n# C ?BmNY -%?ܒIMJf K>]o܃DIz=?+# <{S="BuďJ\4MZ1_\Bl+@J|aKd=wAtJ1[G^c谟4$l! Z& -&s?RdUugddr}뾃E|?m4Q='GHpDOhf2 Ѵk|/!|^3|7lߍ4qwu#񄔖w>F y@Z23g@Rο@`|}G76ΔLcGDi>v_w{ᅐyiI>@3Ʌk }e$8>=h] ]*}v6^a-c"!#]׈pdxEFxtYNhj%f_ݧz {pEZSS5dt}@OOf?]OIKVߡxu=q_b6p|Փv+"| 75Slq7BQgHEV-@DT;[xlk;:i|ŵ fE[iXyQp P*}1 c†Ë0-s Jء|0<stC= *W t&]7#jUbMxMhxd OFXF^%-!جxɧdΆIK\_DcvNH+bqH!o>;?<ׅ{ȈYECdC&OX=m͐y:L!j!}o,xpYi*nz;k|W X (D=RY1rD2k Xe51@`# U{zOe(mwIżzpN v} ͉l%&dj6-[D1obߙ:wt^HuC3YA,\GX|R/!2<"FӳXAÒu`#klՅ]bP7ܝwuKh'5>nLFP-HwDLHĄ}d t1vi!og?3XLE\f4;YS|`!/xLdwy 7gy, bfO m6 @7 ZɃi}4צ#}` fu2]aaM v˟;`v݈:Y'=>?D jT b&հ6&/[5vJJi"{%:;/BV[ r:FoI/rZ0؃\cGm8?86={Nn |ClkYUzf\zPN2hCFmyZIWk}/s~YFXlC_>|d%lo돥'!?:LpJ\>פZGK ß:6V߇A%ȷو]md EK $5"47O{e鈼&;? 7)Ag^Hs^C‘x} 'h ֢t0 &@8;B\~AZ3K]cp ZO͡$p )|RE0V"w?w,P-D| |>7$Ho=}ow 0_Z$U+{_@>خOo+:Nվb0 ;">{4rGB"|NM.;}5x$đ{23xC #vxDCy;].a4^]>7mu<{}gAQHQC ~s1'uPm]ޏ;B|ظ3B#_w?.^޷Nhw4h6uЁ@k..7Tsq ~1}Fj&t$x?l,Nj+zg?1yYy*7 iS@u)lHn ٮhfrlEd0cj9 nX_ɍ9}6%]wv`ȴT?4 [5AlWbMt\;GkrZU6`9\,s/o{πλpڊm~cFUxCuԈ*?"z;&{؟C|HY-d 7no}A>٪ `7"w_|eXp,u898i?)_j |9l!6X9 n&Vk M__1^"{=غ ~N $FpI(20#W9dl\~^^_E~_5[\ϯ zBhq.d9:i7C? zķ%>Fk`^*y${bw*s3orN B1`@MI[vxCv6`Uxe oVBp(8  D0PNTR,Pv+{99`8q'jHvXlf2(‹RWQlsSGXhf;_B9, U@8}wb7=g4b qOUss-_u]}yhƷ75]<+"m{:2g Wu ]i~z CZCݻq}a"N)h;̐af9Kp$N'"}C0E8LR#pp `77cߖ^Zt%@ҏA摠@t[k=-`#*{_8l;X]t`Ξ!|/V\Mopu%qnsv_Vm%aBK,}:-(8ܴ/w^>AowV` ?_ [̖c/e#G&" ;M'Sςi7}*FP'O ;\׸V)Xj-0m'ũCϊ%NKk͑w!{?5/Iwk:!o?eho,s7{a@JQP[ ^|jPsZ꿬dTIHD$lEյ݆JK$wLJkwx%~쿍l0} e LBp_pTi%ҷ^OziE $FE ^u'qpO\Ft&ku,/ Cm{[o?mos)@5VVݹO7ɠ?hЍT@~+~WEEd z 7e g;BL=Hj@פHD Iciwnֲ^qWw7p̧;Yp4^;/ \Qp<7M@ opw^ _h++B I/DrDXgpZbl{O#SGsޠs8Oyɒ[jV;Padhlv{r)=>Y@_;]L}wsYF`owuaeF\L ȅ@ w4B҇T-n}43ep>G 6Gܤ ȷ|O2GJr8ݺ#d {{fŚ&7];"c;::绠_G %小TWy_#X8eUBZ['֦T݌Zw%;[E3o5?,a I~U?]+iaAD@)kĖuDZVR6Zۊagpѷv<0oykLhSho宀>ܳB7 ossZd_aMmc/GRBYo7A3ȼ NF7<-Q״_ \sqV'nv4nҁx@I)EcozG'k?& E2"1w;8wgBnh<<kbl?u#}@ VC| H^a-`+~7A_QQa[52tBDؚi+ZL~c!l\y(<7-@oIdBWn2ccvҼ6vu^i]HYUy޳IR117٬fY젊Al#妺}}lEZ:@dZ6Ŧ(:%Bc{X\X 6[[">:8Df}Mz$3Fϵà*=@fc^*Mm4kFkoW`7*oR |lf׌EZ¢rh`5 B[X[ms!mJ$5/o]Y9>ĺTp|Eh䓚4H<#5A)I҄3>jeDj]i=5̳u6aX+ .Io)*J/̍mݱ6$ju~(49d IlXiアݱ7'hդ:]Y$}P/ײLtZ۩dLG-z ZJr]!])T>IS&}P>ou>KIhq[+_[ S&sXa=œJ:?dC 2&5A}@t+v2KeͥBRx/F|*% (gh#ث ֖Xo뢠?[Hb앍~_~_ vX̓Bs‰~ǁl\Y$. ]y-TDɥSܝ3DEv'VX|^? sm*FҊ@m{]LF-WH{ S.j'Y :Z%$R:kkoլNTe$p+6.%uҮY6=$,'ΧIeQ-嵯- ԲVviL]M}cB\w4X5 vJͺTWճJ6#-q-巊վR8($p]E@YGo~>UzAffXA;߱֜څJ 7dʄgTvRZJ;ͭ8J1,=&䝿eRHlB2fּzwЪ!1CJvZw{9V" u]:0BOzcm>᡺w?r;yuG'P>ȎKhtyķHgB0VV==/G;߭d#y4؉/l:_x+"#5,:ohlsaK~-Dgp:3od-q> hr;Wx?JϢ6 ʇJ[Ɇ-?YU%75N.V,}o_c+'oOW%&^ľc}di 3p]/\a-$U^&Xݟ!=<>\`'P8 _1766 M=H?a͋X7Ӭݖ IޥK-G:T8VPh>:E54PLI}P^yMXڅG B֐;c=gkU*Kɬem5.eNAA: wpwC/P_S97 !3 a;whNbRijq>Րxon=SxtnE : xdȯeUrs.q&'ıts;մ`}zh&C|t72t 7x>״Fݕ|aD؉_lѧZEi||<>}`7AS|#&XA(GK*h9,et3+YY?z< MwXpV+"C+ͭ p&+#"!>vD,V9<(/`f1lNZ| ǶT4arV@vX|`:]Goz#y|l%lo/yb%)p=Et\OxmK.<)'ɀKeSu3]XkcѴ ~`ȋHE`}&."UT hwjc9~hk4&pXkSd}gxρWdO%uwn88zd@#GO]e7Uxpk&mנ$rBN1gF_g"tҙ 膟B%$q@5H6uާU `nQG HKX usEO< Y?9 L V߅ZKkK 4і hS@|h`#>[x"3=O1uFLwc^q}<珐#Y2{CC3s꡽DoYOH.ll㬶=T><~נ`6 n`۵D0V[{lx[;x mwDYB(w <+X%K <sRxPqd5wlYni# ް ;y{EFb=.5ZO3fޒsc{Gxѫ vW~E~X'WKd{Ecf^}OvO\JN;~eNDJ oO"5@]FM0}cVsjSs2GqE$NB'u6f|b1.Nu:Kz=x' HXb0 %ă.{Gbure&Y /Ea<_Mfv> #r)5X'Ho[po^ؒ;rhɿӝBqY~v|6#$TxPϻ0!Q~%ziy$Ͷ37D;*rFnGx?(`>rOUQ4pir40sr?nYlfraiT @Mj1:7G^AUh cJ~u$&wC%xO1r ]\C" Jn\WlE^l\# Of;ru?7UC%˻#+`+'#95نͷ1bLG#e;uwk,7x`p=,#'{xF1.9 ]ZppWDHJH-@D\r?)җi9+rp-_"t,'b1iɦW~?Oa_xW*./1^jÑ^:A A5'Qk`aO4HQISkq֢@I''&^"|ơ XA=%cDԀ?oROsn[wFF覉ք1*ZYא' u︚GDno)芏z7XWH[}T#xY4+ u̖Vd 7!] ̊?% &ت3Mk~ ~ecǠ] , W%iDМWGb_g'KJ#\ǛF$ĭ@xt:~&{f}צ ?W$Xho2P|:-.~ QAXn#K45o?FӁIKꅹHr6(\ ۭB9`lpuͺ!Fbh٫7 ǧK7Wخ'#xqpIz]vn1o:-k%TF"d2ztۈMf\]4>WŲvjf6@z8Q䮜B[ -~f=qWR_!@4P f K-Vw>Gw9ld)-Ƣӈi1WO. 6_')F?O:~>g?4bOd*>d_mAu.=Ҿ❈H=;C*[A0AnXGh.w :?͸ ;W?ϭŦ-6kʧ |;>Xx'Un 9Lgx}W70_:kWVc'i {/+{'^ b+jotŷTuNbG:1wG1lrUpbVU@uXK GJ(yu\{?=P7"< KMXC&HnkjO:$ܪ4"8yXc|q}GVngr\x1=r}BwףH}<\M"dUtY:`/7ij}<ʒ:/*rH\oXwc3,-%NMv[ql)^r7dt gK|gS<Ľ&b>pWPO>WۣA6o{Ql.Һpnƀ`B#X7gr _g~l#ЌUT&(x:J:J2k{ێѐ҆hR?u0dz1pAHLDo5 ?0 oBg'=_'#߀x|~kk|(u(u?n$?wwF?ʯy f!CL!!#8r)ȷX }'3”Yh :ȫeT*$, vI Dxa=8wGD`!d4c=g, Ua-]ӿXR3v5nV;ih )&h6<+f?.vÃ?#j-dws^0?NMqES¬Wh9jLjPu'?J]Pk>$ U ۣe[j;p?q0Y_'jsJ428Zv۩&[F- }-_/,eMr-Ń x>"`=Β~IK1~,f7y|uMdU&2Z-*$2J?J:i$mdE~B Lƪn:xcsr3ӃI皚ܗԞ#/@a>gcVGVl! d ;6ulxɻ`Vh㒿*Н)܂cf 7#OX'@gρ)|#HCE 1ͺ|d+Zs>j'ww2ǀ{ qAXM8'iO>z'W?C:DjKP$!/٥fFss6 __7"yO)?騺<~H ܸ J<RUń?_M?0T]ke9Bܻk?yDI>p A,Cvwk7f^EDy͂WvfHsFʭt,].&VB}a~dff񕣛N;DA~jd$E򇇍J|>Rd˜u.p/Q L.k!dJUZ9ߨOރ9;m%^Ȉ]ٟT0@x 1ax$Pq<ypHD? EEGPJm75.PRet5fY'JzBt?1~#kgj(}h~gm YKh58zXz֚6^;"~sefbsfRs3,b~cմfP>YXo1[[NxDX޷[5DGul2T/).9zq5ER ppx69&im?j"oI/i3O{+Pvߎ~~[ B+eUEej=::d-FPv ;ay[X|Z{d8^TDn.k [dnn*02xD;hcPdxZX F0١>q6Xf뭡+rn*[WĪ6 _XuIJ_ɕxVvԝ*xƴnd *F`[*Q@ o42MQGX*ZG LB66\R"t8$:\y`G9sl=oR#ՠA-ؿpQo 4hVPvds0N(TiK`? zA,Ue$ E޿^3FfI-iكr EEͮY'XΡnZ(e*'@>$b=Gե87V0~DÍR^Kamjo(v" )I4Z_iWOoCyףӪ%/N͒]#)" $䓸CjLYJoZmkI.v'fRI|}B+ዮi:IϤ>RNH*8OjK'/v%BG~_~\}e$#룇ƒ3f V;4JݺH,rRzH_iq a@w?KV(%'x~ϫd沢huKewţڿu_~_:*^T_ՔbVغHe,% ķ,6C'٨+OX#v=/攛UJi}l1푆hLKԥeĖꠅ ҁH oO3<6"^;]d&_(=%)fv++,?].iT!&:IG7hp>wvoKXhþچx٠g{BNsk[B:pvTވ!dSRE+G'4q/Xn[)њړ;kiI'-?]Mr@ at.| xi=I? ePrۃ. QnU>2cMKoIȆ KVhAFSHGiCpW> kcy[y~vtc()9SȚٗ|WQM4Uln(J.I^;CSpA]] .#MA# Ad.yȆ;A䁊VIOŭV[L\but&Ο#zȽ y&jOn62^F;Fz gt9:#_Z+ :4*l>)`u|ߤyL!_w'yP{iUܷqx+><ûWq[kjW.MqVR_Dž,E D&0o{9^Rwv\'K&e m}WC5[Nڒ//?e\92]D)2~ roP׿kٮ~MpMp.!mr*z>'fsvVg9;I-W&iξz2: 'S3wmfϠ2q\/ܬ$E>R1GDRQ 76 ovg[4? n]Ú{@I-JGCFw? d^M><50<>VJ#=RSÁ yyk * hf7(3TH"a/3k!;xad2s7/ :{^`M_,}OUTQHP,%o`_{@:?\ěݼ32('8-2$&.,.Nn1C9|%;6K`Q]ˠ{b ;_w25{A F76LH-tXªe6)JI4twґ[XR][ownLchaʹ%q/Fl=aNY7%!5 (E10Ԑج8(],ǣgL?#oxo->5{|ĮE?qɓZ:FP԰7r g"XX?w.{}CHYxf|س~vcWʻGG%uPnED4B{69c7po7d<_]m! 3pr:m]Td<ώ#|,NIn񮒻LT-ybwǟψ7.E >ҰvZLCodNjdY"1VF:</+pl>W  jxL&]Øc1yH;񒏄D o6@NHSX 7yv3v]Rvږgj5g|$K/hס;  _pq5@Ԇ/}?mXP *]SRO;{ݟP 5I'[ax`zbC aYI|wɷ"fX15J60~Z8s,tD}y$p6 Gaڔ`us3z?.ʄ\M=|V #JtCEt\Ym#lGT~e9\n|XILFv;w/ٯ ]RNbôW3ZL*@]1w`.s3^SjcDk0{ qy젟&1xXx>mZJ\xx,$ۆFi7尟 9)> B?J! "?[EDz] @Gy jAiH䍆,;ֲyj}1swW=|<7)/)|v }x 2u9_N{:e]gHs|?h ڌwrO`CS+d:H>G5w@`73:=nđT+g s 4ϧ#[c߯+X6' >%}w|;MDwq,;GdG13[wLRHe(ض ti &|mnn/8H) )OQ@lrZSd;3߱ahv,]Osxfl ? ʾ !;iD-Eɏygm _ J2\[âT7Y%>עΎPzƒ^TMOo[S4K 6WBұȘYi ޫ[~ h|GK}"^ڈWNo=7zۀA>#g|غ;;ESXd$Ѵ6!Є詢#.*C&q=sm|p?BtT $0Q2V߿V> AA{ 􉐷! PR?'g;ҁXƫ;U5wmEQǖjtֺ! r$g@Q,Kc^u>D|$v#%Xy$<6ќ-L.谩z%W3#x덊|?5N>'[|Od# DŽi*2cy>WS [ VC;lG S=;t7lXd' 3Sc^Oˑo+48[11mή=}K_]%Ln?7x_;ӱ[AHX|ЂW|,y&={ILmHw}cAH<?NIr)nSF27kDZ^`=wbϨ_WA~dA9 z w7wz~K% cnFscug5K`,%wd ^ ݀[ 5wrR{T׫t~dE-6}'( kܿg땺O篋8[ZŃIXjf/-V/Sd3ٿ`i4 c`!7y^7y^OeoB@pg=iM<O뉔2uih_ {,Xt vwv-uDSd !lo~(Ǧ:Lam-55jrfE[n]a~u|)BIGچ ":97jk=]9R WwVk6rO>&oG[CkTWQd[~LP񺖴uV8"]$w(?) Ǟ`}?~D&iЉ:Dz6 Mwis\ϥ *;w?Q0wk6@ع7Y_C1҇*h63^~Xbe @U\JCi) Rݸin^: _wn1/z-ޱm3Q@V]WQAnZ?Fr@ɣ6GQR ӧ uAn6g06ul<`$yq40]*5R r`Rfu%$g~f!wF,v#Xf̄tG=Fga"YcˁkALwl?Cp$grO rՀ +@KKH6 MlΎ##qo~I'O_˃n$~m ah`ҟWFdC_Q) %%-FqhMt)vhЗv. |z9,q^ɖ\i/~f#Z&ۇA[MH5mf7mw!<վy7wYă gѩu.moj;r k3>/wZ&:"*/M(xx Ԋg aaD;DΓ]h4 ,6qg\C Ej!yRb`iamOA)Z0>b&ՌZU->vϯ׌ ׳Zuo m-jPOG|!?Gxh3ˌ`3_,܀GgF?!wR4QS8r>Fx4מh4dm tWk@VIq_Z꺝tدJpj# Npww n{ X   ww ]{vys8f}U7( 'nؽb}`k^$F+nfĽ;#:8JVݶ^2=A})d?̟]@ \ؽ F!UrB"9p9cZ/yR(p2!z BlOؔQ~u bwxvK4-,>.u&>ہhAdԖ ~{ڡhL sbil1RQ e>+E4_ԫ_xs|MB5FӶ @7;j-^ ="հFh;k㷯4>.DW*.vJ^\Kd@|(]0 ֗xhL kGBARDzʯwnWZ]3- V8Bvven6@ qL@TvNgLdzRzیID~Eb $ 4Gx5[nQN|G/x,mp/%e/uBuZ dɂUEm9x?ؐ@V$mnUn?hKmVk{mپ&^Kn$ߐX\=sD{>lctQ kmUɅ=FU=U^#2Ä@!V&` _Z5vVzjl 6ON{jjQ٪: ؓ 2!竧_dHp Z@@ij*G K_qFjRS4#a4PzK]) e4uғY S@_a*If6)brWGd IC'$䒕Ԕ&Vcr`=ӮJ&-5U;|Q<8l*~w9/ר#q_?\\Ի]$Fg !E-=m4 -PU+mmhc=UͰCʧuy5.Fv^}w5ky,wEiua嬩ճ/-Bt}++tfNzLst3>hzb4U:&1ZhLB[o _ϯ0L`H_~-k5t 1]DY;X/Kjb47>P(WepK=u s|W|xinlE[?s`_XߓS9Y,96Uh6ᰫ9V6 m)-B @;Nd"3<Sˁ!߿]_7@~c™v>QaƷ_& qB? @"ObwZ5NG!?Zwd5=X?!j]F˳`Dh{#g _@fC\R H Y"i wzS_$?F@'qyۿcrƿ H^TЂPO ݪӟY[]n/;u'n)-+< 1^7׾kE?3$*_ 4,cR![A B"hy;_!uPxw~w#5wWkDB?'/ATh!\N[y̖p{z)O R MC?.=%DbF)CGpQ?oݾg(ҳY ],4Չ:A;tQ݄H])ݽp0]^hJ f /:i<P!߯"Hat:=ѤT'|=u:?!'Fzw܃oZR 4VHx ~!&fX3kUҿ;  ܉~/yLf6&ÈK2buiﰟ;0=:;]p t&b,17\O5Y]WXbEe6{Y&Ń-_}99D.s vbVcY "(hB@5;4ZpL) o,ˊȾ>f|*:M"Ti?L}wDBaԷ#tKd]dNPqY6{[%#;##pi_̏93mezA0{sﺷF~ ǐ` a2~^;}Lwֽ#^_֢ל'F7Q,ޯf>VоuG#kR[[|IE-/5%~g;G/ 2Z_ $hq,9,2~XJMTEOsMzd6>yΐw~;-vߌ.DbBϓ?!#|(~q]}l-xB';%7&Ol1۟- W{O63^0^-??]=p"O= 8gbÀʃnbXGdD[]WcvgDE$pటFı@WH@%j?wp$>1׹nuZqo4Lw&HDl9J$*ma;7:4#~__M߄U7bRwM_\BX}>:f|>k"{<O K { \o7T8j4k $%LfG qNz7&A>(Hk, nAT&Xz*aSחM> B֟xqo6#jP T@*_a7uH@ 6l +4,jnI4KmM\PU?7~~_?i u3N M`UM6sZ>bOp^^;y2rRXc9ڪ>CdgHϴ8N>b➟s07 ~Zd쁟'%ğDH^5 q-bE.Je/8| C||)c9~7h5^ _paJ@!DB_!`,{OF::1uJy)LNrLϥ]L%Fױ혺 7x}|tD%Ľ~:Avm+^ WG7j.le_}r44KjֺƑa>T`XؘNHwիxVS?=i7'_{G4@[h0t7 |ZFg}Bu)cU5xwC.I(x pt~R Oi;$Gp.K& y|!|f.ٞM'g'b!s2M|@5"`ԝPwbd!|7wW~pξyS,=Fcm8oC=| 7a?LB(x k-ch`91sEÑ-w{VBcQ>G_{KD !M6dČ{k4|ki|a2Et V1wYKduL{շnC/}Wds;5$*΃5;Pg /GwziAP \>o;l[: sW?`8wnglsS/ke]Aw':ͥȟT )4fBN>gxWZGXJf1gG!_o_rgh҆hmV\m;"P|^0Kϸ~In'+ xʡ#L؈hL$ Uv])Uz/ :ᶮk}eZ&l46H?=}װZ|v/y~zLt=z NJ|qxo^_Ҝmj1?FX;+)}xw ude_ t!)Dʷn)D)\$<mww_"!e{aw÷cثFZ BžcM6|lNTPKn2%^yB]+;TYA[IR|#D҃]u_OA2Ѽ\Z)]kTNelUɻimRXzjx>?[Ss{r~w> ~w [FG@_|F>0 qNZ:ɨ>5w'praGsmTG簵 ŵ/}J˜!d}~}` Gt\+= c/9D=}ES]TCtё={O[n I!+{XUG^]`=}8W+Lni/kw:(^i>gs-/ڿrЧ?܂ߐkXНm{*?=~_ÀA<' LTiqJj id/7:jܻ|G~ `#V\X=jw9"P7| }ģlxwh"p9O0 c9@lEn`S4AHl,KOm(93c5`5QS+I&a}u\&y#-fM{hשtFDfKu]?3M^?#J$Nit2@JE|D³\]۵\LwA_\].\W~R\SyX:Ŧ t[-_14s:+Ѱհ ;bH}=8pS[#y:R+M<'m-_td҂LOM$W-v&~3DOϨd8Q/ىU~4y'(VϲrZkC4~{RN~H~6u >OnRtޙ%S'f'>7JG }|l6Kg-E' -,߷mwso$ ~f4kR7ԬVw&]+ulP=$c銔NgK#V#M~J/H΁n/,k.*ǟQ'GE6BhN' LC@uByzں3bBij೘{᫠dR!#߁7Zڟ׺`c\gtG~F`=2V{_JX,.!yԽ_~X}~bNoAFx {w.9ѓA䎜H[re4\ ȃ`뵌2*Ľ8w|r`R2k]lq?+0Zl/v o{}?|0|]%sj8nej[>u6p5L>\pQߓVY~lqr=J~S&BrDh..\8]uM4OS{6l[kwm$Â-?X9T6U07zgRߩ=r;aQ[?teV!qRMRJ5un7㚊usXN**ZEl{X(ss>vL2.y@'pvCjJ`*KՆ6m%up&ۻ8jaml]u~NJAI1Hz]bo3sF`-HߘhDy~WEg',/6v[ P=, F8b'3ߵydDDWfM& t9!n`Keݎf{d'H?kiXe2D&Y>;exuIh?R/dz=|cy |; Gfn8_il*_,Q HoһU\Iuy)Zz'$>u@V"rNUssbaVEӶ(ך\% ZY"Pl$a.J_l=Cv=bG7,t _``(x}t%ǂ#7B@J[']k>n (͕.+Lre=5֜X]2RQל֤&uT`|KK~"z*+-H:J)/e"IkrTгl0DHGP+VQV5QɝUyȟs\?ןY9%VzAwK)yd=+25p~:b$L/ɤ.z[HmQ56CGe}~ՔR[iMeTh।blPj{q3c7#v>Uߚ:UO-eM5!ktUރ03M~@\2].nݢ_[nU>~Pqnb>zI  kM+C|˪5DΉe:HXmu $,pKtO`]AmV[bl/B"9$軞3aZx[c\ R^f$ڛ|/H?Ȏ|koɆoWfZ@N?o'w'jMףvGKt#?~ JXmhGYugFCxGgklM"iu{Jߩ$e219R,†a$~ oMuYrQ PtvrF2(% η|7HGI`W*R~bU{⹞6i>:h;m]3% 3hPDPlv{ד1pVBd㭓]DIB&EDK͝fz0$^;^[bE2D o[ S|e=13/H;[^R?e!T;"#vA+;E5pJ&IPI${cZ#m7BC\Wt6n#0,vH fB80T >T$5‹~ߛJ_X{Nt/$gsA~2<&1:Xo@0r9^pIsYjPgoC{P>h`C4iг@) G xn|cZusboo5 r[7XWpJd{JH#=vg>|n .УxOD3?3>ڶ"ܫ9fԿosS*QIh|\Z,3 :7jCq: _uVb 40o|X黾*-X'̃;stx#ȟ*i0m^(u@zꐨy։>x}ꁮ@3'OuiTjk,% ݩh jtJ^F,&DHw;9Դ7*"d*Z+[8MC+ M5wn.r>~?kg4 x„r𝛏lPX]GCŸ O:NH]@9I,UwwR1kru$6mTģhr G;{𭃚]AW]+'L'w4ִ pVgoNYB;oДp3 k! v`\ 62߹ٿw뉒qxwX#v\!`ja4.{n:'~!^Gz'pf npQdwsZb+ aV6֢H{`g=,/5!pt2wx1gcnLbQTGuy:;]}D^"֪6ԿvzSd"\ ?1I1ȍ#W|GM%cݾɩ:*J2w0L_#JgԁQ@~ɍe.%~^^^ mxc_Iֿw= !A^>ޗ]*WaMXj4Ὗn>*wޱg y;3 ]Фk`IϾJŵSPM w-:S2@4ȟ?m bvs]>*ޟ kE֛OYw:h Ԁixn=j?BfsWޓ I.4D=|k{Q.y`{oQb@;+ <ȗMIwt|z! @cտr=IxذQbAvrNI!*Q03}+xdI"lޟnBjTo^&T7t&+mhf((DBV?/E68,3XrvÈ<]5zInDHp~/mn?w^Agw?ĖÆ\%dO h-L "9CsNӒ̸Ulp 76DbB8s]Jf2rXLl |ϰMUޫa03d0ڟDɏmZF2֒Hd~E^!Q[]&N:9>WMxG217'7j lfFrt&QN6B4^'F"X?*nO*i(dwJ NzwN@ RAa w䙏4/GAY- :=@jO-*gY?L7f'ZwBFM C: i'a9> ]'j[ ?&!"}FI L=$=">9QK}v w#u.pz&7ܑqppDBB+9g }ּO%<G>U]A'?>/FL>M4Œ)a|z=puA|?}+,xG˼F92d*$7▃8X^G,d28آ^^&J z5n3t3qOF껓ah;L k|͠Zz Ml񤏼]8oe+ -' `ERm e Wj~dd47g ߓ P3`VG0X NY잫qE #\,hP!݊ %BJ|ͽv@<7e,?X k͈ pe,xbzDSwfLmqyI?e6ĦZwH\E U3H#IjӞ3壠)})Wwj Ѣ t-^/ c`_hsǖ$Ji?B#_'sxv;t'OBQD2~c\ 8-hDw8b `[.vMso@7 ֯RJ{M!' f&n aklV E?A5<0zc&/6ޖkml)d֭fFpwuH<= KǢnG}vW?9u)TGԿy{ _;a1S**ťL6N߈/l۽D`vnd K%SY-;ߎI# F05Ɠ +P՞*ܜ~Z]'~!n Oa"];l9w(Y?k[CmQlQ!EZ"!jyهvYDhG51_}@pDyXq1YkxR!c=ZGBbKM)FhH뿳s}lC禍 <+ iM-ml1d2T XWh`i`)>#8`_h|Y,j颟rq}iAĂz6PYϾJ&iepY?d`8P<TRqM6%0zDGyYo!w~Xr;l *Iv$5'gCҔl$LLԷc0p7ہ>uCPh{ V>hv(=j&-]$9Ar}m rmm%27]ID~w@P; :9=zyȑmM-FkZ dL3ϐp͜v~R-ߔ뫢=6S@m&!c?2h-X8a}`A0o=|h+mxA;>c[cm-t AWi~R=BV3/( u$  l ܵT?_WHX,BAaؼݴ2xX#A/'w%汱6JB*nZ@@@@l[`7% ܰ؁mb`;\=|&Q忹 zHFKGHvku@@[KVI4ٹy?($|#$nOL \OJa})`#%VT?u:RqudoEV[߻+9hLHR~@gYGՎ:\s#j0U~;?ןsH\fI\+6)fWW)!=d7ԇ;̑;[{kOu Q~ACeJ"#HGfzI6h_ty7LoeSض[_I H9-6m4尸^7]KkkkY-`"Vޢ.-DEYJ` ?Z ~"aFJje:ӢXvz(g} ^ޮRm-⿽H1)$i 籀5>4]ן;~uUD7È*h}iir@Ɯ1h+?X^\ѰglЖ//dU}āM;A+J-fttv_w_^u C4*F.xL_4H2"pPưXwH[gw) :8rY$:]#Բo-exx'Hxck]>N Lk95BsYIaG}oPV_ԝ9;)*ɩ_~,%L'%ߟX}7p}^|N0IDvmIs8TO;+( 0Z#;N[jP"?  7[*[Gƨ$-Tdҋȑv=ݾ1:Y\۪dXkLO;g4*x9<?\%}*/K5q u3y튼?= ;~+kD~^GĻ7[w [7u=' T!=?uc3 Wx-b`fi&i5.qީA #8:2b;Aǣy rHbEh k~5x຿Ե1޾BHEH,+A:_i dyDWkG(b~뺥Z#]OBK;;M=mdJ>ij0d\dIp–?Z!+/!a.dVjN2[̮]tބu]ZG^Ԅwq7wsѪLFTŧaHW: ũ YD@ #dbxZogO=¾nT EGD4ϐ>g< l" _3>"@K憶 >pV#jH| k5s `ډ +7 jVHONM>I>FoшQ*XbbAUC/FWOl/|}7rXxfVߠw͸|"7d2wD[Pu/pOo)^pB.bB75\Xo{~50_؊|ߩ;q~=AR5;6Ӿn|f9|ږvek?X2aqƒhto>#}]h5OCx6Q oC)WRx~;sMxuOw&p#uƪ jaJJ?g=66@}oБx7ZKKj~),G;S1~f1!=!AW|]uY N/-N$rr]~%gMETnnc]GmGU䦹.;aHb\!s |lwư*g)PO]G◳İ:٤t}_~rq>_ޒӯ[`%"6?G3O,7ϊ Jj̈Os/\Dyf*˾c^/4Tey WVva/Ae~3} *g RtKlkKv$7wj݇k㻩v?ȕo0M̫$ 9PM~ݎgŏ~Z_u XMRJJP&77,Xz?' "os`_d>4yצxKL!rApets1`-ű)zQ#?FbHn9?=Oy/ ցQ^I)#e;G|Ed+)13y|wGy@)\VOBOֻ @- $ H꺙1@#>w}Nr&2]0u;I_ zY$"^4)-HXJ8Z+x]=K2T`cdˁw_]) `+9$';҃Oː`(|Q}&94 RwZɮ{<Ea ܆ŏ|)r]f[ڏZ?K_8hp|v}tV;`35FR#oL5%I T牵 8q>cÂjc&ൂklg4:ưlMAG? ݪ = 2;VI2IM4 /$c &gZ=_6#AC5> |P_Z*6r"$(Q/uPwnMRwVݨ k L/.Y3#+8T)Dw"|n$~Qu`7I|pmjf-`=EWm qw;#y* ܾz_RIgCTFƇ~.Ypw c? ~,ZO7jRDGuKl <, c` /oz)ٸJO}v7鈿6nwAƒE0pJ#;! yj M$"^LÙǴTs˹` Ϻ%e?y'bPObCc8x8N6'z ~@g>H?tFq,gDj>"紴$=PCk/ɥMz "3]5# A4^.[ |MO9hwEtJ*uicv!@OgX1b8  vn^?YUu"ASr^cm&zlЊZPqqg!~~Miɨ|[^ !aE=!d<Jڶ!w'xpB !@  8ܽqwwww^+7:=ߕu٧9eO=^UDnsywFǡ녝Z/gaɫ8a9'wL陷@V{ ZCO/L|0O(RgdL@j'4KjS'ր=7|#:4PZ0U)bWHwmbH0T bf `ld/dOk%u}ϡXve#`Я)US 'եLW#Sn{D=/~ "97rq`wkܕ0wOPqw5U_l=6F3^[IV<`Ԡ2qݫw"5H D^2w}N0HYΐ5̏`A窦泥 ;dC8 }+;h qex̶}&sj%-W4~f[FO  U;}%lRJ!?߷=48GOS7$h²5:c0n0wwgYv1˴TTAK-D /w>* M-Ɇ,O9au?dr~mxq?;`ݤi++1uP^j?W-m""d?oe6ԖS`X_bG~vOh JUdZ.8֪YC ޞvN8p[ ׀S4 DE4{gu}Q}ƻ,+*v|US RM^֍G]3;Ifa/*G;E4Dm]9?Wkc,J~ - {yoWTťs5xB`3 -)}c 4d`7Įӱf~z-Ȉb=Ys4u݇]#'-쉟zP:pR0pZ CZRHm!^?N%tvgK <ކÉ~Gc<%ľT ET`C;b ?I0ojcH/@SӔB#_-졭@3+,Z``}`:>E'dh5 \ v~e5IQT &u;gAwԤME;W-i#JO.א)EqI@Np u =V=+vj$d;{a/vK/j;R_YNa_Y[*}_+U m-vRZ$g5DVRXl c*[~[ouFrˎ6:iWi(E%:_וڦ|)lVj}e1zBGvu gowM86PGKyW-e.j/>3g"K.oq,PH8 4ҡҁzv;@W1i,#| =+f9=QCnϗImEBŝNTgzgrDs 5?.)}~ MD}GY@OV8C*D⻂?P<%D!=S2eZ&3пHJq弬UPOtիȵH/kZGavO""nWV}g_r|6;BK;A?n5K$ю lǐ4>(Տx:h)Uj6 ' %kRɷ'Xn#W:Kۿ;~B`O m4 E6[q{FF' ?˵{cHO6/& rl<> ]u}]LKjaaU>:W!j:Y*}" d@?@IȞc_-}&#2 xBz&߮aǵ:4OZ8@`=B{TcX= uIa[XH^.ou7/2 o;T@<{ww/]@ذ+;d>H*($?& v\Jhw2lUV2Xzr"! ŢTDɭɶ٦jWD/ .f;ݫ u>0B#O&9NS7'5uY+~<39f6eSΖ(pFkJF6tB REX2?~Vra^w}.v\Bju"y?۶mm /-ȩ26:8FsnIo{o,: L:" bIL[+\%X@yGOFI %~2ɬr{}7׋a&Vo=!|_Iki'%Y.Y:g{0:hC[u$?[t('{a4OtTwξwwyswEn%<8@5̗Ў×xY{ _6ճq*آU.5KߐطY!cddGVb2X>x8i`γBE>lOUI59}Ee7G},@3r¯x EO冼;R05iXdKiV:#33okР0N T!H"AҞ{gog|=8>.]xtEF gn[ZsspfG~? 䏅oԆ]AJFG.q{*>QO{ۢ$Xl7|g~ "f: 7\u= }B=L;C-\Hfl]A?#) W,}/Kn6|VF0wuuCjm&`kIo1$f;n)p vߚܧXVQ->rHmB'H}OlV! HxٞN#*~欸96 RNLr.0;3/9:cLQ&O7>vL-Xg}}(!̿s*W"juҒ"<-7hu:t ;|5! 5Q AE8*Wå/ݪޠgil~Ma0s+ x߹+R*e;^TdOBs1㙛Q :S7d;=˖eтgBF1Y `{|ψךI4ss. ^p}q梏A4ux=N Gf:=vɎnSD[rY)Q q|ñ'vqtp!->QJXQ+h6VɗA?|k|lsd;Snv~ͫ-m"1_Z@?nT]bkǷҖwVm /g5m--mФ/&@k ,y˘h䡺<]y p;?h͑%/nf?׻u~o|26!}"' _i4PY @ |5zDP* &:AZG ǴrXR:PC"In2h9\nlƳh0ޔП]L`B&~;64##EG2rl4O|w +lk|>̹7,qh*9x{"k8;BĔ 5h`~^S~;w0w ?]!NLmw],, LDIH,&nBG@0L)ce{Km@^H= bxzF?,QOb jn?胵) {B{deoMb?F_:|r߻y (nV:isx?O GsgIl҇vމSɖSH ?6gMA+;}ans su f{+>|nxZ1쨗gv'ݨݫ{tz po 7!{fnoN]cxP􆻭n;';{ϟ]';݈>ٌvr } "rK4 "Usrѝ[='zW@GѾ>= ;_3C|%_ۡ_{^G7dvȘ;!Kp"s2}&U*(vԹ4wtr5n܄{`k]D#3kTA>Op¯>}q72 9o2-kCUjHf׊XT8/GFÅNbãQ-<G ЉǗ_L&CP&!F(DAWeuuWv[E-w$G'KWafXHt3L;&/CPH_;EYV| jRD.E c1l{dnyb{X#簢dx XibXO 꽈^@M_!v4xK8>R6ȝ`vH.ēKl:.]'s ^_Lžoyh7tTH%'}S=g]uRZTvwN 6NGUz2bZdbXur_G'c"/}90i765_l;RZcz)|'*.R ec5-$2I{ ,"M)<{F h2M'EBh~E];LQbB ]/&O=wmK K \s}ϑ۞(Rḱ"t4셆gh/‘^APsyc-Xp:'$Iŧ" 8;'g֐O_Z. fք tջxKL߶3XXjn*Mx1H|e5%.<{U> R['x^MBʃEc0`/j ϣY՛2{"Cy=9f2w>߳p3hl9@\UR=\Ta+v`y8jTVbɹѾd{?GMt#KݙqD[f*-<,9<}Wd77e젟`|8,xOg|cϠYP';5 ~㯂!2^Q)GTȯd4ww},vnmc7Rm@>^i[kEK,kDKxGW;/* s4eLpxA oLZpKK Zl:<| QuJ" /˞[X?knfȕ9wO6.i4%\%NO^'oCAghJ'^ T0]]-@E^& 4\̫Bּ;ܕV*`h ^z:ױ|MC$vW4m?5^7g`ED >9l?"+19zu]2o6>ܵzw?s\D -ږ=jnJ&Cj^6,y(ߊZ)"rˁ` ϊu噔;Y!ɪ`DI2*]ӻ^j0/_ JH]s~~Qns5}/ c9`yjXSRE#G-Ki|sy.'DPTP0 Y_D?e~2%؂e͑ƒGSY3Y[{?7S#O"u&Nr9 2w~wGˉKFXK币TTDP:U[,쩜΍nm=ME0:+Rw $Y?M׳Aq1;;xlC<:uז2CJ[`2[;` bn=>Oh;`O䕔T1]?oq2 (oC nxܵ VNG~SWރ*ML3w׻A^icl~;z^\W-C%Y@|Ԗe3s =O~_$|,*oIv6g^0Zx܌LHQ>D`&%8W'ڿI0_*Z&{~N2Q%Z: }no H+w|ֵog$#aV {w X;`}ݬph+VZ)-劜w`6+"zTI\voJ5ۈj) ^%[>R7 $XS@(d3 WL>D[M iWb~{k*X_.kE6s㎪E: k/-_Y'A|Dzv "?1wNw TTl 6j5p" m(bl:~J[ȿzIMLm?d~/3IɗH>  c^d ayn6:Q5 Tq_iKN\6D ?;;K۵>1+qYY'dljm~9c5Så}RŏS U5 MfkY]x֟NyDD H\T7uH h'ce-"oF.| 7 0 5&( W~? G_xf:*E İnJ<* &KmV`p`0GO.gGTrY'Kl@p6{F`>_砛}OzK&zv\I` wArSBc̉)EL D ̶vng^k\9%e2C>mS-eR |H8[@ek=zF!yil1SbIy,9tumrN:~7-n״x|C __MzTI Fꂟ1^DrIT덥LC2&&: m?hi=e L$wBHQis\?ן&.U$T%}Fft=dJHEbfO^I%dO}$t.$S^ɢE5h?cȾB,ݤu+zK/hORPXpʀK&s4h="fn]sRhVBBP[JuIHN-d1lL^Kdm ._fLI3~J!-ⲲNVk ,:jXZ- 紌%YYJ{۾mgTRo+|"Aߵ>Zt;$;Q,ETohrf j'zF5-^qx^VtzvfG>׀cb;N?z\[Oib oYݮlJ\A`qɬCg~ֽ=[Mize0Ѣ6D_SZ]OH >? tvIvCÓ[B[X=}WİDzv;iw浪7wtF`߲JIa;/]uwuǷ#. YUBM<3NY U@Gk%^C*Z/2_SEd׻^A}І!5#2Y^`?>e<{hIi`4Q'BU#S&rK? .L;gjw}1zylXl|: lȸm%vPH ^(J<9=]n{A=r ~p;>N|{&^]BшVݮX ;4ԧj 4KU]*}Iu3OBt2rb$ D+xpc .41+%Z{d!ij\Fr._ (#:hzmҵz yEAJ`_VvL4q_Z$πzoWhNWG#_RDfYxwEy!1>ޔ.g,f 6,A{WV9Jg V^7{PC}Q#p.rCA_H;T'-b%0D4RzV*Fz $Kb7ݯh,^ntwm*`钾#:dSp$l[C[mYlR4be4<=*wo3tߵYaX; $Qh(31 zh}-0DaK@:jMo?hP)-W$@.7fGSHqnSE:s=Af藚ެY5\"3T&>ZQ x`2_=Xr||<罍wz ~_G܀"#qrG9O|?ӸA7F4֩r6Y-6m_X6.'[BmbE{2`x DKi*pp;72)] G|86Vj=, "_4L$l&VGCQf:_̉~렉N)'r\nW/rwq#`@zam P!r fv;^7w^`z;,,2LjE$`_FHX$V `hUغ;Y[cdXt"dԔ°~8rhz1]wDBzgb"(^N|vW~'X}uA|9ϟGD]2Qv+Qb'8M&n;-S|M@ E xb'>6;iMrGlX_#0|)29?}ʄh;4qTS`CV?u*Vwt?w6ᰗA3:`wWˋs恻nh yӉ8¬]=@? P_HY${|{ U@''K=tO8閡{G]ymBO9UyuYu;[ _Q/%ߴ/֛?SQ|Ix`Lvׂv o؄}x}&+< C,Ae4걟9XÑw#nJGIu~?57O "\Ⓨ%:磑>sB^mM7zI_04p@G|1~0.w2M:b˽tvY`Z?; ߽+ (~_ފbltt-~L>tu6i ]#iug\nGw2OwD{ ݈)g>w-k}t]̝ [L}GdpʄL k ~{܄~ZTp#F)=H>X>$nt5f53F?An,^d_"ԫ%%l0Z뽯]r?_3eTnpezLOi1%%gAe.^Y+uWԿ!Wͪd^7`Ȱ ϞI³~Zd|Ew8~3T =Q:$=M3= ﹈~ǩa(2 %%]FjgdHE,~V+el;-!6Ew6b耿W52}3Jݤ__/TxM[rtoFHMSb!x~ߌ쫐Uˇ 44`<@utΟX)?55QXjY?;j׻6<ky˽'zC/4:A~YXK&Fr"8D"*\nzR]DzV׊[j{g5OnRWzj9rFEPZ7>?ɠ@ųPd~HG߃'~MRb{fNIaq+s׋RSa\ՍD Md%m ?{ٲ1y>@#l `VFd~5vi19~tN-9G~,&N~fJs﫡|Jgɨ5Ԗ_O;}5iMN? {)gZXg嵇Rbr;|]u}Sr[MjOwt)5-)kCDz !c#4o=eiZ;U ey>xvOPsN5TmV:~_AZx|ql#h& ~_|Jz~['m56nA=umPOpFd~MXk?c RLy+-ܢLsׯa0^Lsk; vlhͬ5Rpj? $67 E 'p _~z}RݤB7e{W7X.vwV[7X6"fS̮6GVIas D,uMQ,wO 7yy+S<-ˏDh & tA_g}pD =Uw\~w"/il%6m2hw3_=ZGc0Ʈ[jZz|=mmFO% ~=r|ϡWY.|)fEČ(tIw5ǻt'6R%8|bha:lz}?*n$s7hwvQAGy4ܝoDk]dd먩Dj9yGoJ\[!w )xslp~zq | ܒW,_ pwX047?X'4P~- V,A;^GzƃG-F#@'𬜰IR|t |` .BM & łImFНTC5Mru'0DY:MF"#=5PmXcCylYPzYh>?} Y- ~g ƣ[M`-?inkMyd}/; %~ ڒ0T_%1?H\[snh/qpDs>wd]V} 6~17?͆,FpV[ E:؂e͑4şBX}7dLnTܖH^|O@E$|tp5zfo@`:h|ƀְ Y-O=Y_VcNJR)W:X*p|hUvvC!4Ax*TC -v֑BܟKR uu%SZV[@m뻿ӆPko+u-7ݼVZQ5p >BTOK%[)) ][> bbCt4Qo Cn7Zdl~-u}-k}Wf3_#u6P~Zhu;Ќ8x γ9^ßQh`Y^FI/il\ ,%һ95%#lȏCV8_в2=/Jfk26}o^q`m9մ_>7 /l@6 Nv6xhу~l,Xn/V&-GLd Eb~c4C?y*ϖ'##2> j:'UV YI.HXc;dl\ݴ@Gvn ڶ=o7P FvBHP0RNSDf5^SVx,+V%p&F6Z@seyu=O:YY %T@eϐ!>&!P'0HhX` |n  $&VT: N=0Bë&OO#ì LlʚAkX#џ&kg}#toIKQOY,IrY&MekINEL~h*2V9'-0^oCSb#4B:<@s\VI|F2[$UgÔI vO+9$ 93zc)FjYG#] [k%#L9)5Q3xa|jZ6in{J+ko6fY=|*w+$zٲzERVH/h Dg^/" {ձkSlJkJtчgDO,/k^$6'Uc[3]@&Hl'~ nWE};g5}LߪSh*>+v[f{$<񵕰ZI炤߶| 8'p{k]| E(~mdQM?x\n_tTv[VVI m-) 9|Ǻ|/5C‡^MK~zosB?7 D #"3,]: ttIKDklX"+gɈI,xn*Dk[muZW*r>gq_iaE kbkt Z$sE{Kuko쒝)-5Rh]鐼0|VL7]Ϩ)<k4Y13O^^i|'$C~b&QhJ-Ϗ:'˜= G,{D|JsP'EMXWdKt>BR;2.ݝI*l Լ?q D4hc5p}I`VAr^=>UlxS# Fu}9uVDh!:Inj@ Tnw{F`)yK(;}Q-vY42>WDvjUC ?j}xP#A.u|su1 u>oo} #rVP +EX6!|>t{/s{}dƀJ󺛄Q LlN\},,t AlZf'MV,zravg]cwt}vNc"lIhY?oG$(aSm$Q0Nj ICVB.I,l(߀ωNbrI/OWanp " ?Im.ړ pn)L+4x@!I=<9}mB!||?Ʋss!msWo)J!5/mUav`'t$ :%& u1 !LGcx| ErǗZVT:S|!,tv[]ݚ !9lЕ̐3TLG'd.]W`8qddw w)|#qOߏ}hASQJ=FM P< 35D P6˨ %~'SS  ]cٮO H:9O-NdSqDKPj 𝵰n믒>WNaWKq<[Mr>9 @?|LC ѱJGiSh[Ÿ*r`DЧC?[--z8T%ն~[]oX WG^VR]"q3Y@{ <̱tm6N|ZݔLx~t kHBݳ[.ig5$n#~xn=p{+w%2;vLʎj ;Lw 9 q% XpK0`;CɋF{]Ϛ;D-2jⒷG Owm/#3*cexHgw$Kne`BT,>FHoӨ &n: .=[IIyw=b*?׵(]ËFM J Ap:AF&ݐo08 5u-c9M.y[Ø˵SP`@bF&"b榺Eޗ{;ABj<մ΁WքNH[M2@sg g>''H.RÃXKA]`)w>#>U7m7ٿ XG'2׳{/ҺO|wE~lƼTɜL}!nF`88ra2䏶ێK ʟZ*_ƀ{%̝:Alcy|' u"髐yX.GB`~A\>M\VGo}#n)rPgj2Y2xr;7`mm} O oƑf=%H~,$qW \G7;;/5YTo/n/L"y?sF$<|v{K_,kdtT).gZ{\~GM{ nbh1sD+2/*6D̻.CCO }ۥhfns 5VK)w] s,%2A;tw\1P#ל@6iLPՕdoqby׻k5n;OoPt0aCGB{.)Svv桯WdWD{偺fJS'*DA?4pIJρE>3;Mco y4֬rO#a}87=#.zݝS#eWZZp`,TmCctV) wT}i_< bZ}\![p !@pwwwn;ߜ;wFܑc-tW_{Ϊ}< #TC%߭$TM`@m6@w+~bE7}quϠr_y n>?C6y%A44U:8}7T<D}Z}rAE%T;9uȸ} sh3Hw}]tR <3r׵vII ˟KRˏv%[- zw g+oGbٖ \0:SY |1 FX+>G[=5K=QZ:{B{c7ae>5lhsW??Dj<}<Ҟ/:Sm*qnR?:“\8 ; wsO^PxQMMmyROGL?Q׏|v>ųSuWsfn.*$p>anFNkde&CtW ]7ɨ9~*]7zlRHzYE6cxu$K}ջY o3#6 Ԧ|?T Z_Y{UckK* Qp]7g BBsckdKVQPzzyG \7Up\f㭯5ӲxB4{ _ }^XDys=Sﮐ/ުC1Au)(ѐ8~ߋW`@wx՚eljjAV.ߟ:?2NK*H:gp=f!ģd_2i"qA{wvȭѰ m774S!O|Kj-~sϾAM䮧G6QMU? ?tt2\3Ғ e7,9psN2d.nAVv-iaxe0$W <景h8̣Aalz nKsKa-EYh =Jh5_ۚSm"w௯7˜ <|H<$ĿڲUֈJ:ὑg^:k 0Qw;O|P;tgx>(@9h= ߐ;)eDU rLV%ci!R8݇>.bT,:6\W/|"v 8y[C߃?L#LMb[rjWwȿ;P,x H#K ఖ:Va!wўxߏFz`U1 0iBĵ`}:$aai ZB|zgKU: kzGkzx`ErpDt1"+)Zɯ\4|\u20r~`}~0}} [}9h;KR hu-:h` KvU i d ?Ov]廠g'|;yNۈvYG nBI*<~^ͥdPdJIx nxTw7o >Ӫ_7Unz_{',x%?}D%!:;K[W$d+Od}V} /NQ:ɧ~([#  |࿯XE \!wGf kw )v &:]SO|#v? K(ϳ"M&v˝O?]6!<6|)1mIJ+5dXm&hQ.{?m(Y{ /(z OHɟKķd2;Bae\Xل@% \v;LOo=zRn?pYr1޾_5>yMJr?hO #Mn~ndɇaS-=T3ni+NB-Iܴ=w6r^#~J ҒkZG x=bU7=5ۻX<LVxT*9eLh$"5Juje紞D}svlӪ($A<P"s^Xp=% {tkEݍ,]&b鿓7ʠ;ubjl} ` _R|-v+MȾ+l`W#=.H._ͱ5 ">vl'9>?1V:>2نӿnidV!lTzI7#^-Tk9F<`'MHftQonkbn+vr[gQ󙤐P5 YdV g Dvk+V|g_w<7!CS^x"[u~jK5' ЏU@kϯnb#Yfc0-IWG@;Q8]#{m~ l##@w$ ٺ5}Ei tpW WAպ |.2\ʐrӉDB_ 0 o 0 @1Q8DZ|]l>HGx-qg ǺP 﫻~=^W{ufkHޛLRd;oj{2`몽z_[J %7]71p,|A]`Ove6)dH hH}z9*k䕄 ;]DA 崉%|qmv3iXEAEYL[yU :I kwͺ7@77 vvN+*Y‡<#!UCVR/+LKpp9C`e@F6$]*4:+>[>E)%eB6bJfrJkB22F;aclUYK-YǭO Kj$Pnk>y$d Ov*KC*d)-Qcbb\ N_hd\K(5et~D3l!])I"Z!l\MJ~RU ^K =0(d4R@2.E/,1ǽTRJI$,"ϫ,CDg?k^GHXlNT+RENWTM$zR(7'~Eq*u-G @}l?R6iA->ʣ=$ JK)vXM g עYxnj%)ηV˺jdkA `[($VOu6x@z[hb쌵 =~[@@CSNB+'\^D-b|vZSاR>џ,UE6ǟhk3mFn`Wee@2I$3AW3),6: 2R[[1ˈ>ro%+e}< --a޿BH#}+4ʧNkǵ>֤>ɡOJg}knZOk]@ޤ-.k4lo2B:kPU{kh)At u﬈}g'^rIh[;3>}'v!dLAهW7L\J4|?N -m%$s:ݩ {2Y+lՑ? z4%;Z\ rBb ' ;~UF%%4W˚ wX/k>F}-2LU?3B%r"&kba Y8MB2KjQeEL"K5Ub.pvOدhC }?"ã)풫Nĸɷy3,QhdmM.LlHdrFv"zup n 8\UY_#Я*9%23eybaYႩ86*i< u}>&7^٭s dy4Dǻo4SIg'; D9/JDFʔ `~[Z*jb5uw} gPϛ? 4M\3PU4ci4\]3S/gmwR[ r@~հHk&Q/?:}F+IF?̝LI~+F"yMrC? |ay`X`B! &SkT-?]''^}?c=\G`urz`vCS*)u c'? ,0V<NHK1 tY߲ KB}Nz6M%~ Fr+3mZ|:Օh~BnV QxX]m" \bA-onvl vxdv@Il8ϝ=l(u#"~P>Z%I,}~0( {X9՟\ |]õ|^vuNUw,XN%%&WfpA?R_OL\uOE⋠\\FRxzLN\"WVo=ktq2ErZ~1XP4b3o?;1B^HLId+H".,Ȁ-ΰm&pu訉.ڌ建,ySa O`w=Jug9 (Dm)P5n'^g+wMa^cSTmJD<\@@kkp.=C"?2R[lB7oZP? j{+A=+gQ%{]\wt$N\\ۮd.+*e~O#[D#ws*S'r|%BppYpL*.Xr%g23}Tb$+]3aYMwҖ,+l3X2m1H {#?A -;h*q(}N {%RJ/@m7}_Vvcxtn χ΀D3_Y2|SsW ׉`c$~ 'aL.o&u9^[0RIO@7ڟk,SP|m\C{i:,?ܿٺW|{dU0;%275/9֬fP@A?\Oh:k\uD]` EdU7)5%l }x睩}z<!]n9ZAC-;? pbOW} DWˈm{W &jjxX)A,dþ7alҁN㴕Zi.p.ơTw"c CH½7@p$[dѷhfv %u_r sqoPQ;h0;~"0u9Y4vu0!oN|؟.xP`6&5nS'Ą1TCCɕyd rWَo}P)#[ z-lU U ]^.S0Km goe0|Wdy *u5թG#4t侏# KGPxVl4/_Wn/W!m l( 889.5?1sTEpWN323**2`Ek nR^Ogn3u/BAGb?ƈui{V?K.sW~<4s,衦h~s$?&ZN9#\(=`u3? OLk+dv;h|f v wS+ym'o%Gx afA>VRrS!&M0|E."Sl['"5ޟ;#~&mA\sAΨ>fN3uHLm+ieYmY}(xOruw-;!~6X+i"w mosTA;0~h8bYEee nPT3q]Y ws}LvD< `-=jлǺ[q7p),g7ypxHqX" OC[)5dzP?셈G1gߍ&ǰBTedTpk- W@ݱeO4֞cG)x`r _t|ČT~ZGU~X*,;ۅvN׻d-@Oh(xoE{c%7+_OQ}*;_n%d.quv~>u{M\ONp}s/jn?_K [ Xs-X^v${ 3=HdAаd%weGE{y_ëPP^"X3X|;ZgE˾Gnrdyl?_9?S~#f/2bXxDgggEÒC.P%)@D㱚e{59hMg_Z=4z8ƾix|Ϗ?]b+^- .zk5hZY|}^..N7fo@w'KSmBUzZkaߙCA-8`eAthLbcl5` /Ki J{]v$| G s9A 5" W;nJaWrJ[xHO h^2Uػ7F{cuߋ-h3<}o}FD1:x,q0LhBEk w8?6ϟ+X)ϧJt RtAZEɈdz}a-Mb쐆H@(r-Wz!0Myfxɷd8Ak~k;xbR] ނƶ cTG. R6'z"Rz OM+}u #la<__-'֎LnQ"g8X 3JaV WxdJ}UJ[91{ DBݛ8r .k7E@< Efk$}|])hi鮅@rvl_)L{#Fj ? )- D9~2`ބ$77Ǜ]8O} ϋZݴݞZ_ ek}%]bZi/\if}t' }'P, ṽ/v a?m?-xyRi{}Wj5s&`왟|E?2rrz~Z.-eFn|lsR&&[u翾EK, dB++` [ai˰j mB+!?Wc5Z8v޳"Yf{ S7+n{lߪR#=I"!5 \2@ ~NixۆgAEF40@tAS;*+~&bĝ*՛s_lvaϝ['UF:R571>z _w;`Ss/˱|@}$Mq,/PݞOԝ*d#{[b~ -d׺M#܇~j='u54*'>O!<:>Xv!SO~[ a#8tfE/W/)*J93rU;fT6Gdxk| cQۇ^8 ɑ.+$bbqp0 ΁ 6.DMj&9C}\-DJLiQW~Kͭa&J']'wAK@vG|y^^1ֶ!`H(yd_i Es3T~5a]fDJ#}Z~-#C|-?YU%TvPD^m$ !es(_d (⡞򻾏[:e> Lri2QYGHkCZkcs7>mݳ~5nƳR;-pVE ukHgDHTmfk) c͈, -%޻K^'5:Y !` p)HWj~ՠ"l"Ǥ |H\'$u5ш` 0cI]sSs_ڐ@F[a]H:z,G#m"݄ӟ/+Jd2ZVA~S;f W,Prk7 lM%^j/y*Yq${冬-v{_lE9_#n{Ha`'$oX_M"wZ_i_l7T-ZLWåW#(Udԧi}5Vѱr_nɪ W&r\Bl?{pH:Q,Lݚ2idRPm^'0gEA^VQ|!$OpْHZ|IE[jSY"}!_VҒ ^ʃ챐\3H9&etVHNCQ/J%DX$oOYt)~RE{j,Kb$PZPK'nN6 }$٤|Ǖ^ c6ͤgF٤Ǭ[6Z@z gt:/OD G+9L+e iU8vAcZ@Y \u|~a6^NLq3ѓOЈV~ŶC;jelQw֟G$ksuFզx_Q8HrV"ab+m /%62WH# @eu|hC%D[ +QEkR$lALvCOU=P<wQZ^a_XIb:1QKs>\mzi!Iزrsy4,H0L(KvYX'Ȟ袶-CJE_gFnXNqI%Ӥ ޝҪXa$[|pw宾[ ,(c5Lx@k_|lmJR[)?kylo.lkezC`Hkd+a/-@Ϣjx@CK JBU'il(5|r"yizs-aERq,g`]M  _j #ղڟO5<~>Mٟ7! 'yLsWim/yyFOjo5%7xMŶ^+!B 2J0T),>忬&_Ȝ\W h!2QQGc{ @>^-g`5ϜC*-, Rdv)7 qqT76E#Ne ,w|dxCB[.⠩eu3Wm/I'ilQU/fٰ+H ,.F=mVgvK'`խ ~^{P;+ּ!pHF"僤` NU~O^~ݟ:S ="C&=c ۡ$?#`cN%lE3 5B&mraJ^K)[; |5޾ J<g~^ot~G/L6(nR&&n~u-Yoã=u6[,[?eUEk]߮ÈAnޑ Stu!7m;Ȕ~NOvY1?[OɊ?"}*mEwiv_B^Z#ƇY~'~|Ekut.%~!-wikmhi:QtO J!jCs#{(1,}V2_qUCm {맽!뷠 ۤA [Ժ+@U'Qk\v$"-c#5bAac !K|JfJ})ES+Tcw}nxA.h?Ol&^,/(G4 6{P;Pmx5@kx@?=\!YƤ *FݓO3Qbfb୮D\ޡ;`38BܞV8D~:ȯuͶ E< Dy=ʃ>]}"d(M@GJ%"%-FqؿOXA5fx4~587(k<%DDwxG~BdJS8[m?"Ie,/Ȝ;MCŞ -\'WuGdH{-.Iy7;KՐjo$Cixfj'#~kΠ~^HH# c}U"zrwK_VlCu>#s1H5떲`gwkv4$[JLNlY(V%3m5G>w ڃs)O Gs2|Qd?"Q~D0xzxϖ trH?"ATDD0]uHۍw/ngbmJ-9 wߡ>˥:ߖ#>nm-2# ;yi)DgeM4˂7d-҃\^!嵠nJn-a_{o>#ukN? UVx } _0Q9|DKHz2>kP~ݩ|_;m87=G9xa"6_AK sעx G}_N*vuDGcuLo-%e~?g|4mz,0wsբh q!#?l#^?wu;w¯Lߺsl-hwo$]w },sR!! !w? ;=-a@2unNG~*φaY;V ''O$x}K-qc.+5M$q{wfx ?hd6^ h&e+x ?mhxso+Zc8ejV{˖`l!+9|}ܤǾ{fk8V?Fq ^0OGzU4x;ڋKYn?M'2hvcLKI P頞jHMV]^s6ַvsOFuw6h~??wS' >y.DR^c ^LOmćķA=*I}%. ?^ߦ.nR8N|ٲ[ݧGɗ`Ɏ/-bytkknE"Gd\A=ۑg!Jc)TU9,\"Xng<|Z뉛 dMA~NuSh &_o\74ԉ<謿vGP7 # tKjᯎ650 tF}ǷopO5}7:Kd _Zo1뇷H*p_ _Y2gXe{[Ƣ<mdNma&y|"0CZMqeE_@_EʎAE8ܲH /d;)5*oTJ3b~Q&_ikawx(9E ;qlխ;pY pU.8n$nщziqv/eItv2&?u1$< ֗\?:'xs/CmsD_a ȣnyp0~d<~ Dzm]_ y'38Ю+ߛn:pSb"}k}z h?_P\wu84<ղ侲Ľ^豠5:hhm*hb9ߗM۩ kd6r0i%l]?.$k0N]XܷGW$5ob~v^X_<؈bW,/S#(`}ǚE {]KnI6Maoм;~ `{PbZ 3r\B&k`3}t7: 5@l NA)HxY7u]֧Vw#jF)yFu_][-m ;؂'Ju7}I_WāY럳J|`1aS7^75<=5VuSz:03jBHʒ/V`8`~2;ed>0OH?P$>AA]fQ^ʵ}sC1@2meķm" VS?`9pڟ}Fsmq+I%W4nNMx6.f31%mU Pc[KF)(uOI%w8_`~0_ᜅŊO-2#o!il~~Yt`!oÌX~uMnuy~ ;d_J"dҏf3U<-,@dŵ~B~WJfŦLA }tQN4X+x-ilK 0[q{S\x3ݞ{!ݏ5*Lmɰ=XA=EDC.n*DPm}{-X9$8ZfμlVY.!u&u cQHYG#o Ș+l^/qa iJ S~=FyaDž3GdZrg6=?ؾhěhm=c^Fx۷,wPӘYZ=pZ #`~^L?O:w4^GD 0%&h z%wXxUֵJ5}+a|#~w};*ȹخO1l6پ1hn{{Ղ-JM -˻M͚g'*L0UC-3V؞kur=(_LJUa?+xm!n$Ϥַ69[6+txۙgGvb[0?/ZZ4v 5RDjK$2&|0 S3~pO_}zFn]olI켿w؟Mo߃zSRZ@'"LRKy.ۈx)g_r+ ۹Fuv_Q#-|{20yStCCKAMb4IlD4  odssmm7}j~F7&M 6:[3V*D'CO PgH+Kkwl>bNvvyMJb@:LuXd?~`Smv_ZE𔞒ddm5A$*Gیfꙛ (g6B3 {YV U > N8 N؁hs BϏucpAHA(^||T@Ie,s}6;n3"fY{<%6񏊰Fسo6"{_%dxI.K}jN6MNtҎ?J뮼 @-?cدHQ[O @[5nRpi-F}Xj-cEa h`?uՔ.2_TjHʹSTn%u,#L__5<òDBkI-Y2N9R{^+3>-$չBR[Z!%d}+)ʩ%RHr$ K N}[†6aS_-djT㟻J*OTCѓDgKv}"_!IY䑖#b',)uXwܒyRNw'% 7e\A˴; R:P's;..WȎ5lMl-%G}[Wjtj}c3U-Z^!)GW=M#%紉Ո^Y-{za"l~sKkMͲZמZ_ڟ[Y\וTC{L[v&nwfId+Bake, hp:9!ubnIlaQeLVيY8>O>V7f-;B s3k_ZM+OCUضFFr!{iY!U^Vօw}iy-4X2k` 2b:>@6_ %:˲[QdK`?<7A9 KtQxF!pp:lvLÚB{Z Мvx=LSZYaհl(ӟp]n^ XeBuͰ_3 aF!e b߭dAR޳n_|^ gtndQA쁺1'Bv!YRඍѯBhUP MZ|wQb_8}PW 7!ȗD6;!"ѹ+Zel:ֆِߤu%MWwgewo n[%Km)titN"{KZ<?wɿAfRGD|w\ Sp%\Ke\M Rڟ 6pA?ԕ{;]=_wJnv.nkK?ezO>|}m8١8v \w=<:ttIfYtTx4%KUY;r ߊw9߿Нt{ 'XH.gGx&bf=N\IGy|p#d71iၾAu'd9ڏ Uc0O.:#5JDdH=6 E{g,#=ei0O–',l"sQx>~rOЍd >sgߧZ Da= n]*\5=r8^ o ( ;5~ ]c4?#oh%M0~8&ß |'~>e9<  oeBQ ~/ɮe˼66 $BW~^E| c $3SܮgZɪٯiV{l{z tmik~gd0AĖZ XpD [[u%y߫ \wwC@lc/ zg5%3,"{ ZYg@GNWYX=jhxltL6#f$GSBa+~ψs7Lo$Mrq/x_U $`J-=C5 >ql9vNu`4o%!+ꗧXsDNJ9~yи a,#\m5+O_:ra亂̺JfEJ,( z=a {OL]v%Fz%L!& &㶻~hBtXh ev6l]Q v"A7̭Xv&di Pg)xHa*:(;9W88}o)D|C$5>WY_̸dt0D4rq7DQXou#*ŸXf̓%ХQ9vmCe!hh~r kj|:!Gu:+.>.#KB"ΊM w-80xd'#sw8sj r Q!jހ`ͯ QfuӡwR'דֺȼ ٗ!1lt_l"b<~?t8A/i-ѝEl9Ӊ X\0R)# `y5F/*Q='Ki>\0m|-]?鳐[\|lc<:X7nf @u yf|w r /{%*UGExrmy;jHme?_ɻN=u<,xߊA tJjM쾔?軘sG@y}t:Bv<7HM o*Y)f(؜qpS L)`{b\zUj,Yk~GYȵ~t]bښ]0?_3Ld~*m)  LcA qy5,u "L@Sx!a.0jSF!ysmkeܮq~?1ѐ3YD{jwi.U~_p;S}Xe9G!MdH%wvA*}W m.o{ V7aNԥ~Ǎr%.A5|y yW)g0lm|8{0h䃶!Zb!2> =LVY1z =@7^.f ˿2_ DT$+g2|S@-Qefea*H=/آƹM.6zzoQi{W#HjR?$=Y vϬР~BV[GRlg f7^NDl+/AO*t~ HKTǗkA ^?#yq6)=D+?g`|[GFzL"%5`Y~-< K 'ݍėn҃|}#:+}(X2 ~1vn$ -{#2.x`עH` 4t쓮:#.?,E ]Ar?h~3$<` ܧ9uc7 Z*;CJg1tn#Ã/I"b{l,xErUŕ4x kƑ}71p-q" qF 5KM0:cxK^~7[?!' pߤ6y+s}?;v?%L J}:Syk-duu)u},&?CMtED"|ٮ>Ƞ` 2Ncaa RQXy=,l}sMENxL2ݏ2Szx]Bds?} "j_QDӪF]=u>E'Ũv }w:X׿.1JȔoŋ{\!frM GVfѤ1B =.7ڙo~$ D^c#?JWR/VJōp $ ߠ= ޖ~Tr':%=C")1>oQ>6g X\[#sfg]IemoW.{eru vv&.<,6 _+Ő1.%یD)re7 XN4`?{Ku +{p`>}K0CWj}n~ 'lodn刌]%_/Orjv=dc-xo8VXjWͭqku=^XP~ {NΟ[]-mAkt ^p3+j‹~s$)n'@x8k!^VDK49c̸z":zx׷h@e*(~%LY`J渲RLjx~a]epnxp8db2tvD9cT  `8p~otz sŃ#7u$$:0PEn:y%M{_dK)IkzTM/]z3y?cXoW**/+;k ṅ]~u?+2#} ۥu}!W-vE]Uϕv2+ţ%rI\V$~*29VaGVHY( nڮ ߰2aתp,}ɭe~h&?~yFErq{RhR`\wiw٥|}'YdIG-k1;\NETP1e Hgr \O%*DvߤOyt95`n#[jgRF\ +M:2ZX/H*ڸZU h"u6Ӯ DlO5-w+99==!)5>$ZGsk.eu)hp7Დϓ2Ph];>ǢZ j_i!M`C/m#tpHHKeWץEAb/?_wc~[y*g70*},vzh ur"m&^^#i|;BʲdA#h ҆P? jX>vӾxK5~~ZOTw-a.ICd15/w7ŌVӌ#!^ 02 Z~ f!g1) $8+]PWe+|)YIJHfmS~p;:.8d"] [&](]1p 4TwϦDG7$הsjtH^ p<x@-ꖹH`XTDw<=.kLi2u+ى,ړYov~qX1+PILBLD| C di×"YJ ~2HFM Ǜ UlvCA_%%1UDIɡ@>:UH` 'bxiV%Hd~ww&oZq$t-wV%:J@.ԏ{%C [hyl} \tSNDvw=2Zz?,r['}`Û_w|X Qy{W}tqHOL?Rw9\lXuy$1jbc0޷dK2ou d!u uuNL!+!O+1')Ms)=@˪eva gNAβ?g qⰹiI5|!ߓIn} 5TL_-Mʹϲw;;MB#g[ A2:a&V &"7DT v/:'&?< DФ.IڇW2 Α yuYEvlV'#! ~L} ;$HX3^3د@ҲJ0mg.7ODz&? =Mwu{~):qu&=@fw3ނ_ zW)C}GÈco 0]9Dazd?g&s5$sÙܦsFY:EwbߵGS;e?طSWGmEc(.3_ͭfrU#?.KO@#a.gj7sDL=`}t#NA{G!L6k= ވצ8`%? 俙Bt,WbC}r@߁ 1:x 2K*OԢ^ǿA5gVA=vi}3OtJEzt%=Pu;ɯU ʛlr^yEYGm<%d!hg8NV}xl36/ t)21x' iu<с:g*[VC =V+ !x`#rՃ'/l]~ & k8:Bdm}NZE[HM^=/ÜN-E>׶".FMׁM{xP:dW2mM~ZX69Uj`ZbgЬۥUWx,hr7;JJ=o:tY}|iu~DGM2g|B< T+ԆCy zuzd4'NzwSO(\]>`XxZ[ϵW >2<`g6g&ϯ;N[ 9!uKC~'+ |TDpr%R wGӍxuhݻek4U*id$h` c*p]b&ۑ8_x~M[gye.\a6U"%Wx~t WѤ>X n=no9~~?DA3ɠd0w:Q[JK _姡hcqzXLI((jW-wz/_MINbMDv_d 敉hc1rﶁy" Z'YgkIC?!!^,A,6 õwc%6ֈsl뱛1װ:7F .Ht8E޻FgXwJ5!͊ȳ-utG[.`Dkmq\91p W d^7 \ jZ[eXGh ^} 5AvQz~ tE }>V vo&_1H J غI'~z d{eF-6)i^b{.{B#2m c0;9p oFzVJL\Ih*^ [u<JzZkS _,w|-5\0Ve;Gwᡟl r[W^嫋j@U^+0`xMG x=[06An p3_dİM,W}a 8GTʧ |POyˑwπ67z1ha9@뾻lDPr],aO=ɧM׈{| 9'HOa"jo&ai2 EP:blz40ϟgh+9:[)À[tS-ü><~FW/foyXr3k[60N>-Ȉu&( :⧆lP!_!0C-TgDNDX׮/SN?Ålz.%DAּ c/H*КӮ_r-hE%3񐁠tW}Glxd,nN(z /zJּHL,GL/?lO%ؕT4Q0F?j>q1= Ϗ8/ǧ.b܏aOK5 ^\yϪj˯9 ~zN6F)3dpe0z,Wlubr}rFO6r)&7SJ^BvgO쬞]ZmJ 75@%~;dATHBV/zzv%\ZxWۣYty['=T}j3[>ϑ~W*T?B譝'ejUЕu\ ]~,} ]g@u05jK3h( ؙ8Tt}ٯcI%ߔ0 X,S* bC NWcip57ܣbFVOEINl9?/,0቟ذ3|v'mNV*c5& ~[__ׂzK蠷$l =}ѱϐdׂ~6慜&3&&Yܗov1 lw{OJkjh`16ğ<?V=~3[=ַ{#jL'%C;/x6/9f.)[j\fBd8-ɱdr="y5?%:0MokWhI%%&A@]K\%;zUwe\;5V_ծFnkr,'&3)y.79 'T4eM􍎐pиZlAn.~rIŮT+MKHHB_:T}`υޘQb9{Ї ] ;-ȟ ~<+~ZxZg=_HP|&v9&-jSsIخphds}R b?El& ۤ{:$gk fM@rc5ٟP|N]n|lsP/z h;r{"l﮻񁼚OB۾׿^6QL0F!6D 4@x"t$@W}K$>QBk=s ǁLB^!.+ꮻ2O XX+K{6&X.$O !߿Ret [i䬫lU۸Ϥ^G`xcmK;b-)wO!' WG6!yTyt4[ں$Z%\#ۍmsc]vش#lCrP8*uLؿ*Wc\` ?v5%p)].)M=,ؤ;u=ߋ"ecJ2nYk_jc= i/LT/rx44CJ+>u||F{k~ޡǡpOu(1LHVCϮTs\|Ϧ'!4DChKnO|aoʆIWjG;oNk@@@@.A@Sb(0BιrMhoY\nL޹kr_>%bky a<=\w1dJ{s+kdC@X~yD|3'}d7z0.ĒrɅn)ef/;>Wj7/lW}+ ;6;>uuKEuNRG[j8)IzggJhUutv+&̾/fV_;Dm/t嘍.{\g+'5p=#Ɍ썵Vјj׾jnt$GJ@ ݩCR\z5sבH݅$Kj!-5JxQO%A⴦.KXncKFXAΠW+.19)!$DZ d@zU|w|ҏ(Ab? W4PAgk/+=ZF2&S/W2\ZW+ 似^An+ G~J~&0Ziu}s%O+;H[>$A߈j@s:v#_m}3S͂IfL1W1P҂'iC]\a\u^2Br`Ϗe_H90ѺNdFGzQҒr/ ~NbQ4#خw' ~E~NmvCqst` _V>"_#)}(z=wX8B3iP9hXj |S3" (#:r1!Bžv:TR|8>wȃ'wƃE7!w6"ځwJ51.4(jBnȦK] U܋ E{ֵ(6;-<)y\JIj}>Ӡr +y)O@a CdT'*jd槀v.@TXVOq#D99#sKWDnnKz"cb)92.F*01^ &ԃ]򅤐*԰𺴠Tdg%rcu;={L~h3Yȇ}gX ߊ!ИG*#$W %LtS]<{,lԟ8Dy^G8oJ0k\{`$OOH [=v':,Bv 'Ku*9c -_Cb`^잎NBDrF>{*/{CSdd ~f 6p^N/|kL4;Š)XD'TM$]Z^{`MücD}$^'Gx~|.=/7Ŧ;c}qqUF4ɦMuw5Bt2KKF}%wH݋&6ϒIcPF޻ȿ =Ccg-8aeP!ΡxM͉6%`I5 RdQ1lN8l0z9Of#)I^;ÝvKy3:GG~&8oDuyV~\ߨN.LBL__fwI\c a~O [WؐIc|?y%dBn{*tn߈3<" lw"#x4Pe[VA?@Q#_ Hܯp7wTz c6 tc|O=/vwU=lPkD#u I\f7NQ[ӠϾQ$OJ*<oCw{͓oiF:Z[XP\8EaXR3NQ96ÅV/.EP# F;;g} D×X>*C՚jb6Lxr<@d HR$ճx^Od09M ˆj@ pO J/ʹ.Z e@}l0;!'8~|#o=]Jjzx@BUl`Y}{:qW 6A/Fy<C~{f"[0%=’".:,F) NdG)ɊmA2z:LUM競~Fl߮d*felS;<Oyobl]6C3P|ID dN|ߘZx' 2}DCΔY6|6K{H@4!Oc2Kٵ,ַES3|_Z'G+9(fN ΍O ^kuA?ĕpIzTCqށ\/@rplǷTAo]&_Q3+v/H@=#Nte_Rd` <:&F "`NϥT=`^R϶k/~ d]WΦs5]$'OF;p&Q:jM!8b֕*A=;mnӗa|۝Ca3SeNh#,ZxM&Ku~% C-yS݀6A=.kA8{9VFօqv`h&6cwnPq\^1SOn8{@n}[u_9l7җ.d4d˂|ݡEݘ3\9 vpޘ>A|3WZj*2:OH?+|7P^|5}WyG*ޮe턌i]­G `=Gb/R;*zLMO{~!gWbI] TmA#0jgDZtl%s$ }X'?U0\ ޛklYߒ^W|[k|`6Z؀]K o8wvoA(}6!u?e.5ߨ+cÁ[t&.T!ݗSbW?aѾZ=t|@Wzf#aQ?Z ʝ~ ~ ;~? l>%#&k9 >!Envש6 xA6'磱2$?i>+w!/q~Jx^'>wj~[QS+7آUwu]\tO"l4/Clb~ |5$/ b&ɫ}]MNL^W{#cOTep@ `M'kuӱtNd0 )rށ9~)mh`_†KxUQaEJ:P |} lut_j3e!l'>Q'cK>ՃG-$PØZI_[_\W频«3%`>ƃD]Ӳg?clN7xgR\5>׎ 7b, _n+Jv[I|anv"X _n䈇Dt2xF]E WZr^__?`6=Yc$uHݫ5/*XWܽtНv6z:E> 䴈3L9#>;)7T9ԾMuv$ /x@qׅX.߻ϳxWĮ JJ"8fe&2 ߏ6;OX)Y\!q_XBn;.!d? nOJl,tk$Yfi`՟;|ƧFG6ƮQ4=bfƔrj֕s"YӘ;mWt=یG0,Ik=OE!P&>H;Of/(=(B.|.+#5UYuNNߖb0g<Ʋf&VJ;h֓lcmD]_?ԫD}+_%k XTIU1^3%}]҂iwkΔ)-.KGN2ל oW9Sqr1.WP!vmJ] x1owGgD~˂ALu\.b>lVGu:I}U]iƍTTo]}SݗRIa˫JLqw0E> >G:pRzT]rlXc~?\S*|D ~/mh6෼H݉DU:F7ƒ}'l3lSEs9?#a}5k Wб"+S!6e{שS.zZJIP2LBפXbcw[ޑ/i@WgZǢhfS,rق-eep ]N6|Gڑd74=ʫhT_Qb\#J¬VJ%s\*䜨M[['Șa4!m] ">Kg!wkRE r6+;Ua~] ҡxtNitAE+gA`Z3Y u$&j]&AM8=+9bmI/@,L#{}1ȁˈ1`^A(#쪄kJCew &A'Iz O9))Gں,.tLW X}'|.6ho0|K[ANk4(v'ֵTu d4 hCP_rAO7"돓rŵt*ֲؕ ]+W[j7qd[vX?J\0V *T+nu}?;*J/\ak溺Ms]醻T}L%]gW&vﺻn sdvik`K{*LX)aWjH:&R$彌%v;Fc;K «تő>a_y)P7ŗRi&-uH2Kû1-?`D~HiDnԊP~|t;KRG:DNTBUVT/:[SkPZLHw.ZO juM x}щ:@h}*|>q >H^HKATOhdM-4xglTkriNtzPM*E\54{ˉ]z;KtM5ޓ΢u3ϫ Zskl s:VSB2.?h{Y\DZk-$1V%K%RlJU?>_FWݦ?KF, ;}n,WIjRma,D #鈂rJRXЅu/ B@DR==)s}|.WNO :H LEEb!DK2ͪgD`c[u(7\ZwGZCÖ(yJQtQe@ks:v/ (oI Aw:^;b4bwH%u Z|AfL/o2aoܔH̿+ݼ>!`wC&;9ɨ> Ю9gBDvy0M:>0c@AWAm3ذ>w~}!װ{o?8ޗW~A7ɈXF"F tw51ͤ yR6א3lqxGEP/|x/xx vOhOk2!X:V!~k=?'iy&F:讇A4 ƛםa닒 r yoQ¿{d-Ϝ|DN1>mQ3>>zHBOk#]Itu0&DGpf|y9 o݅5x2هf5Iʸ Y{=L#c-ȳ=6 r ^D¡2tLC=1oqTzEڹTA?+⚸||ַl5|zF~3_&ärIuc=n_$Xr舦jp"wU2AM4щ,UdA?}cIݖ/рz-g%h0sڭ}RRSˈJD \ *ڙz&'OR@*shPaY :N~f\XPd& h(U̐UvA?kI՗bS"#Rp~_W^Sp7N#NQCZ;T AtCD-'*'ܼN^x=sQtv'2i5TDS7Qiy|C[^&K@M A u^RZ:H]JI|?0:,s}٨ָ>.)0{;Zr*`+EnOFei dkjc3"-ШM \)]f:D"P%+w ~VP&mi7⿝An%G%ph` 9G"d:Tz,+fH+awP'Wf9 u7Z3oϠy}+2,a>#w!dOL}&7]bN?ۻM}96|dJH!Ӟ &ԕ@XT9&Y"4ƹ9L? @LڈxhmDݦnhaUMKC FHGԗ*}28n= m{e% j{:$Pe OϦG  mrdq,θ,Ml[Ky%ޫjA;w'@ 4{p!k͜Ι;g9w޽.{}W $~컶 k]$"VҺwwD,Rx< ::"y.+?z8gRL-KFxwH|oO „Iqy>J -, kfˍEYxx[H {zE19ȚH+鴰Y<;j l7IJbGBy|$c#s]''ǐ!A|]b Z@/-}[8{SSG^ȎGIEZMAҺ.*šSg^;~?l?>%~w?`+  Ij5>u=)rQá]mu&6F.Lo~5[߽ӦMކ]!Km;ԣ.e-!SZd@HzG?3NHW5HY%&s].̝CƋ|bm#6ߎ {x;XX#ZC'|$$PhYd~Q~zk?ΧomRMUa]`jTr|=HVlv?A\`M$olCɆcȉ79bSc!6b $$>%ji6湭#=O6FzK}5-P +6$gA̟v{wl;OI}khbY&:P^K(}hq;~M|x4&ë Ն󭐾٬ ,΅ѣb-z?1g s{ "%}%Η@JpozȞo9!io]6{d.7!YպW&Z>kA(TJ~ Kh :xR>dɠ}㊺X ߼!Tg: {*;b6A+nׂ UdSbGV-61;-W 88Pw ,jv#y`we+uY~B3_i<lE`?gbg]5&!Rs2`]4APWiYٚsUmr2"&1;@~ P>D+?fyK~&~nB|VHz޹ĮH@Sc3qKo x4(e},\a}4)} _Zs_w'?S_w_6MwG-5~bstz~V+WwfS>sς=癇Z%`JNr3jDVz/3c)h3K\1O.~ų`|&Kٰ`b?2#{w2+َA#.NfFP`CØI1[e kSU" Y'ߐ }R.l&Mm**OeșOa u)`"?]*䏦gԻTS%C=@Yz_&?_wd<ϳ.?/}]cEw[eHOB؃?a۩ |m pKddڞc'W{!_^~L{W$gCzL2|^ٹt]`Sznka)|;fT-T(dRloydxW*~]D̵S$pDdۏe"6!W\ohf;bScklPWw<&(/+l!!~EZB n4fַU4u![ra9{hsMJW5ϐ1FWME3?I+"oUM %Ԣ2kԦU,rv耟t>.FբWr8USJVKZIY#ċc+#sg\ɧt=q1]r;t++ .Nua(L8 -|Z֧i}Z֧K}=|\UauJr]I]l^ms񒻚.k긎h$+|72ܧse7:2K\jٮ+_u{+Eg@6'w!%I]Ԓ'n+2rq,. gѫGHW3zA-NO}\: Y2W1lns?.MhAmȯZ\g815j *s!Z[uit v_wXCR,) kOv8(a}"!Vf$n/ٰ2MfF5ܔgM*C5Aqb`WaE׮d9WZBi5F;i] -A_bW[`_@,x~?WLbir-}j ,[~y* ϤF$?ޑZ !Vd~:Y;2}tx~F7{f2ZSih}+rWKiT7i7p'h4|Pô~&UݗR@Xlct.{թ 䞔@G'"HTW[b5t<8LkiJ| =NjNﮜ>q%![qKno2b. E aZMl}AsT _ZĿanҌ<>+6C"uˮg$""U Y~F{FqoW}}n~KN1]ke@~T5$ R/mװ~m+s_۵+2?'SLS|XOVNOZп2{ŐzT-h HpX",1\bJs)513G iJdۉպU Y 8p=dePbzxc /yK$ dXQн X̟H'Ѩz xG% SѲvkjs_lFB{ݑ3˩ֽ y01P?ɉ_~.5CyU7߉w zڌY;|%II4Og_3%A C](ѐo'/yy=}D>G"~ l(.dxȏ\qՑDj]$ClH4zM‚eE/4WGX)rUW<2W5#>Qkp\uP DI> W8xw=)@mkIw|N!Gav>*M$.2oƫKa:RQ~7a~~+xK&e-yDT__Mȍ-G7-M+'ihx:X^\|7<,cgIbh'._ ͌XywO3rۨϱ|Y~D7l.'% "AAj{nX<:-y39qY R~n=#K rxE7ݭOgZxgONA>MVnt!ӣ~n^ -xk=]2.Q|ilF ethb;s~:Tgt+,d*n+.9 v/E`'q~BvVb`6خ40 _!=b^sga ;S{h]S“ \Cx"?2Ҽ^拲ϭ;ʣ) ݒ܂<ď8 뇚8hA ؛OL_T+;M-\o&?u ya ~ D!o|Wx<s@BA !ʑih$q]bdr]˂>#V9Noef]WKa.$2 6~2'Kx#!cƒ'?S ̈́֊5gʒC~bu}&bZl>];yl&./]2,e 514qW>#^Q|O0YZ2;5QDT")$/ M'qIN }#Zo6?pr=G@?GOFGT? oCO2D袿R\" wkt*HψK:h5-{aRwWV' el5Pu?oy|Rw`Dd=#u ﻃGDjx>5K2s!4eV .Γߋ3 G3h"OEV;|U=+< L4lI{~%"*$8 k3%=b9>PĆ1z/>%.Ԧ<'"Kfmjm 1>r۔~`Z7:eGİc JT;%,H36$, 3EAF 1/fj!mk<楤 ?XIyOvڋO;OC|Џ8{"n2TJ?##|Xw>"/*|m &710?GQ\K ^.}] g1]Opdx&V (>ϿQsp4i?;q1dͥsvtg` mpqQ7 9>޳Y0=f:Ċq.T6ݐ}".'?wE<~Fɯ$>+7ӈh  (]])w%U0[`x;6D2GsL*~ck=tCfƻYOG4SR Xİx@yxd50Tg=?$SMWHAKq|Y' sU;b6'{׆s.yBզI?Z#]ӀߟR/A0dȸo>O }9%xu@qݎ6 +P=o9YɌvHAs͑"aV9 I߭fln:|8&RMHn_$}A.&-7R nݭDF9/aEo/BbW' ,b}vdz3<j}\&c%g)x`,=مᳬl|4FZ9(cOJTo]#Q2>κ 9o=B_&haDu_byw_'IK<{v{`6p#'$. {F -~? F`w@tI~KT^Fii=Nz׮.Og5sP,۟"˽#+dlwvO(.\dGEM?)x(]A ̖}/8缬{"{zXKF6p‰Fp37=Y F]GuI'>L왨VJcD<䏞yTX"+X|&TpŨ"+<|bgaS;==l3-9 vn\> ^Xg>2^rwId]ŵV%qQJwqe> m>YsDRϿ"3̤5ޑаżº".Ϳyg'vi}fŧaadbڎ%gZѮo[CSp+l?*A_śd0przC`,L&L4hg~] ^oBL/z$@ 1g~]LLt%U1u'szw A]eꔰ+ߦNžW~JmLJMjS~xz<5^!^[R'>ԫeEqK_騇5ߎm!ٵ)>#u2C$'K y~SfpM};bOn]*i^Ь|k)UU,GX  m?eķKR"%^ojbi%,"1QXs?I=?T\C^r@v-޶&>"#jWm[Y~zyAT?{OK! ATT>F_085vW~gLoK{ZȻ҄j:>`*وC^1Qqאַ9߂udE^Y@4xMVSRzC;lid[xx6A%,-vH\Hm֗dB;{b3Ϯ**Rot4|Џ/hEwC 6V5{oXxpw_5}&gAI9]`Z%\"[+ r  'nUpZ.}v]2w%%&i ,=ueD2,VJusp$NuSM,CutQWq*]#}~!\@ Z`+{75z^s{h+d(}o쑕 a;>&Hg@e(jӞ5UtccJY5wd.Kspٺh_T"? @Fí³ +8څϓ⣇nH> czf FW]G~Xb F%pw50z ipJPז-OwV.&O-&Uޛ* ..Ko?*qS m>,uw{. pe[QI #Nk)폊DB{C7wK)K$];K[wYi$&Uo>Ku.se2oWW粹ВO{T+J "mptxt:BhCB5'Y^ٞ`@5ҕuskOV(ʈ 3 _zJImVVJ{vզW[BBuFCdںj_@K(IMm+k!2[m⾪Ԟ^R4C({ y+$dtrU\ȿʚ]pt]hݠ[tė H52\26K$t6Y_sz9lM4L+0s#+UpRCh#P=]Q_SI֩X9Z׋[:RC!{TO*DN^i='$ A9YEU*;!0WKkI<]CD'u4.  5(Q4^l0 %OtK]!3X E[mIC,žvMd ^J! ^Uh.7ՎGkh!^Wn$Y. ,It_Ik }!D_RMZ??=ǿM*{[\r"kdɊoWDΈZL;"s,.$ mBZ|P'"{8~ oPߏ 6zcAA!P0A|Vf{ųsͥ5^A{7⢂6XqWPM/Su H8./XKlί~sD2 hH@oIy܄ UMr|)?#f?roJ",߸$CmlvNa{?~k]zrKZsT47_NKIgJxqxrKNe̟vGn>|컿[ ~ 28KP^&%+̏'ImDJ2AsXCf!T .AWMtS (Vnu'$Į:5h#&$Ji= zy|H'Lj'A$ hGIG<ױxlLl[L?b# c"!݅!CG9&zwtVۮ0%z'U6ͨ&D`@LD+ bWޓ`yZfNBExrVn]Q}_rTA%ӷUOd !Y\r01|6i/CPķuD./>~wy` NpCj/  B~Ggxa]YmpA%oջ]T"O͚x9)Kr뎱]~!!U9-fݏ}"DCIX Kr6CzraFZHwwd ]Xs x%Jn=X; ?DhWtYv^#o$Ж`CBug_.)+6KNֳ집"؏sGeL8'ΡOކ>98GO`pCTdӕR*9]C@ @Gf]/b#w1]Mn2QF󞀗ym^a]D!}"*H^ADnG nxkՈUXzHjQ^d%G3?# {>0 x3!bb_ H菣/?S^Euq@&L~N xNn'3dج=<m]ǂCF 66A/R[*fe, Q-Ͽȵ~'m oK _LsAߡb}lX..G~"f κTIŀNJq`)wkqAoŲr5po#EZba73ޗP{K6iAqFC*&x[} ^0Xw D};: [kݰȿo8Hz 5uoaayNXJɍe3ܧ_d>"u61t_w[BnDޟ|2wz(?|~GMoqg;>PGOJ"@"V~}_l5ru8o|'uW;CbnselBFvi~8'=8wE4TAj{_H`B'VAZc16- ZLY(yc$EmpVό:;$ii&# pd41kɝmrĻu'jK.9q@RoS/!n绁["tw$N\  t*qGLj+)L`+(goЕ МXjIlF"^0_~wXrDnū8TvyϠÐy-_bD={:Ȏ&]{l:EVϩ[[ͭXY .#ᅭo]aÚ`<M7o+y ڪeEC7O|+aߡ,ZU&]og}jL}çwB^Wٿw57X<궘ڬc#!h8rwEsI9}j+> {^8k=>F|b~ )AW4bS0_o]pl&f;=\m?;heχw#}1m CD~,K'j5·ܾC6:O؄uǻISź܂S<Kx"0p b/Q߹H~ij2JJlݟ{yG~ܗ rIό7[bBOq>]D+y<|Nmzb:/}z>޸'`J8r:IzHto9| -@p&x}t ׄDLm>&Q}|{*ѱKB[Pc`X-`uXW: 7LZf^<&A[bӠKJ~i`pDr@*| l_UG_O~ԅѯWCӊJw xktɪ? f>Y6%;gQe]+eq1!qb*c/go@n/p ~=[DtxYb[!N~KLEHZ?Id-uT Y\uw(`â6;1C<<2n)t#1-ї W,'#꩑14"oؾ;]Af{MGu;_;FY`q?}??Xk|MρZGhw ܯ\:Z\~"3o.τ.<:/ 6nsFJa(mz8P V}\"f&4_;?o璺n.u]Rrs^ki`!++zrw pl*6O>'}g^7O[*XpTv6ϛs4WA"X]Ŷ3Ql}{vfsOkL;N>alz<`<>dH{Mgþ:@߻o-_Į+v^wo#{?v&==;˟ 鳂gq`tϨ~{b!lXOY"U_7]@ [Iv=g@PjuNL:)^}3ͦT5-ZӐ|^ar.7lhKM-bBWu=kq.,|, w]c+kL*V.HgfZDz:pz?Jkn g#gA[0GwʶP۽x9|2ڟۅ&ZŒ_x~E2` _ eaAOs$6k)g7kA-e]S>[IZ9AuQY)\&oNb.صԳ Y da8:' nB@-4Qh*F[YXݗ\pZH= F%DFa2['\zPnfZB$$rEVwrCดӥw#M4>G-BF ]5_sYZ`2,vˏ L4y-@k:StG<]SwKRw#{# ze . Lι$0y2{%ΓF1(xT!f :LFb3#wda0?ҹ0ǮVD[\X+OL&\7IIUJ]TVGv'V9N mq qɂneS!i}Z֧i}Z֧o.+qXop>I,Fr\qYx>?&r kq$ʭ| kq;N. ޥ o^ ]<2{vD %'ۥrBxB9:p@xewqi t;;VK}_M%$?J>Lds\UGt dvccrYzj%Vi1cIjMM+H#ז[ՀvGuhސ}]i #:^;kפ+}'m5ӫ@seNT ǥq֝f+3Miоwlw M=Rt.ҝ: R@ \|" = WRQ&i,^kͣ9:Y)ĐܗQ@ XE.??Yn#G[FgIܕ|ZGs]!֥#}:Ik":Ke-mZLp_V~;IF_ՄX6ֱG#q[YI6# tG(0H^^GC "W1_KI-A'NׄA3'RL tJPOw@ lzk0DN۷3Tk E^DX=,fP)_>'ڳ񎫺]AM:w08v?Jgw%ϛ {&n5~Rˮ: ]bbyZsA*AM>'՗z ^H\vǏ[Dz7`Nb}=^nI0oXh_.3! Fn#\n+d|l1O -;Xl x:>䴗dzF O@\%RKT,?)BL9# K c \-dnk'r~GۺY۽뿞GAppX'KL>[g28Uo:>qё[XZiAnt4ڟ ^{p|h,ɐړ 9aa ~]TI`+v`]@Ȥ5l(NEΕLfE:'˯r]^>XVl5*HTt #j{ o$-iDO2"b.p E?\}7e*rcgy8 uy<( 5&3B~{G 﨑C^'qgfjsS%4% ΤO뢺"Xթ{E}0n rЎ~菋#_j{B[T^";^;5\@ lGWZw@ΤU%6d3xu=/n_ɅG% xqZ0.,~|ϘX#wxőW[4Й1<_q\mITVA\I .W8[YۊDHd0h~H :5'1~=A]\Trq]MAZuຩ|_js$r/e brM's 駾D^`ȨO"l¬Bj.3U.IMLħ?~Ul~?*+ՏVAdv nݩ۱b0~+!->џ%I)N|NsB杲ϣˇ) I$B CS<>,eY`CU0GPz2]| VtI,*aI_{@*#t摝 Er:|7*> %ƣ ~ 8S_ 3-.)NԮze UYlo$XwSlq^+ K3P+_ST 4|P}||p\z v˪sY Y_d_}IlPKMIx@ݣknkU!{yRO@Bn[/URĽ#ox9rnGޤ N/+&g{^OAà E϶wގ%) Kn,wmxn^:@-z<%~b9DB.bA+|>fruAXߎo1{d7UF0V3)!l2p$b0J~@ y1Iߎr 0`|oPn3ak PK Rӥ5J3֝ K~l kK?^okFj>e \k}73bGm]ce̛Irg;$/ w M*>C'H^D]Fn[ Z6\n} v+mH\ZkPKUzU% έ8,V~ĮC`.bhf4LA.jlV*.مTO| z"g8ZlERi*](>W]u!y_Bp`ͅk\PIw]5E߽grBO,t_m&L- O v+YD8}u]~+YL9V~v*I8U-u?o)0;Op_&+jwHC/ SGGhz[؁ߺZ甓æ˗eʐ3_{MßJ$ g5$VĮzavDқ&4 W%w`?C`;ԛ}g. 7w;fO8\ Y;|&LF3P|x$^Svn_H̵ӏnpW,[Q1QT@JPJE.ivs>g[^wgff7yX07|4;"4] ?F` Pd=b!:w@\J$= a8Q~2$FGtԀ5&ydinEi41Wov_> 4 i Z6axt-7ONvsR9 %olJ!$ 3cqp42oD6>]tx?hu mG&L罹OL+?q?W(dVs{i1ۥA;=%p+2U& >y`d %u@j,-_n-̙aAJ\v6Iwnv<{@mվ9_}ջt餴|!uK`7=b.=yLD@,Lԟ89{`SuǀcZ}+oYUueI e߁ {l]禠,}6;76-: uG 9eB~W%z&խѢ!s\ߕ3w=#8wӻ8E|g\׌H[&-z?q#[i?뷆1 ܙQ~6I[J` _+4z /#QoG~^7vOIvYR{C_";,O[ /T֥HZs_a^Bx4{VLl0By'gMKXG8 -7*D߯+? dǿwz4ӱtrH7&n]~Ć%23K 94)AvX: Aw2o9Ovst&-׉tiA{6wsSׁKuo2s䏋>fZ )Ƀ-ʜh`& XⳁȽ|* ޜ[w0:-e-Zg[59ȗZ\`]wܞѹH7O=HKg,!{EzW;?kܯ$nb-VZ)L` ''0}ldAx۳=X N '5ƇH.A`{Jbo k zM^bI^mw cq`-H8KM bRC)7sąe"-.'k)=?lsRUCE״kxx1?뷄%0ۓ;yY<,^o?Mzϴ~ʲ[пIePP DعUBRw}Z!:pfS45q`-xo-)F7Oɔbm5Ľ\P `j,=6&&(\(MjG;w,O׊Aj4_$s{SHM)l*RDRװo'O`dEI&\z } n-pxP κ{PVޔ:﹐ v^ݗ-Ќ,>!тl=6Qi2bTԸHv&x=O^Y3K:p| s/66HhrI{>;/5``wW7'/B{o +ۂHi 󧳜|u"^J_jߍnprnrAF>X \.+C;! &GLa ++ ~!t߻J-b`69QS,VUv}B̑M:A^ (I$-(~IWzMKE_7e~h_XcGtԦL6Fi X 紷}kXm;.6{ƣ3cPg+Vk PNJ.}6 dz:9l X*g- zEH=:$kl1.[--XJ[hK5!MNAZߚl66fZuǺ: |?h41f&n2t`;֊1UAw{e,5m&om f @N8#CR{ Fᶁ(H#€{-l/`c gfDOLle̶eč: ge僟tRb]qEwɊ#K=~Q_13Y[w‰TE % ]:Zjy|0O&KZ[䗂 c'zS +~2mj 7Zh1u9[I `aq%_?FR%;k9}e|.6iae? Gt&,و 'Q07؈cv.z5ԮpegzEZز%w@|>b L/hRrv\]4T ߣj ])C>Ğ1{\ yv+$5:^*"<>]Շlx@k:ZN>5E#,ر_ q{7#t0n0GI@6$-򟭬lOC٨=I [݆b~w9Qhb"^D}Nr,1; UPVslQ HW-%#geaIZ0J SRD2'Ý YۃpcqF?x;z r7xu$8nY@@s-2\ľ~"czZ;=D 3+eFzHf@L{דbh ?1OIc-w`?z%Bߜ[& cmȶ lf7 EӐ,W'1M™n^rL 8nkL%h9/4;y_WyE[c0P~QUXϝ^GĽ^[Cӣ"׉Ű_|G "b#-7OBu~l& Mvԃ(FCR| O /ӷBAb+e4n6ޛ8t{NOw1p~ Gnp/v~'%H$C~6me L /eEd"5|}XcmH︡V?Q OZҀ0 {qyrm"6?e v+BF{mBЛQޠ{wn5H|O{m-TII;]uOk6%@R7g nuy]-dCre ,\;=A>0-lz?O,TDW6ubw#x"-&OE?,:k-VAhwb_ 6-Nu鉅 /Buن>c~?p݁6 e^x҈ !.Q!z擑Т˜".L VVHg> -Z/\wgi>Tnao.?Q/ w{?E8zpb ,L=d]`zAQ[SYXGMF*C W|oܯ>.ԩ<  [\AXc4q Lk;H]<o >gy s3KN.; IqۥAryanbI|#K&~&9DFqRݾÙh-5[É`v,I')K}Ou`/ ڣh6 ȍ.4:ʧ[|?3DΧ<;t~@I#s.Q?~:O:Rn:dzu:|GwppMO#7 { O"䔭|g.BDr(F ڧl(sCM#ܕZ6.ww{+|s2ޢ-AH JFlzeq󀏛Տ`Lw%hۭ''KN,(YxUװjFi]D#aUdx@ 2f: =Dc~=Z"ɇ+e8d3*lh7~_SO8v 2,W s '{>Xc="vg LԀYA Mf/0DSPws/kl䚨nGG5m2;[XoEGu^&l=ym4Mt{ɃzLj,]V7g6t}`~ ` )A5:X*ޛ/|1y1&r[op19Ɂ7׼>>eFgG"P$se砗/}I1Hz.ػݾjt?fÞ#D0~.T<ؿLA^>Y Qy8}~GRx'Ѿ+$l? .kt>uݱ\0t2>5:c";<ƒwZ" )JCс9`0v}G: _w}gP6nt}˷N|uo NEKmQϑOO6PHsSܔ ׳ywL';}OUs3[g?HY=Oql7a魆/Zslu v2R]6۫ym>F.?f >'}t ߞ 'I!Ct͸k'Q~<<1 lcG 6IWilq=Br3†f 3`( 6k7X'!*翸or$7)f02۰A>\U.۴͍E[lُ3=Kx>^ut]ȼ ._;; gI}q5:Io)숟sA#Z|sgycȷ-K]^H-:%0kd-rr伃xz?RS[Zu%'`4.&Rp*΃~qM07HE-8w7}-5B4 SOoߒBv.$}H8r0TT}n/*l*7@Mr!h暦,oCR}¬XwGGR8bJ۶n".Ɇza> 0Gl>~O9Β1G Vy7u WW4?N0_WFڻle2{zkK"ugeE&^+heb 0CLiJDqgRNDeC4DئV&; O$]3=ƣ[t}3S fepcL8>;7A2A&LR\&bռ :mcW3|6]EET lLMj 0f&G?c-t_ɧ`ʖHʚvKZJ` g*ץ-Q:,u ]owp%2OπmDsyu9%$[tgn߸ +)ȭJ3R۫)IHuw+# zMY' dDt?gw'Eԃk)Dsl _\y8Ow57yJ/ |ͿytHg{&KFpk~kFˆ=/$NL'+Yaғ i5qlq^T|U)z[/yŊǩSN `hԉaY~_L?">Q8@]DMkMjwJ- F0?i#Lp{#^,#}K+D{ͻ Z&*uijQ[kR2آU\J>YӰg#=K; O[DT$0q=)ݹ,-#A>u_˒waT0W',Ovsw Ր5p)q$+_񬧟v?ZP^Kbs[bb߯!2^.w y|ubZ;,s+ J'9ˆm}TK[+LY;ʛR3"zx5@>mnb؍p[5y9{VJ}ĊNhʹ>'V&Sa݈xaĈ\h>ήl[Rs!C?]d Ѥ 3 r>%&/- g -B/lmeu4lD9.Ow fA/l 2ɚ"hjdlM!v@hc|aE;WizyOp]lܕo*ecflXd`Ζd\ݲ[^ad?/V} 97 <Ҕ,/n6 } wv*󪱩/RL3& YB۪儭ov*.%秤J,6C?ޭ࠵QV-ȝ|1gr]9ɌKg2۴RL94e~^z^z^߻2Q ^NPK\)I|5Pb? CV>'$)(^?B*I`Uey7q3+صe# )'ϥ!r\VޭeԔz f+N'٥h%d?s_ZEFޕ|I--Ҫe@ 5ݣ4}d1m )%ʹV؇TIW>G~sPkJy]C:tY&ݵYj{Ŭ~ޱ XVNiZ!йY(IVWr[r߿R^c$ Wo!~Y} k-fOf?qb+m-vBXBHh\̒Rj ʆX5=sMc4:&h@dtPןݳS|c hbM'.^dQ~|f#:ddQj?T6ͮx!֗,Ոq]$vk-'`E#*j*[j& xdm ҃8.y݊I_Y֖Ӯir}V렝EmͳZ0 tqzYoD\\}@@x" `J6x6Y]B;brGX-%hlW ugt7 *}|b:l{\˴/HB}*OS@b=n[k~7og-i ԳӶOkF? {jI쌝|i-т-_YaVi:7}/}tƣӇ[. ͇Y3/gE "qO y1 9آ&Q9ګ+X-؎kf]Z6$t[xV`uw*>Փh&“G0@QM^}XLNThYOA<ŰR޴5Jƨu@Sa9,:faz|m`|h3xlWB I'0~i(w+p\6:mg36z]740w=%#m;Yp; }Ia xҞh2`=VQ\96Ku#] ;zHFoHN\T$#Jh4O)G ae``g+ (`Z}Å!{dX@y])0hFʁZ_fHc綄9ڨkGu XWJ 2 : ց+ G`=D]޸X?)~Y}`R~Snz#wfcM$j6KUB"kWABKDȜ& $%,Vmٚc`?֏Fݱj c%Vc{5-K/#C8jɂI8?M-8Ȑ ;~u |E/{?h"+nG'tPwq=|(ubDZYvr=dG즍#ODwo6i)?p|5M57r]7ϝ~yM4'az9CuWq=& M dp26[߯+!H&nhK4^EpQ3>t.9Sj< =֤X:}r"=M>sˈ`(DƬZZ6^2ͦQgR J.{ij TX=}\watnյ7DC0"pȃox*Rbl s|O#>.^hk?i:?dloؿyWbv|Lw7=br Sa|12)^6p^҂) e۶3Ru+̿RQS7.='H_ t/ꮍwUSu0 5ws,"zNp׉=G 6| %c3lRsm;gu#BBo7nt3~K`܎(R 9uum#Dܟ:r-މ 0̛dus cŚxsOnstw>νnP]/vTFf']ןB5[`¯*Ax/BFҫs.)Nk {fMg] :Cl&rl#|MЭIv,tA?tVOzyG [t3F''v4qB'X[5"q8nq{m{ց(3߷ܡ &A) < aT;v{@棼vDž- yDH% vwOMlxZș[ E܆*5y,y$ՈSYwb^$؆])``!t):]&FRz[4w3vm ܤ1F;}^,"^ Qx3[l,AQ-FJjc$V]x}wh;X:ʂk$u\˩~L,,:Բ<~^;]!}WNG//7c b N` ۡ~"e$UJ4S `υ# ct#c6,@ϟ>S ,>B?c|c)sysuoZxz;? S+o'/}E|.I'=nTN!W:D'ӱ<_Ƚwr3h탎v{ xwgNa̵g"C:CFs{MYZr|Ulfj.Xmϐ}a`9Up3I:׉no3n/TENA?rl'@,|};v܃,#ad=X` `8 FcǵXu|2 /UG!úIȹٗAFLa+aK701[x{ z Z΁]/hcߙ J{$_&>^Ҹd>nx2׸GyDM=xyzGO|؊^SlMd셶D?\2Q|Aec{7#;l;V{yn~Lxop_{*-]ռ:&G[a2pԉDtNȗ >H>E SjX} .=/.3kq0w?&& V,71};SӦÖ.w<|t{!q~h8)TnNz< a34q4gfU~Zd<~\` 7dܿ0{Z=տ[z ]XaIlt76.tҸG34ax|wG#?IǛ %6/ -n~vQ_'R-x_\:/e |w79ռ;}_Z?ւ}ya<آ`E $,mRsZ[D8,@){+UQ {EMSYX>8hei`QH+-fnru<VNG =ќ+5֝{nݚ?Lꧠ ntAn+/a2OkE8ݦ!v:91zN ܢ2v}62#5PG*Bx\80 f񭕽 ;!;X'bRl: ]5uIܞ;5 5>崘0;>_x%dwHm;ìvu26Rvq{#STqBt4Ϙ@fTԉy@q\|_A{M (#~Sj~J$?w=OS`wlGxV_x'I )2t^x`8)Xɖ#;bv <Ķp~*,}7e>i%Kn6ĶnѶ訐."45r̻#6Qƛ{i_~ HgxpIJE߁\X=F=]]o6ؿ:(B#\:r\:=Gld߯>9uwƤjuE=N"x#4nytV@ [?[sHG}gB&4;#n@Oj$q\s?D'~O .BgnJ䮈\&d%`6IOX/TܪAd alv@@vDsSmў(΢ `1Hq$ml)>#\oԄ"rh%ɔ[U6dbWKFX4x( |Ӊ75]Bdg$ɧ"j!3 9hfoj05rZ5|UwR[2& f`u[Mͻpsޟbd̻3t <#n~ /f`!yU`)''="[b{473L$$6|*%x:@Xna|'- 5sgŽaz'ކj/ɣV-+,uK5n &wã`g`S`kXǗnݥ-B?_55%RռĂ}CIzs=F+ /;2}'Y!nn4tCL:g3!sjSǾh`%3|j"TnB !&V3 Yۨ:"a0`AX RU%jY)V_Pg{UWdOXk w;"IN|)i^^hX\UZ+yiѱ~Ÿ jB|(Mn޶V'ZB\0@̖]:>>| WD`$ :O{FuU{h#6.f?3¡:&Y=~=:R'{ݱtE;m}cM`8\;e$g+UZsP@[ă]{zYV;?ddGmmhM#߿DPT#y` OdC$`I6 +k_wLW7F{|/4Rxj'a<ޜvl%x4~:Л^6beNd>X)%'uPBDLn[~<-Ҿ8#BxbjqG ȣBmϿ%έkD <|Hoϩ^%mH-Wq|U6u}NQC= h M5>VBkoJrpd#U[eoZ)URJ73.3JN±rw}rFJ&ɫ1d߷2Q#.2]ސM"΅z^z^z^_E3KۯdIJuIWTK6)(%% eAݾJ,$һ=5\yW[IiJHEWB<* Wv-9w]I/df'z.ۤ얘 2Y^A$.+5ύsJ&4vS?/ezNh]5RO/h+4:+3XUGVX5e,e6D5n`7yZP/Ir`w8VaP]r* ]}lnV>@ַ"T\w3ZZsgdylВB/-?2R_zi%l7V{ZM.Y`ΰ=mmkvkl_c_/C+UzKk3m1t 1bʖꂉW]MJXk ]ʊׁv(o{^zV>gdi:oINfH,/@'41<}Oꇠ+2lL_zX}ЅM!޶6wנ8xE k5M BI&"wDH-hb!q*xpղjvwO/z^|C%񨷍L_8Q%1JF!?+ēĻ_Mcm  ]!Sahu-f- f'X^;f|vbjY%;J%Lb prڝFJ 'ʂػ?*jo슥 |oO,E״~`WW1 O-+:$.opA&Kܹx-Z/bC*4x0Uj_2XO!lY})Az%x YK`|X:_o[gCK'@|;ah ~1:AW!yN낑(}[ sm{VmIfh}h%Ly<%1%hE, _;ޅJ2[It8dDZ}VHm9֎ ]k23q=ղx}k,^ wf Ի+Gg|&ׁxՒO*6Γp=`r)ieID3?iz[j2#mR%O9[e]jJ95MHX(d@$eCieM.w:gW@r8:p]P#-&y2Yi"$e/ogũz N΂f0EmX4D v U*?6I$͉װTEZLi)|g(H/ :Q-:(mu O(+mr#}}~'C@@>@*"%iـo˃a:G"E_U+6\Sve?α`XAD\ LEbi`ܯH_]&MyY<>Յy%.ֿ o?׃^C҉X<"|YrC& !$#9Q |c1 VRnqr|g ^RdS Ouj`=EY`i4X!Ͷ ]F;>& E+8&8ᵚzU$+c%SΏ7%~R$QQM?'H`9CJK6^Scv_c"EEzG//xqwW$Uu2D)́oqQk[|pE'{!{@gΧK` }?_G]ָȔU% Ox rrvLZ[]?+H(ژRMh ˎ\X+;s}q^"7xgDt\!S3DhTVh[rڸĽ=?[g[,:>G3ǯ D-t9xC'`*9÷FS]DE0V~u$5X+$ZņBZg:4:zFkz/ (#^' عȽv<7u;}NQ-ߢK~Ě}h!i-/H팃N*z] vÅ}Ǔ >纃?Efr6>O~tc/}{7xn{v%jA'ZJc?mww2Nc@2ppKsN;ijEfib[EWK=GDF#`s|E\В^YkKF8{`i-\XN)l#RNi:ѾQd9*M }ze)kq ҟ |kߵZ?/.ʹd,Ae ݌%Z-hk9u-V 亙φ:Z])? 5~ k • \=+TkW-mjDKXu^pOwSq]Dƃ6xkWfDx˙ 2+as0l95mAi0nJ ˟H4N;սj}\WCU:wq}7 -l/]xDèDcOv=3?}\;TqJ࿳ ٤#cvXV[0D@HH0?Oiu&7aoNps+ɯ)16މFP5 t/.*[fFn};@/}7?XCfD||z _sdL2V s%zM&5{ O݂m"$Ju8~̛|gYu7 "ݢ"w'7=0]Fxh*snנT}좄BDX!VnY|z DM^uzbN l׎.3~~Va~k& B?Sm||c XťL&X>N3%h`.p}?w~3ёiϮ׬(u覥*%IHm"\^K9)d-CʵH} Q'Mu5fa`{3%>}mr nC M̼L5 '`nMA}oL a2hH.̮̏Xx-=bsdU ϖE-~vwKOB:JH!-)<BF|?^kjKhrAV_È.mn˅]{"6ܟ]%K̾*+Ťf[l9IMk4t:a+jnҁ~_б(xBޟc`Bw4}`B"u-i$,Иئ/6zDe}W^KyɔR)ݼV? xwįL7' f1) "EĂkRխ }_pSA ?m*'9xߥC|l܉~. :^ըyX9ߒaQHM Yt5 `9 ~0 Ƞ:q"mMc'w 8N.PRy>1% ΂K$i"gv+l>)c~?n3 O%]$cG$$sLM}/|r?s%Wu;e٬ZL>ӕ Œ\_SY?Q>1}XBe?kѩbsn/?3|M;Nkr CZ+sR`+7VM£vh\7=b8P=p}בՁ Ntgʹ(ѐ @/nY}kq߆+@U ޳h0r 7չG]&;nM|Bbd.FtD&6Ӣh`V6R s&2pݽy&s\7;r"=?'-Cs, d#ld=[m-?\RQޓDV@|Tus=nRpHsaxy!bnN_ubD#IwD8Ľ>6JkhǕ<8d-tV7[ AOXy)V=T}f&ˊb} 29e 6Bs[;Mu0^4۬npl_ `uWoײ޿HnȉdYy rՉ&Ȫ"VÆ[@r+/x(Gy,8 'Ͻ5,xeίp_؞Z"B9tu kQ8?ԵƪKow]`3\IDd];HnQռ煶@nbzT_g x^pQZ&Z-F7Vt R/m --Q *@6~v 88+`8gY|; Uoq5Z@k{[gL4:^sG v::>/F0>$V ЂQ[kr@Y;rdw VA#> _Ɔ {^sݭ 1"k};EKY# 8oZ( gvK.%kw E'Z"FnMrXc] Lt$/g,ޅv ?,~t=xߝ|9_ާi;l& zDHRh<`םL(9jQ@G.K/nk먕Z9Dy[Oyy9JH i_lu*Mx&pWR\+D2!<^9^2IǶ %b4Pڮ=պ0CWrS\w?,xJ =1HF3"*ܞjL4T&IFQKVJY9rh.h[-< JK 炋X@I>?geYh%[ }%f_Cr(DrK߭ֈ n|v>4ܶ96iZM7lG2L hhkFtn?4I'ƕF`NiFguo|/dz1V]IwU]H%!hsqwwn- !g$=3c߹簫ꩧٻJy)'n l+:V^Bjo&$}~_~_~_oRO M(ɉC9+T]*/6rIvnew7}cR &B* KU\Z^y$|M]Kf9MdlBȞvYDx2͒ahHwdEHbj},{-]嚼~|4&՘Y/M/EMawٝdﴬRhJM,=dBz=&k\UFORG|]i40:.@req-ųbf _i& څk\ՕIp'c厴c:VW^mutlRkhX;_[ llPi\}-5n~吜X0;#t^#oX6^jcm35fauWDAK5Jif~E!`]TTiI ŮksՈ] a%hAw{/g2LBA@XmS`PDQ>PYxlU'iG EFEC*DSU 9.t4wUFw>Xv~/$ϵ_ku˺Eoi o/ mtt1hr@HBn:˞oϮ9/0Ma|OMz! ;>t4US(= "1DҚVY3~.@'+}=?9wx1} ?bL\F?t}JԖ]pGvz]:xǐޝ۬ypM}'^o滾İką8zetTkI#`I}Mru2 v%r.#۽B[}]{w}/V~F\,bUi$ "@;++T?ۀ5H@m@Ӂ*,8׆ Q>2{ |WڣeypQ&v[)I9budFkS}'Hy?˝GQtO]-"2;h/`st\9)5xHqqt Z6O{0,:;+^]27!,->\z]>Rhhjܽ8$a&j>X+#}w(AB%v|Bحm=8-d^9=1\:uvpXC舘`h/]O!q'팴}|u6s%7wEu*m|ϲ[gͪV;PTL8+6U>$'MB[0mBd,;&> Ẁw8Vƣ{\_檆D`>ʪf@ (җ}Yػ:via:`nys^RZjI4I;dy[tbQG4}j Kx> to<'7!C1~^>VeaV.Z|.Y\ĩl_zh3|:ꩥ nNfib}ϖF&}wD:/WCl daAi0o g"/%)hω&ɓ/"4 YG>_ü<q8X6HPH_EkYdk۰ȉ|.+ " ^udqBKUvAhGyX]!>QI'*L$% U^Q^Ji&xy/t ^EC`AlAal 3t&_SGw1}@qv ;[) @`:0/+j!,֟ODӑwoA,9u Vȯɰvax!ڊ53|p}(j D:_}TX {Ti*bH#VNa܇.k}cqtLU8bWd 9s}6 tE/ آ3*ȂvS/($+X(9Z;[6܈ ?mZ8`Yau?c4̧3h* ذ&G_} z bө<7d#^fQpS y<'}gK l{{`C3oYMٻص2TK`>㱼/IwGn+O>D&6 gދmD)|r9q@h~5J,.}7bXu< SK ]9bU|+Cq1Og~_{P?.ź5&Cɟ*+c{xH;`T*|M?S`+a:hyF.pKu3NGr4'hw fw~>sU?SlC$kdѐ#`$"ǤMo? PWwsu~#YflM= t#(~WAU>BMĉ M UƓ*q K|_UWbk`$M VZםv$Il'<'w΁Fkg-ZjT$s9!cv`WJ Wn+=ɁݴNDZty.HPE+H)7qBր@Z۪w5Hz.[79z- 3uHmgnM%=3v~ ;qs Q\H ($.TKj ,ק*ΎY]_+j$ K—OC1-<~;`%7 qXG e}ϳ\\I>*SUl:8g ćK ɌP7Q$҅8-[DwS W&#?' $˛X.Bg烙t裱TY~zH&/E5Op"< hVA6b 热:$X. ݅?Y&$49R8rN΁jrSB>!2\ODpzM yw ]%$y*~dS'w|XId| 8"ip*pOUfJ0,_0Ak3~. k3XY I+M3M2=]&հlpdgr3|MFS_VrZCm,#Nk4{O~߮'TR)ID΂bl62Y'#C؋Z߬5U9}nRϏ0coD~"fFE|HC^W x\TA[?߂bY[svU?+D!f~<gbY|M2|W,<\bd14 Z'jI8x LaclYaMw$0XnjCĴD] +5 x}"DW^ [7!2,F/u"-æ  ᳣trzU`#L3rp\iBf5Mkr<_}Եaёξ~*-y`N믽$ǖ>WGI )J~Y+1Gv@a Qnޟ׊ Džvz7,oL7QGi!%Q2l"}I= o{k_p񻄥d"qS- VL"NdcDrzQ#ӊ nZ?Xurc'^vu3^,"POm%ri?'y+C^ "UcbtHm YlA!+>-4Q7۝_snl s܅;%E:-+Fܣ$az [^BX.oDUhn#Ge?$U{lW N krNer_;r3zwE;U9Z;Zb/ԃב ;,!߮T d;d7󁾠{_&# F w ÝͰH]]3pGbY8`ߑO+#vɐA:JyNÿJ=bS) K&7YmeF}ESոny|&9&*c-'YWX]hQp=Te3fKjQ !ᯇBN<0X88&ˈ 1T4l g-YfH]ԖRT $#;CpOsj)!2րV`Јfmg%oos?&b;.s~dy[0wTHXyVՋaH{\ZU`}djJCzgKJg,yHK{O`kmjjRքGm6<~,% rʴIZb zfĢhYY ωox֥;@lXODsk"b@>s^^^seq$MFOgzH@OTɆSC;s݈9ɌHl&]D~q4"~>:r|a~d^gYC͑:RNܙ Smi~ERNUNJR!|)%T |72R\Yi3+dPW1ujwn"9/Tp*9$ ]|gĒ`6,d t"hq +jT>D&^yk $tROg9&#rՑ2M2"Am0^H`"錃詂D$Cnjm>vޯzޯzޯ+0+dRTդ"{S@-ZJYVZSuLR=D[ %o9k3)I2UFY!3A9&M$~NRR%C4s]6jcC+5~Q^cXëiM$);0(i,)tZXj#c$tײZW+U-."<+f;&lz oVA'I+) $EO,_3EX4wULh!+TѺȗYʶ:M tQ [ZZyg#}FBO aβXr m}gwO/}mui.-j퉾X%[Z}!yGݪy@t'WzEU@Ň=XxYlaM?w]qN29zqY# NғzJς97z@oIA}b/3=Y(l }`Dh2J2fyݢu<ݥA?Z~O Z |}b xZ_Hh=(K$&l:YOM~;卵s}?GC7ugAd',?mMDIZ!^|:"0OPw46:x?Gc7&hKT:'d<'ᵑ4\/x.*^a(vwf6RT7 d!؀~@[&#NpR ի3tVC/s}/IXyLcj>0bXۭAbEh;A,L}Š䙾T -Ys+r{W#=|gzf׮BI?2yz}hs͏}ǫ/,ΐ:ZZZп}$w=mN$^Abpq,88ɼ:Hy o'{𡅳S">IȌ0=@2]wBᾏ)t0˹_'=wZϡ0+X9Nn#PYa8 Oe5 uQRM u|.'~owzK?ƲagG'?HdI F~A)-LrRFRB#\ Xp$#p LGc^^sw~ߧo#ȕ5%( tח߯_{Mc0*"8u~^ w 7Ar[_X"hĎC-]j#f'@rEOTz:^߯4\ hlmGBvw1prO|I4,?mv[ȟ)bJJm/ݖ#,ߥ3ja5.>Wqc ʞ_MAo{3| ODFtӺBi|t+7Vc/ā}#D)x?8l8oxg'Np ^%'}X *Zl8d$>r [%ݝgx ߳<\pYq; /G7|w^>ҟ;}ʒ'm3<* O40$ROZ0@"u3^ca'Ve7w>H 8@48cX"5`%d3d΁,m*<}Ϣ{{?}+O=kg!(dzɒ9D*\(}~?,3ho-n -e|}b"R Тw.Kk^ma[l`WdeAS4PɎj d~V)Zփr`w?wn=:i4ٗv>>H2?γi%|_Gv󍵬GP?=$EdšRM3`v۞P]c? d6IL\+컦قu]ϩlgX^ 왍jyf0vbUI#~܏{oZdtޏot--OL8VfAUtTx< "$gl&WpaYRx*j\OCBkaE?ð g=|{H35/c)_,dDk #{?MjnF 9v 䒇w/XK<~uo+0GlfD3^M ގ'O!Qg~ svz[TbU@)pR/G;%怄 OlǁHN&#B%lq8  Ԉ?XNxTcJfK-մ R> i6"au[A~֍j =9YhNVVoQо@?M#/kYE37W7zP)I)̗$Z9nyTǮwxVsFdԄ-M!#.vz0&y3tJ'<aO/Kx" Yl5:ym*6t3|wn˒ڊ_O{]'+!sWлdxq_j/ bkWDrGC\%; ³=@8١Uwh7W.;I{:"&كaI!vbc!2+[®]UV? #NS5 xKX3[7FjG8ЖQOH6򗑩24K[ G~0,ڟN: _&~|hi֭AďT` U <-ӇoF +Y;2|z wC~f|{=oUǛc.`zsz&a|#A%\WzSk<+{ Ofhh]-*Y`y `"X&~# z:ha,z=%] r"fQW : ،NY CA(tAoxnJy sRBd,6볙 xV- s@y2;¢}Q" ]}-lj*ӈ 93BH~ֆiuraR%77<;"ҡ`[F6;k-]A+Ix hw8Ȼ _nwh-:+W"#}/G a~7q+6݌Ms40ǺZ^ Èg;o&_DԄ0\[ 4wq,;.s_TT0>wqsP-Zjk'xOi$a,16ku vm)[ET۵Y:2)':ѼSc4c/R/]pza64܄M_SLӨx2Dƪug||mh9+ok>;`f 1pڡd5_--anwHw wnt8'h'%`DIEMjJl%wFgS~ o?ޯ>mNG}fQ ]ɥvnѸ߷֡NO9&;ܑ՚> Ԗ&RXHcsd|)5$^Ѥ;Bj^ &c.3*Wè]@ -U{?^ޞzjvKlq,u=#%vRGh=? $Q-#0͡&4NYQbqlEBb K?:9D~Nw gG&8PoiaTF^3Oܨ- q0$'7$A<2Y #K-߬9PYj!;疽ξO{]w\_4!OJ3}MPouXGXMCvY4ۆ ϖ@ 7+HGHGHEҀ=Zۇvw Íݩ+`{ k&~R`cb?%pcol l7zݕT!̇K<(֮`oiin^?}{oej`dI]H[W~>LlݞAg_rT246F HL9hI.iE>G|[8`b9,݄:uRA;&֋hq_=_E[(C[R@ 쒖="$"H?'f}|J7Ql:h2 2ECcvf|߁^i(mӅ3?:H_X ݬښYOϦz"jX24uw{1vMl/%!sWϸnZ4'AY@ +6d94ᣉYiJ y`z4d08'~u74,_M#jvLZ߭TLqH̟tZY4}DA\e.֞ V: hY)bēC>䗛w+'+).4gS/hZ;WwtfyP ǀugTBazނ~wq1䩮vhqS*ςdkxW'Ryv~0x A΋]'*fHG,?Oe<vc'h <gC6AΡ}i"@mPw? |[ִZ4iOA.*ZcJޕRzZzsW)bl"'>cro 58-k-/ j#,PwFmkpK'ƸփHXv-܌l`)/VZBK @wCi)fVQWxlcdGjb`l֌6U~Bz;ϬԒ{zd*Y$u$OŨ;$%457QjA^i=k+.r'DΪҊ @oR,X{8XtuԚQH<_Y{l)(d, =$!_,ԕ?QWzI?6_ X), R+YWFI=D.j[uQ3D=%Z[ԩ`$^R,Т˫gxNŐG]uvV^e*(Xmm-vNw'I ɸűsy)-vcᯃچW~:6/mjgHn y|W1,HnSX{]G{}+48uwZIJ"YDlM.A+co'G ݢuշhe^֤{ë@~DX-;XYiq)b;_G\/.|wz|]E7֏j?8 Dķ{PoBj2i3,j?]`|rPlOzp=|G`??0U] ۇE td| 2A^$^i],[[>PpuiGs\_u9+? j }kDN=B#~ d $dOsu/4ே_ǐ릞puA&}~{_rjE0Ү|\-7,]Ɵ@>:@3}-\x|m=x4{|0ylߢjVͶYm"--.:|K= y`NVb: Uº!jP xހ) *86ArxdlE-!r&V r 2Jga=A@02u+# 8b~,N? 2Ȟ>{'>+DZ\":ccHu6 -Ʋ@ZfcQ}{G {㻞'GMb =C?X$0v+,V; cA {w3 Hp2zqُ籹OkȅP eBXcc)`R>y,6*y袯ևz4><}'=X=Qo6/75 HXϸ XZ{FoHS'+*lf?p.@c~8T@w^b#hmx _x.p3 Yy[0!yOu?sԟ/Xv}ߛZZl<fts.c2dԼDGDly6糁nݾ`PQOjZ|)*KTnt>?\ZCk^հ4?m7:z,~s)-9 h4bXVSKnI-0J0MM Y$!q6=A?p|{tKmZDFOkUxsM#d}{GxL,ֱŖj- #aR[J,=^ ɮߏ}a)ȾL>mG7w"Go'9L.஖tGOQvIKS͖DNijQH:9% ndڈ+88&A>'vKW@CMu]rfir"9.wEF3;*# ]PA/ An3T_nF KsyviIYonqPwYYGK6#Dh-O\Go wutr%4`NHLϬ6Yw\ȽOsSA Xdޕ:A߅[[/75,-GW|nJObL~WZ?Gwwߋuo;R{?,6@F{uNRiمNb|򂟄Ի g#Gjt^@3<2 `RśZy7g<Vl} cLQl0<.ym=k{D#]ZX#דVˣpnF'BhXf2h f鎀t0g iՐ= #f]: ݃O9A| ĺձl{}_g˩* Mgy4XT`% ~m$m {#m`zPO8'dq`Q(~,`%tSAX%gW!Bn;]7 8hvƳ7[9nAP_!zl1]Q)Ls 4BS;&|˨7-4<+\ l]Z.v@f|6ڨ q}A<])g@v- %O"7q įG6R$6 x c;R;L ե'"mI;\߉9-G{c[l;^XGKE"ޯ~R~36g3;uD,0;Qd|'[@~k.1Mn'u#9S g5lX;fs-} `-9c?}27,Ƌ>ΞhDsKc2ߔFp3قOVX:A^춗=Odf~ՄݒZ]b-oBto: ?~֟%ē_I2]\åjm'Dsvgo}vڵ1OW1;,%Pp4ZҷCny%|^jT@TRX k!x+7qS,KJk_7&B6Nk u\f^â`\ЋOn9=@oG5xI.;wKpAZK\ $wAn('%?}ǵN֞k#BL ׆ ;Nă?m'ZNxBs!Y8ǣv7F4N hbͧɨ^Hur' {˜XJbE-#y=\XJy]u&n.ٶ^Gh!. U:9U2 n.n~/:Vݾ.5%9F m5i'Uc R M`.M/Oٺ Tȑ*xԟ9`"g=4 Xφg98)E3{^o9!! "ėw+X {O?(OoWa<5nbRkOY_*G~=ѯ`$fJEKY2H^'ŷ['8nɷ-}܃:~)5LG?Mǣm~ &hK+KPI*Ti$ a]g<>L>H=o{ߦ3D` dnCͭvXKQ%hƴtVȐђF5T$!jL- f{+;DO!+HtW5(gOբcHuߏO,XB0SxW"'qp`ŻTa<^Njs}&yB3.Z C1)˃ 7+.(=%{_vDŽ:r @++<9p6ʼnpnAX@)1.A$=#ȭsV~hT1$Cuxh1i 6~9^n|l3!18)ux?<>ad+42NgIR!5-DjHzSo#\&$6>7a`(wGH"$yWP}tj3E| kF&-Y,sW7Ş`x;qh*l^B?R=̀w\5*eUx&-%a'2@&cWx˽Ӵv v5?Pݔ ^ ww6e_$v R李,j&,ݲZhnidHJm77(/@Lv~L̜?&ޟ/U&B@1gIqc,^ja?!-]ۥ8ex1<-bHΈ܅B>Lm/ f6!ઇ?^e\9M[KkbK k_BYT82Î9!ݧ߃0Ihg "=Z^C1b5F&IC)&ẗd0Jd-jWɾDƻMܠ)6>ܱ5/%ʃw7#ճIVB!䪧?^p@5˃,ϑr#zAbS8| eˣ"ȗ]k:Jm*fh[]-#&g+ޜUNpؾmTt4'WN+eɗo~:a-uQ@p .B% www';k}gms^^kٽfWUcQbixds5\=9lIWT?4\y7x QV НޕAޱu; 1kh覸8Jv'F d O4>O=_ 7w ~]]@_Q!IuhM@w;NP1^u9k27e5E`#mk\Jn*%Կgn, a?`:pzqw=']¨R&J9mTd\`;L8o,I$c%vrRw,;Yin͢t<?(Cw~_)].d.dP"|_i(ͤѴ%œp0g+䋹|$rLHm,_YKIGA~ZeD-){k&=jlu\Mճ8,d<2YhL h \|-i5q]nҀ)ԄHw"9/ܐq AN+_K'5^#C~}.iNk[b;0HPUWՕDNCa?׮_^Ků~!OIy#:J#itMԚ a%yу?rZl#s$!=({|e?\ b8]yo"kE(V5MWNMڿ19] 7l5awZq9%eq^,z^NK*,䚄?>GqdJE3-*)V 4yb4%n#ĿdeY.&C=p<\~]y;580Fp[,}q 1~$ƹ3 \xl;.~/eLC~5=,3}^7PJL;_Qw ݒTg`}\V|:?[ < ,$uw}+:(o#/;Ћ:ZJ!P0{ tÉmT.Ke\Zk7>4p?lgu?8#Szs8ű'͗XF)rd}$Dېt|>o3Lzp MD-GȮk$?6V%t_hH} YWe>8?u+?~э2#{%FOB׭Zn,#.!I7 MADQځ3M_/~ALq|e:^ b{!Ke< |iuVG;fMX${#I))&#JG;E m;7Zcgd;G-hn.ϣpxVnv_uYGt1 | f7#{R+ƟKۊCXv3VւIV _kOm}ZC?! B ƜĢ $ 4aN9܏mDbWP2`>?/("*Gl/p31u~N'o5?_ԼWҺ&'+vݍD7aWSWc'* OS"m(ps >b~d16 Ci6 G*m _vZ|-Ә)8poh<<\a~WUŵPQ(^9_XE} /H88y@bV>ްmߟ'F緐&s} U^}-xo;'`]ILP[V$`ֻ v-Yb뷺ыD-@Owyk SHEpnĎ~wh))?k;-S}1rLUb ]-w΍ۻ| ע W4{,9~~s示t [%Vh+YgUS zf.%bpﬡ6䁿$Pr9Xq(W_{yU'R P( ۠~`şz{b#L Џ%|g-u Rh>Yt3w?mr%1փnp?0Lf#Vf.rޟk'z$ܞA.JTHS4 -kw6 C}8aۀy+yc7180 Z'bC ą?Iot82[ ɑ?ԩbY?7|L3G6wm亶Bjdj3~⚲"ҚkP3fa/9>O.HWxrO&a~)MwiF8)V9 ifbq Am.dZ#$;-9$Hp n.QUykTY~M'FmUf -Ajґn;֑Rl!4#џ%B/_1U_/!͉=-AwDŽK)O5Ů0;b4i o:m~B]Gv2t`޾Skwz#SZ.N_S]Qwa㉂݅ЀfheV,ewP&L "]#1ub~G/ǕFFKb]A) ̃X@g,<btFf`vxs'o(M{#!:euRsu\fl/i|t^OTr௚8"-zSgU#nTc[D[1_g>W"Co=َnaA\Uld$X0q]~a7F #A| ~x8o&8°e2VR:M ]$=w ~H"c.9v;JKh ܶs[ɮ崘^⻃bG:5᚟CBIʏAl"!o;^%3%םmrg5`kb h̯d6ݯNt0s§'h>ن(NG+KmLdv=[%#7`is  t%%T/qՅHo$(,(/n+xgud&g7$>tTAΛeX^Fمܸ-N"N V1r>J\ͧ:,_X Jى9h<>+kdf֟!t!;b] 12޵œYuB q !,wֲG7p=jFk M1~s:*쿌/d庹ĦqUM~GXTzF}dÈ c leZDzZO-'Ѭp$vx@W2ѽận/؊V8a_xA%+AnD4`'ѢXQ&--h{43| W{ 7ûy^=,?KF|"NN |pB q{.D"sb :SAav} esn{tL!Fb)% VH+k:"|Jj#hrXrn֊ȭ@Kbbn@4߻{'~BZ?(z}CnaDSurhb광R~ziv]qWEhOrTzWn[}Lsկn^'9$恮 Z ߒb#вb~ޒo' :ֺ:Pՠj*XVJN.CЛxy|3?m3 B󀗱yό~kDҰ{ǵӒқ^;۵rYpA)~k5mS^~uNﰙe_yRRh%lbwCbQg]?dU 4`|dʺ7w_kͅEl1@Vӂ8&9Əb|s1vѲ |ɩuZM?7Ii6'o}PL>3`HW+4nЏA7u+qM:G2POiןKu>[sMq]@OG۵:HM9퇔?bх x-PzM +E$C\/_i@*P5>؄&_\OBmU"פX\|:[K31Qs)@0JrHYes4 ^CqX%O\\x`@5(\Bl{MpL[feۈ ו#zl xƠ$(3 ?CKc P62߉NtӮ]ms1hsx6C#!h@uD%<趆48?%>q.Wtc]_|9u'IHDJ~)Ψ了CrS JFw]x&9e\.l;.un!s_%44Wti 4זEJIDpG+SJ&d҇vY$Ygk4)~iy~%r5 ӹȻ$ԫH;F=*eu,te'i-}~/$FԚK+i R<ú%<6ECi6Y(l)$MwXkEI"S-`^4 +O ꈺ:HI_GUsx!CY.W(r?+I};9L vRocVKl ?Zvfy_$W Ap$' ~OܒAnZ l %5@Mܿ?2ߟͼG|_>]>(d=h{8J 0o?WoٴV"ZVGk=m%~;teGPVf/!U9W?Cƻ5/$1^[ 2f@+qN-X|I/r!3X@L,{[NCel ؆ո- 5%i"K D@sAߏ|zzL+ ʑ`JyAbl$F*pȲp:1]0X ԥv%kg3 HPmCt@{{5?R xq`|DV-vXv`3cx?,Q ^GF쿵ۯr׮^-0=ovJpﲌ]aUl]*AZx*lGw1~Je% d\^>Ǐp`mPoÚO ud=nx zu> Z9#%OX#bM,åX5 ޻5<}y2ꝾRj-4eXt@ѝ`@q/=f8U?QjGFtֺH 8{=n*{v*e o.]wd O}K śn-pi<~|Z_/RϨat7hB=xn[ރ `|'cc?8_x",_*Z^RAU᠄@Z5_/V U=y"ɴ6Ae6L_se'>UH,vۊgׄہע|w%l6_[$eǻ|ټNAZ"X@%u6О qX7 BO"*t̢P[R{8(v^ VN\&-GLNg Ϻ,`.9h"_$,'P \&[nkmЇg^[+8g8k<vV`9g 1a⚽sb f|Ii#-5s+Kߋ$솹 OµMPh{͒ϣyUtnap @g XHICMl~o/oL[69+$pg˿NǡBW] GAPr ow  7 LxWz>GA '. }d5"T:-1{+A6lv_O;@!4[ωÕxRNd#C< joG}~w Vk{$nkCw;fjn) O?_+l5!׾ a"u H+v!Wf|\߹d>~^MWu26/NE҃Q4`֢)oXW= =B7ixs j5_C(| 6ROJAb4v'?o:*|ߓUhCK_ƒ[3^AF,r) NJCHsՈÂ͛8ڿ k} "mbuj G*~N`  e%Uwp0aI$ K`?%|U-5a >kTK:K)|'40Q1#=1*塿\/Zle37PV!W7Dֵת? :ׄXAsPԁU$T&KH-}ڜ?)$vXPu؄s&I: gmoQ_^*_a2X_ľK5m=$'ܲD/CYdH~z![]d~Gg/=ݚ|,Tr%\{n0aٝ`~6|nk{7Lu )t$]92)"aYj&ƸZ@=eDG_n 88$O?7F#‰P؁\p]"h9p\%/]e?u4 xH/Fas#hB?5Kwu_I52w!tSL"q?V Ǎn4㏈(?;M?-xkG+ tl^z[ohYX4n;,:JHlb_A K\ČKp./{!HVZ E_56b@s6h2t1,'nñzy`h3֒@/nrSo$sL#L"/уT5W7wx`_8a=-aԮZS9uC6B .pp,d&.Ej.ZZ{dݏ= 屻쑿4 Wg(KR@"-j>G Xl| Gsz R+s]d~WA4_L%m7dYD׬dv"6\ E4V)٪"jVqQ`X CƿڽljyJ73n૵ށ #R@oȉ4G1"hXO^Ww E q^EӐAi=n@2p AIs;oX_ ??Nl.r[t{Z;&}jC|ƭSX~:mt/=DdXZ W%h.] =݇^b#VI欯.Gd9T?跾t8g.[lVw:[U >ԥh͟D,ФBֹ.Ѝt9Z$ Hh9(h$1p.X/]|j^s5y|Z Ց02Ɓ&#T#~ЀzR_m_Ctמ?6 m̱n)݃-U *jIy2veh .dc$~.{v -%<23D.i.UH2rUl?;Ik mygq)#wEdjg⣢𛡪 џsdEdP|ل'[{Bm%9׷q)]V׈mUB=|+YJdM&G :lw`uiz&`Hu-{$!+ADM_b>ق?S8jÛX>$2Ap~x7|:>*`%-kQ"Vi0VzVwKh7C|.h|[hop*FS4b=H {yEAw")WK&DՈ% gI|oCíqchoF۰;ZS_C^= {Ђϱ_.p]`$ KO9~4Dz_B}玁Ӽ܈ g\YsžӼ~ ?I0?4&HQӕu ȀHzHMdk]239$j5!llX(['9׹8f`wUkAC>\uúXkC2Tݬ2Ҿ]=Q=8Kw1F67ŗx*hu*՚/աB"}Tu zW:iô;U^XPӬe5ב:nB/V ZT)+9KP:hKWt 2Tj92wp#\[ciuaa ;~rLn+-t7_?H[j"} `l26􋮗&) % :%sWjov?O>?$utt D+NލD+tAE⪺=:rKD%*AǂFE,Хt&GGdVe!N~"9↘ts} P%TwF;湉.DAق2YtxLv2΍u;Rה<'"^1;iΕv?ˎGjZwxNzzu]^2qKʈ2zRNzծ2 4)GGYh즺-.D鮰K9vYs0ik/Q2xwwGcBX. N5w]+ǜD]^tZ#UpIxL4 64>O4>O|d$ (E(05'Mc}twGVhMt.)mU"[nHb+%Ԓ `@_ȃDYIpV?!!M&QUܓ R3ч(@&޸f⮹A:VhiΠqt6ԸS:iGC<&{~OJ]i`i|}.ŪZeԜZI4:͵CXc"KsQZܚLl[V,)"j8ͪst U4r](UdW$(Z]iM`͢j :`;' AtMߝVG䜼.Ո9*ORd=щI<ȮUtu֥ ƾKpq$L]:!P~ }? Xuxgj _ .H:9EIs~i,A3)/HVw$ ׺;ZKPf]=~ȴ*FΗye'@~IHOmh\b!WH +"Z9 |v%|NqglYgQlc6zrh1~ܜGC1kT@ xi-O\UGpm/ n@Oė;[H5y"pO[}^X n5#yNxfK ^I ,͂A>*iTJ$Zmm,"D6q8; у(&Pz W@~ ұQYAGg;jXߧzmQ<֟٬Fa02D\$ Ai @D%&ԧdx}Y|':@o7%MZEskl/x d~%q0?UOU:-LѼވ_󽠖ƒ0>z&=cABOzOSHmpgt_{At~F?C#Ba~&yyO~#whU2' >_FwoC};/\3<~֗FVkdPE `v?7_b7}zn {OJtߋm7hx9OѶˉuz!_72=`)\n!4ڌRW0XTE/B$Pm^xAꮍ2~Q30$h5T :y<;41iG@U;<仄p;7vOD"AEu1l[5!n4+NBZ[ '#b}y9"KCDt5&7 0#,p(§x[RYGdTSu!6N!F(o[&/{cl2Ԇݠ1nP(9# wMnնDzрp&[+#%F`A)ժ'L܋ޣw$ N35Aϸf 60 M+_.վ*<[%ryQg}g#篩pq gׄ͢_h? L<'=y3H; Bsu0@R_ vV.$^x4c2Xi5AFcU1k}{gRHѿtQeNvC$|7B6,7;ɗm9.M2 ߰ *oGmoQЈp-m \dKS$Kz=utʭ~s<}kbh'nL4ӕ׷{Ŝݙ ^6Db8Ooo?7o|834*Z;NGJyUeݍ"]'vn}w_ݠ'i[F|OqL25 k"q$6T D!;x$qƓ@ր İ`9:{wXߦ^+}=}=(R@q? `xt"µJ9K80<ƫ2 ?u4@^UN}#fz6;WcU'!6-Iv( @Pw{@[U@|z%E^#޳V]왟]YA`e`w'@U B|3ThYЕVSJHhEH )W*iU 3})Di bi:%~V9Ĺޤ=0 q[_0XGUCi)#EAЖ '-}ak W3%UTRR=~98nAaE9}[M:o+q-Jr2O(bwXT80@=/E |Tx%Y$'(GOzO/Ÿo8!0YM!/wq틔?D?Oku`ՑKo|=8j9~%Ț7Û\EK΀Xv"~o04$נ tq_+itmEy3? ;gv"ؿ 9b.r.O|'ђ&'] }}rT(Z13`_<3Arhm]U8% _/GX;0x0n|FP0RT:g@Ue~}5S`(4 U5^.5b_b':|RQbxwᤕKZM 73p:LpJ-Cij݀t$Vnk]?_5&YM\-Dw&wU]a9YtX] E} -:[Ky(!⚂7^эp+&R zǿ\?u x'[Hoψ`׈6C_7$- aAX{罼ͣ>єG[ՏzG:xW[0Pc~ou_+2\|;'iTbXF'gWJ5bs=-GP V3Th@6׶ù"Alz9ViП[#ӎp[JF{ބp:퉯Q|s|UTM'ym+%Kl&ϥtIs8[U;UlOv}u-pg W@].6Jмo߲Бu1bl" Qi9< `9@a/!^u|6xW 6 'ۅ6L0l8Xv3Bуx?t ?l'BIPWbu~#,H4NtFv qZCc(]Nԋla1h?V_ W^_J4?9LuxX<"02Єy|tЀCo_nV7.Aq`Qc~' 6z=,ZpFQ#u2&/\w\;A#<di&#仿]ᇃ z>+tzM@Wzb5c!aD>TR&/#dqS\>I~ʾx^cφzʛm&zo>@K `goJ!4d;h2"J&]D19nPkO~w4 O"(ho^Yz"|YZZP/sM_e%WEl] N7jm L[vݞH,Ntߜś[i#𺼅_/ӡ:r4pM_+wFA8y_b2@p;﶐kŊI,s'lzrZ.,>;][a- u /}ܽ@W#r%=ڝ~gX]2U OwWd?Uߍ=dH ^` qha9?:D3JpXt9Wii,(@}?2]$3 cNݒ.$#ɤ?ieP !I%`1hHNwhEZO{:Zl5T;o .ީ}=Kt>(^ 4eTqߺf.28n}jZ"\г_ =01f Ji"-ߠ'N?x'>ZO{~; *P~rMn{,{SYmhw<>NLx@"MimJړWvE/<YpȗMKñ&hb⺒nm%W@D_k((=n׉W]Ёn*'?KD?U4sM?i\vm_I#Po3i-SkJ}~&-t=AG>#A[i2;< V_Gud'%}yxGH4kJ>$ZZ{&dǰ8򜈠! :ZUp\EfFfškמX0 oCG]N R5q57-tAG쳋;>/hM{ "hyABZhO`AGjb}W}N_'i|o|n=H4בǥ{ovՕ{W!x B ACp$kpww 3w'ٻ5EH+M[@쌮i6B '*fVY[pHmLU{oÛ; r+6ZY`[ }N C`ln PT.N@Pe=P0v~ۊO|9?߂)lқXxe300!G{y,ۤ4^1]@b2@}*~K tȖkZc4jLcMwG9/}e0-̕fZBKw f h2R> 䖤. 9JjS!qk'%J=~'E6r4aͬC H,uȳ% .RM>WR2Ks]Iu: )|WJ=2I\#|'$ѥ 'ZLIjϵבZHK"R`БIr`rJf#HדgJL?[iWin-5B/$KO}TV)rTgGh*?>UZy`ݨ[KjS6o3lUU?QE:#z96*~kwjY+EVXkm?#^~VN gMZ7ݫ4(8nOykl,EQY߀uC@l/qu_ ~_oݯOm¶^HUvVܞgܬ>幎ZZ*p;#O7Cg_46Yl-oK7v&h1s ev?7RwXqVbPabQ$X(bG%O̞]Z Y܊xu^'FD}=>whe/^kjPѭ!7}FV~΢%|ɧxW oa@ZY"_JB*h)绠Sh.Ylt* 0]};   AYP09:8:Bݐ;* J]ID^˭o3_9'ym1*Xg]'F7!#UFz7*U?:rJz.&f/x}XB߽~o~Op/O/'|і#_#E|saI&層r:YAu:?w+/`3uN'7]@3ϴuj#yAPv:LI7 ߡӰ |>/'/x?N:TWV-m!ͰD -򠏄6 ~X{?O~*2!,R^3?c0yO] ɺ[뻼uV^=o{=" e x\(Hk-5!2vSkK((tWs4 E1_I/Z^65Oy0pģFhv6xCIڠw~=$"My9D󽿯-ec_ѾЂy)@d {7Yz@&T* 9R:B]}00xp`n]HvC;MƳOWᒺOw+ȇ{hSlE;ۑO'Ni?{Ƴ q,lz~k|{Z:o56h4G%=uGG){dClΔ􊔕_AA#+w>ǣvB-|IOC~6KųwAFfk}jjvs ms~U W$cQUWFB@P?+;k/5;sF6 jOp.xb4^~RO#2܂]wT?Bo;SXXK >ǿ}:+7:`ZWsH@o_ CVw=lj^-alz;W6Q9o%M0uzr HK~P{7™ 禥F4)Lh $<9ko2dvBO/֢ 7WxG2 n~D#@]+z2W_շKXAVf fxX ߞ}į/p9 ,#7J {\ :bcs3~.|Yޑ-듂Ȑm is'%|9szF _!<.һ 㨊\_ء=3ttk` VӰXc=~c"`B/AYE2NwcX#OӣiD:pZgHfDZ6p=Q?}W_}H7f5ђ!^Z]7JKI\*nYlp=\DAS"wD _+ʙ6m=@1`}r=a\/~2`8FF9&6k5I4K! CLvwP6|B!s~g7@wMlG+MҽlVf[`XZN> e?CN>9hQ\kxk4þ#su}s]/`&zŰw)/BN1@܌s=屔ws"8+eEOm_CST:y$_9DA |o 2O*B_v"Yo d#_=1! Q yO>#y(Ao`y&[?M_[qq|_Z{`Xo62oAD!>%BhD˞Sao9ZȡQFWdHLR~jzZ)h_o!9Y3t'7Lў}5T< 1S3 :z-=2h@p O4)6UVNqVkaWz7.Hh3C'Q^D`/| B[.rdI/fPo!Yts,` x~M|FAH y;S|Yv2D8M6j+F]!a C?ϪO+)4>G KJ&upƃBwi,'-ڃ^&WfҼȸGk2=f)h N |7pf2 $?K,=o&z is} <} шo/ FვmPYO?7s]d*uD#ڝN%O.jApVb~L"]e~V\&b\WxF`{_obewmoCy^W%%~c'yJ?/6σ-l²w-~r@t_%FfQCBGaU Z\ &"wwsn h&RuA}}z}EuM_Zu2Ecd'7ns|.KG'B[>lVaU6 , ƊYgI`RkDlqޯrcY>>FBƞ2L`=D,(kvtv$X6 ]"G+#Zc'$phhMI{HZ?Y@M~n=`9@72UV?׭˫c/x!6Iɤ5tT>@z~x, wDrCܤ۾/||[pDWWIR$/#"SJΥ}M;f-?qyﻄ>F IBJ.lUO g;[!u.ߺﲇ-?!b2~svȟ~2b㦤-?bZGߥ1w1"`3$݂-`I3?x9W yv8Pk yj lKI2Z[:IUbM>Ws\ܚxytKf*h,D_b]+Xns(yO'b[*h,vGz-/}$gDbpO~BF{5g! -AY!>)Zq0pM Y A5!+R (I,0w|_V>S7 NeE|^d>Z[;=cx'8GD$w?NRtc]O}~X]OGn'x؊XCE;{9AH4qw~FĻQf`#i'2@1l~w<ޭ#6iFhdv3 X&+ֵBudBH;57 j  [}8_6<] sW`=MaAL`fsBc)A;,bUGJyKN~HuWo; :M6# P6h8KC ~k&-K&,`- ~ iΑ&^ﭐӭ F #+nɌрl`ͯcmLG?uT aSgM<`e! AԓUrO#<5"|佩xůTǐ&1R׹1vL`ݺ|Z*2[C QNJKTL?!{#u;¯/j%@F%.jO[J2ܧ/9+nlН٤4ލ on>z+[< ͮOf5KY1U;w}sKJe|+mS?rJ~(Md~e/+܌T6Q-y:GNXnj{Iv@2MwY|uxo?cK5GGV).%5l]p}/bn_wwe /o@2kAo_'%D|r>$Droa<ȓ c;rb{XRT#8KI"2xn/q,ypZ̾v7C_iA_Ut=8Y-g+t3r+`RH F b;?Gd;Mf>-lB/r,s42]u~a{ r0!'XV,d$Xd >* 5a]d;졝ú !A*Xvkkm3!–]2!,I§怀5 1݅K=Rj_Ș733 Wv-J/ha S}Jn)0w;7fZQMְDB*9h je Wnc묩{ >(bu`E'DC6-&5x†nG_NNj }s9WȒ@: (KaAMy{erRO-A$߰<؁6%pltqB {cQ2ZzMN;"cPQUKrX(je<[Kp6Q$&p"4;G\B¦V]c ,&f` /)kz=n\2 t !v E, uנmkT3w_$?6~-ʿxdRVIYJpNo+b@<[)?Z*)1p5ه7{>KZU9Qq^N6z)O*$@ S`xu9 #H%%6 î1wS7xFSI?̑,_vJɡ%^lR2{='JY:Ja;DH)lGJ%m,3~҈x@t@!]kg~So9eղ& vWZHw}َuq+4+:AS!q^.ѷa|0U#*WgHv)3P̖H|X9q#UMS]{~@h]O.uhFn|?\mRoti~7q"֭.A.8>Rоv` M-1S߿ b^u˾*R^ix Ab|-f4 !=_oG"_~4zح \<`.G>:BǑ7|oK;R4wLVp=H_;b׻8OReX|rqIs+ KxD2UZ6DndD^=N=0DTt[Ѻ/>BӅ0'l[?ҳ81V=O{Y_7m#h6t?[bl!b_ ;Lsk NkF7^iu)M+UxFb` jT ֓Fa)0Y{ho ]#| ϻ'Dx0&yO}mVLn[ lzdR_nC48M;㮳G5|߭oIou u<_l"P;a{<_;u3KlLq M< K|4ߍH~7&k`Vd[?ƶD%a x -Fm♣0LV3R)6J[A[ %Q{H'+ mK=;=k=mw6E SAxw]ơ @|gK+t /oYj6J ]팍* ߯@k5X{q݇c跚 &⿄G"u+ݞǹpsdV?~G.D-T,l)}Jg-(>9\gÍ hu2=}T/M:iG|ag[Up0O%>zx M9|oIanb,*wiy}8.k1iFįŶ\,1ː}!8/exͺH+;H 5w노*?070.V;ߧk#ϸ.1#@Hۏ) ..#:~CƤ bgj9<,OAȟ,~{Dq?|(|d{g΁AU3&½ sLBnXY43G~LJ5L < 'Y0 ޑK Y|hfy†`_io<qӀ:m?irGDӺԗRHp]/\ݧaR&Zr=×y~Tdkn=l {8, iLrW*nyq;J?&bN74\d0'DBVmMm7sIu ދ'-3K%tfYUGrKv%njYneUpxr+_l=THKD*Z2EU ߞ~y{ yԢ |rfY*©jwCbDKY_i hnƝ[=tsbwa_"9f1uG&.zi$'DF `9㇁IDFޗ#{?Ykc ;hZ0XGG*yd>ᵟ/oGfMq ."{2$}p;o:ö2Mb%~H&Y/2@eװ*sH )%J\p>aJ㹻꺋s_: Ym,nPWFb~q0 ێD߰OԸu:w! x ?7؂5>|Np??PMz@F~t $KQH#kǽnnbb:/Ǣ^s1Vy,#mS:䟎~΁kFNy SV2R$%يo.b 8g {IH_">~}--]x=^h?\ǰxc:$7^*k rP9^꩛TbiȿIt9nmBZHKG"uAod}W VdZ& &xF21c =:x@}(׀7K9--v1H6Lx = 9Jj-JlU މ\xE3d)@O?h? u\Oŧz뀠mзNR"Plnz 3j7dXԥB%a}a9Wf>P딺aþwmbI,>Un~)V_;oȠ` q]= n.eЯCH欻X7*-_S;yW&oG-) 伔-g"5={gW]?<Iͳi?|(ۂymXN^od򤋆hd =@ji#9o"T""6 c6V{v$ W=&Xv++nrIkaT?Yc{5~G "a})=GrߟW|/ vk6^>(3q2ۊ. WzܼC#Mg'SV3 =Q2?p'y? 6|G `=yE9h`/ E3a=t02~ \X"'6XuO}s}r󀆏5>U&@3*ދH~'䯙|3B%=+ϝ%^"!%nQpz+'#ݱilzDЦX&D~1_c~`< l[vWJ݊1A|ox~ p $jY9|&R61x;h}z?|0yn^pNMЫհBw,"Wrغm6DVd8#UBKeuZXCa@Uix?{{~Êg>Ng㛻 yg)zW E/w|VM(d+ '_ y%ؖޒSCf/Dxb2ô~]ꤳD*t0/NʳaglhX<\7\QRs)G~G+aecpK8@AHb_ß"; U[$M `_ؗ!dY#t{fu {b?3d{[8}wsn`~[|puun(hnG47w+/&!|pl_ [dY*;'F ~  o AsxQȎ|%kօ$_ 4s_)K.'\on]/soïY;G ))_0 8DV-Ѧ{#}6+yqG3OkU#yگxۆW 'Lp{i %SW#<ӢPvxǾ`1Obeu) d !/uQK2I~@@@@;"49/TX6RX` ؞"p ,AMB; Q fyD\ z N OF $D |ϰ*{i,m༅ T 4 t~nf-ʿxRO嘁'6ZK>/۵  G|/K!ǿrԐ$%Ģˮ0^R+=k9cd2fpžD&4i.eL(HYTHm~n&=etȝGǏH]TF`Οǟǟǟǟǟ/G\6w%%3S+nR_2JUJ:zJdG 02]Jzm_'eY!}{Me }:aԃWʹ;d3r,aAՈW~MlUs';KS c'ӆxS#yxE{{ܛL~H>dA~%F~E7#s C &%t\!Xf(! ֯l>Y#xd:ϟ&`KdE.,ːڋe~_}r+ J[cl!dFli88نnA,v' |Liy)ž;Y5s}aRgOkE5DK WvҔ7r/[FR O=jM?l@(is7ZzW~nOK:Qա20DpL0 lc9 x\/Оd)mC ާɱuq=rUz<{h+kcit gRGVgDz ҇jdc `؁\{;n5ι?T/^HPí nV^mP0T$$gQ|FQl7׋snm>n/!/ p.#|==n&u2 :\ O#MŢgAKx[L7 #rVWA>ėR zn>) |Sf͇94߂ cuυ'W^Y \'R .۶u?@RiD. wr3F-Dyl0fl 2~_yr.8RN/nben H 7M1:C;F#N[NZd[iMd MkQ xq,ܯ_J[DiI6QZM RJzH=iߎ? [u7Z r "9ew (~Nýc^ `rhd7_G'h_RYSo9jUd_*Nl&~{l?ܿ7[߉ Mgo\vJ[& +!?$D+H&~<+TnӞX@&4;I@ގ[n LmALh!K_[I?^Ps]c>m\'$_:)cpwvr2ZZ}9GSd0H8]+:Z|;J wUj;y?t O7KWy1~u%12#?̕ H gGwtMp툡T RNb~pdqSk:瞶B J78ni ˧'xl]ޱ{E:@ԜA퀜QuzXKlâ7ZiP&F9>uo+sr5Lym$*z{l2Inz$y;~*eAz͐jr76mƎYUVaj`d /|6\=cWB54E8\I]SŠ|]װ$mkTӚ?/GypDNu+:cEyZ?9U*?}|;0wj%Maa'W*ǫH^ȏhȊd7z^KնW}&p~^ļHa`BO JD+xN]Ə.j)2I~a_3uwZxh`/%zߐg{inb~Mr<|/raDز>h*/c|fh`j1YRHuQ7}f]qpnwOl| a' WVǦnoLxMO;y>;@śb`VSDVo OpsɂS;? duB?J\l~,tTYMGkyEoȢow剦|jj CkglToky1υÛ:oP6v%2&+'!6rp&}' r~"?96jYmH"e 10~^&^#[x8_#R+ =B:k;€I,1!$^&"|׿-<_;F#J,=#/)nlśKo^-GvޑDT-}^;:DZ"1DmX2s<壶!6F< 2˻qsbKBd_TQOxb/Z4꧀)?xYdnx!6 _sN.-d6d<00lLl? j;8D# Gb/Z&f3> r9ELB3zmNu*4qwy>!=ݨ?fw54̦[^s𾊖 ΐ.i;v4/m}'֍y>BÄc~1q}cZe8V6z:=}= |ԭK ;~mZV~"% YZ.K{仃W`k65* 2"=UH_ F /~$C ~:ԊHM;ж=ҋ$RMbݜI<:^z񓛇sOZ{kdu6a֡>?u֬ݢuMEd6+7t!@dz_AiIdV9_ЅhCI0xu=r]V&k }[*N4گVvV.ړ7+G;KyHR|y+}[59pbNk,?v0qQ}w>|ݭA=5x0؂xߑ,uxE6\!|dCBPMO/|KXP$Z(&#vYc{Ʒ?؂8 md|>΃urG]}u`ZĖEsk^#=x|pwn]đ'|rί/j]g`Go%}n–k9C8]&=D?]TÒ3uY>$NF^}}%hDŠ9^Z(l"L%WG7WDT/W*e[@[y-iUp-@ \,wwwwww $}{O}kk^*{fRtl<}g[ƶg4Bċm İ,~XS( Pz--\`nIߐ.`s.DwW :Gg0p{w:2#%x ~A_׆RuS[Z5S-3]ݿŮwi\$X?ϓxEK@O 0L0sX8D%#LEvH;j%ieJ"P~/x $YîuFkIiq[\7鴿`:u>f^<@V/mq::E,(I%Yx~1U|=ww֜'"~-pC{XC]XSb_l䶘qWa`ˉjdJ{2DilqU\RJN'<}q^,8H]Vp;d]i+tTַZ^ngg,3߭/!7:hEM3ހ  柛(I-,D*/%e\3*}O57-h~?z PhHM\buwsMA|g;0U 4zjXm<omNj|PXew`Om =!wdf6w9K8BXmal>L7jcQ`l9p1Z#>Aou='RxSQgQVFi%U4߽/,w`,3~M~=Kr`(P3ȐT-0rX%Tb 5g Hh ck|e$V!qw vH`m9D;F9=_xK[ol,~1[@@;^J(˽X٥VK8e;]JM ON쑞'JFiV8Qk-A=ZUI]XjI`FRKw)df-:CFRJߵson,|-m s\?ן6WJ2H^I_٤,<%u0oU+ JjHys"w,wW)v:]i.ߵRI2* %nInV~].4P6J?MJ~?)⏽J ,_Bhgk,5z]6I*]Ce|oIM\k?kkMm4\1V*|$vm_[Z[7KӭնT}luVͺ[*^:"TN-Ŀ*5%VijMۺ.QYRZ9Ko, -ۖX e?iW\ o&TuͥƞYSj.Vږ c19`VzDEEP 0J@fK.&ږz?h"n(6OeqBR}#uY0=ԣ~*PIUFW*I!)ap7e@|69~]"Sl5`Q> ݏ<#bZ&ʚZU>-ֵ`@`ҒZZ]ȶBo=Ax^>=,{|Hg"^>Da-;0Irx Rr{|8]K@8wǷ_ ``Ų@{_1ڔ8ȶ䓐sr\D~ rXRFR|~9趒wW"w{* ~ae{7R͚ti6dz%Rh]ns,r=|MwrCO9h*-w<φW]4\:Ğ 'n-y,lYȔCYM=h uAm&A9Aֆb uTVlQj[$-x{ ;G;N?"O\8}#'Hs{>wǐ>qZKYC &=]2Z.fPfNȽ8D]~#Ŕy|0`==2_}}tR7}%*Qd {\eiwE+@~yvJl!&u Oamr:y9}`#lEP)`[:Ϗ;9M׺ɗ`#ćzJӺ~_32[u5vO t;c˨ZWx?C40`R֒%XwNY]R:q8XD\;{|p2"b=K ; c4uQլ'Gq8'r;Թ~B @v&uvN{~ǯD*'6Kj >1\>Πf`l)Yq!l0=Y?\ؽp Ro'@|| qF _\"/4ݥ?n")pc<{tP:[}N >s ~+!"swW" ?w؇Gϒoa<[;jNy(A e~`&"r.iffaPY-&,PܕГW1ne*x~#My>) &:fgwBb]dm+nh6A:+  ׂ&5N|:O_tNOiC{Jl[ІMO&xHkj}| wLRYzoD佴|sxOصghNk_ԣbl|O^ۿ3BN0^͊+wEhAtb0D>nҶ@ewEUs 9LoolVEʨT,P`QU[vFH?k ˟]*5 9[v!rp< 2QXM6ERu8ec)a%D]* o<WvZ[c9t4Jݛ{ ;`"*fV:3 0q$·CbŽ Vff}@Ix!ClmӴL1]^;n OmG#;1EE9 jhCIv{ sg엌6JV4xBI5x<9q?-N"/3X]i,[Dh(sS~n+<*9e\gԍ%>4X?khjŠAh,%D|5+݋Q6K ʟ\zH)@^w3]oS'fc>H)^i-%"ulcdK낧U/$d"o%uChgaVUׇ-7]ME;*XIptWTt}7+ɥA|u3uPSÍx[_PZK.׆dt̶Mze0j o|ב#&";'$c|7d|qB~˂CNTAԧ"Vk Dn#*2z_qX~6ԊB $Fp0h~\~9v33&n"eɇAб*^&;37v=M'hcbp;Ǘc#/n\ֆ0>.ّrV?#n uXDw0<&2ZbwwsnɅ:To?L>پL/ώ&-ṣh 5$wpVLtyQ?qݑ~-\Bn.5Y1+={o%gCW~nk"7jpz7ƳAIb;j{~j&|gݕ z8cJ\8޵ êr\A(cCu݄|}7KZN_J\ 𝽧Z2G?^l=k}hl5k'0Q6~N;;ZEbQp|3xwލ;97M~bcVm,NJk%kU?e?nD:?8@DB6x0-b""lsz/ =4| C 8V=ű\WrHwG1T}AO#~\F3nBxss]w~BJKNL`,iK7hsG0:!;U h-I=H%{&D@t wl.7-ʚC5Oq}b>ϐO8 6c/7s_qo=W!TWȿWn? #sܤ9uOwgՊ]'*,q߂|%^>|eIցu ;-DZaHf]O/s條4MGިM宛imNnV r: o!l*dQh?g ϫc!Y ۋW[%y]pESso sYRb_2Ke\>F7v~wYЄx@z,&Ddh3  \t}Ooj9[ķ 9X| $RRVo:`bשQ?^p\MF 4[\_@oMEPwoDA>M1_b+өջͰE~&Ӵj (+. GbhVq,''*ubAXO 걯W I#5s*uD@:g}8J v('f{H00}O.MKaI,/Ȳa͒O-LdNZ|/~NOk{:h,-@;7`%*m~I5 |˻~S?* eDMm=B{ԟqt@dql=g ģ'h}8 m]+rXsryrO;%Sow k?Y9&pk'E yl7cphf/mE al3ղ)vhHlGeԈDi#Go ڨ㳣 )FKesvaL{DP}5u?+fݝD3s+bx9~_ݟoV J?~H]lYF[MQ+H>sl趖ٸs#|?}sNc`,ӮH7Qo>x孆﹎'n$|URwGXw~Lep]~Gr Mk> {";o:-xNP?&"0`lY擄#NT2W"T>"U-luN= xUwTEȅ3@V!# SHć|dKZkc@ை{G޸ D6TMH>ZU&Z?' !s ^]b}heW/%k|at $D߁X`B#d9~`Z|6^]_жhbh\KX?lw"yko\V˚` uROi> lDX,jQHX ~C#JG"*D5"S!γOa- >1ߠ%x&k|#䷼沝7I{3 m/ Z_ Q2C:gq]U|/穴TRF *|r};sǐ;"D՟G.c#+#|v,y7'k!6-gZQbkWFFNrnO_({ EC9cn1F,B7vn&57 8S`WVjȟ[J2WhaOps-k lqF0|}nat kkGO6N[Za@A`T}+NԹ@K\?L8L"7’S[ nƋ#"2O]wy}7_oz @_| 첎 ijKiS? o5ɧ, 71g $bܼD[LB>DSɎ`VfI/5:nv GDg0I|ryjCf}ɟ/B@UޟUi9䖳~YDI` _VLI+,śV^Qր49 >9RpUQӆR/qօ9Z 8J#ɥlK99\xt;Y2XL&p}H &E~h++=0ZXgs; }i؋X +TrYܜ Didisȴߡaz5NJ0s!9{z#-rBȾs2W[.n3Kym#_r0~NO2ؿ ?|;ph!w2,sYMoF,ѺTXnQݹupkh?Vv&LcuO-WO4ǿ#r~uo7ɍ HKacl$ B@:pᅶ +3,M/a,]-`^Sⳃ X\?xG?Pӥ~U~_Z_3 ҏ+~"C}=QPC;A e&g[S/oG`A/\炶lu/Ʒں[{+o9 h+~YSҟ5)ҹKtF΋ŴhzcxXh]ˎ'4<&ZR$$4Bmxxgz_ǩZEяA9ȫ]pC[V+kU#&E%ԖdHwƇ%5<#uݭkZݧ̞jO ~k價$~c{5%d{h ™TȪ..4pIOg #3lE려YCDǿJIRn䝆{Yp2Zp p 91FVrZ< i+@j<"& >زZ Ӏrnz{0?Ȗ kXC56rdN3 y* ~~-{Mh[;֑bU~ OW@DV:XO8aG6Zݴ`̞*HHNk"fg]Wa0X{Aws?!҆'BΑ2^(C ۰%:(З*Vc~Zi 'i-YY$R2j@x| pgpif} ,-ѰH}'v.iɋnK-ӐҚ땹ȆSR&VZI{( tǯnVvT;| M\~LA0Cu-b#l͡rb,INgFAc2uNP"AR׽w7w70k@'<\slp[kaNoםBH^|:[k_Y^MCJG,dX/:|,߭wt 5R,O~8]Ws"<NdAwosC :[)m`A/_@a$,%/+jh1p?؀<|SNhx낞bd553a)<n75 nr^Ix7Dۏ.Zb<~/pq_ _ȯrO䵔Vd"tP5NWj6ktձ<‹;,w3q#{\^nﮛ^oG#K'ADqXm&;3JEq Åy䖶JB7^#>2ܑօJ I3M-3 ȹϭF uW#_1A*+g7O8e"ơ|'5~"eQF!VkjM#1,.D TTꚃ:ħ'iJ/yύB)CTnf{DV(ӝ}a|7Vbc8(κCNZQ2PS} D;>7sNjJrL?3Os9'{- u$% 6AA3=%; ݂(),=6dnM3Mb Ty6RHorRg"֗NgÅwqWuGL+/{K,q P}~u78AmA:\\/}WBnHnoFEtC7рkw/)誾uӮ~B}GD"پk#`ˠT2?y O` @3 |'9,]tE,-ٍbd1H=B{G؆? 6.{K2|o)5qO ~ hlрdZƻ 1T]dl0uy}?UrkN|`&69xٮAßCZVw2Y6+g_ٷX`.-,),n[|n8|w$jVK`S7a>¯]DVz>Y55|,doA1wmPZ*}V4m-`b贈d2o0w݋ߗ(>#o9q^STͮvl]"@2> ߅G ɈW' \̷^,]:g;v=gmZ)uHߪ!M{t:~UzΟ-7^XYyp"+j٭Lc}4 Xk,u[e4׹o~Oނuw?i@Ay.wG n3< SMkЀ!ﮖJdy-x}<#Jl厤GJq]OcG|į -8.\o@.Sko;V>AE=`]tt'1_47#'.#tG|HXx ]݇6!>Z6z[s\a)ugLO$Hw?Ė/d f -Yv\ܺct]b6|e09y/(x^Ÿ,mᬅD"7ɽ8XEn G `T%7I_}:ȠHd>^?iCX $;@x_l}b`6tQBA>:Jgˮc _b?`A~w?_##[Sxl?*?~xRjC0SHP` <`iMKk} C0îQ\Gd m&ovW5]?DW`[#pzCXwAܢO΃36dVU[xi,_em$Ohywu_ O-}`Nd.r,lw6ߎGORiSM~ϱh+ Z^J9ԒX{Mkv րz`Kخ6K~bݴRg-@l8Ҿddi{;2P#Bֆr` ʡUe鷁s'}m:p_Z3p/ӯu7:B\d߃uL< :腅$7%/랗2kJ\"tjvS7\$I\eqx YG9*20nqwsyd)u3#7 w>0 ln+~E{NPk{/C 5=nl=%aAJ2Y\ pC?m?<T4k.&V^}x~:Z{|_&uޑ`-_BR^.'TA}f0_h?Hó^1^n\ܢs;uGr}suPXz &K QKniSgXm K<m򳍧ceگ[pV-}ExPk~8'9 -\;Rr?V#>#w4!->P[Z$LZ:[}/CxI?b?3/Q}'EZ P-Czw !x!}I 4o6KglJ+Yj}douW07{#vqbתߏRȕiѾ#霺IZ m9;yÏ^ZA[J)I%ȃh"oTF>Љ)i㡩mҢMԴxDm;L;>qhlClgv!D))+%dWr**3, 等;[S[ dbXaSmۨ"; %m+8QgGj`7VI l9egT=`>׫O24q=l2f3|b<5"B>|E!͡[ȿH;|2 k0S_~+~ZNٸA1G{Fd!z[l5 wՖm(C$q,]m]'>uֽ֎w/6 u)&`}[bAĹAVrH[VaxB9/ogbH} ҕψRؿ 9onM%H;[xšs:g:8I3". כ=d?#Wls B` մ\Fvgm7H#+!H5:g59}?3 l!lnU |"\!Ǘ#|WXVOST{ǣal&JV>W'.!+ԟ+) NZ[8Ȃ 5 ?B9\HݵOnOI4br|MG.u;(kVN^.i&)p m;=Ou%4V  ;F[u['*l-RXbVb)Idu/ bלDW1wW6vO`۫:KFuWĵkz wWR$wW]zhV{JH]һ[!XkA;f-#B~ҖeƁDb"+2,օM6&y7B3VS)/V앦` d9 K: ODz^J&Fֻ~5Bb:XS jt3p=$ W&~Zo.Bl xdSkS8ZGĀ &BܞfwP co5Eax1RT(&k:7l-rZC8>T|UZyomF Dx*9lQHjXw+f!Yv^ua9Om4r@`V. ' YdZ,?G qBMy9b~򃍹xmfb]-Ў$ Z #oeSs-q|?cA/u8ۈ0viM0 ]&o]_~hIw'@%l~BXi$VFZқWzw|yH~%V=:(hw,|3%eZIH ܏f [ s[\Xtž &=CV<ېw:܏ ]i0:hA`+sS [hm9|jcӭ6>p_+8-kHj9+l{9-?cHtp>p,Yo:#nJF( nnЕd™6:*S"fC8`q 5vh<vYt:%ڏwHFtn%/,׸X=(>]?nw. S:}l3]MZ6xX௼hx::>O ŗ _;s;qգIs<Ȕ T~\| oò OxrQΐv߇Ur^}MD{.u"]2@D3QFku2liiC-n ͺ++?h# v1!U$lKWwG ûNw=x̠d#﯆lotkDҍZXH3P溾-:\'H9sO=xbߙMis}#%R dKAy7fhf'ăI!򥐾uWkOMNſZaXNu? Y}g;t;^{*D;maa3=uH=9M~v8e2HMG}]H◩n;Ks2G7kSɸ6[uA/xmfGܗ'+NtJqaÄ`kx_ suOVȟ**M߱l~q@>2ViC}W{ TP>-ASE"_U-[Q#wwvgfM~m` 9=Չ5LbFI|Gmt @T[.=&feou&GEsq [d L.,kNIѷdgFn_18n?-oyy.OxޏT`-Ae깡 l|֎#Fw,?#vZnW#L TܶiR<9g37+f$KtCvU&Ԕ⺽"_Ƕ J<)h8 Dƙd\+;rvq:H I毎Y?K }|ej x@~KePdzlv* e:.<ƺ?ݴ N/cXZpX?+G}jvϘE .ys-:*E>xF%0`΀+L;SWsf:w;oE7 t^yɒW+xBOj8NϞMx#PW( (%tǎn{jFz?WD#s5?7QƊm CesS].|gL#BܜipJw;<+@ _O>Uc[\i&\ 9B>c553c䱜caH73}ȰK}7 #aGukVL@lxCLs]/70hLNrS|d&Y_; yz#>0;!]7~O"l*4|<)a2]B>p_?| ,;7ؿϰtDru {>ى%wJxvU$^w]cZ|eѧBWtӺ=W̍z 0d0HJ_utvz%6#0YYe>D#W.~IЯ|J<EtrSE|JVp W| pܖn),|<BtHnZCfKt5VLF/GY=>uceƳScQ)`G著3URBFi) MDx'ޑn^^+fп>6ߘ6\7 ;hL7!Clq!O{r$I9s0kw. ͨ76W`7l7|?* ֟J]3,xWoGtF7{+ZH~P7U0cQk嵣R+&K b, U7Zފ5/yȔF{2yu;x|DknlNƒ&jFHCd+}',rKL: zku`|fP~fCk.8p}&[|9\Qop,u?#1oɱzx~xw I ,HƵaE~wԊA-ۆ&]L- >߃шxftpRv'"@+, ڈ9:;΢xz)$sYد MdOn$RD}y9sgψջw_i+=OWv2YYh!=Ȓ3}x{ E m?cWunIqdWJRI mYَͫ_TwQl^N'u'n"po+oTvT.X$)?jv=(ZMY0wr ٦#PQ|a^0^3|?/9Yl-u$V~u uY _b`C&Pg]& sid/L]QwZtUm<ww 4BB ACp wܵ9o{>e֚Uc_O߆7\sLr+޵pdܤH?O9# b]a?\{Al4 )Tu;@谔r1FpߢH޾!s?~g);t=)̲A}[tt*|X0:Hl4?|.B=4 :ѻ$e~;jd0zNNG:N":f'2ߌE:AIlYt R6sW5]c`, D~4ܕ~Ya0mmN:ɥKpF~`>ZjԾ0 V|ԛ`HE ܑz PyGZC| e=.vs-{eSXg$g k R"jqe6 ݤDbSucVӚ[ $[Uk ӑWL1>]ِW47 2},"߯3uHNݧ0܉7s;5KJۧ~־ڂlO N>g"kc0ଯǑ6#NЯ[{e1^@rJz> u sӞ- ƵN{x^ 4pY)|\xl_㥖x{\nDag7  !k z){M2ƚwXg8)bQv3.3$ xIxBsx5RAԔX&c:ȟϘ3trSIGn xMWy mFuJ?\P(5Qh:࿯RVQD' ^H5\0pCl*|DŽ]}"RsHψIBE )r۹ΜA7ىVݦ` J'd:onbܝ>4@H]B'xcΦy{aK@̸{d?5. +"߸PJ!9Q KE x7Ş+fkt%~D$*׻3)1q>!9g!t*5_[XpHcy{J,,0Ɵߏ>ϲ~(ag:F pdHd~B4_/-_,߄ 6BoR/2|`?ۛ n;ubn;k1] Yw|Z뀮u#3]O.H` C(%cWwڸC%px&}]]χj`wh жWb*Rb꣉}%=+22__gH gwo^뎩+]^3-Rf6W?#h%[̣}f}Vsĵ*IaI.%!~be6|TG%Uz  _r ZU!jܱӶ}kjlE <*߿^դ)r\nb:&a-r-w=r_ * v{7#kh۩+HdC`7Rܬ-%Ivq)ljO-LgZj?{DޒNY+_r9Uj6ҹRB[zH[$e`ml }n?>HVl9]*+l}o@ 7ٶ?:ډ'IZ?_ ^1kĠ;ye{bhx^>Y!l<p>!NxJZ{n[-T`{?HjHl`Y36),-^KD,,DsW}!),ЬD^G(msL^;m _i{'v6p M`}7[[Xpۻ]Yzا-^ZP7[z5쓄?֙><:}lGdO? Ԁ9VיS`/򕴒TX@KPq}X F ܳ649 4<70:*$WW{8QGY')5}(*u Dd b (gk,G24 (CeJk)oBuLnIV d !TPuu펽\^J*<5v­/o[$RYNCUY(-%K5{O=B.`pdЍ ceԕRF LG%ŃE\?ן4R*?-,y;$"i%5~Hk[p.%%2"x"|(>>ϥRP[:*ȭ|L5x_ jy,{YIN9:A#j *VBBwz®%sZ/{%I!o,6FVJjZYwROu>˕ puMOPۤVNkIi5ޛfchm5L觉_*& rkкBSX{f,Ŷd G[~}_l;;B K"^:(OG\bXx_cs"ymemTU~:6ȲXMdT.騎8G>c3z/k]g>eܕMlN wl-l1Pz`h֏8D=zG2SKk|d9n)lVׇ bKn:wVO6߅#kcH{I-~Q{7e xyUKv^i.k OY> uz)@|?Hٳ-+=W}mm~F{qU>ҲX8{$ֶhk|^o+Y#'\߲`DEeӫj3ҐMfqK&6 >MJKd(uD=st! W&FvzS3ysrI1z+i_ ߑ1z䂐*xP g+V`M`Do4Ur`W+| (r=F}%ϟaQ0(`=Qk}%MAIax@&<䥺j P:i,!`_/7)/{M]xݠnF[@5v x<8dpc{<+ )i4 RDu8[JJ2);o)˫^:yo-muciA*[`b8PQOOq0XjC \h+m: Hl_a}ﰙK2ns=3AWD Y|Mu._~gO * DDСͅ ,uCC1lȟG{dx\(O& fb7t.&[x>ٞhBpZ+ȈiD1b'OxH:?4%LlE~zI!M{U$2׿2<;,I|ðGx*$7-/xXLc ω}`<`,?~i"$(PC,zԽ[.m;t03Davy~׉Ժl%߃ þ]3rjluzj-P'+!GY_jWw{$؏uZGudn>Yfx[>8z ?R7C]:gvΆx ',u%M7.4r'u!moA p;k}Z$5ESc N'EP)J]SB:Y\IY YSwB.KBl'mHӃ{mFtHp/V7#$:->R0ɀwsX-4Q8k=V}vY0n^b<-= a뾇QMY-Y%<!b`gO*Av_6\I 2F #]#vob>yk".x>MdBe%D|B|puԪ;ggQW=,7kv-f}Yxx>R#jJ N~Bif]#XA 8λb,ףnSlKHիV /G:3HQ*ܾ%+own;Xi%8 G>}&~kʀ ) &/TVOy;@$7bx@ AD<6[]J,OA W4%F"d7D< 9kus>ρLNt]W~2ypvs9Rg0f-?j.W'^'m&Q5¾R󳌖}oAH5xívD~16~GL߁ x:HXph?N;'NhSu\_~27dҥ.2U!atˬꃰypnlK|#V#pqrX7ja?3>HN}<',䵋]~R4Zh0L2HND8_:b&衳}wӦ[$4 !“܌V;x;]À\om~_Fv3;jOK`qW-97+QsNVP LۄwFi: =GJ78*Z|pSQu"ztrw g(t_nzʥV9]?`hDGXKk86JU씦^zOq3fJo?9܍;daG}|״h$>)uS;ͳ7.zר#N۫=D*'ܗUX+e m/Dr$w&)7F˯g rOHzOyVR[-PKxO|elXo%天#-&74]D0p8Tz _.ݩ tDV\u\}ht~q'YhUuF꫒@B#Sr1g.+0;oy =3g7s ?3H81uܗ.`+Eu 6S/`X/m 9 K hNYHU 嶊k[/kmQ$>h_.?$ޔ/Eݛ*p'Qul gC_iaiTcj3&8=|nK1׀/`? i%nuju9]0MkL@k눟wS7$@DXnU֓A̒Vn ;ۏ?XI7ą;&u< B'1;awȚxrj~` U *D떔ȊS5dRPߊrvO.nVs,XƇO.kT`y!f_}_-D3gd ؖ5nLPU~DB*i*szzާJKF!‚]@9\X8z8S$(_Ou!ҀmBi_9'}˃XuTצȨ` j ;M n\^!$d\3kosht09uGoT dMT "-+ee)X%\0ky#BML}B=swOF^qWxb7H@>L_ LR!fTR߫b>|%@Vr|ݎ{DoE؛]tXy $" +Her O>qɉMɔ=&b<~7 O_:6ﮟѼ֔zwRnlby[Ԗ8ȓ^ԢZXᅡ\׋J5RV< 3<lbke\C!40, xaNa\_Ag!iu^ HEw^GZ lHlܑҰR[XYr2@DX@.ؠ |?[v)D(0z{.Q@[fONKBU'oF"7WUNRDw?#~]6| G_b0[k좵 <k~!gt4rt$ڨn~s*d0ēTn.CтV'c)ع"W ƾQԋ='{N.צWo6OAMSSԄe ؏:5~MȄxK|?YwtvD?V!j_[S ?֯`m`/w\[䴷03Zoxcm6GWT,~QЖ{p>R#"ULXG+iEт쓀yy=C#"^MA?M FFby7>uBK=ө3[*KI%cuQv6$g) }Dx䠂O[hqa}WVѺاvh\EJ*wzCC=5<}C6;Ƿc<.ojl>qB`WP?%-B T`'&JUnwnPU |dž_ n_!#/3b`]$F'Vn6v>غVO4)f2k@$|N&ä<k@@+QJH`O:R$H*.q0Ӷj[ds@DZm7)|flY0)6?[CP` OzTJNamk"7.h^ϴ梑@Ɲ͎v[&Q[{翶ʂE-!6Ŋ36[@0[fZ*ϒ1GVE/\/tvXHd׬w`̞9WzU>!lۿp2-{Ƀ[mzr[B}`-#5*X`M=B|j,հ$q%mm:ZI))3f%}3yO~NCbIJ+?d:!)ў s\?׿yeϿ s@LM I$ [I%VB I}-ͥ|rJ*NPJ/: )=+?6+&o!{dd*S)]шN[*CuVrI,%{LJ2$t6_RԻ3ix}F|԰t*vYo;_-udlcʹvT, NI?!nF9i)ѵw*Y1Ke?dմb5qŬ-#ОTtT&Aʈǧ+dFe'NضSKrY_+`!پ&*-69/援y)AF֧FWk.%5j\ܺkn6ƲqUT?^>嗂Phdg6 MI"kd)'2F,峒 z4ǚ ,\>*"}+bZo[e6yGnGfZTa}8ۻ5idAlVuzXzTZ)Ԥ"{};YgZ\߳[ۭz_Y)0oѮ-v^Cه b#ٰ"&"G6~I4=ުHVVBXu_ЇHi?b v?6,fOYrI(nH?j5\8qUC" ? iI]lA#ckxBk3dXOJCvh 2Dh:5XnuET% ~;vÓ%wO|}GwABV9X46l x2Uլ;RukiɆY4 jϿ\IrSIRx\R2`MyPW >\w<% 㵹+9A;pR%3Vpmk_[p2SgOd&gq{giM4 HnI=?Y(n=4,a랒%kS!&dh:6$^tp:_s~PycWo;Րѐ$ cgtK.0D{ui&џ:Y@.۪$]RHaO :9dqm>Ex@m= ϧ#.T I09|4~'I;\ kp.>0_(xúZ=Q.V2SjhvVy,dذ|ppFbv/\Wu:p}|6.FzۊU x-;.,q7M`boձwRk^py`vi J6ީNx;:}Mᑣx`o܏u]SnvE"uah훍bᏝ#xtV?q& >:Z^ 6]"h+髙_IXNFyxx3j97͋Hlm2HЍJj8Ѭ\"ذE$$O+9GU#@wXҜ~OPq|\XNIu! ֶxDwޫn&xlx|89cQ]d뭥WiQu}}<ވ,tu&A[rsLxe{h_o-Ǐkxjυ^C7K`#{4/Zڵ>~#U_t4n;qND $xLg[Ǔ`͜ປ$3nv2e+hwԾaax,T0Ѽ_!; {7ql , _#;_QVNY?)mNJ+niɔ t!*Jv4³Nu$ @mVJ0"ͲtS!WM@XU}D s`J-xfi HfS nSnk' )&rD&5n*6:xmxN zrz4>4f`{Jji%v=\E{?na@`V+HR-`n<7ϻNhؗ?L͐4'H77F2`B"Dbdwe{]6m<_k$Ư;oXm?XM53Nz 1> Q~UIS.zl'@2u)@sr"9r`/s Vvsoہfr3:Do}G^Ւ fǠ&c«xb24; ~l_J/qg힐B[jrC1<:D>3hMD]:G~_&nh<<:=Zp{/ {KA^@T a>2" re JI md9@pԭG)w#:cQ] cns*i+ wWRϴ6wbX )$>J>߷ HwfDݲU ڮ1oAUߪژT9am=t`^V=i.#*zxppgųM,D|tcW/ģKl=YPvZ=Jr{aC4mPy۫|H5Ԏj5vC 2[y*ܬBlQFF?ݶM)D@5XOh58jgi6M%:ĎI5)up f5vĦyj5[I2a{CkƇ k2"PϥTw]%!ɬ?hiR62J6jEb /?3App0XU,,s=X&}cgAVUAĹ?MPbSNHR?GǾn RDX;TÑFhX]@x Ck?v%K[xU8d)\:O&p}>S!!@~2z;#=1,Ucd+ï Aom]dp>$zu-6#6 8xtxNP "9n z]RcV= *޻XkNvwրܛͽJVh5:JUx9B5 0rW斗2Mv B^c7{'+};8^_OɃUo4B [ BW*LOzYilǑmCdF_OT8][Uc{HmW"JIOe"w|(Hn`uDX~Zb~uQ#+Tz*/"L38PHIm;"DS7GRO;UI>.֍Jv ʾ&RQ _?jK!d$`[vI/dv2Զ5\?ן^89̒\t쾖)N$Ց=7ϔԹ)[Q,_o.<FFLY&/QtD!qY)<=R^S$ޓv򩜔E:Og\,Ya5-ǟO#iӽZF<;aLRgheKaHlԁH#}?| 2a2Qeg?~={m}le;  Lͮbd·O7"}d~䮣]v*>ޚ"=^g~ut"2[iAEI#{u}Elu bXXZv`53+hMPZV?I~j.єwURVnq/ն*H3m6 [?#J*kb=:K+] ]=^Hc7|ߨV X#$ob i6C9nkz^Ȑ9C[q+j"s]ۡcho"X[8z"-ĶJS){ʌKȷrX&k-Km-1 Dr+o }-bY83gC]"nZu;'KB. %ZzZ ؾDYJLa4)h%;j9Th"u!#4ޠZ瀔C#e^|wn5b+}->ߟ a6!{ms@EbdE?~ۭ<=~s=/hdxf}~Ca`BNKdqB-t0rˬ!pNnY-0BO!=3lށ/iBȿOp6K'c]^v4=)8غYmZWB*Y/'.(wneu N ~j~'௾"koxv G!u;b,q L'mĎ7k/s) 9{oúX9q1=7(V5DWIpEsbv†Zn-V ROlͿ74hGS|{P^|c~Qr5뉇nx[;J#) vjmD[ @<8 K_Fz'"6>C}0SH8J* ǣV 8eiBPe./鴶 A`YIP]sM!w\kDI&OP2 %:qWukvЇ56ޞVْv||` wعf%NsxCtd HݎPpvGDDF&ax41RV3_+ oLto̠r*CAdD~k;~M_kx{n.'߻?LF{O܀fF&&򢝹 C|B7(X1,\Ak%"^ǚjIu=#49K@|`un}ū#Sc==?Ev<OJoQ`a&dQYXC%Cnwaxd㺁?Kkh♺+ONX ́SZyg_P93_ `e, 쫬Dlwُ PGvxcZAC;X/ 9;9 7ߕvRrWVwR\YD${T#okJ&?&< b$LpD+vrE!} Cb}xkϩ7ىFWaEil<渢CZDk͌ Q>#鎺MP^Z)N^υ%'AsX91l%"wY߲JoI`StN:wi~n9 "8Pi?{nz:lv$%=źcsYƊ=v#.V 2GF>{Knarc\1e3,s=䙏#Ucy3D {91< 'u6<_6x[M|R \瓰kMW;00J_B::Mkc;Me5c:JL~#{_FK̠"`*(ge>yXS I&!P|4X7RWlŬ/fiWd_ & QIѸXDH.2~w/a˾p`zAkYzZUl8 @.i4TP.# ןDR:+/ws6H1ma̗o^|~,{9>N:60 ĴV0[uT!hgLu ֖8y+X ) &׆A&o9J[<=|+V{w]vC? ؾɌnҐ5RS϶Awn`Kb+H NTY-|V yy$d@/]^ŏ u"%!oZ6@FF;糽˃nj`*/ P=(%:-ÀFůd>vrAFW-iZ,莓~W Py ~zK͸ so,7@ĮF(3>N׫e^8-$ YK+d/Ȍ5y dݡE=Gzq=%BYXotvLH,66Vo⭅.7mȊ[=7. l(/j:e>&ޱK|{'o^"C::Q,Z tM X~jd:涃6L4 8H';EH7M@O;:4>|MC lZ5@jT?#v!KQ.u;\ȇnI7~?M \桯)Bo=.xBgm3[+[ԑ5EMeda/?3>A_ڋ[oCӵvTEx8W} J2ZzA;&B]@`EM4&G mA]N~wj.s [`ld*7klO?pΣ+얒[s_|5sG@ZRd dd( ;?Ii>F߹nWN1\]_Lh 9`|9ge쑦hb&0w_L >>+.>RG]뉔 =svzRUrl=9mrn#aqwm |'2@^^}x (WO` {>Ӣ !K6H?~'wt{* )a6&xgdv%e[{gW(fFIl mfޗٻoi=u$K {Fl9m-z[ַTty?5ҟ⽟ABF RĤkZ0nDu?Ay oZ@/_ k?SXg;M1W+~{|b˟:8egkbxV*711M2s&3_ӗPڹn8HsFqߕvBXǯe0: :Gx)hs _HjщB^OlƘHnV_q\E #7uY8ogtli%D؁~-x\_0Vrj CDcv;v8N4uJAcCSUӃ 9U`X5H kr"Gk:_= d\w;`?I,NҐG;]ᦝ^ IyG`℄1hJc/oL( 2e6i yÓݤDHwk4#+bﯭvac1g>٩^w~ `F읠w DwtOBkO0L8ލz'A|͂smO`{&;_lM|DCT~4u|,wFm_\Mvֳ{fXd{[xvDJ !fvoO`,֜G3m!:WxiC?_1;3n99I(A^oa!XX2mD, pOLrKv)zCh`1; <{6O$K4"<>4XC/]<2\v,?L@nO#*&ϤD0L7QxJ*^w C^ڜ7VZi+ AK;'6ڸll'n*JNk7#mc=`څ)vߛOϤunT޻WdSt7y̘Tq9J;=ot=wގoK0*AS.!jޙ.乱x@fw|.@ Ej)ner ._#8CmJ:L֢v+ZXOdƂuU? 絛`z߯&L5u$%Lu l .s]7qn:bW'rܒ28x}RDn47.&>%$ 45d>OӰ,3Kɨ{4] nR=wnH{Q=smݲ=KښX=-l%!뜻nX|?In v #f讈E]:]K> Rw6%GcQd`2ςd X Xt%?^p VP%q2{bJU#c)ff ~8j YZjv8`c<= HuxRϧ]/ʰ` YDF{<r4_cE,'/u:CW=p"{?Pv2DJ^]A!<G]iMS)q杰5\\d?k -Wmī'iW?"A;j*|D6 DÈE]M `7 .}{VrBtK\=U===`G=a935g/^0J!&NW 4Lti)%vT V'Xr~i#zpY!Lo?|0#\GBK٪o[i&i*V»ܖZP4H3fj'qЙHwj{HS<ߤcSw-6_$h/HY j<ͣQ$jmԣ:O'@P~Dlb"~ZXQfCN~C+in҂#u?mWR[dR?Om4@ʋrjFyΨ!0HK{<2IIkWFYڀع=e d1E`sT3rJNUr~#b %<s%p wL2 kIav$6d-M?QqoWV Jaf;2~ tUim$by;&B ~ڍ8 &cӚKB29:ZsilZ0#ʏuC uBCFE_hb!Vk HoFo):US{KYSG@F-htSYt .ZooVrS2򖊶 lײH\.Q+ABnK,I BuS>: ̧$EN:uBĀINד3[g6*t ֏-G$6>[JBT'+ N*!)dE\(+^K/o'{FʰÞ4 7i(|fl60? JcDu/&^h$6  $ pxD~ޑ@ؾCȆÞVIzsSۥ$z CS9~{S* E^lkQj]&dt$ێPQQ{r!nPVq K`KmkZ _dEx weLy \_{?t2Q9 \xE {r}~6oBo.iUaad;Q-b<2YT>Q 4ytEPťR\QnӲ6_`띮cZLBl^n AV&-4xK!4Q:`y[xt"i$#̸v{)}K>0.8q?竣Pj̓h.`+| SZ8!c W]} $1$'ǖF߸G|䲤+oH/'Sy\0BV09G!s|p52֕(x?1~ӄ 72(q@x< ^}g2^`h&>0YȀ;9$+eswECg# Q7nZ2 T3p䦱gLVϤ4Ovo;} /`@G GAl1tx%"')"rħDx^>NG<ߤ7MU3 ^ vZ`MOԂ΄ϖ 9gƛ2б3o 7XIIX}ޢ9nLE+^؉Od=zpW&|LBcR\^ԎmeA晹]zJI=Ş9]5EŨUQɘ2 "`h^ Mt]^ }?[:׌9Sk_2yx`#AÒJi{l ƧR9k'T;E`Kibҙ^?󗣝Y@|-c#QZ%aృ`2]"i_WL W{E;~0uxC2nX1pxZ]7$`ѽ(}Lf4dǒo;|B&[N 6Fde0 uՌБzi1%ݼE/ݥݜFR=-'M:=7e L A O^KA~x9A╮*~: Ϟkc0dpjHw$;3gB@}tDzu@Jju& 'nXi4|+=ՠ zҁد'7*^Y@tػCƫ}1(ju{G>$]: 3)olK0Tt'Vrfrp.;W@ndj/`]W52‘77cd#5}g,z,Z^e`&%HP-Wjg;">hEi㫃l^ͨ~blpw YX,x/wbk]B!\v vN{O15ˁLkQ})oi yxklCЄXvMob;"( М6!.47Wp'C ٙ/ሂxxA!tϨe`~3"Z^1h NE f?L\GtL#2D1*pv!l򖛋9IԬn nH ^9䡩;#cg\x"9qrWWJf!> =PwJt?K#u<'шk`Atd!Ԁ%NZEwȾϑcO~9%s+X,c/X:[Q$F=h倛rXB r? eQ[ /IZntQy56LTmZ]Ylt_~$$_Qwue`B'6h^=߉ oYHԂ7v"P CHc:blp1Zk8oȮ)*_LjDC,ͫ1ś3[b"6>m< (=",K~?RW~Aiz%/@ s^ j'?|˧0()_yWZS\CVD$?{=ǟc<'Ů.~ Iޘ)f%z[BL@7ltpvpC>%~G_ 6r)*ыz a|8v NIGw_je"NDOx oYjkiDX_)kpI wSSlkY{ÏiOZvJ$XqbȷA5S˞(AR۞Bq3SD"ςaWTOHAS` j7戩kbgBzl _a'ąsus_V/EH-C<՝z ~Ɨ킸QJ Ƈ:䋆w],oA"?D =om&~@ei;,׆P:@Ӄn9QPo4S2{u]skp&nq|lYXN)Xџ[®m䰳b9Nլݵuo=9.WCF 0zߧ g/H 5A= o#<=VcǏb^#ֻheYlW\rӡFv61w_,GTIQ-FuSOLC/YI:/ z6Or =س@ `;Dw?:ԚPH0P<79m zmp9 MP hWIZnW[2v5ܝAȓ*9P]fg{0f>ŢZCt53^ X fa+)v^g$WsX{r}E`7Q |$f%gL=`CvZ2Mq7Y"kmO샜hJ*6+蝀㺁촄(# u9l_[jyxb-<8u 8qQx<]cbkO葱 4&gnTGܜ;Xe0?rHIí*a{ ېw=>ps0ia ~:GNnm$/J0<|.=&>8fړ 8$: O3XL).: l肗t3Pm`;Et2 g+j$T:ۢidrX= B޵Ȱ#&ɟщOzHk|:AG h йHj'g_v4w!Mq>; ;2?aFJ;dh Xly'Cf MGKᮓ@ޮ}w(߃W ֻk綂z>kjqMڜ y)y߈ݝyc?[^f &V9`/E[.:̜JvsOf~W}7;뻄JmkTā33BTᦶo b+xRS@|x(!PoߗygbHgj }|xRFPr%ӑ>Kcjv{&O3ӹhNZ:>tA w->1W$WT`Gvޭe$:ܺXRcDg8j`{y!\7g XM&ɩUṁ:y^8E[dx~-SIoWˤ0(N-3?KrϽh_rSv7N>Kk\*E_,9}jXM-Vg*{= ]쐨ij>RH8wW^9 n^y QGKMAnV@mYfZ{[<䁴X^F4/o?+k˱(1 LpŸi;o W=W+k7Ycn=6M/qψk"%zK>z;NsA`vo|Ao:^'“[ S6uM)ovG f#mr2N*ܦҋ\t%Q=7"kW>5$)W|OWVЯƓ&dTvbxszxf&Htc-aGb fl(C*&{7]˴$_*kJf1PEb4ntSnP+c5w|JC6F~O^?3@hD=ة=`x&H˫ Jh YpWz?;Ϧ.3cJ|:!'v&ٕJ)?v@KU-W&_UՔ2qTuo߯ZDԸ}m3ݜD.b?̠f>7"5|=.NȃQL8YR'ğs!eUwBK Ip;l,3 A$t.=~Vw?jz0f,%S%Ka:3y+WjZZv7= LDltҧ@.  敉lsFkgDJÇ*h1OEMG ޥ@_rhnU<5Tx ޲X⳽a.Msr2-,vѳ,?,g$b+i@L 6rٔ`啛(gRZmlML㛁`4''%Gj<|$({0<v">rs)$n`mA0R̮}qZ%|Lc{=d3g&>z :[,k\2DrLQL҃zN?K0XVgA+*3;1 yG;˓œ@Tg`˱t&{i& US_Nx:y>R'& 0Oƙ>VH66)0HI89d*H;?jU6JbIdcBIs2I>b>x^s\??vR$do} atw%[Je&qoSC_Ğʃ-߽RbӴ470I5,OzuЮԞm/ۼ?t"\EuFߋ {dzS>J}Nkkp?9_F! Ʉ\Ե:L{$IMC43&|'e!X.EԃǗzBo XqM"@t0p`:V2 -Jz5-x~䩋u3GbX7Q`dX{;@v,Ct |T<)oy__ e<{,I?ύ<zt $#Jʓ j"_H^!U'G5M-48IxVZ-7CKF-3o$ ^OF [)Sxd?bzwUUS#6U7LK7{7`k9:C^HBJ*7%ZWӌ  u! ҁ'd('|oLQf)c߯`cޤ 5 7E_R{9,"d$K<ZO\礭ʟ`vKIB%oN0Iψ\Y*щ SJʕ`}@vSN뙚n}ſ"Re! S1_0! :CLl"G槲%œ!" y'[=wRD.fQ>-4GB?OJ/65DQ>_xK)ƿ62`vԖTrKym ɲLV#63)>n&49iɈR A627 *xo\WuKl=>Ḅ_aTK3C,/&'T^eYcO[:ot(d 6Ƃye]/ a/ <* +ҷs3KV7E!6^6?L=7^ۣRlr\R^\Ct' lGYEz3^vD.6dQ]5sx]Iyb☘^?IkJh=t^{kJb> T ~K\mW;0[st#ۻ^k)vHI].xN zr*Mϋg' <{OG(Zܒ,?|IhSp~Bm7`061XgrW6G "I*94HOh*O$^?TJc &rݚmCﴳcqϒ׹p_3w Dtp7V=5qB]OIHF|GozEmU49IN߆/n"zX[#Ϡb $AF[R~fEt87Uklmըk5Uwwvx:Rz=+|ub6']ۻm@֜T%u|2%_/=9~ L*㙴@?/>givʤ-d /R#uP.+ԲR}r~YOaߥ$L̡V@V!+w455g܉hNLMy/nPm`]Gdl( ΀Xs$kS @r~3#^<$ Lo()5ǙCd۠]} $/U;+$p~bdWl{¿\bo {*"N0AKAp;.8~F!4Ji7 Ot3^vnqvztZ_G$"!0/\KTW{0t? uߗPD72d]I۰3%#bFhP#o-p?߇6R핧ɇ[{jQ>e:[ޖE0n2= M+!n&^ޘU`s`5Ʊ?#R .Ɵs >\[H6Mj xhh"MRmߴ|%2ސMΩE{j&D9}&k.X+хb'ۥӲ@*ZP|#}òO;Ϳɡω^+jNo#M2س?4~`ym7\IG<>q+@mT.91>]/Z{YKyrHRN?ſɘMu6] q*v$J}̗a}~[B*fzjfT59'M[Bsg ޾|F|/.AHLraY q47ύ$8}kj̑{vf #+jlpZOՌ0î_I"?r#w Ew)v!Z*%im}ڬ4KE4CF-]]F[&` tw X S5ӊ]mQۯ>j± ԋNxh@'#]? S A)b#9t9c1->brU08<{wÃXID G'%VGZ қbg@m_\ Az-ط1v 0]ݵimY#L-]XgO}CϳUdnmbe'ݠV̫*`}~ 0 >p&tω Ei5|`STEf#Gi2vӻ6< 83y?v su۩py^S-kgWnj*R>??cOOݵhb phσσx.K?5Cٲy϶wU7]3*~ۢT7kM\Z VLʝ '' ݵH3R~V1jnnlw޲wr :_K|Uk0n>h2@U+O#]NcqdZ8bdWt1P ) D "^{~IIN-C |]MB3% 0Lv3aLH9x#7m!!f},yq'eI'cO3;zַ]P7#cmGǐAeTJiꙧ6 ϦU=o@DtYmuK"Dv&Wx=CԌw!WZydR@HlŎS{1vCDllgw )k;)g7>pWٽQSduR{L&x/ Lۊn?@Ou7QB3KbS*;18-Q ߹{`Nvo8'!'~IjsO?/{ON1N $qo :#Go⹽IXF7j Ep0j殤&ĆއϽ %9P]M  w;)RpzMyG+O.aQr >_Vnx@%3o`|8y'wzQ#Q&U{]u9h׽Rϋ|_+3y"#)ewliHƥ{s;lo`FWs 9\oLC}:SB2ueq o&Մ?Txn!*ӫSyH F~n/$6fnG~+(PuLoJ`v7UM$sRq9HCvARMx1cg[%+u+C/0 "hYU-(}* d2ps5 A."">ZhoR$#5DVjiM_4c=g:R16WsM_m$(QfF_a27S5t^tSJ ;Z }4d I,4U> ')1&1'Zy76HfM*RrSP;ksi˯'oa=+5\ l;8P.50;yOm&&-^ G!zh+4-Y fi_tHZT_MML7 lo85g-.r҂ <&PtwFi8hYDKxKȌGJc{y-EOxF3 NO?i1OU+mu[B"h1[NdǦreš2kf80U4b>]_i[=ёVQ7 qҴ6/NdL=3]WOpm~%*I=[NB3?ef4h~Vòpf&!=5/NEؚ(im` Ie|?rǢyMsRO{M H*R5M?Q%G6tYD9-MK?4Jl̆={sGJor=M1)(82SBv户s\?cWy/ljkSݥ0y_S3 L R mLhgF0 _^@>25cASs#TDH3&L5*T㪀%SY&H/Y>:ZiY'{1Mc ϟV6$IG/%2;L٠qr@Oy*$H[*$1 J!dj&ܔBjm5-rJ k5~:G+)W=^iYEkAZLJ ]5ZAK#c/ٴU.y0XmAg  M9$)JECkmĥԎY3h8d&`n6"ݢu|ZAo7.]\5%׹LI#Mw%;~pNjYny]_S5tt??JJ2msjF,@wJH$=< G=Dw'Vs@F%-?@^/c k um/sHIo21Eȡ@ZUho +*B7WV&8nbK 4&FnGHh|$2c.5h]^lD!s4N7\2ݩ"jz[Ŀ켟U8"dNԵxKɠ#X"EleFdݮ+5H-Ad[3_]=5$6E?[)L?s8#bUALwĀgw8 a'E .84&IL7 ^ipûJʠB#oL,I۶}"C.hpJ2H^ȩ3!chv^B7ufRՌJi+e2RVBZnT#2#߁~<}v;Kp002y"v^{DA/ȿZR[~n2x}^ElXI (?^QQc!l7WB0.+t*Ru 詶cAO}Đ HV;&zjA3x+G{" |ARAzr)@=`YRJ FFۃG;OR,;'s"WF/m $ ?F{Wex;)Ib'D >v<Ѷ"+/ 3IerK<,@BRԼ7eMF^Hp73Q`K'$ 4zq)} `@ckh`mh:M>H4,K主zC(ϊģ'o`JG=;JzMc}j<8Cدh8>p2tB}̶+w|#qd/>srr!)[/c9& ĥ2?gb@vI8s7Ton@?!+4f{#tF>IwzvU!YՆ$h1L]]sGnUɅRv x9#rt8B߈ W01,(>>RYhsX@kbz*f,73%n2BYFܟlV;89zqwwBE`ٝg~cgasCJMzM[V~"j 5]y-!^?_"aiJЮ_J;?< .Ht5<|ۉm!U7%;r[rf\HP!33o%FE;+3{tr["] N$DVlEDi#uJ76, v\C0亞2K`J{<y.y!^Sbcߨ;SsiQu`q]nsM,~Mse"wQX%3dK}LKF=?vlMC5 /CE!@nI$$IES9.r`h~u.$;|~ >k .1SdqUZ({+dpr ZjoPkLh{+U2?s\`D˦ X8* 7= ,bٻ'<=-mRǂrtzGCHrѬ/ldDqS|.W wXjL RG,O/fejK2ܫS}@ K&}!n8?̃~]jj~VMo{>R'F2 Do#Ӏ$~>.L13? R#yt< / 'J봔zؾʣ h}xݰf׋8U& 8亀g"W mEelG$%/, |Y͏퐾&rGˌcuHw`.{Xt%;es];[dWσb;$AHz^rR{!NX2vݟuLr-% To?7 /ӵX%$dS>Y!5xLlLY_i8oir&zm7DTe ~ޞvH?Tk']TB'ܧZxpbz^ZMu/NeQ)95GM)Z#@-hlD~>[zm&CLF~]yVNǵq.,9 [kIgZI~M[; }ǖ@X?d kkb@A#XOAN;E.^?''BhiÏi5g | 2't'8~$G@Upe R*vX#\/ ""LUf)1Y@EHϐ]'I3#^!h.r9e||?qE'wÉ=8` ޺C4VM4[~"\S@_ 9?4t}('-u#l s_c}lWxu K<C?ٹw=UD:]vMJv C*X:S:PzFcCx6 9r4O\3Y;3Z#} b%~P ^ׅ| _YH׀'J#`_@z4 4B~/=}}7~JL哙ZVf#.og%?r3Od' ]n |-Xz >Oz']}_ωH1Oo];Uaɀ-!gւv\; O.qX' i"p8dl~?ŗ#&?Uۏrbˡϱf#4r / <مW6=)ؗ_tPNc _/h4D#amlϟVΨIAjR!( &6.M5<~;nOx)l碛X^>{ɭW )X#`4jR+ТeKغ<%&%KX$N Cg9 6&fҾMr36 E^22Vpl_:+Yǂ|ubsQ5 qb\&Un`ks4o-#K]H 鏋 籍b@)tuN_/; [Y]"s4l-7 \6&Vlߋu3_'1- '@B; ^jU2G-UE6 X\ W׊%^OxvcHOeGgR72c2Z14*uOE`_O%xK쒻|%`}Z3l#AѾ~}wGoa'\zXI}c} 2d$ GfD|_YJzZ<0p."5ƒjsU/5 ՟$lS口%~%οO$aYH g}r/`yYby9Z8Gbrס<%SD;Zj.s?wX̣O_?bS kLgܕ$/9P}x_#6 y4TAs^ڑGOJ]=/Vtj yJVah!6Y1S!گ`]Ϸ[ p;Jk5]fܾՍ]@ '+B $[oJt rG֬D{y=v lV"dFH_H[iq>-M UZ>sE7/?O[f$Z 1,xHkks puac/pi5mƧU%>h&Uo@Iۣ=dxCNdLF. oRA] Kl̳s}>">,O-%ns Fxf&M]cJl=,>G53qWH2n_O.X ;G?ӑI{qQC&K#W_[\fP`48(*.WG;nSW?r.r} c=u. hc tmFq3+~ua^*rߪ1p=o3S֡,ϛMW7MeZ>;v[h):dʁ,4ВN|ó񎗒gR|vk4H[꯶e}5s"YE8H'c)Kwp)M﨣yq׉`8.&숫.%1Pپ 2[P;o_Y̐!4^qZn"a5&",jIr)IC>G^\/?pb,|#~/~D~C)!ȅԓjeu a+`UЋzXjol>HQե+&%j޾d=sXsX^zp[27Υ=oo #tӹ?᤮#.&豫u>ͥ'+p}aޮ\g"!gHސx!Tv?O)\DM]S)']eUTr~>IMkDֱ'C{[’RnK[ֻn[ֻm ?QswR/L.G-߭w\)򸆰f̿8$hO7(vN OLp#;~LQ u_:rK~C 3QQ~PO 3V 2--uv\&9yu҉j2$]'eu AU GV> +veѩ:]+kBm^ i8J j[=B„LлMo,twf7-H>_ϊu=-5MȯVtZOi ó5Ly`F(h-=}"y^+j}#4 ^hMMtizHڍZ1~Boǹ?V> &ӂ WZb5|O`eA>>UKɦ4bJ70 vZK; A>% n mtA6:\S^5ܖgRA54v:[jI}!e|,h8XB/> +O-߰c|{\#WB\[G[RnϥRuz_Ǖ:^[`A6m&Fttau]pv˲U]%;ϐ*)2t#uH`3=Z`>CE]Nd[Dh5nڮ7(4"7Ւе_`Mnkg%?m!C]uGVȡt$2k <`φ҇@ Ε1ޗ5߹_H,ZFc9 ԁ CdoI YtWz(M@ +3\I")֫R sMNKtSM~/ܖ@-=pQ{iyeS<u%]~*$ϒ].))$U졄\-g :ފ@;vuKCp MB7!_T\OVzn*Dx d|$a:k,G?&` lHhh=A ^xre9:A4R Od5l3⹎>4,WZUDtrVi#-ƒIyM (QcM!R`arR- YIsҹ_’#b"H{_AgHo"G)ֿ WKeH/ Cf}t {etQ]}mZI?!'%&ٜ]K0hAkP2;+$hHH2匿]a@~JE&IsS$/aG%# '-s8?0WL*p4f>v/f2WʌM6Q?)tFK>pwk= ;|J2DXA*p"ؑ#+ e`9tuI~ȜxbyWSR Kg+4,GDY .nZ= X_|]B_5@?Adxd_ݬ׵$u1-]m|7RH!o!_T}*σvi=#ľ#"}sw(LaYxK)_Ӹ.?2Ee vt]碠 Q9-@xoviX$5&"Hxa7KkK2lAU31);G.t0+޿m"Yv<$%>np_5&Z?Vd<#W8g7 `R= ʽlGܟF;ɭAlUTш2c^%:.pF?:萏b]FFSF7$_tA/3bsz?N){|Oh(?$k̑u9mt]80_|ё潿&?V󳨩wM2J`9@?Orn N*^*Ɉv>Z tЋh!?GC.|Uc'[[GH(i K9$kk#sT ''~YϐNL_AdB; hs HZ+Sw˷6#u #&CZ=Pڠ)ԬXVΕauj9vMZϼh䵵%r # /T?V!]Y<&_r?o3wCa3 %\lFZɓM&{oDl;|ק-H◠d=Ne|ZRJ9#e \wGOd Ioo|@iIxus9$3٠;0Dk{?3}ǜGC4LؙتZ]JAu[VRM F_OםU~o368RD&16Ӻ$&l"HXm?ZDdYW#~w?8F>j^wAjpg|ZY}D3z#,.:hO.hNca[?OZg<Z<=<<^a?28t]qrM\9wovߐ&^uS~vE09^?g/nl~6kC'8buH7$r_JiWT2d0LWmwܛ'=ʊ {Z9^;4L-q_M./@tj2w sSk4~7_+ۅHbS݆p_ l/_Fc7ZG<?#1LzFKTnFSsbvE}U:PVNg}>h|F֠G'nKmsT)}[rtCɢ`@`ě%y7g.O Or&| IS. $gn[}s౭|0v}3tQ=uvh9,h8:IaaTzOLY^HAogu-n7%Ud;X` XX s&xe4"z Wo"[z:AWk3Own#MrzTX{coi%ȶnV6dx}5ha<6C#Tw9v&4Ҭqc.ۖJF!8My%3ү @x&6O1UtH*[(uТ M>%+l6"`gߺd8{Fd F(? "isfsI!oFؾuo_c2(vk KH|8ކ@4ven5U9`JɱmG,Ԑ]PL 8Ed'ƛUx__C vh4=z#&!x"ehQGͦ=kL5:Zpd{P0&7ÿ`ns"lmk,a~ 6poY ۅ^;kx|V &%Cfot./(!Y%\>W=;Jg=<[L/A~6< fXG1ho?gz=r;\i``. )\bjO|\2ij+/10?Vn'alu\oE%Xv-aj$,[nzXAX>p^SM O,+JS\*u\o~_<|WJd⤠?k{=٬ܝI?'lWuNOtPkdOW9R雷na;-ldz A*< kVĮ wnl߳mxJhqXs"*ٽ#pl`r:Xg~KY@]W=ٵv\s¾/-)IM""sH|/Ks=@)YNnv=䷩=aW0xr$yi:Pb%[f.寥!~`U%p]]X.H(5ivg3M(ڑhO)HӮ$<@|! B`8߯2.~vIS|b '~/C']J''*%[ޖ% d]!KLxMp 2`[5Z3qaTW2\< R PJC]Րf.^4.jvC+ ux"gL%ZwMsOh`Nz/eՓTrz|l3Dڲ?h^ڧXDsW5~'}>zv&Y>!&Fm/G]V@et&եu=,ke%G:6@2h㨮W9L@?7d  |ӕ>b'wƕ=*$sPihڐ<q 7(wpj`:4Dq,)LOk}wJ.+rP} $D.|OH-!9%Rv0|n.έgΑfndڶ[ GnjAM|?窹jVBp -!?E\sϻn[ֻn[߻rD.Q@O+-]]Qj'+FWwLNdsy:,7 Ovpm]f.RdFi?Js+χ}am9ա 2EKR9rG_aeIMݟ*'fY!\#HI ]o(5d/qe3-?AYv~vG:NTM #]uNHV7:}=+7Uuk].'v&vҚX_H$n֚Wౖ^"],w]{W8y;W9,+W73iͥ\^axFͣ:յ$u>@ g\Jd-m׊]j? ̕ F~\#hh)ב:_ A2c@ 7ڠ~28]nF*~>NW{_"k K{b{{]kc֞Bets1LRP<)wPV1?թ(emZdkC仢fXq褠V:G#LP){3Ri >zA2hKt%uɕx:X?%_USDAdݥn>x{],V0m*W,O\erK] uЌX856ODŲezmb^(#tnjjN3t9zCsIKriɊ'vcR%u@XoILGd Pw ;|ftIq+ R>DZ Xe6\|`]k0>?;M~^: 7h [vIX,k|z8%BEѭKxY/!MuQA#h-7l%5` gJ Suc W['f4'~s/>\h:*J~sפ.X8(޲#h^Ou ;=ՐA8-?$k,&c'#~c kz^QB#9PQy|n68Y%˨s#a)Pa}nNH,E~V ,O(^%#2ZA\\&: Bv5躚Hҫ+WG(߈DQU&4P#DʮPP\mr}&^Aފ_b#W$m]Kh(d|~7H rf$NfDAy^_ +)]@ o+-; IE\H>|./AlH88'%jJSj텎F%bw^4 H-_a΅i' z`&u\V$վ:>)~,3b}K/qJI'kc} 9JD RQ2*n4!@"ۮbߧHA5qsup^x_"WG?>GV2<{|@F  -Sؿ=!v5yXg uD&caN4$z=glB$WW*飈5O 4<|-VWBWcqD{JM#5nE :kX Ss?(-5cG0I&LFFH> D0n`M`|շ(g o80} Tll!Xu>+ Q X҃䋑0AVJ_ 6|{E%7cHiv3gSbc٦DLC3Ԧ}>#go^  >P }gcߐYF`a'n)1mR%"Zl 4 ;峣n߰d5u ?~ߑ'쬣x1a H`vaD;gOM[A|zSuF `rut V諻@|`W[Ϩa/EC|fLo!̯s:`};q ;᭽z]s6!8?,䝱Xs8?mݪh` ovy氓z8} ?ݐ<>;FmO}eFc,gΫ|ύ-vXN+P}?qrOeM~nV kF@kZ.*)/Yp1fhJyz?fLzbxCls7wMCwќ[ޅ>T/勀v>w$,m3>i=kciH9^\qp={jUN աs.ɷ01k9qn+:@[%`=(d2rܦt.B9|{9< =N=v7LEE}k:Mȩ$ 0s4goVqz]=~1 zu@Ax|Sr^},iCv~t*$3OE6.zz=)?c}?'7ѸĦV[ P/״HgE G;Fkg)껊ng_;[M+9Du8?+7|v#ɲt|b+?uZGeuTR " \}BM&R|ǿ }d/E:>AǰFNg.^I'2Y') e ˥T 3'Pzm=^vo:6X;BO"!~EI?\{Bu;b=N;$dגI &mm5 ,@oeb߭r?q>OZC[l]$F &dfB,XB }$az>KXG~e_Gl?l+'̽DI6ζYmGg*"? |oUp>9@̎m"r;@]#~Gnth_V9W FMiGWe'@ƻo=g!ϒƐNcb2zl̩ npK_7=W n\KiMƶ nV_2~v_a#^}?agKj%Bj OcQWkmiCxv5;.w[ {,Ψ0MְA:-I@d3G,{cHRWMIWܫ˷,~q}9|5i0hImj1Mݓg%uSLja-]pIS+{U%{Fv0Lp:ϳ+|̠-X)-DKBzI |n0^g+(JDAED?Óckcˈ,̯{xNv9* ۳y%"{}4Dj3^}ĺ +n2p~SkJ[4n75VA +weљ#1z C'et#;:-*񎏉E9[垺:џ`vU/**Wݢ@.$#6_uX=d;6oz:!rcn? B҄?W}zKJTEmUF\"ߺ1 NAsJ= A⟿J[oA1ǿ\Ͽmevo}ޭwzޭwzˎ'SWaet PdzŞE[w+>p]g.+ ˅8EVKZ;6嚸IFj8(/Tsu\ }eDM{& y.eҝ~;݋>u=ƾ۽Սo.d6О:Z7{vOShS 6dΕ_`%5%fUJ2Eɨ=t:v4q5r} sg>GiIYl&d0WTjm"{4h%Fjt0G)l+G +5T:*]] Nf_nJac_{Yvг[:CGou R H󢗤%|胠y++erg{ZTkzN"V_/ԣGt\]տ s+z%xΰНz7!M>OIaz}/2PǪ탽ۻ%vb_YAE &Th5,/:^٦ߣDv^tSNT+H+$d+FVE 06L-BG!OP[`ߡ9Hǧ톴^q>1 uB?̼`\9nƖ=\~{M7>~ܐE`]:6D 'D$=u3'qaWrȥAUߥ7"o`j,7C~2} ? %S@\E ʈM Ϧ<ސK{)ۈ4!>z%IJJ<`8As| x|^ sY\BƝu|7NW![f.W,?:[O?uO$.>I|6l\c Q\$ 8Yڰ:حJH!)"xVvxO;wZƦ%unX'0j{_鉋aX{џrp<?AkU_1[hD0nȟUw\E7~$@:h#ZGX1L U1"pRO޾>kekdl,nӢBx_La?Hu]$~\k>VAגH/E{CFa!'L&}-c3460X-W|Kb{ni"cBܢh(A6_]/ >]=Iv2\έ VOH>]C/byEpIW*+d_%WO>|uq@c6${86,'u/`C'/QzN4d'WfR{D_Bck!fVJCv,iN:A`Q," {X8iǽ&sՙ` }1Pr"-X>5ZH54T}M4-iU]֢SU$GeD;#E0&{DuKkaxxDc,?Y@06`fĐ}zf1T1n5}Dm$@P9<>PY^nƿG[p/KL}gELX7Q'vO]U@s@Mܝ.kڒbב9((MVɓyWr= u!u< OģlF:5^9Zz 4s ,|p;ɀYgq=X'+d{?KP Go˹G&/$'snLꂄYκ_f ^j$04X;t=aY7Dي|E3~Nv?㺘?%mJ}Z ㌎"p *}v2PI}'d^ h=Or:F>BK{x1oX ZO/=;&M5R7}RgMRo1u2;bsDқ\8XZ#yl$1O5wId8jeRf<)9,aKPK-9Re! nׯr2g1{V.KJ< BQ~KJoҹnP#S?," t=fkP%AA2 x|$O|+Kxܺ?$ɉ8Ym}AM..R)?*y {9LCnzw]e npdY s. ]-~bz2FO(:R#][t) #暸Ex|J*vZLFHf]_!:$~].)lځHꯅBdatLp8̱FZ>~J䚋X9:*wp{5z?wL>>H?/=|~~_)݈z](tFwYXxz@wbCl/.U)UAp.Uz|] b/BJOBf/mチwd-s—үX |fÙEYl/1R,fA,[ڂ~ͥnHoz|I'8FV BH0(c-5}k*RZ(^+ tG1ro` 100 V<(5Dm=uM2cu!M^Xd ~:B?$3"P_e.ݎTH?uX`3gD9mć{~2^g|E?mA(,9 i3ZZXҮl@xVeX0Xa<]tB``MdDDKrUF;䰯 u3mn GҶTuPw]ݍmbDqڞ3_9`~]5XaJ)]TM6e{Ixv<+;Zpx<.RsIufXϷ߅X+Lo݃863PŪ=̪s&4G;|di )O-*NXy\5w˥"7^Js1} I#s(_Cp P7ndO|oeo2WCɒ-}+R$;hSl}Gc㭏b/,lxAl- vObfvXx4"zi [v(ry|X,ns 5|َmn\e-ZIGx?!-wr1b{l6H@WZW*4N<.cS_H\Xr&;Oﱾ>EL'C+~9ft5${ljAސW I d-_m=.[R g"b?k#mn|B%:1, ??Op,1 ,?#5=Hfum cl>h_3|?Bl%OY/ؔ3~XvY4=_.M F1]&Y-OA~(ͽgNɿ}!`!,>z+5џ#8υ$,TH 5?~5H3hvCtw ; x+m1) ݰf)( --)N=7{؂2K^- J^jH6<'j)0_^,H^;C2;zVߎ3֕/HD'9fI[ÞjAdTD|XO5[a Tԩ}5Yw;Cz*^=!]nv@$KưG>SA~?%L ![Gk!1&@©1+vW8O4y3꧇?<3xֿ\_復L\oClu]2%G+\RGa~aHE5<ifnrnw3R⢃+ZlsV}GiS˳ Te *iː&Eick5E~,`1T\w{ r 6eD`c {z#.|5c?5 .wZnwwǝv,N_υ ƁvN`Ozi1Ęf+NEX2KoE{RUZ>ni쐟MØ]3_ dGU~j)N~w +k_cj+tҳڸfvͅ{gsW"vn;V !+ ">3߈a> dSpM/yĕ24kBw!ӻ=qn!'x5zba|7Hw!kcs}q]?8a-*(DD'e F#o:1LE=ut9 l!og{|9Ͽ;sc_&\)v1Dwė+,Mj!)e#$*F}pgDȖH ~',0Y ; njzMc6J}mjB~ Dj5!#ŽÌڻBN]C*pX2(;w/BMp|~\RrLD[ <HOWѪg'>\@3|9Yαk`FG{:Q%6Ķ9|+n Dh|HljsqZ|˞vt]mo.fF:ސ=UoJ߹@~]"}/+dTD_H+I> 7]m%$  3[ckZQ4XʎI{9%jF2xuxkuRs` /"&Q߱L'S JE*id'6S L|%m[cS]be!2]%TƵD`l&1.DH}W{`PqxA4;'Cj߿JI>IK6 #xx(ǛhcUD| !uՏ+^_: ÕʸኌVꣃDow?Vq{^w"q4=R!.U\lC]dàa9*7X zF7K+4v ;vˢZ/жuY"!3]EFuy_=x/ri@3-l 3URj Hofzql"9Bu0FnDi"h/?\)TR^ޔOI۶O_K?$?ްs%sd'oKO?CPiv+o0팝hm}4/m~ޓDF-7岨D-|4g-Uϭ5=LvZShl}a5ֱk@K;)VeoeN6Ԇ%VRWgžl島6(e]ke&ʢPzWZUnTY:kg@Bݬմz|b`5xSh2C!ђcI, ̧r HSyYd𱆁}yezktVkY0cHX?ARc4rD߇UWK_#=SzB]zK1aqȗ]@ƴx|LrUa|\(;ToGHLH# d~Ð( Ƕ%K ԗbB'^C Ͻ*kkjPe\`ewe`~*Q&W'>/4vIS&h^^HMYm<:lvPRW:8uڸ|?|,ojj$ > ~dz٧;TneՐ8u f{ B⍺Y!u8u \<>Q { >&27^n@g [,lz*VIK. wSNhaO`Qoѥ:q z8$ z;DuU"&ji_}]Y09k\dw?ΤߎGt8O$&'EDvx f!j"9/.-^fN_.O:f702h.CwM+k~l:քB3Tj|{7cqp ئwpm%vx=CDc;;gfFiv7 Hp{m)ÐFLUը `xsuh4<4]퓐9u?.! =v;y ~|V#L$&'Ji-{òGO~&$Sz_lړ,xU}|Ng$=o+f/zLD\ű;VfX;4 oTԁwT YdM_o׽v]͖#J< HDXZA@'ЩhhO83n)qOy억ZA>~aytկSsM䫹Ro"Dߡ/v" z Q$F!XMT݌EԴDf\|r6${wvAX^󓴏#4|Lj{|:@.%h븟uΚhۭ%wP(%!cLc5k"{0m~M/EdCgH9w =\'`;bX򕨄  5_\v8]m.w+a}z~Y\SgCd,?--%:6acH{bEZb`'Q>1/"?xJ3A[qqӞ̶+N}b`ߗ-X|+q"p7X~TxU7Y]?/^0 l6zb3b^qq>w=_ztᦨLqs3N <dі X^nao`Zon,9@GwNOÃ~B;\_ʓm[-*;YKvIms\}8pm)v\}#dg^ݮ?-`WR9|㲣-(bajv_K%,_X{]}nr4O/Gb6D@wȔpy?L^X +HfLz] ZF"fT^11@Wv#' 9?oUdF pQ/x\pZZD,%x 1rV :hsrF{w ?MS')h# f`Kx/g (1w.\]w-n"GևTmg E3ࡓlxf,hG!1wtG]~;n0*1Q*Uow7@+lm*rP޳V֕>{_oz|w q+ '7k1KO9:(o 5m FࢠFMlm5p)# :Gj[߇Dx_nlCT:Vj"sP ]KDD-y?]5%3\X`Yxbgo` kjNnG"M=M_nkn+I O#fu1Ig 1|T\Du_nzadA; | X=nM !=hA;tV  X)WuP&kroZODOƻcApϒt4yߴxm&f%TܿK9a[lOo !b{hR?6Yb^^. J?p(ѝh+k3;U K8lEHOd ޙ"Hb}gun~~8cP46fyoi1M3r~f1s ^޶.VOXJgݧaJJ[& nUYH3A'5Er{^rvY, @x>8VC<+~7>gg~=:0[?LFu#[<1RB)|f :n'VH_˟oZ.^ y=g9HP=d+#SFXMJ44}7;I8} >$/HUd?k{F{7'>^|5q\o _# Xd?o"x6@oو_z?O4"ݫ N Iofw39 +^h[jc u@e㐴-\&7%ʼn b9 t%,r9e7lma6L!򝶢N)\Kp; ^;yZJ{E^r^$damYgp]KEY)4' oqm' wvs*yS-h)]wSpv\/q+@f1{Y TwLdsRvVآTyA%ty뻕PI -`8Y>!q Twq[mu >&!]x6'V}߳%,etFv)ݭ> lF-vfFl-/[d-$F~'iNR9l0tE{'ZOX `K郮:5qᵤ%vӶDc|e+49u-ܹ߱*Pj!H͵ V"[&[3[`m& 7?1 ѿ>jnfP^ [߹\K>@U~+}wZk;6d/Y ba]l<5SMU-X夲$˼#k^RYt[Wm#\چlکŻ!hp exˎ-rB{\禮wZniƵdHA|衞E zMt0 Iw! bցE롸/>M`mRcVg_q/u]ΐ[6̰ amRӃx{okS[l|4++s-5X߈oYG4TY@v;i']֏P=CX+7XS~g>ҙie]&`Ⴜ Olz[ rA{4Ѓjg bXKKSfs\]b ^ &":X5<>D-O,dS-y5gc^bQ $P[ẍe# OsE.s;s#}-d:Ɏݭ0(ī *s%bw"053:xl>J<݁v6am4$82l֑']zy=|esWʲ)PNP#[SJ@TgR5V~OOf;ۥy1ё=-2;:6xM, }A-&W7[cNW!~::=W2fFL. NHLq`Ɉ$Gĵ6l`mQ99聐L*D)r"=p{SVk~`|wLHMd[.:>fk`@A/*P'[omŗR^vVE#~Q|<:lϷw}sDU'u3ba5`KuQDd'!"F X@;~ ز9(]O Y ]C.:x8;kDNۋ>p{W|AW&\C{ cX 9F Hހ,h'}\ś(^q$V`EEzDOaGfh}M-M ݴT݃>4;* &/>gpֺ}gbbm{nԵ:9gCTkh2^Ɏs~]] f$X @e!y"P \5j&oyvT<}{:8ƴO"낷O`;b[dA*\vKl1]Gg|<ކ}+ST\MOD;gq]EĐcPA̟ [!_h.ˤ$&#vdB.<`ض3=` Gs\7~ T>~oXf~IE`1|8`nb~76-D/]23w2q95>_E6RYMRǼJ~$ u3L8==,'F{]-篓O@K^F\\$fG |L[}dzp3x>>{~G@KI's|xVt0 :"/C'|fD%?Bi$~;AiXm>cܦwhd]/Y |B>w۸W }?Vxa۰Ht5,.3bb,*$7I=ӳ׬vл%|~)8zBG7oyͯ;ݼgL=Wxzlǿ'dlm%DAJ(|GVsu $Z ~JFby$6s}EXv-0F{ú+wdo}ۑ9u= U#}o휶bFŗtERa?]s7{${]E:? q%.DC!^ Nݍk=w2bEbha_D<[Ax7jG h5wL?::ZE޵=giD'ԀBUVKz8 MhG|%&nӈah=yanۉà:.F7<-7 K*r(/|yajw$k,kh}@xhe8sW}7%p.Y NOG5 F >.Ԛd8ųuH4Ȧ@s,^K\/E>7 n8n:-r c[çW%Nq[us%?!Zk,~l[ɤTJ*}zL-< hfC4eīKU|wc`GDeS ڬ+ԒXbѻl^8m=tO#=0&_̙`a=]07 ?l4"9M}"G/+ԗZk8j}j|vy 9mIH9xÈ^HOK {4e1㽩v :˪'䴔cX2wrNss>DQ~bdJsF~Bu4n|N#*4ٲ[r^m `ν/߿ݚ`9|x$0?eI$w- ^69wg{wz%πo4P'VLƯ`|W02 GynV c|m^%=&/ =`@2{׾kdձ! /L*9?n?uǿ9Os=ERrݼД{n"&0'=K̫kUH]#RSƲZ=m|G&֝!qI`)lQ:j͌tǍ#X|O]'vFi0^ו-i/*=ǻ{>Wtmcs2? bӉjщ7gGd?tF&QR]/b6NuQCz6 Z%qm Mun{z >$ \5mm+hCnh2IJR nb~px؀kRX"!jlj|nUY?-at(X>f#R+:;+3k\hlpH^Mr^iη̌'lvY/0 =9rG~O C9`FkLj0bM=[W[f|gnZ \R O֊ y=#HIaw* >Bqt4O Z#3^D/ꧽ7]3IWi* b9{ 2$7kyKx:ďq-2xioFKBF 2nS-lq@2W قGB/爈{w8YMLwܱ11RkRo _8*_dN v׹.CXi3{;K=_/QnOaX*̿.Z?C[mP#9DA7TT~TsYD5jQx }R C=dt~5,SCi3WxBfsxJaT@HL}E-'G7ujvT?IM23"9ĒڊJrT\ƯnK~9uWu} dw?@]4!˓!{ y 9Ӯ)y$Uɋy.4a|<1927ۆ6u>0? # uU;[w\ C;A=v#"c'U`Nb zu|u{V I' Ĵ_Ѭ-Ӌ@w#ਞ,vJT|[sTR\zd*Dt9"Cqz>;p}-nmqYkCYl+9q֋ۇ~sKC} ewl$Qnu}b3Yd!"%OW8UanI,dkXs=E )hI|+K̯BC`5vwJa88mYk /5CMnYLmM6Yd,dhV:J{[}!?K.f{%߳6ܞH8@vb@E2]ySѕJI+ɪ KmY 6RgK3xnB{ F__+=H{Ϣ&P׷6ZPJpgc79k8g#eLkoc(+L2HUqRI~G:^R9$W\T]eEeҴ~&liyWd-rG_z^z^z^?veG䒆j?TvH IG\ARowg0I"qFҚg <&YR\HMiJs_I$R(yEr/[o,徼&dQ*%%=:WQb$DHAm,=._#qR=k.iJI )*9Hw+QZrH%blzUZjhliW &tרezm/ш`Bh0gȐLC٤0km鬚unuZHiղ6XsRn4!'!,|Y>9#h%nlg83g=RY2me i:[?3BX䑏DQ66Xcu~69OLO};a}hc=N> [߽n)mn5l?ǪZBoE c-md 6|!#g4A3Irb"~{W\]j9lK~*Kc};kavAZƦX (x?<8b_X{_kC)'M՛YAe=h$nUl &>Zb ^1RPQ f`ǫy䳪REbhri4- S|}k2 `A}"NX@VKICy?DF4\b,qݬ[ ggl> 35/%? U6h&uV`pRac%)pӚhN??,TWNۙ) v Ds];bmRUFJZ&{+K"9Bd^0pv۶`xE@)t1X| pnA ?5톦𨛿ꡮ &~b{sWLw|isQb- nt8m?vhq/'&]q%xqaO@'Nz3B*ϬWSE7&";8okĿ@`Al ն>@M5D[5E~ U$n?x҇c $ mmwɄB Lr^^}Gc}RZ>レE߲|~R txCV 'zTa ,?mEۡu($߀q]qp-='BoIABd ~FCaHZӈʨ ٱHN^X&KQhX!CiBg0riI6C6o=INsGExxluo v |/x5!s Q ~2brؒ:o DsXaƵ #U{޽ ~CFtQ||%츊ͷ5,q27 h^ }Ƨk>0'4v̔K]5M%x@Y?:g|;+7A7x1XŢ?7_[#ȁ<;+ A`Vf?}b?*N?~Qj?Y=s=Pyybk8̠2~6̆V(xI^\]mF^49k+DUw]=}zU:zg# *!m^x0b!1RDTYῳ@ <RSb@ c]-ea^)%FZ  oѵ殓wƵdçGcZ/ޅsF),woZ܏Ng րi/|@;#} 8dvnzCc%W"l0-5j=̓.Vj#+)_CJsI69qŮ7eM_x>@鑹0ؘOp} 5#+E/3f,I>lMBOҁ%e Y".U a-e'=tX߲?x_E٦/45t;Ρk+q9v"!^؅XnBaPros\MDnmoX`KJ|e}_0bwqxL['l-ONNƌ;QmSxgϕwy0Y=?\㻂W`L9lumk n'~QWI{ˁӐiaw]b<˳Ӑnw8p ס_`-" GbTJ [H{,ī]?;|ǭFb|@ru8L`^]L@}dǶ<7c0w. ZVՁdk<9k\t/RinBrtD, Øel l '%)R[f['º vlo"Zp|~:>4H㓱l;2nb QzwN2{X~ueUbd1ݧ#>Gȶ׮!Usm=#~&݌SE w4!|'}]F;nr6X.4V"%V:{^Dp~?)˹ao\`F]xwU|GAGw4-%S-fLĴ裏Jhdb=x<s-79#潫Bwa?V,׾D㡵JJ)%L~`]~O=E%f 'c-< Ӓ!?2JBET<AI1!HDʈIUQ1Arx|q\?}` 7`i?2/ϑ ϥ67=἟5 IGF8QA}p))YCObnVy>w?nƇ_:o6({iRl2nx눟4^ÈR)U)v,T?:q4<QVr}p<&N =XA*13-hC e ○brQhMjNE],7g d,nE 㖺Q;~ʠ-Z@,){Ǫ!o>VK$<#YM 7*vjd;Zz,5 }+mmdD~Fdw;&?"AX{ޅߧӏDYzBlVxn8pWϴy.֟)"?VKiH5Uam:jx[N)w.U+R)v E4/\ƪNY^'l>U%`fX;>RS#o^>"/l~ W'r[~HSc[@zZs}]H|_"h-"3|֖ǻJ+̗V%S9HoThϵ;H|?^ND KͰVKVꐤVz]&yuH~qE>*mG7n}DX{VI.6A䱺0$`G f~xțE73)~D[VCX>__W^)+_nuWwڵDm$a]dïm-A/}2Q:zE$/5BX߳%4?HzSTf\{հ6NORMBPeoHBqk#ܱɶ똛n R 4JK*m^|9{?}IXtI [K>mh뵮]`+hm?xfq_snu+3J̔vX{6<#ZM]ץ ,+kt!tZ]@Ô tl)uVg/led׳2TNkj /IyYL (٩^z^z^?~Lzpynifti-0.20100607.1/tests/test_extensions.py0000664000175000017500000000417111414645202020476 0ustar michaelmichael#emacs: -*- mode: python-mode; py-indent-offset: 4; indent-tabs-mode: nil -*- #ex: set sts=4 ts=4 sw=4 et: ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ## # # See COPYING file distributed along with the PyNIfTI package for the # copyright and license terms. # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ## """Unit tests for PyNIfTI extension handling""" __docformat__ = 'restructuredtext' from nifti.format import NiftiFormat from nifti import NiftiImage import os import unittest import numpy as N class NiftiExtensionTests(unittest.TestCase): def testExtensions(self): nim = NiftiFormat(os.path.join('data', 'example4d.nii.gz')) # basic checks of the available extensions ext = nim.extensions self.failUnless(len(ext) == 2) self.failUnless(ext.count('comment') == 2) self.failUnless(ext.count('afni') == 0) self.failUnless(ext.ecodes == [6, 6]) # first extension should be short one self.failUnless(ext[0] == 'extcomment1') # add one ext += ('afni', '') self.failUnless(ext.ecodes == [6, 6, 4]) self.failUnless(ext.count('comment') == 2) self.failUnless(ext.count('afni') == 1) # delete one del ext[1] self.failUnless(ext.ecodes == [6, 4]) self.failUnless(ext.count('comment') == 1) self.failUnless(ext.count('afni') == 1) def testMetaData(self): # come up with image nim = NiftiImage(N.arange(24).reshape(1,2,3,4)) nim.meta['test1'] = range(5) # test whether meta data makes it into header dict self.failUnless(nim.header.has_key('meta')) self.failUnless(nim.header['meta']['test1'] == range(5)) # clone image # test whether meta data makes it again into header dict nim2 = NiftiImage(nim.data, nim.header) self.failUnless(nim2.header.has_key('meta')) self.failUnless(nim2.header['meta']['test1'] == range(5)) def suite(): return unittest.makeSuite(NiftiExtensionTests) if __name__ == '__main__': unittest.main() pynifti-0.20100607.1/setup_egg.py0000644000175000017500000000006411076676635016075 0ustar michaelmichaelfrom setuptools import setup execfile('setup.py') pynifti-0.20100607.1/setup.py0000664000175000017500000000661311414645764015256 0ustar michaelmichael#!/usr/bin/env python #emacs: -*- mode: python-mode; py-indent-offset: 4; indent-tabs-mode: nil -*- #ex: set sts=4 ts=4 sw=4 et: ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ## # # See COPYING file distributed along with the PyNIfTI package for the # copyright and license terms. # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ## """Build helper.""" __docformat__ = 'restructuredtext' from numpy.distutils.core import setup, Extension import os.path import sys from glob import glob ######################## # Common configuration # ######################## extra_link_args = ['--Wl,--no-undefined'] include_dirs = [] library_dirs = [] defines = [] link_libs = [] # for some additional swig flags, but see below swig_opts = [] # a more reliable way to pass options to SWIG os.environ['SWIG_FEATURES'] = '-O -v' ############################# # Check for 3rd party stuff # ############################# # make use of the local nifticlibs copy, only if it was compiled before if os.path.exists(os.path.join('build', 'nifticlibs', 'libniftiio.a')): include_dirs += [os.path.join('3rd', 'nifticlibs')] library_dirs += [os.path.join('build', 'nifticlibs')] # need to link against additional libs in case of the local static lib link_libs += ['znz', 'z'] else: # try to look for nifticlibs in some place if not sys.platform.startswith('win'): include_dirs += ['/usr/include/nifti', '/usr/include/nifticlibs', '/usr/local/include/nifti', '/usr/local/include/nifticlibs', '/usr/local/include'] else: # no clue on windows pass ########################### # Platform-specific setup # ########################### # win32 stuff if sys.platform.startswith('win'): os.environ['SWIG_FEATURES'] = '-DWIN32 ' + os.environ['SWIG_FEATURES'] defines.append(('WIN32', None)) # apple stuff if sys.platform == "darwin": extra_link_args.append("-bundle") ############## # Extensions # ############## nifticlib_ext = Extension( 'nifti._clib', sources = ['nifti/clib.i'], define_macros = defines, include_dirs = include_dirs, library_dirs = library_dirs, libraries = ['niftiio'] + link_libs, extra_link_args = extra_link_args, swig_opts = swig_opts) # Notes on the setup # Version scheme is: # 0.<4-digit-year><2-digit-month><2-digit-day>. setup(name = 'pynifti', version = '0.20100607.1', author = 'Michael Hanke', author_email = 'michael.hanke@gmail.com', license = 'MIT License', url = 'http://niftilib.sf.net/pynifti', description = 'Python interface for the NIfTI IO libraries', long_description = \ "PyNIfTI aims to provide easy access to NIfTI images from within " \ "Python. It uses SWIG-generated wrappers for the NIfTI reference " \ "library and provides the NiftiImage class for Python-style " \ "access to the image data.\n" \ "While PyNIfTI is not yet complete (i.e. doesn't support " \ "everything the C library can do), it already provides access to " \ "the most important features of the NIfTI-1 data format and " \ "libniftiio capabilities.", packages = ['nifti'], scripts = glob('bin/*'), ext_modules = [nifticlib_ext] )