[ VIGRA Homepage | Function Index | Class Index | Namespaces | File List | Main Page ]

vigra/hdf5impex.hxx |

    00001 /************************************************************************/
    00002 /*                                                                      */
    00003 /*       Copyright 2009 by Michael Hanselmann and Ullrich Koethe        */
    00004 /*                                                                      */
    00005 /*    This file is part of the VIGRA computer vision library.           */
    00006 /*    The VIGRA Website is                                              */
    00007 /*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
    00008 /*    Please direct questions, bug reports, and contributions to        */
    00009 /*        ullrich.koethe@iwr.uni-heidelberg.de    or                    */
    00010 /*        vigra@informatik.uni-hamburg.de                               */
    00011 /*                                                                      */
    00012 /*    Permission is hereby granted, free of charge, to any person       */
    00013 /*    obtaining a copy of this software and associated documentation    */
    00014 /*    files (the "Software"), to deal in the Software without           */
    00015 /*    restriction, including without limitation the rights to use,      */
    00016 /*    copy, modify, merge, publish, distribute, sublicense, and/or      */
    00017 /*    sell copies of the Software, and to permit persons to whom the    */
    00018 /*    Software is furnished to do so, subject to the following          */
    00019 /*    conditions:                                                       */
    00020 /*                                                                      */
    00021 /*    The above copyright notice and this permission notice shall be    */
    00022 /*    included in all copies or substantial portions of the             */
    00023 /*    Software.                                                         */
    00024 /*                                                                      */
    00025 /*    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND    */
    00026 /*    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES   */
    00027 /*    OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND          */
    00028 /*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
    00029 /*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
    00030 /*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
    00031 /*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
    00032 /*    OTHER DEALINGS IN THE SOFTWARE.                                   */
    00033 /*                                                                      */
    00034 /************************************************************************/
    00035
    00036 #ifndef VIGRA_HDF5IMPEX_HXX
    00037 #define VIGRA_HDF5IMPEX_HXX
    00038
    00039 #include <string>
    00040
    00041 #define H5Gcreate_vers 2
    00042 #define H5Gopen_vers 2
    00043 #define H5Dopen_vers 2
    00044 #define H5Dcreate_vers 2
    00045 #define H5Acreate_vers 2
    00046
    00047 #include <hdf5.h>
    00048
    00049 #if (H5_VERS_MAJOR == 1 && H5_VERS_MINOR <= 6)
    00050 # ifndef H5Gopen
    00051 #   define H5Gopen(a, b, c) H5Gopen(a, b)
    00052 # endif
    00053 # ifndef H5Gcreate
    00054 #  define H5Gcreate(a, b, c, d, e) H5Gcreate(a, b, 1)
    00055 # endif
    00056 # ifndef H5Dopen
    00057 #  define H5Dopen(a, b, c) H5Dopen(a, b)
    00058 # endif
    00059 # ifndef H5Dcreate
    00060 #  define H5Dcreate(a, b, c, d, e, f, g) H5Dcreate(a, b, c, d, f)
    00061 # endif
    00062 # ifndef H5Acreate
    00063 #  define H5Acreate(a, b, c, d, e, f) H5Acreate(a, b, c, d, e)
    00064 # endif
    00065 # include <H5LT.h>
    00066 #else
    00067 # include <hdf5_hl.h>
    00068 #endif
    00069
    00070 #include "impex.hxx"
    00071 #include "multi_array.hxx"
    00072 #include "multi_impex.hxx"
    00073
    00074 namespace vigra {
    00075
    00076 /** \addtogroup VigraHDF5Impex Import/Export of Images and Arrays in HDF5 Format
    00077
    00078     Supports arrays with arbitrary element types and arbitrary many dimensions.
    00079     See the <a href="http://www.hdfgroup.org/HDF5/">HDF5 Website</a> for more
    00080     information on the HDF5 file format.
    00081 **/
    00082 //@{
    00083
    00084     /** \brief Wrapper for hid_t objects.
    00085
    00086     Newly created or opened HDF5 handles are usually stored as objects of type 'hid_t'. When the handle
    00087     is no longer needed, the appropriate close function must be called. However, if a function is
    00088     aborted by an exception, this is difficult to ensure. Class HDF5Handle is a smart pointer that
    00089     solves this problem by calling the close function in the destructor (This is analogous to how
    00090     std::auto_ptr calls 'delete' on the contained pointer). A pointer to the close function must be
    00091     passed to the constructor, along with an error message that is raised when creation/opening fails.
    00092
    00093     Since HDF5Handle objects are convertible to hid_t, they can be used in the code in place
    00094     of the latter.
    00095
    00096     <b>Usage:</b>
    00097
    00098     \code
    00099     HDF5Handle file_id(H5Fopen(filename, H5F_ACC_RDWR, H5P_DEFAULT),
    00100                        &H5Fclose,
    00101                        "Error message.");
    00102
    00103     ... // use file_id in the same way as a plain hid_t object
    00104     \endcode
    00105
    00106     <b>\#include</b> <<a href="hdf5impex_8hxx_source.html">vigra/hdf5impex.hxx</a>><br>
    00107     Namespace: vigra
    00108     **/
    00109 class HDF5Handle
    00110 {
    00111 public:
    00112     typedef herr_t (*Destructor)(hid_t);
    00113
    00114 private:
    00115     hid_t handle_;
    00116     Destructor destructor_;
    00117
    00118 public:
    00119
    00120         /** \brief Default constuctor.
    00121             Creates a NULL handle.
    00122         **/
    00123     HDF5Handle()
    00124     : handle_( 0 ),
    00125       destructor_(0)
    00126     {}
    00127
    00128         /** \brief Create a wrapper for a hid_t object.
    00129
    00130         The hid_t object \a h is assumed to be the return value of an open or create function.
    00131         It will be closed with the given close function \a destructor as soon as this
    00132         HDF5Handle is destructed, except when \a destructor is a NULL pointer (in which
    00133         case nothing happens at destruction time). If \a h has a value that indicates
    00134         failed opening or creation (by HDF5 convention, this means if it is a negative number),
    00135         an exception is raised by calling <tt>vigra_fail(error_message)</tt>.
    00136
    00137         <b>Usage:</b>
    00138
    00139         \code
    00140         HDF5Handle file_id(H5Fopen(filename, H5F_ACC_RDWR, H5P_DEFAULT),
    00141                            &H5Fclose,
    00142                            "Error message.");
    00143
    00144         ... // use file_id in the same way
    00145         \endcode
    00146         **/
    00147     HDF5Handle(hid_t h, Destructor destructor, const char * error_message)
    00148     : handle_( h ),
    00149       destructor_(destructor)
    00150     {
    00151         if(handle_ < 0)
    00152             vigra_fail(error_message);
    00153     }
    00154
    00155         /** \brief Copy constructor.
    00156             Hands over ownership of the RHS handle (analogous to std::auto_ptr).
    00157         **/
    00158     HDF5Handle(HDF5Handle const & h)
    00159     : handle_( h.handle_ ),
    00160       destructor_(h.destructor_)
    00161     {
    00162         const_cast<HDF5Handle &>(h).handle_ = 0;
    00163     }
    00164
    00165         /** \brief Assignment.
    00166             Calls close() for the LHS handle and hands over ownership of the
    00167             RHS handle (analogous to std::auto_ptr).
    00168         **/
    00169     HDF5Handle & operator=(HDF5Handle const & h)
    00170     {
    00171         if(h.handle_ != handle_)
    00172         {
    00173             close();
    00174             handle_ = h.handle_;
    00175             destructor_ = h.destructor_;
    00176             const_cast<HDF5Handle &>(h).handle_ = 0;
    00177         }
    00178         return *this;
    00179     }
    00180
    00181         /** \brief Destreuctor.
    00182             Calls close() for the contained handle.
    00183         **/
    00184     ~HDF5Handle()
    00185     {
    00186         close();
    00187     }
    00188
    00189         /** \brief Explicitly call the stored function (if one has been stored within
    00190              this object) for the contained handle and set the handle to NULL.
    00191         **/
    00192     herr_t close()
    00193     {
    00194         herr_t res = 1;
    00195         if(handle_ && destructor_)
    00196             res = (*destructor_)(handle_);
    00197         handle_ = 0;
    00198         return res;
    00199     }
    00200
    00201         /** \brief Get a temporary hid_t object for the contained handle.
    00202             Do not call a close function on the return value - a crash will be likely
    00203             otherwise.
    00204         **/
    00205     hid_t get() const
    00206     {
    00207         return handle_;
    00208     }
    00209
    00210         /** \brief Convert to a plain hid_t object.
    00211
    00212         This function ensures that hid_t objects can be transparently replaced with
    00213         HDF5Handle objects in user code. Do not call a close function on the return
    00214         value - a crash will be likely otherwise.
    00215         **/
    00216     operator hid_t() const
    00217     {
    00218         return handle_;
    00219     }
    00220
    00221         /** \brief Equality comparison of the contained handle.
    00222         **/
    00223     bool operator==(HDF5Handle const & h) const
    00224     {
    00225         return handle_ == h.handle_;
    00226     }
    00227
    00228         /** \brief Equality comparison of the contained handle.
    00229         **/
    00230     bool operator==(hid_t h) const
    00231     {
    00232         return handle_ == h;
    00233     }
    00234
    00235         /** \brief Unequality comparison of the contained handle.
    00236         **/
    00237     bool operator!=(HDF5Handle const & h) const
    00238     {
    00239         return handle_ != h.handle_;
    00240     }
    00241
    00242         /** \brief Unequality comparison of the contained handle.
    00243         **/
    00244     bool operator!=(hid_t h) const
    00245     {
    00246         return handle_ != h;
    00247     }
    00248 };
    00249
    00250
    00251 /********************************************************/
    00252 /*                                                      */
    00253 /*                   HDF5ImportInfo                     */
    00254 /*                                                      */
    00255 /********************************************************/
    00256
    00257 /** \brief Argument object for the function readHDF5().
    00258
    00259 See \ref readHDF5() for a usage example. This object must be
    00260 used to read an image or array from a HDF5 file
    00261 and enquire about its properties.
    00262
    00263 <b>\#include</b> <<a href="hdf5impex_8hxx_source.html">vigra/hdf5impex.hxx</a>><br>
    00264 Namespace: vigra
    00265 **/
    00266 class HDF5ImportInfo
    00267 {
    00268   public:
    00269     enum PixelType { UINT8, UINT16, UINT32, UINT64,
    00270                      INT8, INT16, INT32, INT64,
    00271                      FLOAT, DOUBLE };
    00272
    00273         /** Construct HDF5ImportInfo object.
    00274
    00275             The dataset \a pathInFile in the HDF5 file \a filename is accessed to
    00276             read its properties. \a pathInFile may contain '/'-separated group
    00277             names, but must end with the name of the desired dataset:
    00278
    00279             \code
    00280             HDF5ImportInfo info(filename, "/group1/group2/my_dataset");
    00281             \endcode
    00282          **/
    00283     VIGRA_EXPORT HDF5ImportInfo( const char* filePath, const char* pathInFile );
    00284
    00285     VIGRA_EXPORT ~HDF5ImportInfo();
    00286
    00287         /** Get the filename of this HDF5 object.
    00288          **/
    00289     VIGRA_EXPORT const std::string& getFilePath() const;
    00290
    00291         /** Get the dataset's full name in the HDF5 file.
    00292          **/
    00293     VIGRA_EXPORT const std::string& getPathInFile() const;
    00294
    00295         /** Get a handle to the file represented by this info object.
    00296          **/
    00297     VIGRA_EXPORT hid_t getH5FileHandle() const;
    00298
    00299         /** Get a handle to the dataset represented by this info object.
    00300          **/
    00301     VIGRA_EXPORT hid_t getDatasetHandle() const;
    00302
    00303         /** Get the number of dimensions of the dataset represented by this info object.
    00304          **/
    00305     VIGRA_EXPORT MultiArrayIndex numDimensions() const;
    00306
    00307         /** Get the shape of the dataset represented by this info object.
    00308          **/
    00309     VIGRA_EXPORT ArrayVector<hsize_t> const & shape() const
    00310     {
    00311         return m_dims;
    00312     }
    00313
    00314         /** Get the shape (length) of the dataset along dimension \a dim.
    00315          **/
    00316     VIGRA_EXPORT MultiArrayIndex shapeOfDimension(const int dim) const;
    00317
    00318         /** Query the pixel type of the dataset.
    00319
    00320             Possible values are:
    00321             <DL>
    00322             <DT>"UINT8"<DD> 8-bit unsigned integer (unsigned char)
    00323             <DT>"INT16"<DD> 16-bit signed integer (short)
    00324             <DT>"UINT16"<DD> 16-bit unsigned integer (unsigned short)
    00325             <DT>"INT32"<DD> 32-bit signed integer (long)
    00326             <DT>"UINT32"<DD> 32-bit unsigned integer (unsigned long)
    00327             <DT>"FLOAT"<DD> 32-bit floating point (float)
    00328             <DT>"DOUBLE"<DD> 64-bit floating point (double)
    00329             </DL>
    00330          **/
    00331     VIGRA_EXPORT const char * getPixelType() const;
    00332
    00333         /** Query the pixel type of the dataset.
    00334
    00335             Same as getPixelType(), but the result is returned as a
    00336             ImageImportInfo::PixelType enum. This is useful to implement
    00337             a switch() on the pixel type.
    00338
    00339             Possible values are:
    00340             <DL>
    00341             <DT>UINT8<DD> 8-bit unsigned integer (unsigned char)
    00342             <DT>INT16<DD> 16-bit signed integer (short)
    00343             <DT>UINT16<DD> 16-bit unsigned integer (unsigned short)
    00344             <DT>INT32<DD> 32-bit signed integer (long)
    00345             <DT>UINT32<DD> 32-bit unsigned integer (unsigned long)
    00346             <DT>FLOAT<DD> 32-bit floating point (float)
    00347             <DT>DOUBLE<DD> 64-bit floating point (double)
    00348             </DL>
    00349          **/
    00350     VIGRA_EXPORT PixelType pixelType() const;
    00351
    00352   private:
    00353     HDF5Handle m_file_handle, m_dataset_handle;
    00354     std::string m_filename, m_path, m_pixeltype;
    00355     hssize_t m_dimensions;
    00356     ArrayVector<hsize_t> m_dims;
    00357 };
    00358
    00359
    00360 namespace detail {
    00361
    00362 template<class type>
    00363 inline hid_t getH5DataType()
    00364 {
    00365     std::runtime_error("getH5DataType(): invalid type");
    00366     return 0;
    00367 }
    00368
    00369 #define VIGRA_H5_DATATYPE(type, h5type) \
    00370 template<> \
    00371 inline hid_t getH5DataType<type>() \
    00372 { return h5type;}
    00373 VIGRA_H5_DATATYPE(char, H5T_NATIVE_CHAR)
    00374 VIGRA_H5_DATATYPE(Int8, H5T_NATIVE_INT8)
    00375 VIGRA_H5_DATATYPE(Int16, H5T_NATIVE_INT16)
    00376 VIGRA_H5_DATATYPE(Int32, H5T_NATIVE_INT32)
    00377 VIGRA_H5_DATATYPE(Int64, H5T_NATIVE_INT64)
    00378 VIGRA_H5_DATATYPE(UInt8, H5T_NATIVE_UINT8)
    00379 VIGRA_H5_DATATYPE(UInt16, H5T_NATIVE_UINT16)
    00380 VIGRA_H5_DATATYPE(UInt32, H5T_NATIVE_UINT32)
    00381 VIGRA_H5_DATATYPE(UInt64, H5T_NATIVE_UINT64)
    00382 VIGRA_H5_DATATYPE(float, H5T_NATIVE_FLOAT)
    00383 VIGRA_H5_DATATYPE(double, H5T_NATIVE_DOUBLE)
    00384 VIGRA_H5_DATATYPE(long double, H5T_NATIVE_LDOUBLE)
    00385
    00386 #undef VIGRA_H5_DATATYPE
    00387
    00388 } // namespace detail
    00389
    00390
    00391
    00392
    00393 /********************************************************/
    00394 /*                                                      */
    00395 /*                     HDF5File                         */
    00396 /*                                                      */
    00397 /********************************************************/
    00398
    00399
    00400 /** \brief Access to HDF5 files
    00401
    00402 HDF5File proviedes a convenient way of accessing data in HDF5 files. vigra::MultiArray
    00403 structures of any dimension can be stored to / loaded from HDF5 files. Typical
    00404 HDF5 features like subvolume access, chunks and data compression are available,
    00405 string attributes can be attached to any dataset or group. Group- or dataset-handles
    00406 are encapsulated in the class and managed automatically. The internal file-system like
    00407 structure can be accessed by functions like "cd()" or "mkdir()".
    00408
    00409
    00410 <b>Example:</b>
    00411 Write the MultiArray out_multi_array to file. Change the current directory to
    00412 "/group" and read in the same MultiArray as in_multi_array.
    00413 \code
    00414 HDF5File file("/path/to/file",HDF5File::New);
    00415 file.mkdir("group");
    00416 file.write("/group/dataset", out_multi_array);
    00417
    00418 file.cd("/group");
    00419 file.read("dataset", in_multi_array);
    00420
    00421 \endcode
    00422
    00423 <b>\#include</b> <<a href="hdf5impex_8hxx_source.html">vigra/hdf5impex.hxx</a>><br>
    00424 Namespace: vigra
    00425 **/
    00426 class HDF5File
    00427 {
    00428   private:
    00429     HDF5Handle fileHandle_;
    00430
    00431     // current group handle
    00432     HDF5Handle cGroupHandle_;
    00433
    00434
    00435     // datastructure to hold a list of dataset and group names
    00436     struct lsOpData
    00437     {
    00438         std::vector<std::string> objects;
    00439     };
    00440
    00441     // operator function, used by H5Literate
    00442     static herr_t opFunc (hid_t loc_id, const char *name, const H5L_info_t *info, void *operator_data)
    00443     {
    00444         // get information about object
    00445         H5O_info_t      infobuf;
    00446         H5Oget_info_by_name (loc_id, name, &infobuf, H5P_DEFAULT);
    00447
    00448         // add name to list, if object is a dataset or a group
    00449         if(infobuf.type == H5O_TYPE_GROUP)
    00450         {
    00451             (*(struct lsOpData *) operator_data).objects.push_back(std::string(name)+"/");
    00452         }
    00453         if(infobuf.type == H5O_TYPE_DATASET)
    00454         {
    00455             (*(struct lsOpData *) operator_data).objects.push_back(std::string(name));
    00456         }
    00457
    00458         return 0;
    00459     }
    00460
    00461   public:
    00462     /** \brief Set how a file is opened.
    00463       OpenMode::New creates a new file. If the file already exists, overwrite it.
    00464
    00465       OpenMode::Open opens a file for reading/writing. The file will be created,
    00466       if nescessary.
    00467     **/
    00468     enum OpenMode {
    00469         New,           // Create new empty file (existing file will be deleted).
    00470         Open           // Open file. Create if not existing.
    00471     };
    00472
    00473
    00474     /** \brief Create a HDF5File object.
    00475
    00476     Creates or opens HDF5 file at position filename. The current group is set
    00477     to "/".
    00478     **/
    00479     HDF5File(std::string filename, OpenMode mode)
    00480     {
    00481         std::string errorMessage = "HDF5File: Could not create file '" + filename + "'.";
    00482         fileHandle_ = HDF5Handle(createFile_(filename, mode), &H5Fclose, errorMessage.c_str());
    00483         cGroupHandle_ = HDF5Handle(openCreateGroup_("/"), &H5Gclose, "HDF5File(): Failed to open root group.");
    00484     }
    00485
    00486
    00487     /** \brief Destructor to make sure that all data is flushed before closing the file.
    00488      */
    00489     ~HDF5File()
    00490     {
    00491         //Write everything to disk before closing
    00492         H5Fflush(fileHandle_, H5F_SCOPE_GLOBAL);
    00493     }
    00494
    00495
    00496     /** \brief Change current group to "/".
    00497      */
    00498     void root()
    00499     {
    00500         std::string message = "HDF5File::root(): Could not open group '/'.";
    00501         cGroupHandle_ = HDF5Handle(H5Gopen(fileHandle_, "/", H5P_DEFAULT),&H5Gclose,message.c_str());
    00502     }
    00503
    00504
    00505     /** \brief Change the current group.
    00506       If the first character is a "/", the path will be interpreted as absolute path,
    00507       otherwise it will be interpreted as path relative to the current group.
    00508      */
    00509     void cd(std::string groupName)
    00510     {
    00511         std::string message = "HDF5File::cd(): Could not open group '" + groupName + "'.\n";
    00512         if(groupName == "/")
    00513         {
    00514             cGroupHandle_ = HDF5Handle(openCreateGroup_("/"),&H5Gclose,message.c_str());
    00515             return;
    00516         }
    00517         else if(groupName =="..")
    00518         {
    00519             cd_up();
    00520         }
    00521         else{
    00522             if(relativePath_(groupName))
    00523             {
    00524                 if (H5Lexists(cGroupHandle_, groupName.c_str(), H5P_DEFAULT) == 0)
    00525                 {
    00526                     std::cerr << message;
    00527                     return;
    00528                 }
    00529                 cGroupHandle_ = HDF5Handle(openCreateGroup_(groupName),&H5Gclose,message.c_str());
    00530             }
    00531             else
    00532             {
    00533                 if (H5Lexists(fileHandle_, groupName.c_str(), H5P_DEFAULT) == 0)
    00534                 {
    00535                     std::cerr << message;
    00536                     return;
    00537                 }
    00538                 cGroupHandle_ = HDF5Handle(openCreateGroup_(groupName),&H5Gclose,message.c_str());
    00539             }
    00540         }
    00541     }
    00542
    00543     /** \brief Change the current group to its parent group.
    00544       returns true if successful, false otherwise.
    00545      */
    00546     bool cd_up()
    00547     {
    00548         std::string groupName = currentGroupName_();
    00549
    00550         //do not try to move up if we already in "/"
    00551         if(groupName == "/"){
    00552             return false;
    00553         }
    00554
    00555         size_t lastSlash = groupName.find_last_of('/');
    00556
    00557         std::string parentGroup (groupName.begin(), groupName.begin()+lastSlash+1);
    00558
    00559         cd(parentGroup);
    00560
    00561         return true;
    00562     }
    00563     void cd_up(int levels)
    00564     {
    00565         for(int i = 0; i<levels; i++)
    00566             cd_up();
    00567     }
    00568
    00569
    00570     /** \brief Create a new group.
    00571       If the first character is a "/", the path will be interpreted as absolute path,
    00572       otherwise it will be interpreted as path relative to the current group.
    00573      */
    00574     void mkdir(std::string groupName)
    00575     {
    00576         hid_t handle = openCreateGroup_(groupName.c_str());
    00577         if (handle != cGroupHandle_){
    00578             H5Gclose(handle);
    00579         }
    00580     }
    00581
    00582     /** \brief Change the current group; create it if nescessary.
    00583       If the first character is a "/", the path will be interpreted as absolute path,
    00584       otherwise it will be interpreted as path relative to the current group.
    00585      */
    00586     void cd_mk(std::string groupName)
    00587     {
    00588         std::string  message = "HDF5File::cd_mk(): Could not create group '" + groupName + "'.";
    00589         cGroupHandle_ = HDF5Handle(openCreateGroup_(groupName.c_str()),&H5Gclose,message.c_str());
    00590     }
    00591
    00592
    00593
    00594     /** \brief List the content of the current group.
    00595       The function returns a vector of strings holding the entries of the current
    00596       group. Only datasets and groups are listed, other objects (e.g. datatypes)
    00597       are ignored. Group names always have an ending "/".
    00598      */
    00599     std::vector<std::string> ls()
    00600     {
    00601         lsOpData data;
    00602         H5Literate(cGroupHandle_,H5_INDEX_NAME,H5_ITER_NATIVE,NULL, &opFunc, (void *) &data);
    00603
    00604         return data.objects;
    00605     }
    00606
    00607
    00608     /** \brief Get the path of the current group.
    00609      */
    00610     std::string pwd()
    00611     {
    00612         return currentGroupName_();
    00613     }
    00614
    00615     /** \brief Get the name of the associated file.
    00616      */
    00617     std::string filename()
    00618     {
    00619         return fileName_();
    00620     }
    00621
    00622     /** \brief Get the number of dimensions of a certain dataset
    00623       If the first character is a "/", the path will be interpreted as absolute path,
    00624       otherwise it will be interpreted as path relative to the current group.
    00625      */
    00626     hssize_t getDatasetDimensions(std::string datasetName)
    00627     {
    00628         //Open dataset and dataspace
    00629         std::string errorMessage = "HDF5File::getDatasetDimensions(): Unable to open dataset '" + datasetName + "'.";
    00630         HDF5Handle datasetHandle = HDF5Handle(getDatasetHandle_(datasetName), &H5Dclose, errorMessage.c_str());
    00631
    00632         errorMessage = "HDF5File::getDatasetDimensions(): Unable to access dataspace.";
    00633         HDF5Handle dataspaceHandle(H5Dget_space(datasetHandle), &H5Sclose, errorMessage.c_str());
    00634
    00635         //return dimension information
    00636         return H5Sget_simple_extent_ndims(dataspaceHandle);
    00637     }
    00638
    00639     /** \brief Get the shape of each dimension of a certain dataset.
    00640       Normally, this function is called after determining the dimension of the
    00641       dataset using \ref getDatasetDimensions().
    00642       If the first character is a "/", the path will be interpreted as absolute path,
    00643       otherwise it will be interpreted as path relative to the current group.
    00644      */
    00645     ArrayVector<hsize_t> getDatasetShape(std::string datasetName)
    00646     {
    00647         //Open dataset and dataspace
    00648         std::string errorMessage = "HDF5File::getDatasetShape(): Unable to open dataset '" + datasetName + "'.";
    00649         HDF5Handle datasetHandle = HDF5Handle(getDatasetHandle_(datasetName), &H5Dclose, errorMessage.c_str());
    00650
    00651         errorMessage = "HDF5File::getDatasetShape(): Unable to access dataspace.";
    00652         HDF5Handle dataspaceHandle(H5Dget_space(datasetHandle), &H5Sclose, errorMessage.c_str());
    00653
    00654         //get dimension information
    00655         ArrayVector<hsize_t>::size_type dimensions = H5Sget_simple_extent_ndims(dataspaceHandle);
    00656
    00657         ArrayVector<hsize_t> shape(dimensions);
    00658         ArrayVector<hsize_t> maxdims(dimensions);
    00659         H5Sget_simple_extent_dims(dataspaceHandle, shape.data(), maxdims.data());
    00660
    00661
    00662         // invert the dimensions to guarantee c-order
    00663         ArrayVector<hsize_t> shape_inv(dimensions);
    00664         for(ArrayVector<hsize_t>::size_type i=0; i<shape.size(); i++) {
    00665             shape_inv[i] = shape[dimensions-1-i];
    00666         }
    00667
    00668         return shape_inv;
    00669     }
    00670
    00671     /** \brief Attach a string attribute to an existing object.
    00672       The attribute can be attached to datasets and groups. The string may have arbitrary length.
    00673      */
    00674     void setAttribute(std::string datasetName, std::string attributeName, std::string text)
    00675     {
    00676         std::string groupname = SplitString(datasetName).first();
    00677         std::string setname = SplitString(datasetName).last();
    00678
    00679         std::string errorMessage ("HDF5File::setAttribute(): Unable to open group '" + groupname + "'.");
    00680         HDF5Handle groupHandle (openCreateGroup_(groupname), &H5Gclose, errorMessage.c_str());
    00681
    00682         H5LTset_attribute_string(groupHandle,setname.c_str(), attributeName.c_str(),text.c_str());
    00683     }
    00684
    00685
    00686     /** \brief Get an attribute string of an object.
    00687      */
    00688     std::string getAttribute(std::string datasetName, std::string attributeName)
    00689     {
    00690         typedef ArrayVector<char>::size_type SizeType;
    00691         if (H5Lexists(fileHandle_, datasetName.c_str(), H5P_DEFAULT) == 0)
    00692         {
    00693             std::cerr << "HDF5File::getAttribute(): Dataset '" << datasetName << "' does not exist.\n";
    00694             return "error - dataset not found";
    00695         }
    00696
    00697         std::string groupname = SplitString(datasetName).first();
    00698         std::string setname = SplitString(datasetName).last();
    00699
    00700         std::string errorMessage ("HDF5File::setAttribute(): Unable to open group '" + groupname + "'.");
    00701         HDF5Handle groupHandle (openCreateGroup_(groupname), &H5Gclose, errorMessage.c_str());
    00702
    00703         // get the size of the attribute
    00704         HDF5Handle AttrHandle (H5Aopen_by_name(groupHandle,setname.c_str(),attributeName.c_str(),H5P_DEFAULT, H5P_DEFAULT),&H5Aclose, "HDF5File::getAttribute(): Unable to open attribute.");
    00705         SizeType len = (SizeType)H5Aget_storage_size(AttrHandle);
    00706
    00707         //read the attribute
    00708         ArrayVector<char> text (len+1,0);
    00709         H5LTget_attribute_string(groupHandle, setname.c_str(), attributeName.c_str(), text.begin());
    00710
    00711         return std::string(text.begin());
    00712     }
    00713
    00714
    00715     // Writing data
    00716
    00717     /** \brief Write multi arrays.
    00718       Chunks can be activated by setting \code iChunkSize = size; //size > 0 \endcode .
    00719       The chunks will be hypercubes with edge length size.
    00720
    00721       Compression can be activated by setting \code compression = parameter; // 0 < parameter <= 9 \endcode
    00722       where 0 stands for no compression and 9 for maximum compression.
    00723
    00724       If the first character of datasetName is a "/", the path will be interpreted as absolute path,
    00725       otherwise it will be interpreted as path relative to the current group.
    00726      */
    00727     template<unsigned int N, class T>
    00728     inline void write(std::string datasetName, const MultiArrayView<N, T, UnstridedArrayTag> & array, int iChunkSize = 0, int compression = 0)
    00729     {
    00730         typename MultiArrayShape<N>::type chunkSize;
    00731         for(int i = 0; i < N; i++){
    00732             chunkSize[i] = iChunkSize;
    00733         }
    00734         write_(datasetName, array, detail::getH5DataType<T>(), 1, chunkSize, compression);
    00735     }
    00736
    00737     /** \brief Write multi arrays.
    00738       Chunks can be activated by providing a MultiArrayShape as chunkSize.
    00739       chunkSize must have equal dimension as array.
    00740
    00741       Compression can be activated by setting \code compression = parameter; // 0 < parameter <= 9 \endcode
    00742       where 0 stands for no compression and 9 for maximum compression.
    00743
    00744       If the first character of datasetName is a "/", the path will be interpreted as absolute path,
    00745       otherwise it will be interpreted as path relative to the current group.
    00746      */
    00747     template<unsigned int N, class T>
    00748     inline void write(std::string datasetName, const MultiArrayView<N, T, UnstridedArrayTag> & array, typename MultiArrayShape<N>::type chunkSize, int compression = 0)
    00749     {
    00750         write_(datasetName, array, detail::getH5DataType<T>(), 1, chunkSize, compression);
    00751     }
    00752
    00753     /** \brief Write a multi array into a larger volume.
    00754       blockOffset determines the position, where array is written.
    00755
    00756       Chunks can be activated by providing a MultiArrayShape as chunkSize.
    00757       chunkSize must have equal dimension as array.
    00758
    00759       Compression can be activated by setting \code compression = parameter; // 0 < parameter <= 9 \endcode
    00760       where 0 stands for no compression and 9 for maximum compression.
    00761
    00762       If the first character of datasetName is a "/", the path will be interpreted as absolute path,
    00763       otherwise it will be interpreted as path relative to the current group.
    00764      */
    00765     template<unsigned int N, class T>
    00766     inline void writeBlock(std::string datasetName, typename MultiArrayShape<N>::type blockOffset, const MultiArrayView<N, T, UnstridedArrayTag> & array)
    00767     {
    00768         writeBlock_(datasetName, blockOffset, array, detail::getH5DataType<T>(), 1);
    00769     }
    00770
    00771     // non-scalar (TinyVector) and unstrided multi arrays
    00772     template<unsigned int N, class T, int SIZE>
    00773     inline void write(std::string datasetName, const MultiArrayView<N, TinyVector<T, SIZE>, UnstridedArrayTag> & array, int iChunkSize = 0, int compression = 0)
    00774     {
    00775         typename MultiArrayShape<N>::type chunkSize;
    00776         for(int i = 0; i < N; i++){
    00777             chunkSize[i] = iChunkSize;
    00778         }
    00779         write_(datasetName, array, detail::getH5DataType<T>(), SIZE, chunkSize, compression);
    00780     }
    00781
    00782     template<unsigned int N, class T, int SIZE>
    00783     inline void write(std::string datasetName, const MultiArrayView<N, TinyVector<T, SIZE>, UnstridedArrayTag> & array, typename MultiArrayShape<N>::type chunkSize, int compression = 0)
    00784     {
    00785         write_(datasetName, array, detail::getH5DataType<T>(), SIZE, chunkSize, compression);
    00786     }
    00787
    00788     template<unsigned int N, class T, int SIZE>
    00789     inline void writeBlock(std::string datasetName, typename MultiArrayShape<N>::type blockOffset, const MultiArrayView<N, TinyVector<T, SIZE>, UnstridedArrayTag> & array)
    00790     {
    00791         writeBlock_(datasetName, blockOffset, array, detail::getH5DataType<T>(), SIZE);
    00792     }
    00793
    00794     // non-scalar (RGBValue) and unstrided multi arrays
    00795     template<unsigned int N, class T>
    00796     inline void write(std::string datasetName, const MultiArrayView<N, RGBValue<T>, UnstridedArrayTag> & array, int iChunkSize = 0, int compression = 0)
    00797     {
    00798         typename MultiArrayShape<N>::type chunkSize;
    00799         for(int i = 0; i < N; i++){
    00800             chunkSize[i] = iChunkSize;
    00801         }
    00802         write_(datasetName, array, detail::getH5DataType<T>(), 3, chunkSize, compression);
    00803     }
    00804
    00805     template<unsigned int N, class T>
    00806     inline void write(std::string datasetName, const MultiArrayView<N, RGBValue<T>, UnstridedArrayTag> & array, typename MultiArrayShape<N>::type chunkSize, int compression = 0)
    00807     {
    00808         write_(datasetName, array, detail::getH5DataType<T>(), 3, chunkSize, compression);
    00809     }
    00810
    00811     template<unsigned int N, class T>
    00812     inline void writeBlock(std::string datasetName, typename MultiArrayShape<N>::type blockOffset, const MultiArrayView<N, RGBValue<T>, UnstridedArrayTag> & array)
    00813     {
    00814         writeBlock_(datasetName, blockOffset, array, detail::getH5DataType<T>(), 3);
    00815     }
    00816
    00817     /** \brief Write single value as dataset.
    00818       This functions allows to write data of atomic datatypes (int, long, double)
    00819       as a dataset in the HDF5 file. So it is not nescessary to create a MultiArray
    00820       of size 1 to write a single number.
    00821
    00822       If the first character of datasetName is a "/", the path will be interpreted as absolute path,
    00823       otherwise it will be interpreted as path relative to the current group.
    00824      */
    00825    template<class T>
    00826     inline void writeAtomic(std::string datasetName, const T data)
    00827     {
    00828         typename MultiArrayShape<1>::type chunkSize;
    00829         chunkSize[0] = 0;
    00830         MultiArray<1,T> array(MultiArrayShape<1>::type(1));
    00831         array[0] = data;
    00832         write_(datasetName, array, detail::getH5DataType<T>(), 1, chunkSize,0);
    00833     }
    00834
    00835
    00836     /* Reading data. */
    00837
    00838     /** \brief Read data into a multi array.
    00839       If the first character of datasetName is a "/", the path will be interpreted as absolute path,
    00840       otherwise it will be interpreted as path relative to the current group.
    00841      */
    00842     template<unsigned int N, class T>
    00843     inline void read(std::string datasetName, MultiArrayView<N, T, UnstridedArrayTag> array)
    00844     {
    00845         read_(datasetName, array, detail::getH5DataType<T>(), 1);
    00846     }
    00847
    00848     /** \brief Read a block of data into s multi array.
    00849       This function allows to read a small block out of a larger volume stored
    00850       in a HDF5 dataset.
    00851
    00852       blockOffset determines the position of the block.
    00853       blockSize determines the size in each dimension of the block.
    00854
    00855       If the first character of datasetName is a "/", the path will be interpreted as absolute path,
    00856       otherwise it will be interpreted as path relative to the current group.
    00857      */
    00858     template<unsigned int N, class T>
    00859     inline void readBlock(std::string datasetName, typename MultiArrayShape<N>::type blockOffset, typename MultiArrayShape<N>::type blockShape, MultiArrayView<N, T, UnstridedArrayTag> array)
    00860     {
    00861         readBlock_(datasetName, blockOffset, blockShape, array, detail::getH5DataType<T>(), 1);
    00862     }
    00863
    00864     // non-scalar (TinyVector) and unstrided target multi array
    00865     template<unsigned int N, class T, int SIZE>
    00866     inline void read(std::string datasetName, MultiArrayView<N, TinyVector<T, SIZE>, UnstridedArrayTag> array)
    00867     {
    00868         read_(datasetName, array, detail::getH5DataType<T>(), SIZE);
    00869     }
    00870
    00871     template<unsigned int N, class T, int SIZE>
    00872     inline void readBlock(std::string datasetName, typename MultiArrayShape<N>::type blockOffset, typename MultiArrayShape<N>::type blockShape, MultiArrayView<N, TinyVector<T, SIZE>, UnstridedArrayTag> array)
    00873     {
    00874         readBlock_(datasetName, blockOffset, blockShape, array, detail::getH5DataType<T>(), SIZE);
    00875     }
    00876
    00877     // non-scalar (RGBValue) and unstrided target multi array
    00878     template<unsigned int N, class T>
    00879     inline void read(std::string datasetName, MultiArrayView<N, RGBValue<T>, UnstridedArrayTag> array)
    00880     {
    00881         read_(datasetName, array, detail::getH5DataType<T>(), 3);
    00882     }
    00883
    00884     template<unsigned int N, class T>
    00885     inline void readBlock(std::string datasetName, typename MultiArrayShape<N>::type blockOffset, typename MultiArrayShape<N>::type blockShape, MultiArrayView<N, RGBValue<T>, UnstridedArrayTag> array)
    00886     {
    00887         readBlock_(datasetName, blockOffset, blockShape, array, detail::getH5DataType<T>(), 3);
    00888     }
    00889
    00890     /** \brief Read a single value.
    00891       This functions allows to read a single datum of atomic datatype (int, long, double)
    00892       from the HDF5 file. So it is not nescessary to create a MultiArray
    00893       of size 1 to read a single number.
    00894
    00895       If the first character of datasetName is a "/", the path will be interpreted as absolute path,
    00896       otherwise it will be interpreted as path relative to the current group.
    00897      */
    00898     template<class T>
    00899     inline void readAtomic(std::string datasetName, T & data)
    00900     {
    00901         MultiArray<1,T> array(MultiArrayShape<1>::type(1));
    00902         read_(datasetName, array, detail::getH5DataType<T>(), 1);
    00903         data = array[0];
    00904     }
    00905
    00906
    00907     /** \brief Create a new dataset.
    00908       This function can be used to create a dataset filled with a default value,
    00909       for example before writing data into it using \ref writeBlock().
    00910       Attention: only atomic datatypes are provided. For spectral data, add an
    00911       dimension (case RGB: add one dimension of size 3).
    00912
    00913       shape determines the dimension and the size of the dataset.
    00914
    00915       Chunks can be activated by providing a MultiArrayShape as chunkSize.
    00916       chunkSize must have equal dimension as array.
    00917
    00918       Compression can be activated by setting \code compression = parameter; // 0 < parameter <= 9 \endcode
    00919       where 0 stands for no compression and 9 for maximum compression.
    00920
    00921       If the first character of datasetName is a "/", the path will be interpreted as absolute path,
    00922       otherwise it will be interpreted as path relative to the current group.
    00923      */
    00924     template<unsigned int N, class T>
    00925     inline void createDataset(std::string datasetName, typename MultiArrayShape<N>::type shape, T init, int iChunkSize = 0, int compressionParameter = 0)
    00926     {
    00927         typename MultiArrayShape<N>::type chunkSize;
    00928         for(int i = 0; i < N; i++){
    00929             chunkSize[i] = iChunkSize;
    00930         }
    00931         createDataset<N,T>(datasetName, shape, init, chunkSize, compressionParameter);
    00932     }
    00933
    00934     template<unsigned int N, class T>
    00935     inline void createDataset(std::string datasetName, typename MultiArrayShape<N>::type shape, T init, typename MultiArrayShape<N>::type chunkSize, int compressionParameter = 0)
    00936     {
    00937         std::string groupname = SplitString(datasetName).first();
    00938         std::string setname = SplitString(datasetName).last();
    00939
    00940         hid_t parent = openCreateGroup_(groupname);
    00941
    00942         // delete the dataset if it already exists
    00943         deleteDataset_(parent, setname);
    00944
    00945         // create dataspace
    00946         // add an extra dimension in case that the data is non-scalar
    00947         HDF5Handle dataspaceHandle;
    00948
    00949         // invert dimensions to guarantee c-order
    00950         hsize_t shape_inv[N];
    00951         for(unsigned int k=0; k<N; ++k)
    00952             shape_inv[N-1-k] = shape[k];
    00953
    00954         // create dataspace
    00955         dataspaceHandle = HDF5Handle(H5Screate_simple(N, shape_inv, NULL),
    00956                                     &H5Sclose, "HDF5File::createDataset(): unable to create dataspace for scalar data.");
    00957
    00958         // set fill value
    00959         HDF5Handle plist ( H5Pcreate(H5P_DATASET_CREATE), &H5Pclose, "HDF5File::createDataset(): unable to create property list." );
    00960         H5Pset_fill_value(plist,detail::getH5DataType<T>(), &init);
    00961
    00962         // enable chunks
    00963         if(chunkSize[0] > 0)
    00964         {
    00965             hsize_t cSize [N];
    00966             for(int i = 0; i<N; i++)
    00967             {
    00968                 cSize[i] = chunkSize[N-1-i];
    00969             }
    00970             H5Pset_chunk (plist, N, cSize);
    00971         }
    00972
    00973         // enable compression
    00974         if(compressionParameter > 0)
    00975         {
    00976             H5Pset_deflate(plist, compressionParameter);
    00977         }
    00978
    00979         //create the dataset.
    00980         HDF5Handle datasetHandle ( H5Dcreate(parent, setname.c_str(), detail::getH5DataType<T>(), dataspaceHandle, H5P_DEFAULT, plist, H5P_DEFAULT),
    00981                                   &H5Dclose, "HDF5File::createDataset(): unable to create dataset.");
    00982         if(parent != cGroupHandle_)
    00983             H5Gclose(parent);
    00984     }
    00985
    00986     /** \brief Immediately write all data to disk
    00987      */
    00988     void flushToDisk()
    00989     {
    00990         H5Fflush(fileHandle_, H5F_SCOPE_GLOBAL);
    00991     }
    00992
    00993
    00994   private:
    00995
    00996     /* Simple extension of std::string for splitting into two parts
    00997      *
    00998      *  Strings (in particular: file/dataset paths) will be split into two
    00999      *  parts. The split is made at the last occurance of the delimiter.
    01000      *
    01001      *  For example, "/path/to/some/file" will be split (delimiter = "/") into
    01002      *  first() = "/path/to/some" and last() = "file".
    01003      */
    01004     class SplitString: public std::string {
    01005     public:
    01006         SplitString(std::string &sstring): std::string(sstring) {};
    01007
    01008         // return the part of the string before the delimiter
    01009         std::string first(char delimiter = '/')
    01010         {
    01011             size_t last = find_last_of(delimiter);
    01012             if(last == std::string::npos) // delimiter not found --> no first
    01013                 return "";
    01014
    01015             return std::string(begin(), begin()+last+1);
    01016         }
    01017
    01018         // return the part of the string after the delimiter
    01019         std::string last(char delimiter = '/')
    01020         {
    01021             size_t last = find_last_of(delimiter);
    01022             if(last == std::string::npos) // delimiter not found --> only last
    01023                 return std::string(*this);
    01024             return std::string(begin()+last+1, end());
    01025         }
    01026     };
    01027
    01028     inline bool relativePath_(std::string & path)
    01029     {
    01030         std::string::size_type pos = path.find('/') ;
    01031         if(pos == 0)
    01032             return false;
    01033
    01034         return true;
    01035     }
    01036
    01037
    01038     std::string currentGroupName_()
    01039     {
    01040         int len = H5Iget_name(cGroupHandle_,NULL,1000);
    01041         ArrayVector<char> name (len+1,0);
    01042         H5Iget_name(cGroupHandle_,name.begin(),len+1);
    01043
    01044         return std::string(name.begin());
    01045     }
    01046
    01047     std::string fileName_()
    01048     {
    01049         int len = H5Fget_name(fileHandle_,NULL,1000);
    01050         ArrayVector<char> name (len+1,0);
    01051         H5Fget_name(fileHandle_,name.begin(),len+1);
    01052
    01053         return std::string(name.begin());
    01054     }
    01055
    01056
    01057     inline hid_t createFile_(std::string filePath, OpenMode mode = Open)
    01058     {
    01059         // try to open file
    01060         FILE * pFile;
    01061         pFile = fopen ( filePath.c_str(), "r" );
    01062         hid_t fileId;
    01063
    01064         // check if opening was successful (= file exists)
    01065         if ( pFile == NULL )
    01066         {
    01067             fileId = H5Fcreate(filePath.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
    01068         }
    01069         else if(mode == Open)
    01070         {
    01071             fclose( pFile );
    01072             fileId = H5Fopen(filePath.c_str(), H5F_ACC_RDWR, H5P_DEFAULT);
    01073         }
    01074         else
    01075         {
    01076             fclose(pFile);
    01077             std::remove(filePath.c_str());
    01078             fileId = H5Fcreate(filePath.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
    01079         }
    01080         return fileId;
    01081     }
    01082
    01083
    01084     // open a group and subgroups. Create if nescessary.
    01085     inline hid_t openCreateGroup_(std::string groupName)
    01086     {
    01087         // check if groupName is absolute or relative
    01088         hid_t parent;
    01089         if(relativePath_(groupName))
    01090         {
    01091             parent = cGroupHandle_;
    01092         }
    01093         else
    01094         {
    01095             // open root group
    01096             parent = H5Gopen(fileHandle_, "/", H5P_DEFAULT);
    01097             if(groupName == "/")
    01098             {
    01099                 return parent;
    01100             }
    01101
    01102             // remove leading /
    01103             groupName = std::string(groupName.begin()+1, groupName.end());
    01104         }
    01105
    01106
    01107         // check if the groupName has the right format
    01108         if( groupName.size() != 0 && *groupName.rbegin() != '/')
    01109         {
    01110             groupName = groupName + '/';
    01111         }
    01112
    01113
    01114         //create subgroups one by one
    01115         std::string::size_type begin = 0, end = groupName.find('/');
    01116         int ii =  0;
    01117         while (end != std::string::npos)
    01118         {
    01119             std::string group(groupName.begin()+begin, groupName.begin()+end);
    01120             hid_t prevParent = parent;
    01121
    01122             if(H5LTfind_dataset(parent, group.c_str()) == 0)
    01123             {
    01124                 parent = H5Gcreate(prevParent, group.c_str(), H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
    01125             } else {
    01126                 parent = H5Gopen(prevParent, group.c_str(), H5P_DEFAULT);
    01127             }
    01128
    01129             if(ii != 0)
    01130             {
    01131                 H5Gclose(prevParent);
    01132             }
    01133             if(parent < 0)
    01134             {
    01135                 return parent;
    01136             }
    01137             ++ii;
    01138             begin = end + 1;
    01139             end = groupName.find('/', begin);
    01140         }
    01141
    01142
    01143         return parent;
    01144     }
    01145
    01146
    01147     inline void deleteDataset_(hid_t parent, std::string datasetName)
    01148     {
    01149         // delete existing data and create new dataset
    01150         if(H5LTfind_dataset(parent, datasetName.c_str()))
    01151         {
    01152             //std::cout << "dataset already exists" << std::endl;
    01153     #if (H5_VERS_MAJOR == 1 && H5_VERS_MINOR <= 6)
    01154             if(H5Gunlink(parent, datasetName.c_str()) < 0)
    01155             {
    01156                 vigra_postcondition(false, "HDF5File::deleteDataset_(): Unable to delete existing data.");
    01157             }
    01158     #else
    01159             if(H5Ldelete(parent, datasetName.c_str(), H5P_DEFAULT ) < 0)
    01160             {
    01161                 vigra_postcondition(false, "HDF5File::deleteDataset_(): Unable to delete existing data.");
    01162             }
    01163     #endif
    01164         }
    01165     }
    01166
    01167     hid_t getDatasetHandle_(std::string datasetName)
    01168     {
    01169         std::string groupname = SplitString(datasetName).first();
    01170         std::string setname = SplitString(datasetName).last();
    01171
    01172         if(relativePath_(datasetName))
    01173         {
    01174             if (H5Lexists(cGroupHandle_, datasetName.c_str(), H5P_DEFAULT) != 1)
    01175             {
    01176                 std::cerr << "HDF5File::getDatasetHandle_(): Dataset '" << datasetName << "' does not exist.\n";
    01177                 return -1;
    01178             }
    01179             //Open parent group
    01180             hid_t groupHandle = openCreateGroup_(groupname);
    01181
    01182             hid_t datasetHandle = H5Dopen(groupHandle, setname.c_str(), H5P_DEFAULT);
    01183
    01184             if(groupHandle != cGroupHandle_){
    01185                 H5Gclose(groupHandle);
    01186             }
    01187
    01188             //return dataset handle
    01189             return datasetHandle;
    01190         }
    01191         else
    01192         {
    01193             if (H5Lexists(fileHandle_, datasetName.c_str(), H5P_DEFAULT) != 1)
    01194             {
    01195                 std::cerr << "HDF5File::getDatasetHandle_(): Dataset '" << datasetName << "' does not exist.\n";
    01196                 return -1;
    01197             }
    01198
    01199             //Open parent group
    01200             hid_t groupHandle = openCreateGroup_(groupname);
    01201
    01202             hid_t datasetHandle = H5Dopen(groupHandle, setname.c_str(), H5P_DEFAULT);
    01203
    01204             if(groupHandle != cGroupHandle_){
    01205                 H5Gclose(groupHandle);
    01206             }
    01207
    01208             //return dataset handle
    01209             return datasetHandle;
    01210         }
    01211     }
    01212
    01213
    01214     // unstrided multi arrays
    01215     template<unsigned int N, class T>
    01216     void write_(std::string &datasetName, const MultiArrayView<N, T, UnstridedArrayTag> & array, const hid_t datatype, const int numBandsOfType, typename MultiArrayShape<N>::type &chunkSize, int compressionParameter = 0)
    01217     {
    01218         std::string groupname = SplitString(datasetName).first();
    01219         std::string setname = SplitString(datasetName).last();
    01220
    01221         // shape of the array. Add one dimension, if array contains non-scalars.
    01222         ArrayVector<hsize_t> shape(N + (numBandsOfType > 1),0);
    01223         for(int i = 0; i < N; i++){
    01224             shape[N-1-i] = array.shape(i); // reverse order
    01225         }
    01226
    01227         if(numBandsOfType > 1)
    01228             shape[N] = numBandsOfType;
    01229
    01230         HDF5Handle dataspace ( H5Screate_simple(N + (numBandsOfType > 1), shape.begin(), NULL), &H5Sclose, "HDF5File::write(): Can not create dataspace.");
    01231
    01232         // create and open group:
    01233         std::string errorMessage ("HDF5File::write(): can not create group '" + groupname + "'.");
    01234         hid_t groupHandle = openCreateGroup_(groupname);
    01235         if(groupHandle <= 0)
    01236         {
    01237             std::cerr << errorMessage << "\n";
    01238         }
    01239
    01240         // delete dataset, if it already exists
    01241         deleteDataset_(groupHandle, setname.c_str());
    01242
    01243         // set up properties list
    01244         HDF5Handle plist ( H5Pcreate(H5P_DATASET_CREATE), &H5Pclose, "HDF5File::write(): unable to create property list." );
    01245
    01246         // enable chunks
    01247         if(chunkSize[0] > 0)
    01248         {
    01249             ArrayVector<hsize_t> cSize(N + (numBandsOfType > 1),0);
    01250             for(int i = 0; i<N; i++)
    01251             {
    01252                 cSize[i] = chunkSize[N-1-i];
    01253             }
    01254             if(numBandsOfType > 1)
    01255                 cSize[N] = numBandsOfType;
    01256
    01257             H5Pset_chunk (plist, N + (numBandsOfType > 1), cSize.begin());
    01258         }
    01259
    01260         // enable compression
    01261         if(compressionParameter > 0)
    01262         {
    01263             H5Pset_deflate(plist, compressionParameter);
    01264         }
    01265
    01266         // create dataset
    01267         HDF5Handle datasetHandle (H5Dcreate(groupHandle, setname.c_str(), datatype, dataspace,H5P_DEFAULT, plist, H5P_DEFAULT), &H5Dclose, "HDF5File::write(): Can not create dataset.");
    01268
    01269         // Write the data to the HDF5 dataset as is
    01270         H5Dwrite( datasetHandle, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, array.data());
    01271
    01272         if(groupHandle != cGroupHandle_)
    01273         {
    01274             H5Gclose(groupHandle);
    01275         }
    01276     }
    01277
    01278     // unstrided target multi array
    01279     template<unsigned int N, class T>
    01280     void read_(std::string datasetName, MultiArrayView<N, T, UnstridedArrayTag> array, const hid_t datatype, const int numBandsOfType)
    01281     {
    01282         //Prepare to read without using HDF5ImportInfo
    01283         ArrayVector<hsize_t> dimshape = getDatasetShape(datasetName);
    01284         hssize_t dimensions = getDatasetDimensions(datasetName);
    01285
    01286         std::string errorMessage ("HDF5File::read(): Unable to open dataset '" + datasetName + "'.");
    01287         HDF5Handle datasetHandle (getDatasetHandle_(datasetName), &H5Dclose, errorMessage.c_str());
    01288
    01289         int offset = (numBandsOfType > 1);
    01290
    01291         vigra_precondition(( (N + offset ) ==  MultiArrayIndex(dimensions)), // the object in the HDF5 file may have one additional dimension which we then interpret as the pixel type bands
    01292             "HDF5File::read(): Array dimension disagrees with dataset dimension.");
    01293
    01294         typename MultiArrayShape<N>::type shape;
    01295         for(int k=offset; k< MultiArrayIndex(dimensions); ++k) {
    01296             shape[k-offset] = MultiArrayIndex(dimshape[k]);
    01297         }
    01298
    01299         vigra_precondition(shape == array.shape(),
    01300                            "HDF5File::read(): Array shape disagrees with dataset shape.");
    01301
    01302         // simply read in the data as is
    01303         H5Dread( datasetHandle, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, array.data() ); // .data() possible since void pointer!
    01304     }
    01305
    01306     template<unsigned int N, class T>
    01307     void writeBlock_(std::string datasetName, typename MultiArrayShape<N>::type &blockOffset, const MultiArrayView<N, T, UnstridedArrayTag> & array, const hid_t datatype, const int numBandsOfType)
    01308     {
    01309         // open dataset if it exists
    01310         std::string errorMessage = "HDF5File::writeBlock(): Error opening dataset '" + datasetName + "'.";
    01311         HDF5Handle datasetHandle (getDatasetHandle_(datasetName), &H5Dclose, errorMessage.c_str());
    01312
    01313
    01314         // hyperslab parameters for position, size, ...
    01315         hsize_t boffset [N];
    01316         hsize_t bshape [N];
    01317         hsize_t bones [N];
    01318
    01319         for(int i = 0; i < N; i++){
    01320             boffset[i] = blockOffset[N-1-i];
    01321             bshape[i] = array.size(N-1-i);
    01322             bones[i] = 1;
    01323         }
    01324
    01325         // create a target dataspace in memory with the shape of the desired block
    01326         HDF5Handle memspace_handle (H5Screate_simple(N,bshape,NULL),&H5Sclose,"Unable to get origin dataspace");
    01327
    01328         // get file dataspace and select the desired block
    01329         HDF5Handle dataspaceHandle (H5Dget_space(datasetHandle),&H5Sclose,"Unable to create target dataspace");
    01330         H5Sselect_hyperslab(dataspaceHandle, H5S_SELECT_SET, boffset, bones, bones, bshape);
    01331
    01332         // Write the data to the HDF5 dataset as is
    01333         H5Dwrite( datasetHandle, datatype, memspace_handle, dataspaceHandle, H5P_DEFAULT, array.data()); // .data() possible since void pointer!
    01334     }
    01335
    01336
    01337
    01338     // unstrided target multi array
    01339     // read a block of a HDF5 dataset into a MultiArray
    01340     template<unsigned int N, class T>
    01341     void readBlock_(std::string datasetName, typename MultiArrayShape<N>::type &blockOffset, typename MultiArrayShape<N>::type &blockShape, MultiArrayView<N, T, UnstridedArrayTag> &array, const hid_t datatype, const int numBandsOfType)
    01342     {
    01343         //Prepare to read without using HDF5ImportInfo
    01344         //ArrayVector<hsize_t> dimshape = getDatasetShape(datasetName) ;
    01345         hssize_t dimensions = getDatasetDimensions(datasetName);
    01346
    01347         std::string errorMessage ("HDF5File::readBlock(): Unable to open dataset '" + datasetName + "'.");
    01348         HDF5Handle datasetHandle (getDatasetHandle_(datasetName), &H5Dclose, errorMessage.c_str());
    01349
    01350
    01351         int offset = (numBandsOfType > 1);
    01352
    01353         vigra_precondition(( (N + offset ) ==  MultiArrayIndex(dimensions)), // the object in the HDF5 file may have one additional dimension which we then interpret as the pixel type bands
    01354             "readHDF5_block(): Array dimension disagrees with data dimension.");
    01355
    01356         vigra_precondition(blockShape == array.shape(),
    01357              "readHDF5_block(): Array shape disagrees with block size.");
    01358
    01359         // hyperslab parameters for position, size, ...
    01360         hsize_t boffset [N];
    01361         hsize_t bshape [N];
    01362         hsize_t bones [N];
    01363
    01364         for(int i = 0; i < N; i++){
    01365             // virgra and hdf5 use different indexing
    01366             boffset[i] = blockOffset[N-1-i];
    01367             //bshape[i] = blockShape[i];
    01368             bshape[i] = blockShape[N-1-i];
    01369             //boffset[i] = blockOffset[N-1-i];
    01370             bones[i] = 1;
    01371         }
    01372
    01373         // create a target dataspace in memory with the shape of the desired block
    01374         HDF5Handle memspace_handle (H5Screate_simple(N,bshape,NULL),&H5Sclose,"Unable to create target dataspace");
    01375
    01376         // get file dataspace and select the desired block
    01377         HDF5Handle dataspaceHandle (H5Dget_space(datasetHandle),&H5Sclose,"Unable to get dataspace");
    01378         H5Sselect_hyperslab(dataspaceHandle, H5S_SELECT_SET, boffset, bones, bones, bshape);
    01379
    01380         // now read the data
    01381         H5Dread( datasetHandle, datatype, memspace_handle, dataspaceHandle, H5P_DEFAULT, array.data() ); // .data() possible since void pointer!
    01382     }
    01383
    01384 };  /* class HDF5File */
    01385
    01386
    01387
    01388
    01389
    01390
    01391
    01392 namespace detail {
    01393
    01394 template <class Shape>
    01395 inline void
    01396 selectHyperslabs(HDF5Handle & mid1, HDF5Handle & mid2, Shape const & shape, int & counter, const int elements, const int numBandsOfType)
    01397 {
    01398     // select hyperslab in HDF5 file
    01399     hsize_t shapeHDF5[2];
    01400     shapeHDF5[0] = 1;
    01401     shapeHDF5[1] = elements;
    01402     hsize_t startHDF5[2];
    01403     startHDF5[0] = 0;
    01404     startHDF5[1] = counter * numBandsOfType * shape[0]; // we have to reserve space for the pixel type channel(s)
    01405     hsize_t strideHDF5[2];
    01406     strideHDF5[0] = 1;
    01407     strideHDF5[1] = 1;
    01408     hsize_t countHDF5[2];
    01409     countHDF5[0] = 1;
    01410     countHDF5[1] = numBandsOfType * shape[0];
    01411     hsize_t blockHDF5[2];
    01412     blockHDF5[0] = 1;
    01413     blockHDF5[1] = 1;
    01414     mid1 = HDF5Handle(H5Screate_simple(2, shapeHDF5, NULL),
    01415                       &H5Sclose, "unable to create hyperslabs.");
    01416     H5Sselect_hyperslab(mid1, H5S_SELECT_SET, startHDF5, strideHDF5, countHDF5, blockHDF5);
    01417     // select hyperslab in input data object
    01418     hsize_t shapeData[2];
    01419     shapeData[0] = 1;
    01420     shapeData[1] = numBandsOfType * shape[0];
    01421     hsize_t startData[2];
    01422     startData[0] = 0;
    01423     startData[1] = 0;
    01424     hsize_t strideData[2];
    01425     strideData[0] = 1;
    01426     strideData[1] = 1;
    01427     hsize_t countData[2];
    01428     countData[0] = 1;
    01429     countData[1] = numBandsOfType * shape[0];
    01430     hsize_t blockData[2];
    01431     blockData[0] = 1;
    01432     blockData[1] = 1;
    01433     mid2 = HDF5Handle(H5Screate_simple(2, shapeData, NULL),
    01434                       &H5Sclose, "unable to create hyperslabs.");
    01435     H5Sselect_hyperslab(mid2, H5S_SELECT_SET, startData, strideData, countData, blockData);
    01436 }
    01437
    01438 template <class DestIterator, class Shape, class T>
    01439 inline void
    01440 readHDF5Impl(DestIterator d, Shape const & shape, const hid_t dataset_id, const hid_t datatype, ArrayVector<T> & buffer, int & counter, const int elements, const int numBandsOfType, MetaInt<0>)
    01441 {
    01442     HDF5Handle mid1, mid2;
    01443
    01444     // select hyperslabs
    01445     selectHyperslabs(mid1, mid2, shape, counter, elements, numBandsOfType);
    01446
    01447     // read from hdf5
    01448     H5Dread(dataset_id, datatype, mid2, mid1, H5P_DEFAULT, buffer.data());
    01449
    01450     // increase counter
    01451     counter++;
    01452
    01453
    01454     //std::cout << "numBandsOfType: " << numBandsOfType << std::endl;
    01455     DestIterator dend = d + shape[0];
    01456     int k = 0;
    01457     for(; d < dend; ++d, k++)
    01458     {
    01459         *d = buffer[k];
    01460         //std::cout << buffer[k] << "| ";
    01461     }
    01462
    01463 }
    01464
    01465 template <class DestIterator, class Shape, class T, int N>
    01466 void
    01467 readHDF5Impl(DestIterator d, Shape const & shape, const hid_t dataset_id, const hid_t datatype, ArrayVector<T> & buffer, int & counter, const int elements, const int numBandsOfType, MetaInt<N>)
    01468 {
    01469     DestIterator dend = d + shape[N];
    01470     for(; d < dend; ++d)
    01471     {
    01472         readHDF5Impl(d.begin(), shape, dataset_id, datatype, buffer, counter, elements, numBandsOfType, MetaInt<N-1>());
    01473     }
    01474 }
    01475
    01476 } // namespace detail
    01477
    01478     /** \brief Read the data specified by the given \ref vigra::HDF5ImportInfo object
    01479                 and write the into the given 'array'.
    01480
    01481     The array must have the correct number of dimensions and shape for the dataset
    01482     represented by 'info'. When the element type of 'array' differs from the stored element
    01483     type, HDF5 will convert the type on the fly (except when the HDF5 version is 1.6 or below,
    01484     in which case an error will result). Multi-channel element types (i.e. \ref vigra::RGBValue
    01485     and \ref vigra::TinyVector) are recognized and handled correctly.
    01486
    01487     <b> Declaration:</b>
    01488
    01489     \code
    01490     namespace vigra {
    01491         template<unsigned int N, class T, class StrideTag>
    01492         void
    01493         readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, T, StrideTag> array);
    01494     }
    01495     \endcode
    01496
    01497     <b> Usage:</b>
    01498
    01499     <b>\#include</b> <<a href="hdf5impex_8hxx_source.html">vigra/hdf5impex.hxx</a>><br>
    01500     Namespace: vigra
    01501
    01502     \code
    01503
    01504     HDF5ImportInfo info(filename, dataset_name);
    01505     vigra_precondition(info.numDimensions() == 3, "Dataset must be 3-dimensional.");
    01506
    01507     MultiArrayShape<3>::type shape(info.shape().begin());
    01508     MultiArray<3, int> array(shape);
    01509
    01510     readHDF5(info, array);
    01511     \endcode
    01512 */
    01513 doxygen_overloaded_function(template <...> void readHDF5)
    01514
    01515 // scalar and unstrided target multi array
    01516 template<unsigned int N, class T>
    01517 inline void readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, T, UnstridedArrayTag> array) // scalar
    01518 {
    01519     readHDF5(info, array, detail::getH5DataType<T>(), 1);
    01520 }
    01521
    01522 // non-scalar (TinyVector) and unstrided target multi array
    01523 template<unsigned int N, class T, int SIZE>
    01524 inline void readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, TinyVector<T, SIZE>, UnstridedArrayTag> array)
    01525 {
    01526     readHDF5(info, array, detail::getH5DataType<T>(), SIZE);
    01527 }
    01528
    01529 // non-scalar (RGBValue) and unstrided target multi array
    01530 template<unsigned int N, class T>
    01531 inline void readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, RGBValue<T>, UnstridedArrayTag> array)
    01532 {
    01533     readHDF5(info, array, detail::getH5DataType<T>(), 3);
    01534 }
    01535
    01536 // unstrided target multi array
    01537 template<unsigned int N, class T>
    01538 void readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, T, UnstridedArrayTag> array, const hid_t datatype, const int numBandsOfType)
    01539 {
    01540     int offset = (numBandsOfType > 1);
    01541
    01542     //std::cout << "offset: " << offset << ", N: " << N << ", dims: " << info.numDimensions() << std::endl;
    01543     vigra_precondition(( (N + offset ) == info.numDimensions()), // the object in the HDF5 file may have one additional dimension which we then interpret as the pixel type bands
    01544         "readHDF5(): Array dimension disagrees with HDF5ImportInfo.numDimensions().");
    01545
    01546     typename MultiArrayShape<N>::type shape;
    01547     for(int k=offset; k<info.numDimensions(); ++k) {
    01548         shape[k-offset] = info.shapeOfDimension(k);
    01549     }
    01550
    01551     vigra_precondition(shape == array.shape(),
    01552          "readHDF5(): Array shape disagrees with HDF5ImportInfo.");
    01553
    01554     // simply read in the data as is
    01555     H5Dread( info.getDatasetHandle(), datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, array.data() ); // .data() possible since void pointer!
    01556 }
    01557
    01558 // scalar and strided target multi array
    01559 template<unsigned int N, class T>
    01560 inline void readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, T, StridedArrayTag> array) // scalar
    01561 {
    01562     readHDF5(info, array, detail::getH5DataType<T>(), 1);
    01563 }
    01564
    01565 // non-scalar (TinyVector) and strided target multi array
    01566 template<unsigned int N, class T, int SIZE>
    01567 inline void readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, TinyVector<T, SIZE>, StridedArrayTag> array)
    01568 {
    01569     readHDF5(info, array, detail::getH5DataType<T>(), SIZE);
    01570 }
    01571
    01572 // non-scalar (RGBValue) and strided target multi array
    01573 template<unsigned int N, class T>
    01574 inline void readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, RGBValue<T>, StridedArrayTag> array)
    01575 {
    01576     readHDF5(info, array, detail::getH5DataType<T>(), 3);
    01577 }
    01578
    01579 // strided target multi array
    01580 template<unsigned int N, class T>
    01581 void readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, T, StridedArrayTag> array, const hid_t datatype, const int numBandsOfType)
    01582 {
    01583     int offset = (numBandsOfType > 1);
    01584
    01585     //std::cout << "offset: " << offset << ", N: " << N << ", dims: " << info.numDimensions() << std::endl;
    01586     vigra_precondition(( (N + offset ) == info.numDimensions()), // the object in the HDF5 file may have one additional dimension which we then interpret as the pixel type bands
    01587         "readHDF5(): Array dimension disagrees with HDF5ImportInfo.numDimensions().");
    01588
    01589     typename MultiArrayShape<N>::type shape;
    01590     for(int k=offset; k<info.numDimensions(); ++k) {
    01591         shape[k-offset] = info.shapeOfDimension(k);
    01592     }
    01593
    01594     vigra_precondition(shape == array.shape(),
    01595          "readHDF5(): Array shape disagrees with HDF5ImportInfo.");
    01596
    01597     //Get the data
    01598     int counter = 0;
    01599     int elements = numBandsOfType;
    01600     for(unsigned int i=0;i<N;++i)
    01601         elements *= shape[i];
    01602     ArrayVector<T> buffer(shape[0]);
    01603     detail::readHDF5Impl(array.traverser_begin(), shape, info.getDatasetHandle(), datatype, buffer, counter, elements, numBandsOfType, vigra::MetaInt<N-1>());
    01604 }
    01605
    01606 inline hid_t openGroup(hid_t parent, std::string group_name)
    01607 {
    01608     //std::cout << group_name << std::endl;
    01609     size_t last_slash = group_name.find_last_of('/');
    01610     if (last_slash == std::string::npos || last_slash != group_name.size() - 1)
    01611         group_name = group_name + '/';
    01612     std::string::size_type begin = 0, end = group_name.find('/');
    01613     int ii =  0;
    01614     while (end != std::string::npos)
    01615     {
    01616         std::string group(group_name.begin()+begin, group_name.begin()+end);
    01617         hid_t prev_parent = parent;
    01618         parent = H5Gopen(prev_parent, group.c_str(), H5P_DEFAULT);
    01619
    01620         if(ii != 0)     H5Gclose(prev_parent);
    01621         if(parent < 0)  return parent;
    01622         ++ii;
    01623         begin = end + 1;
    01624         end = group_name.find('/', begin);
    01625     }
    01626     return parent;
    01627 }
    01628
    01629 inline hid_t createGroup(hid_t parent, std::string group_name)
    01630 {
    01631     if(group_name.size() == 0 ||*group_name.rbegin() != '/')
    01632         group_name = group_name + '/';
    01633     if(group_name == "/")
    01634         return H5Gopen(parent, group_name.c_str(), H5P_DEFAULT);
    01635
    01636     std::string::size_type begin = 0, end = group_name.find('/');
    01637     int ii =  0;
    01638     while (end != std::string::npos)
    01639     {
    01640         std::string group(group_name.begin()+begin, group_name.begin()+end);
    01641         hid_t prev_parent = parent;
    01642
    01643         if(H5LTfind_dataset(parent, group.c_str()) == 0)
    01644         {
    01645             parent = H5Gcreate(prev_parent, group.c_str(), H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
    01646         } else {
    01647             parent = H5Gopen(prev_parent, group.c_str(), H5P_DEFAULT);
    01648         }
    01649
    01650         if(ii != 0)     H5Gclose(prev_parent);
    01651         if(parent < 0)  return parent;
    01652         ++ii;
    01653         begin = end + 1;
    01654         end = group_name.find('/', begin);
    01655     }
    01656     return parent;
    01657 }
    01658
    01659 inline void deleteDataset(hid_t parent, std::string dataset_name)
    01660 {
    01661     // delete existing data and create new dataset
    01662     if(H5LTfind_dataset(parent, dataset_name.c_str()))
    01663     {
    01664         //std::cout << "dataset already exists" << std::endl;
    01665 #if (H5_VERS_MAJOR == 1 && H5_VERS_MINOR <= 6)
    01666         if(H5Gunlink(parent, dataset_name.c_str()) < 0)
    01667         {
    01668             vigra_postcondition(false, "writeToHDF5File(): Unable to delete existing data.");
    01669         }
    01670 #else
    01671         if(H5Ldelete(parent, dataset_name.c_str(), H5P_DEFAULT ) < 0)
    01672         {
    01673             vigra_postcondition(false, "createDataset(): Unable to delete existing data.");
    01674         }
    01675 #endif
    01676     }
    01677 }
    01678
    01679 inline hid_t createFile(std::string filePath, bool append_ = true)
    01680 {
    01681     FILE * pFile;
    01682     pFile = fopen ( filePath.c_str(), "r" );
    01683     hid_t file_id;
    01684     if ( pFile == NULL )
    01685     {
    01686         file_id = H5Fcreate(filePath.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
    01687     }
    01688     else if(append_)
    01689     {
    01690         fclose( pFile );
    01691         file_id = H5Fopen(filePath.c_str(), H5F_ACC_RDWR, H5P_DEFAULT);
    01692     }
    01693     else
    01694     {
    01695         fclose(pFile);
    01696         std::remove(filePath.c_str());
    01697         file_id = H5Fcreate(filePath.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
    01698     }
    01699     return file_id;
    01700 }
    01701
    01702 template<unsigned int N, class T, class Tag>
    01703 void createDataset(const char* filePath, const char* pathInFile, const MultiArrayView<N, T, Tag> & array, const hid_t datatype, const int numBandsOfType, HDF5Handle & file_handle, HDF5Handle & dataset_handle)
    01704 {
    01705     std::string path_name(pathInFile), group_name, data_set_name, message;
    01706     std::string::size_type delimiter = path_name.rfind('/');
    01707
    01708     //create or open file
    01709     file_handle = HDF5Handle(createFile(filePath), &H5Fclose,
    01710                        "createDataset(): unable to open output file.");
    01711
    01712     // get the groupname and the filename
    01713     if(delimiter == std::string::npos)
    01714     {
    01715         group_name    = "/";
    01716         data_set_name = path_name;
    01717     }
    01718     else
    01719     {
    01720         group_name = std::string(path_name.begin(), path_name.begin()+delimiter);
    01721         data_set_name = std::string(path_name.begin()+delimiter+1, path_name.end());
    01722     }
    01723
    01724     // create all groups
    01725     HDF5Handle group(createGroup(file_handle, group_name), &H5Gclose,
    01726                      "createDataset(): Unable to create and open group. generic v");
    01727
    01728     // delete the dataset if it already exists
    01729     deleteDataset(group, data_set_name);
    01730
    01731     // create dataspace
    01732     // add an extra dimension in case that the data is non-scalar
    01733     HDF5Handle dataspace_handle;
    01734     if(numBandsOfType > 1) {
    01735         // invert dimensions to guarantee c-order
    01736         hsize_t shape_inv[N+1]; // one additional dimension for pixel type channel(s)
    01737         for(unsigned int k=0; k<N; ++k) {
    01738             shape_inv[N-1-k] = array.shape(k);  // the channels (eg of an RGB image) are represented by the first dimension (before inversion)
    01739             //std::cout << shape_inv[N-k] << " (" << N << ")";
    01740         }
    01741         shape_inv[N] = numBandsOfType;
    01742
    01743         // create dataspace
    01744         dataspace_handle = HDF5Handle(H5Screate_simple(N+1, shape_inv, NULL),
    01745                                     &H5Sclose, "createDataset(): unable to create dataspace for non-scalar data.");
    01746     } else {
    01747         // invert dimensions to guarantee c-order
    01748         hsize_t shape_inv[N];
    01749         for(unsigned int k=0; k<N; ++k)
    01750             shape_inv[N-1-k] = array.shape(k);
    01751
    01752         // create dataspace
    01753         dataspace_handle = HDF5Handle(H5Screate_simple(N, shape_inv, NULL),
    01754                                     &H5Sclose, "createDataset(): unable to create dataspace for scalar data.");
    01755     }
    01756
    01757     //alloc memory for dataset.
    01758     dataset_handle = HDF5Handle(H5Dcreate(group,
    01759                                         data_set_name.c_str(),
    01760                                         datatype,
    01761                                         dataspace_handle,
    01762                                         H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT),
    01763                               &H5Dclose, "createDataset(): unable to create dataset.");
    01764 }
    01765
    01766
    01767
    01768 namespace detail {
    01769
    01770 template <class DestIterator, class Shape, class T>
    01771 inline void
    01772 writeHDF5Impl(DestIterator d, Shape const & shape, const hid_t dataset_id, const hid_t datatype, ArrayVector<T> & buffer, int & counter, const int elements, const int numBandsOfType, MetaInt<0>)
    01773 {
    01774     DestIterator dend = d + (typename DestIterator::difference_type)shape[0];
    01775     int k = 0;
    01776     //std::cout << "new:" << std::endl;
    01777     for(; d < dend; ++d, k++)
    01778     {
    01779         buffer[k] = *d;
    01780         //std::cout << buffer[k] << " ";
    01781     }
    01782     //std::cout << std::endl;
    01783     HDF5Handle mid1, mid2;
    01784
    01785     // select hyperslabs
    01786     selectHyperslabs(mid1, mid2, shape, counter, elements, numBandsOfType);
    01787
    01788     // write to hdf5
    01789     H5Dwrite(dataset_id, datatype, mid2, mid1, H5P_DEFAULT, buffer.data());
    01790     // increase counter
    01791     counter++;
    01792 }
    01793
    01794 template <class DestIterator, class Shape, class T, int N>
    01795 void
    01796 writeHDF5Impl(DestIterator d, Shape const & shape, const hid_t dataset_id, const hid_t datatype, ArrayVector<T> & buffer, int & counter, const int elements, const int numBandsOfType, MetaInt<N>)
    01797 {
    01798         DestIterator dend = d + (typename DestIterator::difference_type)shape[N];
    01799         for(; d < dend; ++d)
    01800         {
    01801             writeHDF5Impl(d.begin(), shape, dataset_id, datatype, buffer, counter, elements, numBandsOfType, MetaInt<N-1>());
    01802         }
    01803 }
    01804
    01805 } // namespace detail
    01806
    01807     /** \brief Store array data in an HDF5 file.
    01808
    01809     The number of dimensions, shape and element type of the stored dataset is automatically
    01810     determined from the properties of the given \a array. Strided arrays are stored in an
    01811     unstrided way, i.e. in contiguous scan-order. Multi-channel element types
    01812     (i.e. \ref vigra::RGBValue and \ref vigra::TinyVector) are recognized and handled correctly
    01813     (in particular, the will form the innermost dimension of the stored dataset).
    01814     \a pathInFile may contain '/'-separated group names, but must end with the name
    01815     of the dataset to be created.
    01816
    01817     <b> Declaration:</b>
    01818
    01819     \code
    01820     namespace vigra {
    01821         template<unsigned int N, class T, class StrideTag>
    01822         void
    01823         writeHDF5(const char* filePath, const char* pathInFile,
    01824                   MultiArrayView<N, T, StrideTag>const  & array);
    01825     }
    01826     \endcode
    01827
    01828     <b> Usage:</b>
    01829
    01830     <b>\#include</b> <<a href="hdf5impex_8hxx_source.html">vigra/hdf5impex.hxx</a>><br>
    01831     Namespace: vigra
    01832
    01833     \code
    01834     MultiArrayShape<3>::type shape(100, 200, 20);
    01835     MultiArray<3, int> array(shape);
    01836     ... // fill array with data
    01837
    01838     writeHDF5("mydata.h5", "/group1/my_dataset", array);
    01839     \endcode
    01840 */
    01841 doxygen_overloaded_function(template <...> void writeHDF5)
    01842
    01843 // scalar and unstrided multi arrays
    01844 template<unsigned int N, class T>
    01845 inline void writeHDF5(const char* filePath, const char* pathInFile, const MultiArrayView<N, T, UnstridedArrayTag> & array) // scalar
    01846 {
    01847     writeHDF5(filePath, pathInFile, array, detail::getH5DataType<T>(), 1);
    01848 }
    01849
    01850 // non-scalar (TinyVector) and unstrided multi arrays
    01851 template<unsigned int N, class T, int SIZE>
    01852 inline void writeHDF5(const char* filePath, const char* pathInFile, const MultiArrayView<N, TinyVector<T, SIZE>, UnstridedArrayTag> & array)
    01853 {
    01854     writeHDF5(filePath, pathInFile, array, detail::getH5DataType<T>(), SIZE);
    01855 }
    01856
    01857 // non-scalar (RGBValue) and unstrided multi arrays
    01858 template<unsigned int N, class T>
    01859 inline void writeHDF5(const char* filePath, const char* pathInFile, const MultiArrayView<N, RGBValue<T>, UnstridedArrayTag> & array)
    01860 {
    01861     writeHDF5(filePath, pathInFile, array, detail::getH5DataType<T>(), 3);
    01862 }
    01863
    01864 // unstrided multi arrays
    01865 template<unsigned int N, class T>
    01866 void writeHDF5(const char* filePath, const char* pathInFile, const MultiArrayView<N, T, UnstridedArrayTag> & array, const hid_t datatype, const int numBandsOfType)
    01867 {
    01868     HDF5Handle file_handle;
    01869     HDF5Handle dataset_handle;
    01870     createDataset(filePath, pathInFile, array, datatype, numBandsOfType, file_handle, dataset_handle);
    01871
    01872     // Write the data to the HDF5 dataset as is
    01873     H5Dwrite( dataset_handle, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, array.data()); // .data() possible since void pointer!
    01874
    01875     H5Fflush(file_handle, H5F_SCOPE_GLOBAL);
    01876 }
    01877
    01878
    01879 // scalar and strided multi arrays
    01880 template<unsigned int N, class T>
    01881 inline void writeHDF5(const char* filePath, const char* pathInFile, const MultiArrayView<N, T, StridedArrayTag> & array) // scalar
    01882 {
    01883     writeHDF5(filePath, pathInFile, array, detail::getH5DataType<T>(), 1);
    01884 }
    01885
    01886 // non-scalar (TinyVector) and strided multi arrays
    01887 template<unsigned int N, class T, int SIZE>
    01888 inline void writeHDF5(const char* filePath, const char* pathInFile, const MultiArrayView<N, TinyVector<T, SIZE>, StridedArrayTag> & array)
    01889 {
    01890     writeHDF5(filePath, pathInFile, array, detail::getH5DataType<T>(), SIZE);
    01891 }
    01892
    01893 // non-scalar (RGBValue) and strided multi arrays
    01894 template<unsigned int N, class T>
    01895 inline void writeHDF5(const char* filePath, const char* pathInFile, const MultiArrayView<N, RGBValue<T>, StridedArrayTag> & array)
    01896 {
    01897     writeHDF5(filePath, pathInFile, array, detail::getH5DataType<T>(), 3);
    01898 }
    01899
    01900 // strided multi arrays
    01901 template<unsigned int N, class T>
    01902 void writeHDF5(const char* filePath, const char* pathInFile, const MultiArrayView<N, T, StridedArrayTag> & array, const hid_t datatype, const int numBandsOfType)
    01903 {
    01904     HDF5Handle file_handle;
    01905     HDF5Handle dataset_handle;
    01906     createDataset(filePath, pathInFile, array, datatype, numBandsOfType, file_handle, dataset_handle);
    01907
    01908     vigra::TinyVector<int,N> shape;
    01909     vigra::TinyVector<int,N> stride;
    01910     int elements = numBandsOfType;
    01911     for(unsigned int k=0; k<N; ++k)
    01912     {
    01913         shape[k] = array.shape(k);
    01914         stride[k] = array.stride(k);
    01915         elements *= (int)shape[k];
    01916     }
    01917     int counter = 0;
    01918
    01919     ArrayVector<T> buffer((int)array.shape(0));
    01920     detail::writeHDF5Impl(array.traverser_begin(), shape, dataset_handle, datatype, buffer, counter, elements, numBandsOfType, vigra::MetaInt<N-1>());
    01921
    01922     H5Fflush(file_handle, H5F_SCOPE_GLOBAL);
    01923
    01924 }
    01925
    01926 namespace detail
    01927 {
    01928 struct MaxSizeFnc
    01929 {
    01930     size_t size;
    01931
    01932     MaxSizeFnc()
    01933     : size(0)
    01934     {}
    01935
    01936     void operator()(std::string const & in)
    01937     {
    01938         size = in.size() > size ?
    01939                     in.size() :
    01940                     size;
    01941     }
    01942 };
    01943 }
    01944
    01945
    01946 #if (H5_VERS_MAJOR == 1 && H5_VERS_MINOR == 8) || DOXYGEN
    01947 /** Write a numeric MultiArray as an attribute with name \a name
    01948     of the dataset specified by the handle \a loc.
    01949
    01950     <b>\#include</b> <<a href="hdf5impex_8hxx_source.html">vigra/hdf5impex.hxx</a>><br>
    01951     Namespace: vigra
    01952 */
    01953 template<size_t N, class T, class C>
    01954 void writeHDF5Attr(hid_t loc,
    01955                    const char* name,
    01956                    MultiArrayView<N, T, C> const & array)
    01957 {
    01958     if(H5Aexists(loc, name) > 0)
    01959         H5Adelete(loc, name);
    01960
    01961     ArrayVector<hsize_t> shape(array.shape().begin(),
    01962                                array.shape().end());
    01963     HDF5Handle
    01964         dataspace_handle(H5Screate_simple(N, shape.data(), NULL),
    01965                          &H5Sclose,
    01966                          "writeToHDF5File(): unable to create dataspace.");
    01967
    01968     HDF5Handle attr(H5Acreate(loc,
    01969                               name,
    01970                               detail::getH5DataType<T>(),
    01971                               dataspace_handle,
    01972                               H5P_DEFAULT ,H5P_DEFAULT ),
    01973                     &H5Aclose,
    01974                     "writeHDF5Attr: unable to create Attribute");
    01975
    01976     //copy data - since attributes are small - who cares!
    01977     ArrayVector<T> buffer;
    01978     for(int ii = 0; ii < array.size(); ++ii)
    01979         buffer.push_back(array[ii]);
    01980     H5Awrite(attr, detail::getH5DataType<T>(), buffer.data());
    01981 }
    01982
    01983 /** Write a string MultiArray as an attribute with name \a name
    01984     of the dataset specified by the handle \a loc.
    01985
    01986     <b>\#include</b> <<a href="hdf5impex_8hxx_source.html">vigra/hdf5impex.hxx</a>><br>
    01987     Namespace: vigra
    01988 */
    01989 template<size_t N, class C>
    01990 void writeHDF5Attr(hid_t loc,
    01991                    const char* name,
    01992                    MultiArrayView<N, std::string, C> const & array)
    01993 {
    01994     if(H5Aexists(loc, name) > 0)
    01995         H5Adelete(loc, name);
    01996
    01997     ArrayVector<hsize_t> shape(array.shape().begin(),
    01998                                array.shape().end());
    01999     HDF5Handle
    02000         dataspace_handle(H5Screate_simple(N, shape.data(), NULL),
    02001                          &H5Sclose,
    02002                          "writeToHDF5File(): unable to create dataspace.");
    02003
    02004     HDF5Handle atype(H5Tcopy (H5T_C_S1),
    02005                      &H5Tclose,
    02006                      "writeToHDF5File(): unable to create type.");
    02007
    02008     detail::MaxSizeFnc max_size;
    02009     max_size = std::for_each(array.data(),array.data()+ array.size(), max_size);
    02010     H5Tset_size (atype, max_size.size);
    02011
    02012     HDF5Handle attr(H5Acreate(loc,
    02013                               name,
    02014                               atype,
    02015                               dataspace_handle,
    02016                               H5P_DEFAULT ,H5P_DEFAULT ),
    02017                     &H5Aclose,
    02018                     "writeHDF5Attr: unable to create Attribute");
    02019
    02020     std::string buf ="";
    02021     for(int ii = 0; ii < array.size(); ++ii)
    02022     {
    02023         buf = buf + array[ii]
    02024                   + std::string(max_size.size - array[ii].size(), ' ');
    02025     }
    02026     H5Awrite(attr, atype, buf.c_str());
    02027 }
    02028
    02029 /** Write a numeric ArrayVectorView as an attribute with name \a name
    02030     of the dataset specified by the handle \a loc.
    02031
    02032     <b>\#include</b> <<a href="hdf5impex_8hxx_source.html">vigra/hdf5impex.hxx</a>><br>
    02033     Namespace: vigra
    02034 */
    02035 template<class T>
    02036 inline void writeHDF5Attr(  hid_t loc,
    02037                             const char* name,
    02038                             ArrayVectorView<T>  & array)
    02039 {
    02040     writeHDF5Attr(loc, name,
    02041                   MultiArrayView<1, T>(MultiArrayShape<1>::type(array.size()),
    02042                                        array.data()));
    02043 }
    02044
    02045 /** write an Attribute given a file and a path in the file.
    02046  *  the path in the file should have the format
    02047  *  [attribute] or /[subgroups/]dataset.attribute or
    02048  *  /[subgroups/]group.attribute.
    02049  *  The attribute is written to the root group, a dataset or a subgroup
    02050  *  respectively
    02051  */
    02052 template<class Arr>
    02053 inline void writeHDF5Attr(  std::string filePath,
    02054                             std::string pathInFile,
    02055                             Arr  & ar)
    02056 {
    02057     std::string path_name(pathInFile), group_name, data_set_name, message, attr_name;
    02058     std::string::size_type delimiter = path_name.rfind('/');
    02059
    02060     //create or open file
    02061     HDF5Handle file_id(createFile(filePath), &H5Fclose,
    02062                        "writeToHDF5File(): unable to open output file.");
    02063
    02064     // get the groupname and the filename
    02065     if(delimiter == std::string::npos)
    02066     {
    02067         group_name    = "/";
    02068         data_set_name = path_name;
    02069     }
    02070
    02071     else
    02072     {
    02073         group_name = std::string(path_name.begin(), path_name.begin()+delimiter);
    02074         data_set_name = std::string(path_name.begin()+delimiter+1, path_name.end());
    02075     }
    02076     delimiter = data_set_name.rfind('.');
    02077     if(delimiter == std::string::npos)
    02078     {
    02079         attr_name = path_name;
    02080         data_set_name = "/";
    02081     }
    02082     else
    02083     {
    02084         attr_name = std::string(data_set_name.begin()+delimiter+1, data_set_name.end());
    02085         data_set_name = std::string(data_set_name.begin(), data_set_name.begin()+delimiter);
    02086     }
    02087
    02088     HDF5Handle group(openGroup(file_id, group_name), &H5Gclose,
    02089                      "writeToHDF5File(): Unable to create and open group. attr ver");
    02090
    02091     if(data_set_name != "/")
    02092     {
    02093         HDF5Handle dset(H5Dopen(group, data_set_name.c_str(), H5P_DEFAULT), &H5Dclose,
    02094                         "writeHDF5Attr():unable to open dataset");
    02095         writeHDF5Attr(hid_t(dset), attr_name.c_str(), ar);
    02096     }
    02097     else
    02098     {
    02099         writeHDF5Attr(hid_t(group), attr_name.c_str(), ar);
    02100     }
    02101
    02102 }
    02103 #endif
    02104
    02105 //@}
    02106
    02107 } // namespace vigra
    02108
    02109 #endif // VIGRA_HDF5IMPEX_HXX

© Ullrich Köthe (ullrich.koethe@iwr.uni-heidelberg.de) Heidelberg Collaboratory for Image Processing, University of Heidelberg, Germany | html generated using doxygen and Python vigra 1.7.1 (3 Dec 2010)