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

hdf5impex.hxx
1 /************************************************************************/
2 /* */
3 /* Copyright 2009 by Michael Hanselmann and Ullrich Koethe */
4 /* */
5 /* This file is part of the VIGRA computer vision library. */
6 /* The VIGRA Website is */
7 /* http://hci.iwr.uni-heidelberg.de/vigra/ */
8 /* Please direct questions, bug reports, and contributions to */
9 /* ullrich.koethe@iwr.uni-heidelberg.de or */
10 /* vigra@informatik.uni-hamburg.de */
11 /* */
12 /* Permission is hereby granted, free of charge, to any person */
13 /* obtaining a copy of this software and associated documentation */
14 /* files (the "Software"), to deal in the Software without */
15 /* restriction, including without limitation the rights to use, */
16 /* copy, modify, merge, publish, distribute, sublicense, and/or */
17 /* sell copies of the Software, and to permit persons to whom the */
18 /* Software is furnished to do so, subject to the following */
19 /* conditions: */
20 /* */
21 /* The above copyright notice and this permission notice shall be */
22 /* included in all copies or substantial portions of the */
23 /* Software. */
24 /* */
25 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND */
26 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES */
27 /* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */
28 /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT */
29 /* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
30 /* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */
31 /* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */
32 /* OTHER DEALINGS IN THE SOFTWARE. */
33 /* */
34 /************************************************************************/
35 
36 #ifndef VIGRA_HDF5IMPEX_HXX
37 #define VIGRA_HDF5IMPEX_HXX
38 
39 #include <string>
40 
41 #define H5Gcreate_vers 2
42 #define H5Gopen_vers 2
43 #define H5Dopen_vers 2
44 #define H5Dcreate_vers 2
45 #define H5Acreate_vers 2
46 
47 #include <hdf5.h>
48 
49 #if (H5_VERS_MAJOR == 1 && H5_VERS_MINOR <= 6)
50 # ifndef H5Gopen
51 # define H5Gopen(a, b, c) H5Gopen(a, b)
52 # endif
53 # ifndef H5Gcreate
54 # define H5Gcreate(a, b, c, d, e) H5Gcreate(a, b, 1)
55 # endif
56 # ifndef H5Dopen
57 # define H5Dopen(a, b, c) H5Dopen(a, b)
58 # endif
59 # ifndef H5Dcreate
60 # define H5Dcreate(a, b, c, d, e, f, g) H5Dcreate(a, b, c, d, f)
61 # endif
62 # ifndef H5Acreate
63 # define H5Acreate(a, b, c, d, e, f) H5Acreate(a, b, c, d, e)
64 # endif
65 # ifndef H5Pset_obj_track_times
66 # define H5Pset_obj_track_times(a, b) do {} while (0)
67 # endif
68 # include <H5LT.h>
69 #else
70 # include <hdf5_hl.h>
71 #endif
72 
73 #include "impex.hxx"
74 #include "multi_array.hxx"
75 #include "multi_impex.hxx"
76 #include "utilities.hxx"
77 #include "error.hxx"
78 
79 #include <algorithm>
80 
81 namespace vigra {
82 
83 /** \addtogroup VigraHDF5Impex Import/Export of Images and Arrays in HDF5 Format
84 
85  Supports arrays with arbitrary element types and arbitrary many dimensions.
86  See the <a href="http://www.hdfgroup.org/HDF5/">HDF5 Website</a> for more
87  information on the HDF5 file format.
88 */
89 //@{
90 
91  /** \brief Wrapper for hid_t objects.
92 
93  Newly created or opened HDF5 handles are usually stored as objects of type 'hid_t'. When the handle
94  is no longer needed, the appropriate close function must be called. However, if a function is
95  aborted by an exception, this is difficult to ensure. Class HDF5Handle is a smart pointer that
96  solves this problem by calling the close function in the destructor (This is analogous to how
97  VIGRA_UNIQUE_PTR calls 'delete' on the contained pointer). A pointer to the close function must be
98  passed to the constructor, along with an error message that is raised when creation/opening fails.
99 
100  Since HDF5Handle objects are convertible to hid_t, they can be used in the code in place
101  of the latter.
102 
103  <b>Usage:</b>
104 
105  \code
106  HDF5Handle file_id(H5Fopen(filename, H5F_ACC_RDWR, H5P_DEFAULT),
107  &H5Fclose,
108  "Error message.");
109 
110  ... // use file_id in the same way as a plain hid_t object
111  \endcode
112 
113  <b>\#include</b> <vigra/hdf5impex.hxx><br>
114  Namespace: vigra
115  */
117 {
118 public:
119  typedef herr_t (*Destructor)(hid_t);
120 
121 private:
122  hid_t handle_;
123  Destructor destructor_;
124 
125 public:
126 
127  /** \brief Default constructor.
128  Creates a NULL handle.
129  **/
131  : handle_( 0 ),
132  destructor_(0)
133  {}
134 
135  /** \brief Create a wrapper for a hid_t object.
136 
137  The hid_t object \a h is assumed to be the return value of an open or create function.
138  It will be closed with the given close function \a destructor as soon as this
139  HDF5Handle is destructed, except when \a destructor is a NULL pointer (in which
140  case nothing happens at destruction time). If \a h has a value that indicates
141  failed opening or creation (by HDF5 convention, this means if it is a negative number),
142  an exception is raised by calling <tt>vigra_fail(error_message)</tt>.
143 
144  <b>Usage:</b>
145 
146  \code
147  HDF5Handle file_id(H5Fopen(filename, H5F_ACC_RDWR, H5P_DEFAULT),
148  &H5Fclose,
149  "Error message.");
150 
151  ... // use file_id in the same way
152  \endcode
153  */
154  HDF5Handle(hid_t h, Destructor destructor, const char * error_message)
155  : handle_( h ),
156  destructor_(destructor)
157  {
158  if(handle_ < 0)
159  vigra_fail(error_message);
160  }
161 
162  /** \brief Copy constructor.
163  Hands over ownership of the RHS handle (analogous to VIGRA_UNIQUE_PTR).
164  */
166  : handle_( h.handle_ ),
167  destructor_(h.destructor_)
168  {
169  const_cast<HDF5Handle &>(h).handle_ = 0;
170  }
171 
172  /** \brief Assignment.
173  Calls close() for the LHS handle and hands over ownership of the
174  RHS handle (analogous to VIGRA_UNIQUE_PTR).
175  */
177  {
178  if(h.handle_ != handle_)
179  {
180  close();
181  handle_ = h.handle_;
182  destructor_ = h.destructor_;
183  const_cast<HDF5Handle &>(h).handle_ = 0;
184  }
185  return *this;
186  }
187 
188  /** \brief Destructor.
189  Calls close() for the contained handle.
190  */
192  {
193  close();
194  }
195 
196  /** \brief Explicitly call the stored function (if one has been stored within
197  this object) for the contained handle and set the handle to NULL.
198  */
199  herr_t close()
200  {
201  herr_t res = 1;
202  if(handle_ && destructor_)
203  res = (*destructor_)(handle_);
204  handle_ = 0;
205  return res;
206  }
207 
208  /** \brief Get a temporary hid_t object for the contained handle.
209  Do not call a close function on the return value - a crash will be likely
210  otherwise.
211  */
212  hid_t get() const
213  {
214  return handle_;
215  }
216 
217  /** \brief Convert to a plain hid_t object.
218 
219  This function ensures that hid_t objects can be transparently replaced with
220  HDF5Handle objects in user code. Do not call a close function on the return
221  value - a crash will be likely otherwise.
222  */
223  operator hid_t() const
224  {
225  return handle_;
226  }
227 
228  /** \brief Equality comparison of the contained handle.
229  */
230  bool operator==(HDF5Handle const & h) const
231  {
232  return handle_ == h.handle_;
233  }
234 
235  /** \brief Equality comparison of the contained handle.
236  */
237  bool operator==(hid_t h) const
238  {
239  return handle_ == h;
240  }
241 
242  /** \brief Inequality comparison of the contained handle.
243  */
244  bool operator!=(HDF5Handle const & h) const
245  {
246  return handle_ != h.handle_;
247  }
248 
249  /** \brief Inequality comparison of the contained handle.
250  */
251  bool operator!=(hid_t h) const
252  {
253  return handle_ != h;
254  }
255 };
256 
257 
258 /********************************************************/
259 /* */
260 /* HDF5ImportInfo */
261 /* */
262 /********************************************************/
263 
264 /** \brief Argument object for the function readHDF5().
265 
266 See \ref readHDF5() for a usage example. This object must be
267 used to read an image or array from an HDF5 file
268 and enquire about its properties.
269 
270 <b>\#include</b> <vigra/hdf5impex.hxx><br>
271 Namespace: vigra
272 */
274 {
275  public:
276  enum PixelType { UINT8, UINT16, UINT32, UINT64,
277  INT8, INT16, INT32, INT64,
278  FLOAT, DOUBLE };
279 
280  /** Construct HDF5ImportInfo object.
281 
282  The dataset \a pathInFile in the HDF5 file \a filename is accessed to
283  read its properties. \a pathInFile may contain '/'-separated group
284  names, but must end with the name of the desired dataset:
285 
286  \code
287  HDF5ImportInfo info(filename, "/group1/group2/my_dataset");
288  \endcode
289  */
290  VIGRA_EXPORT HDF5ImportInfo( const char* filePath, const char* pathInFile );
291 
292  VIGRA_EXPORT ~HDF5ImportInfo();
293 
294  /** Get the filename of this HDF5 object.
295  */
296  VIGRA_EXPORT const std::string& getFilePath() const;
297 
298  /** Get the dataset's full name in the HDF5 file.
299  */
300  VIGRA_EXPORT const std::string& getPathInFile() const;
301 
302  /** Get a handle to the file represented by this info object.
303  */
304  VIGRA_EXPORT hid_t getH5FileHandle() const;
305 
306  /** Get a handle to the dataset represented by this info object.
307  */
308  VIGRA_EXPORT hid_t getDatasetHandle() const;
309 
310  /** Get the number of dimensions of the dataset represented by this info object.
311  */
312  VIGRA_EXPORT MultiArrayIndex numDimensions() const;
313 
314  /** Get the shape of the dataset represented by this info object.
315 
316  Note that the memory order between VIGRA and HDF5 files differs: VIGRA uses
317  Fortran-order, while HDF5 uses C-order. This function therefore reverses the axis
318  order relative to the file contents. That is, when the axes in the file are
319  ordered as 'z', 'y', 'x', this function will return the shape in the order
320  'x', 'y', 'z'.
321  */
322  VIGRA_EXPORT ArrayVector<hsize_t> const & shape() const
323  {
324  return m_dims;
325  }
326 
327  /** Get the shape (length) of the dataset along dimension \a dim.
328 
329  Note that the memory order between VIGRA and HDF5 files differs: VIGRA uses
330  Fortran-order, while HDF5 uses C-order. This function therefore reverses the axis
331  order relative to the file contents. That is, when the axes in the file are
332  ordered as 'z', 'y', 'x', this function will return the shape in the order
333  'x', 'y', 'z'.
334  */
335  VIGRA_EXPORT MultiArrayIndex shapeOfDimension(const int dim) const;
336 
337  /** Query the pixel type of the dataset.
338 
339  Possible values are:
340  <DL>
341  <DT>"UINT8"<DD> 8-bit unsigned integer (unsigned char)
342  <DT>"INT16"<DD> 16-bit signed integer (short)
343  <DT>"UINT16"<DD> 16-bit unsigned integer (unsigned short)
344  <DT>"INT32"<DD> 32-bit signed integer (long)
345  <DT>"UINT32"<DD> 32-bit unsigned integer (unsigned long)
346  <DT>"FLOAT"<DD> 32-bit floating point (float)
347  <DT>"DOUBLE"<DD> 64-bit floating point (double)
348  </DL>
349  */
350  VIGRA_EXPORT const char * getPixelType() const;
351 
352  /** Query the pixel type of the dataset.
353 
354  Same as getPixelType(), but the result is returned as a
355  ImageImportInfo::PixelType enum. This is useful to implement
356  a switch() on the pixel type.
357 
358  Possible values are:
359  <DL>
360  <DT>UINT8<DD> 8-bit unsigned integer (unsigned char)
361  <DT>INT16<DD> 16-bit signed integer (short)
362  <DT>UINT16<DD> 16-bit unsigned integer (unsigned short)
363  <DT>INT32<DD> 32-bit signed integer (long)
364  <DT>UINT32<DD> 32-bit unsigned integer (unsigned long)
365  <DT>FLOAT<DD> 32-bit floating point (float)
366  <DT>DOUBLE<DD> 64-bit floating point (double)
367  </DL>
368  */
369  VIGRA_EXPORT PixelType pixelType() const;
370 
371  private:
372  HDF5Handle m_file_handle, m_dataset_handle;
373  std::string m_filename, m_path, m_pixeltype;
374  hssize_t m_dimensions;
375  ArrayVector<hsize_t> m_dims;
376 };
377 
378 
379 namespace detail {
380 
381 template<class type>
382 inline hid_t getH5DataType()
383 {
384  std::runtime_error("getH5DataType(): invalid type");
385  return 0;
386 }
387 
388 #define VIGRA_H5_DATATYPE(type, h5type) \
389 template<> \
390 inline hid_t getH5DataType<type>() \
391 { return h5type;}
392 
393 VIGRA_H5_DATATYPE(char, H5T_NATIVE_CHAR)
394 VIGRA_H5_DATATYPE(float, H5T_NATIVE_FLOAT)
395 VIGRA_H5_DATATYPE(double, H5T_NATIVE_DOUBLE)
396 VIGRA_H5_DATATYPE(long double, H5T_NATIVE_LDOUBLE)
397 
398 // char arrays with flexible length require 'handcrafted' H5 datatype
399 template<>
400 inline hid_t getH5DataType<char*>()
401 {
402  hid_t stringtype = H5Tcopy (H5T_C_S1);
403  H5Tset_size(stringtype, H5T_VARIABLE);
404  return stringtype;
405 }
406 template<>
407 inline hid_t getH5DataType<const char*>()
408 {
409  hid_t stringtype = H5Tcopy (H5T_C_S1);
410  H5Tset_size(stringtype, H5T_VARIABLE);
411  return stringtype;
412 }
413 #undef VIGRA_H5_DATATYPE
414 
415 #define VIGRA_H5_SIGNED_DATATYPE(type) \
416 template<> \
417 inline hid_t getH5DataType<type>() \
418 { static hid_t types[] = {0, H5T_NATIVE_INT8, H5T_NATIVE_INT16, 0, H5T_NATIVE_INT32, 0,0,0,H5T_NATIVE_INT64}; \
419  return types[sizeof(type)];}
420 
421 VIGRA_H5_SIGNED_DATATYPE(signed char)
422 VIGRA_H5_SIGNED_DATATYPE(signed short)
423 VIGRA_H5_SIGNED_DATATYPE(signed int)
424 VIGRA_H5_SIGNED_DATATYPE(signed long)
425 VIGRA_H5_SIGNED_DATATYPE(signed long long)
426 
427 #undef VIGRA_H5_SIGNED_DATATYPE
428 
429 #define VIGRA_H5_UNSIGNED_DATATYPE(type) \
430 template<> \
431 inline hid_t getH5DataType<type>() \
432 { static hid_t types[] = {0, H5T_NATIVE_UINT8, H5T_NATIVE_UINT16, 0, H5T_NATIVE_UINT32, 0,0,0,H5T_NATIVE_UINT64}; \
433  return types[sizeof(type)];}
434 
435 VIGRA_H5_UNSIGNED_DATATYPE(unsigned char)
436 VIGRA_H5_UNSIGNED_DATATYPE(unsigned short)
437 VIGRA_H5_UNSIGNED_DATATYPE(unsigned int)
438 VIGRA_H5_UNSIGNED_DATATYPE(unsigned long)
439 VIGRA_H5_UNSIGNED_DATATYPE(unsigned long long)
440 
441 #undef VIGRA_H5_UNSIGNED_DATATYPE
442 
443 #if 0
444 template<>
445 inline hid_t getH5DataType<FFTWComplex<float> >()
446 {
447  hid_t complex_id = H5Tcreate (H5T_COMPOUND, sizeof (FFTWComplex<float>));
448  H5Tinsert (complex_id, "real", 0, H5T_NATIVE_FLOAT);
449  H5Tinsert (complex_id, "imaginary", sizeof(float), H5T_NATIVE_FLOAT);
450  return complex_id;
451 }
452 
453 template<>
454 inline hid_t getH5DataType<FFTWComplex<double> >()
455 {
456  hid_t complex_id = H5Tcreate (H5T_COMPOUND, sizeof (FFTWComplex<double>));
457  H5Tinsert (complex_id, "real", 0, H5T_NATIVE_DOUBLE);
458  H5Tinsert (complex_id, "imaginary", sizeof(double), H5T_NATIVE_DOUBLE);
459  return complex_id;
460 }
461 #endif
462 
463 
464 } // namespace detail
465 
466 // helper friend function for callback HDF5_ls_inserter_callback()
467 void HDF5_ls_insert(void*, const std::string &);
468 // callback function for ls(), called via HDF5File::H5Literate()
469 // see http://www.parashift.com/c++-faq-lite/pointers-to-members.html#faq-33.2
470 // for as to why.
471 
472 VIGRA_EXPORT H5O_type_t HDF5_get_type(hid_t, const char*);
473 extern "C" VIGRA_EXPORT herr_t HDF5_ls_inserter_callback(hid_t, const char*, const H5L_info_t*, void*);
474 
475 /********************************************************/
476 /* */
477 /* HDF5File */
478 /* */
479 /********************************************************/
480 
481 
482 /** \brief Access to HDF5 files
483 
484 HDF5File provides a convenient way of accessing data in HDF5 files. vigra::MultiArray
485 structures of any dimension can be stored to / loaded from HDF5 files. Typical
486 HDF5 features like subvolume access, chunks and data compression are available,
487 string attributes can be attached to any dataset or group. Group- or dataset-handles
488 are encapsulated in the class and managed automatically. The internal file-system like
489 structure can be accessed by functions like "cd()" or "mkdir()".
490 
491 Note that the memory order between VIGRA and HDF5 files differs: VIGRA uses
492 Fortran-order, while HDF5 uses C-order. This means that a VIGRA MultiArray,
493 whose indices represent the 'x'-, 'y'-, and 'z'-axis in that order, is reversed
494 upon writing to an HDF5 file, i.e. in the file the axis order is 'z', 'y', 'x'.
495 Likewise, the order is reversed upon reading.
496 
497 <b>Example:</b>
498 Write the MultiArray out_multi_array to file. Change the current directory to
499 "/group" and read in the same MultiArray as in_multi_array.
500 \code
501 HDF5File file("/path/to/file",HDF5File::New);
502 file.mkdir("group");
503 file.write("/group/dataset", out_multi_array);
504 
505 file.cd("/group");
506 file.read("dataset", in_multi_array);
507 
508 \endcode
509 
510 <b>\#include</b> <vigra/hdf5impex.hxx><br>
511 Namespace: vigra
512 */
513 class HDF5File
514 {
515  protected:
516  HDF5Handle fileHandle_;
517 
518  // current group handle
519  HDF5Handle cGroupHandle_;
520 
521  private:
522  // time tagging of datasets, turned off (= 0) by default.
523  int track_time;
524 
525  // helper class for ls()
526  struct ls_closure
527  {
528  virtual void insert(const std::string &) = 0;
529  virtual ~ls_closure() {}
530  };
531  // datastructure to hold a list of dataset and group names
532  struct lsOpData : public ls_closure
533  {
534  std::vector<std::string> & objects;
535  lsOpData(std::vector<std::string> & o) : objects(o) {}
536  void insert(const std::string & x)
537  {
538  objects.push_back(x);
539  }
540  };
541  // (associative-)container closure
542  template<class Container>
543  struct ls_container_data : public ls_closure
544  {
545  Container & objects;
546  ls_container_data(Container & o) : objects(o) {}
547  void insert(const std::string & x)
548  {
549  objects.insert(std::string(x));
550  }
551  };
552 
553  public:
554 
555  // helper for callback HDF5_ls_inserter_callback(), used by ls()
556  friend void HDF5_ls_insert(void*, const std::string &);
557 
558  /** \brief Set how a file is opened.
559 
560  OpenMode::New creates a new file. If the file already exists, overwrite it.
561 
562  OpenMode::Open opens a file for reading/writing. The file will be created,
563  if necessary.
564  */
565  enum OpenMode {
566  New, // Create new empty file (existing file will be deleted).
567  Open, // Open file. Create if not existing.
568  OpenReadOnly // Open file in read-only mode.
569  };
570 
571  /** \brief Default constructor.
572 
573  A file can later be opened via the open() function.
574 
575  If \a track_creation_times is non-zero, time tagging of datasets will be enabled (it is disabled
576  by default).
577  */
578  HDF5File(int track_creation_times = 0)
579  : track_time(track_creation_times)
580  {}
581 
582  /** \brief Open or create an HDF5File object.
583 
584  Creates or opens HDF5 file with given filename.
585  The current group is set to "/".
586 
587  Note that the HDF5File class is not copyable (the copy constructor is
588  private to enforce this).
589  */
590  HDF5File(std::string filename, OpenMode mode, int track_creation_times = 0)
591  : track_time(track_creation_times)
592  {
593  open(filename, mode);
594  }
595 
596  /** \brief The destructor flushes and closes the file.
597  */
599  {
600  // The members fileHandle_ and cGroupHandle_ are automatically closed
601  // as they are of type HDF5Handle and are properly initialised.
602  // The closing of fileHandle_ implies flushing the file to
603  // the operating system, see
604  // http://www.hdfgroup.org/HDF5/doc/RM/RM_H5F.html#File-Close .
605  }
606 
607  // copying is not permitted.
608  private:
609  HDF5File(const HDF5File &);
610  void operator=(const HDF5File &);
611 
612  public:
613 
614  /** \brief Open or create the given file in the given mode and set the group to "/".
615  If another file is currently open, it is first closed.
616  */
617  void open(std::string filename, OpenMode mode)
618  {
619  close();
620 
621  std::string errorMessage = "HDF5File.open(): Could not open or create file '" + filename + "'.";
622  fileHandle_ = HDF5Handle(createFile_(filename, mode), &H5Fclose, errorMessage.c_str());
623  cGroupHandle_ = HDF5Handle(openCreateGroup_("/"), &H5Gclose, "HDF5File.open(): Failed to open root group.");
624  }
625 
626  /** \brief Close the current file.
627  */
628  void close()
629  {
630  bool success = cGroupHandle_.close() >= 0 && fileHandle_.close() >= 0;
631  vigra_postcondition(success, "HDF5File.close() failed.");
632  }
633 
634  /** \brief Change current group to "/".
635  */
636  inline void root()
637  {
638  std::string message = "HDF5File::root(): Could not open group '/'.";
639  cGroupHandle_ = HDF5Handle(H5Gopen(fileHandle_, "/", H5P_DEFAULT),&H5Gclose,message.c_str());
640  }
641 
642  /** \brief Change the current group.
643  Both absolute and relative group names are allowed.
644  */
645  inline void cd(std::string groupName)
646  {
647  std::string message = "HDF5File::cd(): Could not open group '" + groupName + "'.\n";
648 
649  // make groupName clean
650  groupName = get_absolute_path(groupName);
651 
652  if(groupName == "/")
653  {
654  cGroupHandle_ = HDF5Handle(openCreateGroup_("/"),&H5Gclose,message.c_str());
655  }
656  else
657  {
658  vigra_precondition(H5Lexists(fileHandle_, groupName.c_str(), H5P_DEFAULT) != 0, message);
659  cGroupHandle_ = HDF5Handle(openCreateGroup_(groupName),&H5Gclose,message.c_str());
660  }
661  }
662 
663  /** \brief Change the current group to its parent group.
664  Returns true if successful, false otherwise. If unsuccessful,
665  the group will not change.
666  */
667  inline bool cd_up()
668  {
669  std::string groupName = currentGroupName_();
670 
671  //do not try to move up if we already in "/"
672  if(groupName == "/"){
673  return false;
674  }
675 
676  size_t lastSlash = groupName.find_last_of('/');
677 
678  std::string parentGroup (groupName.begin(), groupName.begin()+lastSlash+1);
679 
680  cd(parentGroup);
681 
682  return true;
683  }
684 
685  /** \brief Change the current group to its parent group.
686  Returns true if successful, false otherwise. If unsuccessful,
687  the group will not change.
688  */
689  inline bool cd_up(int levels)
690  {
691  std::string groupName = currentGroupName_();
692 
693  for(int i = 0; i<levels; i++)
694  {
695  if(!cd_up())
696  {
697  // restore old group if neccessary
698  if(groupName != currentGroupName_())
699  cd(groupName);
700  return false;
701  }
702  }
703  return true;
704  }
705 
706  /** \brief Create a new group.
707  If the first character is a "/", the path will be interpreted as absolute path,
708  otherwise it will be interpreted as path relative to the current group.
709  */
710  inline void mkdir(std::string groupName)
711  {
712  std::string message = "HDF5File::mkdir(): Could not create group '" + groupName + "'.\n";
713 
714  // make groupName clean
715  groupName = get_absolute_path(groupName);
716 
717  HDF5Handle(openCreateGroup_(groupName.c_str()),&H5Gclose,message.c_str());
718  }
719 
720  /** \brief Change the current group; create it if necessary.
721  If the first character is a "/", the path will be interpreted as absolute path,
722  otherwise it will be interpreted as path relative to the current group.
723  */
724  inline void cd_mk(std::string groupName)
725  {
726  std::string message = "HDF5File::cd_mk(): Could not create group '" + groupName + "'.";
727 
728  // make groupName clean
729  groupName = get_absolute_path(groupName);
730 
731  cGroupHandle_ = HDF5Handle(openCreateGroup_(groupName.c_str()),&H5Gclose,message.c_str());
732  }
733 
734  // helper function for the various ls() variants.
735  void ls_H5Literate(ls_closure & data) const
736  {
737  H5Literate(cGroupHandle_, H5_INDEX_NAME, H5_ITER_NATIVE, NULL,
738  HDF5_ls_inserter_callback, static_cast<void*>(&data));
739  }
740 
741  /** \brief List the contents of the current group.
742  The function returns a vector of strings holding the entries of the
743  current group. Only datasets and groups are listed, other objects
744  (e.g. datatypes) are ignored. Group names always have a trailing "/".
745  */
746  inline std::vector<std::string> ls() const
747  {
748  std::vector<std::string> list;
749  lsOpData data(list);
750  ls_H5Literate(data);
751  return list;
752  }
753 
754  /** \brief List the contents of the current group into a container-like
755  object via insert().
756 
757  Only datasets and groups are inserted, other objects (e.g., datatypes) are ignored.
758  Group names always have a trailing "/".
759 
760  The argument cont is presumably an associative container, however,
761  only its member function <tt>cont.insert(std::string)</tt> will be
762  called.
763  \param cont reference to a container supplying a member function
764  <tt>insert(const i_type &)</tt>, where <tt>i_type</tt>
765  is convertible to <tt>std::string</tt>.
766  */
767  template<class Container>
768  void ls(Container & cont) const
769  {
770  ls_container_data<Container> data(cont);
771  ls_H5Literate(data);
772  }
773 
774  /** \brief Get the path of the current group.
775  */
776  inline std::string pwd() const
777  {
778  return currentGroupName_();
779  }
780 
781  /** \brief Get the name of the associated file.
782  */
783  inline std::string filename() const
784  {
785  return fileName_();
786  }
787 
788  /** \brief Get the number of dimensions of a certain dataset
789  If the first character is a "/", the path will be interpreted as absolute path,
790  otherwise it will be interpreted as path relative to the current group.
791  */
792  inline hssize_t getDatasetDimensions(std::string datasetName)
793  {
794  // make datasetName clean
795  datasetName = get_absolute_path(datasetName);
796 
797  //Open dataset and dataspace
798  std::string errorMessage = "HDF5File::getDatasetDimensions(): Unable to open dataset '" + datasetName + "'.";
799  HDF5Handle datasetHandle = HDF5Handle(getDatasetHandle_(datasetName), &H5Dclose, errorMessage.c_str());
800 
801  errorMessage = "HDF5File::getDatasetDimensions(): Unable to access dataspace.";
802  HDF5Handle dataspaceHandle(H5Dget_space(datasetHandle), &H5Sclose, errorMessage.c_str());
803 
804  //return dimension information
805  return H5Sget_simple_extent_ndims(dataspaceHandle);
806  }
807 
808  /** \brief Get the shape of each dimension of a certain dataset.
809 
810  Normally, this function is called after determining the dimension of the
811  dataset using \ref getDatasetDimensions().
812  If the first character is a "/", the path will be interpreted as absolute path,
813  otherwise it will be interpreted as path relative to the current group.
814 
815  Note that the memory order between VIGRA and HDF5 files differs: VIGRA uses
816  Fortran-order, while HDF5 uses C-order. This function therefore reverses the axis
817  order relative to the file contents. That is, when the axes in the file are
818  ordered as 'z', 'y', 'x', this function will return the shape in the order
819  'x', 'y', 'z'.
820  */
821  inline ArrayVector<hsize_t> getDatasetShape(std::string datasetName)
822  {
823  // make datasetName clean
824  datasetName = get_absolute_path(datasetName);
825 
826  //Open dataset and dataspace
827  std::string errorMessage = "HDF5File::getDatasetShape(): Unable to open dataset '" + datasetName + "'.";
828  HDF5Handle datasetHandle = HDF5Handle(getDatasetHandle_(datasetName), &H5Dclose, errorMessage.c_str());
829 
830  errorMessage = "HDF5File::getDatasetShape(): Unable to access dataspace.";
831  HDF5Handle dataspaceHandle(H5Dget_space(datasetHandle), &H5Sclose, errorMessage.c_str());
832 
833  //get dimension information
834  ArrayVector<hsize_t>::size_type dimensions = H5Sget_simple_extent_ndims(dataspaceHandle);
835 
836  ArrayVector<hsize_t> shape(dimensions);
837  ArrayVector<hsize_t> maxdims(dimensions);
838  H5Sget_simple_extent_dims(dataspaceHandle, shape.data(), maxdims.data());
839 
840  // invert the dimensions to guarantee VIGRA-compatible order.
841  std::reverse(shape.begin(), shape.end());
842  return shape;
843  }
844 
845  /** \brief Obtain the HDF5 handle of a dataset.
846  */
847  inline HDF5Handle getDatasetHandle(std::string dataset_name)
848  {
849  std::string errorMessage = "HDF5File::getDatasetHandle(): Unable to open dataset '" + dataset_name + "'.";
850  return HDF5Handle(getDatasetHandle_(dataset_name), &H5Dclose, errorMessage.c_str());
851  }
852 
853  /** \brief Obtain the HDF5 handle of a group.
854  */
855  inline HDF5Handle getGroupHandle(std::string group_name)
856  {
857  std::string errorMessage = "HDF5File::getGroupHandle(): Group '" + group_name + "' not found.";
858 
859  // make group_name clean
860  group_name = get_absolute_path(group_name);
861 
862  // group must exist
863  vigra_precondition(H5Lexists(fileHandle_, group_name.c_str(), H5P_DEFAULT) == 1,
864  errorMessage.c_str());
865 
866  // open group and return group handle
867  return HDF5Handle(openCreateGroup_(group_name), &H5Gclose, "Internal error");
868  }
869 
870  /** \brief Obtain the HDF5 handle of a attribute.
871  */
872  inline HDF5Handle getAttributeHandle(std::string dataset_name, std::string attribute_name)
873  {
874  std::string message = "HDF5File::getAttributeHandle(): Attribute '" + attribute_name + "' not found.";
875  return HDF5Handle(H5Aopen(getDatasetHandle(dataset_name), attribute_name.c_str(), H5P_DEFAULT),
876  &H5Aclose, message.c_str());
877  }
878 
879  /* Writing Attributes */
880 
881  /** \brief Write MultiArray Attributes.
882  * In contrast to datasets, subarray access, chunks and compression are not available.
883  */
884  template<unsigned int N, class T>
885  inline void writeAttribute(std::string object_name, std::string attribute_name, const MultiArrayView<N, T, UnstridedArrayTag> & array)
886  {
887  // make object_name clean
888  object_name = get_absolute_path(object_name);
889 
890  write_attribute_(object_name, attribute_name, array, detail::getH5DataType<T>(), 1);
891  }
892 
893  template<unsigned int N, class T, int SIZE>
894  inline void writeAttribute(std::string datasetName, std::string attributeName, const MultiArrayView<N, TinyVector<T, SIZE>, UnstridedArrayTag> & array)
895  {
896  // make datasetName clean
897  datasetName = get_absolute_path(datasetName);
898 
899  write_attribute_(datasetName, attributeName, array, detail::getH5DataType<T>(), SIZE);
900  }
901 
902  template<unsigned int N, class T>
903  inline void writeAttribute(std::string datasetName, std::string attributeName, const MultiArrayView<N, RGBValue<T>, UnstridedArrayTag> & array)
904  {
905  // make datasetName clean
906  datasetName = get_absolute_path(datasetName);
907 
908  write_attribute_(datasetName, attributeName, array, detail::getH5DataType<T>(), 3);
909  }
910 
911  /** \brief Write a single value.
912  Specialization of the write function for simple datatypes
913  */
914  inline void writeAttribute(std::string object_name, std::string attribute_name, char data)
915  { writeAtomicAttribute(object_name,attribute_name,data); }
916  inline void writeAttribute(std::string datasetName, std::string attributeName, signed char data)
917  { writeAtomicAttribute(datasetName,attributeName,data); }
918  inline void writeAttribute(std::string datasetName, std::string attributeName, signed short data)
919  { writeAtomicAttribute(datasetName,attributeName,data); }
920  inline void writeAttribute(std::string datasetName, std::string attributeName, signed int data)
921  { writeAtomicAttribute(datasetName,attributeName,data); }
922  inline void writeAttribute(std::string datasetName, std::string attributeName, signed long data)
923  { writeAtomicAttribute(datasetName,attributeName,data); }
924  inline void writeAttribute(std::string datasetName, std::string attributeName, signed long long data)
925  { writeAtomicAttribute(datasetName,attributeName,data); }
926  inline void writeAttribute(std::string datasetName, std::string attributeName, unsigned char data)
927  { writeAtomicAttribute(datasetName,attributeName,data); }
928  inline void writeAttribute(std::string datasetName, std::string attributeName, unsigned short data)
929  { writeAtomicAttribute(datasetName,attributeName,data); }
930  inline void writeAttribute(std::string datasetName, std::string attributeName, unsigned int data)
931  { writeAtomicAttribute(datasetName,attributeName,data); }
932  inline void writeAttribute(std::string datasetName, std::string attributeName, unsigned long data)
933  { writeAtomicAttribute(datasetName,attributeName,data); }
934  inline void writeAttribute(std::string datasetName, std::string attributeName, unsigned long long data)
935  { writeAtomicAttribute(datasetName,attributeName,data); }
936  inline void writeAttribute(std::string datasetName, std::string attributeName, float data)
937  { writeAtomicAttribute(datasetName,attributeName,data); }
938  inline void writeAttribute(std::string datasetName, std::string attributeName, double data)
939  { writeAtomicAttribute(datasetName,attributeName,data); }
940  inline void writeAttribute(std::string datasetName, std::string attributeName, long double data)
941  { writeAtomicAttribute(datasetName,attributeName,data); }
942  inline void writeAttribute(std::string datasetName, std::string attributeName, const char* data)
943  { writeAtomicAttribute(datasetName,attributeName,data); }
944  inline void writeAttribute(std::string datasetName, std::string attributeName, std::string const & data)
945  { writeAtomicAttribute(datasetName,attributeName,data.c_str()); }
946 
947  /** \brief Test if attribute exists.
948  */
949  bool existsAttribute(std::string object_name, std::string attribute_name)
950  {
951  std::string obj_path = get_absolute_path(object_name);
952  htri_t exists = H5Aexists_by_name(fileHandle_, obj_path.c_str(),
953  attribute_name.c_str(), H5P_DEFAULT);
954  vigra_precondition(exists >= 0, "HDF5File::existsAttribute(): "
955  "object '" + object_name + "' "
956  "not found.");
957  return exists != 0;
958  }
959 
960  // Reading Attributes
961 
962  /** \brief Read MultiArray Attributes.
963  * In contrast to datasets, subarray access is not available.
964  */
965  template<unsigned int N, class T>
966  inline void readAttribute(std::string object_name, std::string attribute_name, const MultiArrayView<N, T, UnstridedArrayTag> & array)
967  {
968  // make object_name clean
969  object_name = get_absolute_path(object_name);
970 
971  read_attribute_(object_name, attribute_name, array, detail::getH5DataType<T>(), 1);
972  }
973 
974  template<unsigned int N, class T, int SIZE>
975  inline void readAttribute(std::string datasetName, std::string attributeName, const MultiArrayView<N, TinyVector<T, SIZE>, UnstridedArrayTag> & array)
976  {
977  // make datasetName clean
978  datasetName = get_absolute_path(datasetName);
979 
980  read_attribute_(datasetName, attributeName, array, detail::getH5DataType<T>(), SIZE);
981  }
982 
983  template<unsigned int N, class T>
984  inline void readAttribute(std::string datasetName, std::string attributeName, const MultiArrayView<N, RGBValue<T>, UnstridedArrayTag> & array)
985  {
986  // make datasetName clean
987  datasetName = get_absolute_path(datasetName);
988 
989  read_attribute_(datasetName, attributeName, array, detail::getH5DataType<T>(), 3);
990  }
991 
992  /** \brief Read a single value.
993  Specialization of the read function for simple datatypes
994  */
995  inline void readAttribute(std::string object_name, std::string attribute_name, char &data)
996  { readAtomicAttribute(object_name,attribute_name,data); }
997  inline void readAttribute(std::string datasetName, std::string attributeName, signed char &data)
998  { readAtomicAttribute(datasetName,attributeName,data); }
999  inline void readAttribute(std::string datasetName, std::string attributeName, signed short &data)
1000  { readAtomicAttribute(datasetName,attributeName,data); }
1001  inline void readAttribute(std::string datasetName, std::string attributeName, signed int &data)
1002  { readAtomicAttribute(datasetName,attributeName,data); }
1003  inline void readAttribute(std::string datasetName, std::string attributeName, signed long &data)
1004  { readAtomicAttribute(datasetName,attributeName,data); }
1005  inline void readAttribute(std::string datasetName, std::string attributeName, signed long long &data)
1006  { readAtomicAttribute(datasetName,attributeName,data); }
1007  inline void readAttribute(std::string datasetName, std::string attributeName, unsigned char &data)
1008  { readAtomicAttribute(datasetName,attributeName,data); }
1009  inline void readAttribute(std::string datasetName, std::string attributeName, unsigned short &data)
1010  { readAtomicAttribute(datasetName,attributeName,data); }
1011  inline void readAttribute(std::string datasetName, std::string attributeName, unsigned int &data)
1012  { readAtomicAttribute(datasetName,attributeName,data); }
1013  inline void readAttribute(std::string datasetName, std::string attributeName, unsigned long &data)
1014  { readAtomicAttribute(datasetName,attributeName,data); }
1015  inline void readAttribute(std::string datasetName, std::string attributeName, unsigned long long &data)
1016  { readAtomicAttribute(datasetName,attributeName,data); }
1017  inline void readAttribute(std::string datasetName, std::string attributeName, float &data)
1018  { readAtomicAttribute(datasetName,attributeName,data); }
1019  inline void readAttribute(std::string datasetName, std::string attributeName, double &data)
1020  { readAtomicAttribute(datasetName,attributeName,data); }
1021  inline void readAttribute(std::string datasetName, std::string attributeName, long double &data)
1022  { readAtomicAttribute(datasetName,attributeName,data); }
1023  inline void readAttribute(std::string datasetName, std::string attributeName, std::string &data)
1024  { readAtomicAttribute(datasetName,attributeName,data); }
1025 
1026  // Writing data
1027 
1028  /** \brief Write multi arrays.
1029 
1030  Chunks can be activated by setting
1031  \code iChunkSize = size; //size > 0
1032  \endcode .
1033  The chunks will be hypercubes with edge length size.
1034 
1035  Compression can be activated by setting
1036  \code compression = parameter; // 0 < parameter <= 9
1037  \endcode
1038  where 0 stands for no compression and 9 for maximum compression.
1039 
1040  If the first character of datasetName is a "/", the path will be interpreted as absolute path,
1041  otherwise it will be interpreted as path relative to the current group.
1042 
1043  Note that the memory order between VIGRA and HDF5 files differs: VIGRA uses
1044  Fortran-order, while HDF5 uses C-order. This means that a VIGRA MultiArray,
1045  whose indices represent the 'x'-, 'y'-, and 'z'-axis in that order, is reversed
1046  upon writing to an HDF5 file, i.e. in the file the axis order is 'z', 'y', 'x'.
1047  */
1048  template<unsigned int N, class T>
1049  inline void write(std::string datasetName, const MultiArrayView<N, T, UnstridedArrayTag> & array, int iChunkSize = 0, int compression = 0)
1050  {
1051  // make datasetName clean
1052  datasetName = get_absolute_path(datasetName);
1053 
1054  typename MultiArrayShape<N>::type chunkSize;
1055  for(unsigned int i = 0; i < N; i++){
1056  chunkSize[i] = iChunkSize;
1057  }
1058  write_(datasetName, array, detail::getH5DataType<T>(), 1, chunkSize, compression);
1059  }
1060 
1061  /** \brief Write multi arrays.
1062  Chunks can be activated by providing a MultiArrayShape as chunkSize.
1063  chunkSize must have equal dimension as array.
1064 
1065  Compression can be activated by setting
1066  \code compression = parameter; // 0 < parameter <= 9
1067  \endcode
1068  where 0 stands for no compression and 9 for maximum compression.
1069 
1070  If the first character of datasetName is a "/", the path will be interpreted as absolute path,
1071  otherwise it will be interpreted as path relative to the current group.
1072 
1073  Note that the memory order between VIGRA and HDF5 files differs: VIGRA uses
1074  Fortran-order, while HDF5 uses C-order. This means that a VIGRA MultiArray,
1075  whose indices represent the 'x'-, 'y'-, and 'z'-axis in that order, is reversed
1076  upon writing to an HDF5 file, i.e. in the file the axis order is 'z', 'y', 'x'.
1077  */
1078  template<unsigned int N, class T>
1079  inline void write(std::string datasetName, const MultiArrayView<N, T, UnstridedArrayTag> & array, typename MultiArrayShape<N>::type chunkSize, int compression = 0)
1080  {
1081  // make datasetName clean
1082  datasetName = get_absolute_path(datasetName);
1083 
1084  write_(datasetName, array, detail::getH5DataType<T>(), 1, chunkSize, compression);
1085  }
1086 
1087  /** \brief Write a multi array into a larger volume.
1088  blockOffset determines the position, where array is written.
1089 
1090  Chunks can be activated by providing a MultiArrayShape as chunkSize.
1091  chunkSize must have equal dimension as array.
1092 
1093  Compression can be activated by setting
1094  \code compression = parameter; // 0 < parameter <= 9
1095  \endcode
1096  where 0 stands for no compression and 9 for maximum compression.
1097 
1098  If the first character of datasetName is a "/", the path will be interpreted as absolute path,
1099  otherwise it will be interpreted as path relative to the current group.
1100 
1101  Note that the memory order between VIGRA and HDF5 files differs: VIGRA uses
1102  Fortran-order, while HDF5 uses C-order. This means that a VIGRA MultiArray,
1103  whose indices represent the 'x'-, 'y'-, and 'z'-axis in that order, is reversed
1104  upon writing to an HDF5 file, i.e. in the file the axis order is 'z', 'y', 'x'.
1105  */
1106  template<unsigned int N, class T>
1107  inline void writeBlock(std::string datasetName, typename MultiArrayShape<N>::type blockOffset, const MultiArrayView<N, T, UnstridedArrayTag> & array)
1108  {
1109  // make datasetName clean
1110  datasetName = get_absolute_path(datasetName);
1111 
1112  writeBlock_(datasetName, blockOffset, array, detail::getH5DataType<T>(), 1);
1113  }
1114 
1115  // non-scalar (TinyVector) and unstrided multi arrays
1116  template<unsigned int N, class T, int SIZE>
1117  inline void write(std::string datasetName, const MultiArrayView<N, TinyVector<T, SIZE>, UnstridedArrayTag> & array, int iChunkSize = 0, int compression = 0)
1118  {
1119  // make datasetName clean
1120  datasetName = get_absolute_path(datasetName);
1121 
1122  typename MultiArrayShape<N>::type chunkSize;
1123  for(int i = 0; i < N; i++){
1124  chunkSize[i] = iChunkSize;
1125  }
1126  write_(datasetName, array, detail::getH5DataType<T>(), SIZE, chunkSize, compression);
1127  }
1128 
1129  template<unsigned int N, class T, int SIZE>
1130  inline void write(std::string datasetName, const MultiArrayView<N, TinyVector<T, SIZE>, UnstridedArrayTag> & array, typename MultiArrayShape<N>::type chunkSize, int compression = 0)
1131  {
1132  // make datasetName clean
1133  datasetName = get_absolute_path(datasetName);
1134 
1135  write_(datasetName, array, detail::getH5DataType<T>(), SIZE, chunkSize, compression);
1136  }
1137 
1138  /** \brief Write array vectors.
1139 
1140  Compression can be activated by setting
1141  \code compression = parameter; // 0 < parameter <= 9
1142  \endcode
1143  where 0 stands for no compression and 9 for maximum compression.
1144 
1145  If the first character of datasetName is a "/", the path will be interpreted as absolute path,
1146  otherwise it will be interpreted as path relative to the current group.
1147  */
1148  template<class T>
1149  void write(const std::string & datasetName,
1150  const ArrayVectorView<T> & array,
1151  int compression = 0)
1152  {
1153  // convert to a (trivial) MultiArrayView and forward.
1154  MultiArrayShape<1>::type shape(array.size());
1155  const MultiArrayView<1, T> m_array(shape, const_cast<T*>(array.data()));
1156  write(datasetName, m_array, compression);
1157  }
1158 
1159  template<unsigned int N, class T, int SIZE>
1160  inline void writeBlock(std::string datasetName, typename MultiArrayShape<N>::type blockOffset, const MultiArrayView<N, TinyVector<T, SIZE>, UnstridedArrayTag> & array)
1161  {
1162  // make datasetName clean
1163  datasetName = get_absolute_path(datasetName);
1164 
1165  writeBlock_(datasetName, blockOffset, array, detail::getH5DataType<T>(), SIZE);
1166  }
1167 
1168  // non-scalar (RGBValue) and unstrided multi arrays
1169  template<unsigned int N, class T>
1170  inline void write(std::string datasetName, const MultiArrayView<N, RGBValue<T>, UnstridedArrayTag> & array, int iChunkSize = 0, int compression = 0)
1171  {
1172  // make datasetName clean
1173  datasetName = get_absolute_path(datasetName);
1174 
1175  typename MultiArrayShape<N>::type chunkSize;
1176  for(int i = 0; i < N; i++){
1177  chunkSize[i] = iChunkSize;
1178  }
1179  write_(datasetName, array, detail::getH5DataType<T>(), 3, chunkSize, compression);
1180  }
1181 
1182  template<unsigned int N, class T>
1183  inline void write(std::string datasetName, const MultiArrayView<N, RGBValue<T>, UnstridedArrayTag> & array, typename MultiArrayShape<N>::type chunkSize, int compression = 0)
1184  {
1185  // make datasetName clean
1186  datasetName = get_absolute_path(datasetName);
1187 
1188  write_(datasetName, array, detail::getH5DataType<T>(), 3, chunkSize, compression);
1189  }
1190 
1191  template<unsigned int N, class T>
1192  inline void writeBlock(std::string datasetName, typename MultiArrayShape<N>::type blockOffset, const MultiArrayView<N, RGBValue<T>, UnstridedArrayTag> & array)
1193  {
1194  // make datasetName clean
1195  datasetName = get_absolute_path(datasetName);
1196 
1197  writeBlock_(datasetName, blockOffset, array, detail::getH5DataType<T>(), 3);
1198  }
1199 
1200  /** \brief Write a single value.
1201  Specialization of the write function for simple datatypes
1202  */
1203  inline void write(std::string datasetName, char data) { writeAtomic(datasetName,data); }
1204  inline void write(std::string datasetName, signed char data) { writeAtomic(datasetName,data); }
1205  inline void write(std::string datasetName, signed short data) { writeAtomic(datasetName,data); }
1206  inline void write(std::string datasetName, signed int data) { writeAtomic(datasetName,data); }
1207  inline void write(std::string datasetName, signed long data) { writeAtomic(datasetName,data); }
1208  inline void write(std::string datasetName, signed long long data) { writeAtomic(datasetName,data); }
1209  inline void write(std::string datasetName, unsigned char data) { writeAtomic(datasetName,data); }
1210  inline void write(std::string datasetName, unsigned short data) { writeAtomic(datasetName,data); }
1211  inline void write(std::string datasetName, unsigned int data) { writeAtomic(datasetName,data); }
1212  inline void write(std::string datasetName, unsigned long data) { writeAtomic(datasetName,data); }
1213  inline void write(std::string datasetName, unsigned long long data) { writeAtomic(datasetName,data); }
1214  inline void write(std::string datasetName, float data) { writeAtomic(datasetName,data); }
1215  inline void write(std::string datasetName, double data) { writeAtomic(datasetName,data); }
1216  inline void write(std::string datasetName, long double data) { writeAtomic(datasetName,data); }
1217  inline void write(std::string datasetName, const char* data) { writeAtomic(datasetName,data); }
1218  inline void write(std::string datasetName, std::string const & data) { writeAtomic(datasetName,data.c_str()); }
1219 
1220  // Reading data
1221 
1222  /** \brief Read data into a multi array.
1223  If the first character of datasetName is a "/", the path will be interpreted as absolute path,
1224  otherwise it will be interpreted as path relative to the current group.
1225 
1226  Note that the memory order between VIGRA and HDF5 files differs: VIGRA uses
1227  Fortran-order, while HDF5 uses C-order. This means that a HDF5 dataset,
1228  whose indices represent the 'z'-, 'y'-, and 'x'-axis in that order, is reversed
1229  upon reading into a MultiArrayView, i.e. in the array axis order must be 'x', 'y', 'z'.
1230  */
1231  template<unsigned int N, class T>
1232  inline void read(std::string datasetName, MultiArrayView<N, T, UnstridedArrayTag> & array)
1233  {
1234  // make datasetName clean
1235  datasetName = get_absolute_path(datasetName);
1236 
1237  read_(datasetName, array, detail::getH5DataType<T>(), 1);
1238  }
1239 
1240  /** \brief Read data into a MultiArray. Resize MultiArray to the correct size.
1241  If the first character of datasetName is a "/", the path will be interpreted as absolute path,
1242  otherwise it will be interpreted as path relative to the current group.
1243 
1244  Note that the memory order between VIGRA and HDF5 files differs: VIGRA uses
1245  Fortran-order, while HDF5 uses C-order. This means that a HDF5 dataset,
1246  whose indices represent the 'z'-, 'y'-, and 'x'-axis in that order, is reversed
1247  upon reading into a MultiArray, i.e. in the array axis order will be 'x', 'y', 'z'.
1248  */
1249  template<unsigned int N, class T>
1250  inline void readAndResize(std::string datasetName, MultiArray<N, T> & array)
1251  {
1252  // make datasetName clean
1253  datasetName = get_absolute_path(datasetName);
1254 
1255  // get dataset dimension
1256  ArrayVector<hsize_t> dimshape = getDatasetShape(datasetName);
1257 
1258  // check if dimensions are correct
1259  vigra_precondition(N == MultiArrayIndex(dimshape.size()), // the object in the HDF5 file may have one additional dimension which we then interpret as the pixel type bands
1260  "HDF5File::readAndResize(): Array dimension disagrees with dataset dimension.");
1261 
1262  // reshape target MultiArray
1263  typename MultiArrayShape<N>::type shape;
1264  for(int k=0; k < (int)dimshape.size(); ++k)
1265  shape[k] = (MultiArrayIndex)dimshape[k];
1266  array.reshape(shape);
1267 
1268  read_(datasetName, array, detail::getH5DataType<T>(), 1);
1269  }
1270 
1271  /** \brief Read data into an array vector.
1272  If the first character of datasetName is a "/", the path will be interpreted as absolute path,
1273  otherwise it will be interpreted as path relative to the current group.
1274  */
1275  template<class T>
1276  inline void read(const std::string & datasetName, ArrayVectorView<T> & array)
1277  {
1278  // convert to a (trivial) MultiArrayView and forward.
1279  MultiArrayShape<1>::type shape(array.size());
1280  MultiArrayView<1, T> m_array(shape, (array.data()));
1281  read(datasetName, m_array);
1282  }
1283 
1284  /** \brief Read data into an array vector. Resize the array vector to the correct size.
1285  If the first character of datasetName is a "/", the path will be interpreted as absolute path,
1286  otherwise it will be interpreted as path relative to the current group.
1287  */
1288  template<class T>
1289  inline void readAndResize(std::string datasetName,
1290  ArrayVector<T> & array)
1291  {
1292  // make dataset name clean
1293  datasetName = get_absolute_path(datasetName);
1294 
1295  // get dataset dimension
1296  ArrayVector<hsize_t> dimshape = getDatasetShape(datasetName);
1297 
1298  // check if dimensions are correct
1299  vigra_precondition(1 == MultiArrayIndex(dimshape.size()),
1300  "HDF5File::readAndResize(): Array dimension disagrees with Dataset dimension must equal one for vigra::ArrayVector.");
1301 
1302  // resize target array vector
1303  array.resize((typename ArrayVector<T>::size_type)dimshape[0]);
1304  // convert to a (trivial) MultiArrayView and forward.
1305  MultiArrayShape<1>::type shape(array.size());
1306  MultiArrayView<1, T> m_array(shape, (array.data()));
1307 
1308  read_(datasetName, m_array, detail::getH5DataType<T>(), 1);
1309  }
1310 
1311  /** \brief Read a block of data into a multi array.
1312  This function allows to read a small block out of a larger volume stored
1313  in an HDF5 dataset.
1314 
1315  blockOffset determines the position of the block.
1316  blockSize determines the size in each dimension of the block.
1317 
1318  If the first character of datasetName is a "/", the path will be interpreted as absolute path,
1319  otherwise it will be interpreted as path relative to the current group.
1320 
1321  Note that the memory order between VIGRA and HDF5 files differs: VIGRA uses
1322  Fortran-order, while HDF5 uses C-order. This means that a HDF5 dataset,
1323  whose indices represent the 'z'-, 'y'-, and 'x'-axis in that order, is reversed
1324  upon reading into a MultiArray, i.e. in the array axis order will be 'x', 'y', 'z'.
1325  */
1326  template<unsigned int N, class T>
1327  inline void readBlock(std::string datasetName, typename MultiArrayShape<N>::type blockOffset, typename MultiArrayShape<N>::type blockShape, MultiArrayView<N, T, UnstridedArrayTag> & array)
1328  {
1329  // make datasetName clean
1330  datasetName = get_absolute_path(datasetName);
1331 
1332  readBlock_(datasetName, blockOffset, blockShape, array, detail::getH5DataType<T>(), 1);
1333  }
1334 
1335  // non-scalar (TinyVector) and unstrided target MultiArrayView
1336  template<unsigned int N, class T, int SIZE>
1337  inline void read(std::string datasetName, MultiArrayView<N, TinyVector<T, SIZE>, UnstridedArrayTag> & array)
1338  {
1339  // make datasetName clean
1340  datasetName = get_absolute_path(datasetName);
1341 
1342  read_(datasetName, array, detail::getH5DataType<T>(), SIZE);
1343  }
1344 
1345  // non-scalar (TinyVector) MultiArray
1346  template<unsigned int N, class T, int SIZE>
1347  inline void readAndResize(std::string datasetName, MultiArray<N, TinyVector<T, SIZE> > & array)
1348  {
1349  // make datasetName clean
1350  datasetName = get_absolute_path(datasetName);
1351 
1352  // get dataset dimension
1353  ArrayVector<hsize_t> dimshape = getDatasetShape(datasetName);
1354 
1355  // check if dimensions are correct
1356  vigra_precondition((N+1) == MultiArrayIndex(dimshape.size()) &&
1357  SIZE == dimshape[0], // the object in the HDF5 file must have one additional dimension which we interpret as the pixel type bands
1358  "HDF5File::readAndResize(): Array dimension disagrees with dataset dimension.");
1359 
1360  // reshape target MultiArray
1361  typename MultiArrayShape<N>::type shape;
1362  for(int k=1; k < (int)dimshape.size(); ++k)
1363  shape[k-1] = (MultiArrayIndex)dimshape[k];
1364  array.reshape(shape);
1365 
1366  read_(datasetName, array, detail::getH5DataType<T>(), SIZE);
1367  }
1368 
1369  template<unsigned int N, class T, int SIZE>
1370  inline void readBlock(std::string datasetName, typename MultiArrayShape<N>::type blockOffset, typename MultiArrayShape<N>::type blockShape, MultiArrayView<N, TinyVector<T, SIZE>, UnstridedArrayTag> & array)
1371  {
1372  // make datasetName clean
1373  datasetName = get_absolute_path(datasetName);
1374 
1375  readBlock_(datasetName, blockOffset, blockShape, array, detail::getH5DataType<T>(), SIZE);
1376  }
1377 
1378  // non-scalar (RGBValue) and unstrided target MultiArrayView
1379  template<unsigned int N, class T>
1380  inline void read(std::string datasetName, MultiArrayView<N, RGBValue<T>, UnstridedArrayTag> & array)
1381  {
1382  // make datasetName clean
1383  datasetName = get_absolute_path(datasetName);
1384 
1385  read_(datasetName, array, detail::getH5DataType<T>(), 3);
1386  }
1387 
1388  // non-scalar (RGBValue) MultiArray
1389  template<unsigned int N, class T>
1390  inline void readAndResize(std::string datasetName, MultiArray<N, RGBValue<T> > & array)
1391  {
1392  // make datasetName clean
1393  datasetName = get_absolute_path(datasetName);
1394 
1395  // get dataset dimension
1396  ArrayVector<hsize_t> dimshape = getDatasetShape(datasetName);
1397 
1398  // check if dimensions are correct
1399  vigra_precondition((N+1) == MultiArrayIndex(dimshape.size()) &&
1400  3 == dimshape[0], // the object in the HDF5 file must have one additional dimension which we interpret as the pixel type bands
1401  "HDF5File::readAndResize(): Array dimension disagrees with dataset dimension.");
1402 
1403  // reshape target MultiArray
1404  typename MultiArrayShape<N>::type shape;
1405  for(int k=1; k < (int)dimshape.size(); ++k)
1406  shape[k-1] = (MultiArrayIndex)dimshape[k];
1407  array.reshape(shape);
1408 
1409  read_(datasetName, array, detail::getH5DataType<T>(), 3);
1410  }
1411 
1412  template<unsigned int N, class T>
1413  inline void readBlock(std::string datasetName, typename MultiArrayShape<N>::type blockOffset, typename MultiArrayShape<N>::type blockShape, MultiArrayView<N, RGBValue<T>, UnstridedArrayTag> & array)
1414  {
1415  // make datasetName clean
1416  datasetName = get_absolute_path(datasetName);
1417 
1418  readBlock_(datasetName, blockOffset, blockShape, array, detail::getH5DataType<T>(), 3);
1419  }
1420 
1421  /** \brief Read a single value.
1422  Specialization of the read function for simple datatypes
1423  */
1424  inline void read(std::string datasetName, char &data) { readAtomic(datasetName,data); }
1425  inline void read(std::string datasetName, signed char &data) { readAtomic(datasetName,data); }
1426  inline void read(std::string datasetName, signed short &data) { readAtomic(datasetName,data); }
1427  inline void read(std::string datasetName, signed int &data) { readAtomic(datasetName,data); }
1428  inline void read(std::string datasetName, signed long &data) { readAtomic(datasetName,data); }
1429  inline void read(std::string datasetName, signed long long &data) { readAtomic(datasetName,data); }
1430  inline void read(std::string datasetName, unsigned char &data) { readAtomic(datasetName,data); }
1431  inline void read(std::string datasetName, unsigned short &data) { readAtomic(datasetName,data); }
1432  inline void read(std::string datasetName, unsigned int &data) { readAtomic(datasetName,data); }
1433  inline void read(std::string datasetName, unsigned long &data) { readAtomic(datasetName,data); }
1434  inline void read(std::string datasetName, unsigned long long &data) { readAtomic(datasetName,data); }
1435  inline void read(std::string datasetName, float &data) { readAtomic(datasetName,data); }
1436  inline void read(std::string datasetName, double &data) { readAtomic(datasetName,data); }
1437  inline void read(std::string datasetName, long double &data) { readAtomic(datasetName,data); }
1438  inline void read(std::string datasetName, std::string &data) { readAtomic(datasetName,data); }
1439 
1440  /** \brief Create a new dataset.
1441  This function can be used to create a dataset filled with a default value,
1442  for example before writing data into it using \ref writeBlock().
1443  Attention: only atomic datatypes are provided. For spectral data, add an
1444  dimension (case RGB: add one dimension of size 3).
1445 
1446  shape determines the dimension and the size of the dataset.
1447 
1448  Chunks can be activated by providing a MultiArrayShape as chunkSize.
1449  chunkSize must have equal dimension as array.
1450 
1451  Compression can be activated by setting
1452  \code compression = parameter; // 0 < parameter <= 9
1453  \endcode
1454  where 0 stands for no compression and 9 for maximum compression.
1455 
1456  If the first character of datasetName is a "/", the path will be interpreted as absolute path,
1457  otherwise it will be interpreted as path relative to the current group.
1458 
1459  Note that the memory order between VIGRA and HDF5 files differs: VIGRA uses
1460  Fortran-order, while HDF5 uses C-order. This means that a VIGRA MultiArray,
1461  whose indices represent the 'x'-, 'y'-, and 'z'-axis in that order, is reversed
1462  upon writing to an HDF5 file, i.e. in the file the axis order is 'z', 'y', 'x'.
1463  */
1464  template<unsigned int N, class T>
1465  inline void createDataset(std::string datasetName,
1466  typename MultiArrayShape<N>::type shape,
1467  T init = T(),
1468  int iChunkSize = 0,
1469  int compressionParameter = 0)
1470  {
1471  // make datasetName clean
1472  datasetName = get_absolute_path(datasetName);
1473 
1474  typename MultiArrayShape<N>::type chunkSize;
1475  for(int i = 0; i < N; i++){
1476  chunkSize[i] = iChunkSize;
1477  }
1478  createDataset<N,T>(datasetName, shape, init, chunkSize, compressionParameter);
1479  }
1480 
1481  template<unsigned int N, class T>
1482  inline void createDataset(std::string datasetName,
1483  typename MultiArrayShape<N>::type shape,
1484  T init,
1485  typename MultiArrayShape<N>::type chunkSize,
1486  int compressionParameter = 0)
1487  {
1488  // make datasetName clean
1489  datasetName = get_absolute_path(datasetName);
1490 
1491  std::string groupname = SplitString(datasetName).first();
1492  std::string setname = SplitString(datasetName).last();
1493 
1494  hid_t parent = openCreateGroup_(groupname);
1495 
1496  // delete the dataset if it already exists
1497  deleteDataset_(parent, setname);
1498 
1499  // create dataspace
1500  // add an extra dimension in case that the data is non-scalar
1501  HDF5Handle dataspaceHandle;
1502 
1503  // invert dimensions to guarantee c-order
1504  hsize_t shape_inv[N];
1505  for(unsigned int k=0; k<N; ++k)
1506  shape_inv[N-1-k] = shape[k];
1507 
1508  // create dataspace
1509  dataspaceHandle = HDF5Handle(H5Screate_simple(N, shape_inv, NULL),
1510  &H5Sclose, "HDF5File::createDataset(): unable to create dataspace for scalar data.");
1511 
1512  // set fill value
1513  HDF5Handle plist ( H5Pcreate(H5P_DATASET_CREATE), &H5Pclose, "HDF5File::createDataset(): unable to create property list." );
1514  H5Pset_fill_value(plist,detail::getH5DataType<T>(), &init);
1515 
1516  // turn off time tagging of datasets by default.
1517  H5Pset_obj_track_times(plist, track_time);
1518 
1519  // enable chunks
1520  if(chunkSize[0] > 0)
1521  {
1522  hsize_t cSize [N];
1523  for(int i = 0; i<N; i++)
1524  {
1525  cSize[i] = chunkSize[N-1-i];
1526  }
1527  H5Pset_chunk (plist, N, cSize);
1528  }
1529 
1530  // enable compression
1531  if(compressionParameter > 0)
1532  {
1533  H5Pset_deflate(plist, compressionParameter);
1534  }
1535 
1536  //create the dataset.
1537  HDF5Handle datasetHandle ( H5Dcreate(parent, setname.c_str(), detail::getH5DataType<T>(), dataspaceHandle, H5P_DEFAULT, plist, H5P_DEFAULT),
1538  &H5Dclose, "HDF5File::createDataset(): unable to create dataset.");
1539  if(parent != cGroupHandle_)
1540  H5Gclose(parent);
1541  }
1542 
1543  /** \brief Immediately write all data to disk
1544  */
1545  inline void flushToDisk()
1546  {
1547  H5Fflush(fileHandle_, H5F_SCOPE_GLOBAL);
1548  }
1549 
1550  private:
1551 
1552  /* Simple extension of std::string for splitting into two parts
1553  *
1554  * Strings (in particular: file/dataset paths) will be split into two
1555  * parts. The split is made at the last occurrence of the delimiter.
1556  *
1557  * For example, "/path/to/some/file" will be split (delimiter = "/") into
1558  * first() = "/path/to/some" and last() = "file".
1559  */
1560  class SplitString: public std::string {
1561  public:
1562  SplitString(std::string &sstring): std::string(sstring) {};
1563 
1564  // return the part of the string before the delimiter
1565  std::string first(char delimiter = '/')
1566  {
1567  size_t last = find_last_of(delimiter);
1568  if(last == std::string::npos) // delimiter not found --> no first
1569  return "";
1570 
1571  return std::string(begin(), begin()+last+1);
1572  }
1573 
1574  // return the part of the string after the delimiter
1575  std::string last(char delimiter = '/')
1576  {
1577  size_t last = find_last_of(delimiter);
1578  if(last == std::string::npos) // delimiter not found --> only last
1579  return std::string(*this);
1580  return std::string(begin()+last+1, end());
1581  }
1582  };
1583 
1584  public:
1585 
1586  /** \brief takes any path and converts it into an absolute path
1587  in the current file.
1588 
1589  Elements like "." and ".." are treated as expected.
1590  Links are not supported or resolved.
1591  */
1592  inline std::string get_absolute_path(std::string path) const {
1593  // check for empty input or "." and return the current folder
1594  if(path.length() == 0 || path == "."){
1595  return currentGroupName_();
1596  }
1597 
1598  std::string str;
1599  // convert to absolute path
1600  if(relativePath_(path)){
1601  std::string cname = currentGroupName_();
1602  if (cname == "/")
1603  str = currentGroupName_()+path;
1604  else
1605  str = currentGroupName_()+"/"+path;
1606  }else{
1607  str = path;
1608  }
1609 
1610  // cut out "./"
1611  std::string::size_type startpos = 0;
1612  while(str.find(std::string("./"), startpos) != std::string::npos){
1613  std::string::size_type pos = str.find(std::string("./"), startpos);
1614  startpos = pos+1;
1615  // only cut if "./" is not part of "../" (see below)
1616  if(str.substr(pos-1,3) != "../"){
1617  // cut out part of the string
1618  str = str.substr(0,pos) + str.substr(pos+2,str.length()-pos-2);
1619  startpos = pos;
1620  }
1621  }
1622 
1623  // cut out pairs of "bla/../"
1624  while(str.find(std::string("..")) != std::string::npos){
1625  std::string::size_type pos = str.find(std::string(".."));
1626 
1627  // find first slash after ".."
1628  std::string::size_type end = str.find("/",pos);
1629  if(end != std::string::npos){
1630  // also include slash
1631  end++;
1632  }else{
1633  // no "/" after ".." --> this is a group, add a "/"
1634  str = str + "/";
1635  end = str.length();
1636  }
1637 
1638  // find first slash before ".."
1639  std::string::size_type prev_slash = str.rfind("/",pos);
1640  // if the root slash is the first before ".." --> Error
1641  vigra_invariant(prev_slash != 0 && prev_slash != std::string::npos,
1642  "Error parsing path: "+str);
1643  // find second slash before ".."
1644  std::string::size_type begin = str.rfind("/",prev_slash-1);
1645 
1646  // cut out part of the string
1647  str = str.substr(0,begin+1) + str.substr(end,str.length()-end);
1648  }
1649 
1650  return str;
1651  }
1652 
1653  protected:
1654 
1655  /* checks if the given path is a relative path.
1656  */
1657  inline bool relativePath_(std::string & path) const
1658  {
1659  std::string::size_type pos = path.find('/') ;
1660  if(pos == 0)
1661  return false;
1662 
1663  return true;
1664  }
1665 
1666  /* return the name of the current group
1667  */
1668  inline std::string currentGroupName_() const
1669  {
1670  int len = H5Iget_name(cGroupHandle_,NULL,1000);
1671  ArrayVector<char> name (len+1,0);
1672  H5Iget_name(cGroupHandle_,name.begin(),len+1);
1673 
1674  return std::string(name.begin());
1675  }
1676 
1677  /* return the name of the current file
1678  */
1679  inline std::string fileName_() const
1680  {
1681  int len = H5Fget_name(fileHandle_,NULL,1000);
1682  ArrayVector<char> name (len+1,0);
1683  H5Fget_name(fileHandle_,name.begin(),len+1);
1684 
1685  return std::string(name.begin());
1686  }
1687 
1688  /* create an empty file and open is
1689  */
1690  inline hid_t createFile_(std::string filePath, OpenMode mode = Open)
1691  {
1692  // try to open file
1693  FILE * pFile;
1694  pFile = fopen ( filePath.c_str(), "r" );
1695  hid_t fileId;
1696 
1697  // check if opening was successful (= file exists)
1698  if ( pFile == NULL )
1699  {
1700  fileId = H5Fcreate(filePath.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
1701  }
1702  else if(mode == Open)
1703  {
1704  fclose( pFile );
1705  fileId = H5Fopen(filePath.c_str(), H5F_ACC_RDWR, H5P_DEFAULT);
1706  }
1707  else if(mode == OpenReadOnly) {
1708  fclose( pFile );
1709  fileId = H5Fopen(filePath.c_str(), H5F_ACC_RDONLY, H5P_DEFAULT);
1710  }
1711  else
1712  {
1713  fclose(pFile);
1714  std::remove(filePath.c_str());
1715  fileId = H5Fcreate(filePath.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
1716  }
1717  return fileId;
1718  }
1719 
1720  /* open a group and subgroups. Create if necessary.
1721  */
1722  inline hid_t openCreateGroup_(std::string groupName)
1723  {
1724  // make groupName clean
1725  groupName = get_absolute_path(groupName);
1726 
1727  // open root group
1728  hid_t parent = H5Gopen(fileHandle_, "/", H5P_DEFAULT);
1729  if(groupName == "/")
1730  {
1731  return parent;
1732  }
1733 
1734  // remove leading /
1735  groupName = std::string(groupName.begin()+1, groupName.end());
1736 
1737  // check if the groupName has finishing slash
1738  if( groupName.size() != 0 && *groupName.rbegin() != '/')
1739  {
1740  groupName = groupName + '/';
1741  }
1742 
1743  // open or create subgroups one by one
1744  std::string::size_type begin = 0, end = groupName.find('/');
1745  while (end != std::string::npos)
1746  {
1747  std::string group(groupName.begin()+begin, groupName.begin()+end);
1748  hid_t prevParent = parent;
1749 
1750  if(H5LTfind_dataset(parent, group.c_str()) == 0)
1751  {
1752  parent = H5Gcreate(prevParent, group.c_str(), H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
1753  } else {
1754  parent = H5Gopen(prevParent, group.c_str(), H5P_DEFAULT);
1755  }
1756  H5Gclose(prevParent);
1757 
1758  if(parent < 0)
1759  {
1760  return parent;
1761  }
1762  begin = end + 1;
1763  end = groupName.find('/', begin);
1764  }
1765 
1766  return parent;
1767  }
1768 
1769  /* delete a dataset by unlinking it from the file structure. This does not
1770  delete the data!
1771  */
1772  inline void deleteDataset_(hid_t parent, std::string datasetName)
1773  {
1774  // delete existing data and create new dataset
1775  if(H5LTfind_dataset(parent, datasetName.c_str()))
1776  {
1777 
1778  #if (H5_VERS_MAJOR == 1 && H5_VERS_MINOR <= 6)
1779  if(H5Gunlink(parent, datasetName.c_str()) < 0)
1780  {
1781  vigra_postcondition(false, "HDF5File::deleteDataset_(): Unable to delete existing data.");
1782  }
1783  #else
1784  if(H5Ldelete(parent, datasetName.c_str(), H5P_DEFAULT ) < 0)
1785  {
1786  vigra_postcondition(false, "HDF5File::deleteDataset_(): Unable to delete existing data.");
1787  }
1788  #endif
1789  }
1790  }
1791 
1792  /* get the handle of a dataset specified by a string
1793  */
1794  inline hid_t getDatasetHandle_(std::string datasetName)
1795  {
1796  // make datasetName clean
1797  datasetName = get_absolute_path(datasetName);
1798 
1799  std::string groupname = SplitString(datasetName).first();
1800  std::string setname = SplitString(datasetName).last();
1801 
1802  if(H5Lexists(fileHandle_, datasetName.c_str(), H5P_DEFAULT) <= 0)
1803  {
1804  std::cerr << "HDF5File::getDatasetHandle_(): Dataset '" << datasetName << "' does not exist.\n";
1805  return -1;
1806  }
1807 
1808  // Open parent group
1809  HDF5Handle groupHandle(openCreateGroup_(groupname), &H5Gclose, "Internal error");
1810 
1811  return H5Dopen(groupHandle, setname.c_str(), H5P_DEFAULT);
1812  }
1813 
1814  /* get the type of an object specified by a string
1815  */
1816  H5O_type_t get_object_type_(std::string name)
1817  {
1818  name = get_absolute_path(name);
1819  std::string group_name = SplitString(name).first();
1820  std::string object_name = SplitString(name).last();
1821  if (!object_name.size())
1822  return H5O_TYPE_GROUP;
1823 
1824  htri_t exists = H5Lexists(fileHandle_, name.c_str(), H5P_DEFAULT);
1825  vigra_precondition(exists > 0, "HDF5File::get_object_type_(): "
1826  "object \"" + name + "\" "
1827  "not found.");
1828  // open parent group
1829  HDF5Handle group_handle(openCreateGroup_(group_name), &H5Gclose, "Internal error");
1830  return HDF5_get_type(group_handle, name.c_str());
1831  }
1832 
1833  /* low-level write function to write vigra MultiArray data as an attribute
1834  */
1835  template<unsigned int N, class T>
1836  void write_attribute_(std::string name, const std::string & attribute_name,
1837  const MultiArrayView<N, T, UnstridedArrayTag> & array,
1838  const hid_t datatype,
1839  const int numBandsOfType)
1840  {
1841  // shape of the array. Add one dimension, if array contains non-scalars.
1842  ArrayVector<hsize_t> shape(array.shape().begin(), array.shape().end());
1843  std::reverse(shape.begin(), shape.end());
1844  if(numBandsOfType > 1)
1845  shape.push_back(numBandsOfType);
1846 
1847  HDF5Handle dataspace(H5Screate_simple(shape.size(),
1848  shape.begin(), NULL),
1849  &H5Sclose, "HDF5File::writeAttribute(): Can not"
1850  " create dataspace.");
1851 
1852  std::string errorMessage ("HDF5File::writeAttribute(): can not find "
1853  "object '" + name + "'.");
1854 
1855  H5O_type_t h5_type = get_object_type_(name);
1856  bool is_group = h5_type == H5O_TYPE_GROUP;
1857  if (!is_group && h5_type != H5O_TYPE_DATASET)
1858  vigra_precondition(0, "HDF5File::writeAttribute(): object \""
1859  + name + "\" is neither a group nor a "
1860  "dataset.");
1861  // get parent object handle
1862  HDF5Handle object_handle(is_group
1863  ? openCreateGroup_(name)
1864  : getDatasetHandle_(name),
1865  is_group
1866  ? &H5Gclose
1867  : &H5Dclose,
1868  errorMessage.c_str());
1869  // create / open attribute
1870  bool exists = existsAttribute(name, attribute_name);
1871  HDF5Handle attributeHandle(exists
1872  ? H5Aopen(object_handle,
1873  attribute_name.c_str(),
1874  H5P_DEFAULT)
1875  : H5Acreate(object_handle,
1876  attribute_name.c_str(), datatype,
1877  dataspace, H5P_DEFAULT,
1878  H5P_DEFAULT),
1879  &H5Aclose,
1880  "HDF5File::writeAttribute(): Can not create"
1881  " attribute.");
1882 
1883  // Write the data to the HDF5 object
1884  H5Awrite(attributeHandle, datatype, array.data());
1885  }
1886 
1887  /* Write single value attribute
1888  This function allows to write data of atomic datatypes (int, long, double)
1889  as an attribute in the HDF5 file. So it is not necessary to create a MultiArray
1890  of size 1 to write a single number.
1891  */
1892  template<class T>
1893  inline void writeAtomicAttribute(std::string datasetName, std::string attributeName, const T data)
1894  {
1895  // make datasetName clean
1896  datasetName = get_absolute_path(datasetName);
1897 
1898  typename MultiArrayShape<1>::type chunkSize;
1899  chunkSize[0] = 0;
1900  MultiArray<1,T> array(MultiArrayShape<1>::type(1));
1901  array[0] = data;
1902  write_attribute_(datasetName, attributeName, array, detail::getH5DataType<T>(), 1);
1903  }
1904 
1905  /* low-level read function to write vigra MultiArray data from attributes
1906  */
1907  template<unsigned int N, class T>
1908  inline void read_attribute_(std::string datasetName, std::string attributeName, MultiArrayView<N, T, UnstridedArrayTag> array, const hid_t datatype, const int numBandsOfType)
1909  {
1910  std::string dataset_path = get_absolute_path(datasetName);
1911  // open Attribute handle
1912  std::string message = "Error: could not get handle for attribute '"+attributeName+"'' of object '"+dataset_path+"'.";
1913  HDF5Handle attr_handle (H5Aopen_by_name(fileHandle_,dataset_path.c_str(),attributeName.c_str(),H5P_DEFAULT,H5P_DEFAULT),&H5Aclose, message.c_str());
1914 
1915  // get Attribute dataspace
1916  message = "Error: could not get dataspace for attribute '"+attributeName+"'' of object '"+dataset_path+"'.";
1917  HDF5Handle attr_dataspace_handle (H5Aget_space(attr_handle),&H5Sclose,message.c_str());
1918 
1919  // obtain Attribute shape
1920  int dims = H5Sget_simple_extent_ndims(attr_dataspace_handle);
1921  ArrayVector<hsize_t> dimshape(dims);
1922  H5Sget_simple_extent_dims(attr_dataspace_handle, dimshape.data(), NULL);
1923 
1924  // invert the dimensions to guarantee VIGRA-compatible order
1925  std::reverse(dimshape.begin(), dimshape.end());
1926 
1927  int offset = (numBandsOfType > 1)
1928  ? 1
1929  : 0;
1930  message = "Error: Array dimension disagrees with dataset dimension.";
1931  // the object in the HDF5 file may have one additional dimension which we then interpret as the pixel type bands
1932  vigra_precondition((N + offset) == MultiArrayIndex(dims), message);
1933 
1934  typename MultiArrayShape<N>::type shape;
1935  for(int k=offset; k < (int)dimshape.size(); ++k)
1936  shape[k-offset] = (MultiArrayIndex)dimshape[k];
1937 
1938  message = "Error: Array shape disagrees with dataset shape";
1939  vigra_precondition(shape == array.shape(), message);
1940 
1941  // simply read in the data as is
1942  H5Aread( attr_handle, datatype, array.data());
1943  }
1944 
1945  /* Read a single value attribute.
1946  This functions allows to read a single value attribute of atomic datatype (int, long, double)
1947  from the HDF5 file. So it is not necessary to create a MultiArray
1948  of size 1 to read a single number.
1949  */
1950  template<class T>
1951  inline void readAtomicAttribute(std::string datasetName, std::string attributeName, T & data)
1952  {
1953  // make datasetName clean
1954  datasetName = get_absolute_path(datasetName);
1955 
1956  MultiArray<1,T> array(MultiArrayShape<1>::type(1));
1957  read_attribute_(datasetName, attributeName, array, detail::getH5DataType<T>(), 1);
1958  data = array[0];
1959  }
1960 
1961  inline void readAtomicAttribute(std::string datasetName, std::string attributeName, std::string & data)
1962  {
1963  // make datasetName clean
1964  datasetName = get_absolute_path(datasetName);
1965 
1966  MultiArray<1,const char *> array(MultiArrayShape<1>::type(1));
1967  read_attribute_(datasetName, attributeName, array, detail::getH5DataType<const char *>(), 1);
1968  data = std::string(array[0]);
1969  }
1970 
1971  /* low-level write function to write vigra unstrided MultiArray data
1972  */
1973  template<unsigned int N, class T>
1974  inline void write_(std::string &datasetName,
1975  const MultiArrayView<N, T, UnstridedArrayTag> & array,
1976  const hid_t datatype,
1977  const int numBandsOfType,
1978  typename MultiArrayShape<N>::type &chunkSize,
1979  int compressionParameter = 0)
1980  {
1981  std::string groupname = SplitString(datasetName).first();
1982  std::string setname = SplitString(datasetName).last();
1983 
1984  // shape of the array. Add one dimension, if array contains non-scalars.
1985  ArrayVector<hsize_t> shape(array.shape().begin(), array.shape().end());
1986  std::reverse(shape.begin(), shape.end());
1987 
1988  if(numBandsOfType > 1)
1989  shape.push_back(numBandsOfType);
1990 
1991  HDF5Handle dataspace(H5Screate_simple(shape.size(), shape.begin(), NULL), &H5Sclose,
1992  "HDF5File::write(): Can not create dataspace.");
1993 
1994  // create and open group:
1995  std::string errorMessage ("HDF5File::write(): can not create group '" + groupname + "'.");
1996  HDF5Handle groupHandle(openCreateGroup_(groupname), &H5Gclose, errorMessage.c_str());
1997 
1998  // delete dataset, if it already exists
1999  deleteDataset_(groupHandle, setname.c_str());
2000 
2001  // set up properties list
2002  HDF5Handle plist(H5Pcreate(H5P_DATASET_CREATE), &H5Pclose,
2003  "HDF5File::write(): unable to create property list." );
2004 
2005  // turn off time tagging of datasets by default.
2006  H5Pset_obj_track_times(plist, track_time);
2007 
2008  // enable chunks
2009  if(chunkSize[0] > 0)
2010  {
2011  ArrayVector<hsize_t> cSize(chunkSize.begin(), chunkSize.end());
2012  std::reverse(cSize.begin(), cSize.end());
2013  if(numBandsOfType > 1)
2014  cSize.push_back(numBandsOfType);
2015 
2016  H5Pset_chunk (plist, cSize.size(), cSize.begin());
2017  }
2018 
2019  // enable compression
2020  if(compressionParameter > 0)
2021  {
2022  H5Pset_deflate(plist, compressionParameter);
2023  }
2024 
2025  // create dataset
2026  HDF5Handle datasetHandle(H5Dcreate(groupHandle, setname.c_str(), datatype, dataspace,H5P_DEFAULT, plist, H5P_DEFAULT),
2027  &H5Dclose, "HDF5File::write(): Can not create dataset.");
2028 
2029  // Write the data to the HDF5 dataset as is
2030  herr_t write_status = H5Dwrite(datasetHandle, datatype, H5S_ALL,
2031  H5S_ALL, H5P_DEFAULT, array.data());
2032  vigra_precondition(write_status >= 0, "HDF5File::write_(): write to "
2033  "dataset \"" + datasetName + "\" "
2034  "failed.");
2035  }
2036 
2037  /* Write single value as dataset.
2038  This functions allows to write data of atomic datatypes (int, long, double)
2039  as a dataset in the HDF5 file. So it is not necessary to create a MultiArray
2040  of size 1 to write a single number.
2041 
2042  If the first character of datasetName is a "/", the path will be interpreted as absolute path,
2043  otherwise it will be interpreted as path relative to the current group.
2044  */
2045  template<class T>
2046  inline void writeAtomic(std::string datasetName, const T data)
2047  {
2048  // make datasetName clean
2049  datasetName = get_absolute_path(datasetName);
2050 
2051  typename MultiArrayShape<1>::type chunkSize;
2052  chunkSize[0] = 0;
2053  MultiArray<1,T> array(MultiArrayShape<1>::type(1));
2054  array[0] = data;
2055  write_(datasetName, array, detail::getH5DataType<T>(), 1, chunkSize,0);
2056  }
2057 
2058  /* low-level read function to read vigra unstrided MultiArray data
2059  */
2060  template<unsigned int N, class T>
2061  inline void read_(std::string datasetName,
2062  MultiArrayView<N, T, UnstridedArrayTag> array,
2063  const hid_t datatype, const int numBandsOfType)
2064  {
2065  //Prepare to read without using HDF5ImportInfo
2066  ArrayVector<hsize_t> dimshape = getDatasetShape(datasetName);
2067 
2068  std::string errorMessage ("HDF5File::read(): Unable to open dataset '" + datasetName + "'.");
2069  HDF5Handle datasetHandle(getDatasetHandle_(datasetName), &H5Dclose, errorMessage.c_str());
2070 
2071  int offset = (numBandsOfType > 1)
2072  ? 1
2073  : 0;
2074 
2075  vigra_precondition((N + offset ) == MultiArrayIndex(dimshape.size()), // the object in the HDF5 file may have one additional dimension which we then interpret as the pixel type bands
2076  "HDF5File::read(): Array dimension disagrees with dataset dimension.");
2077 
2078  typename MultiArrayShape<N>::type shape;
2079  for(int k=offset; k < (int)dimshape.size(); ++k)
2080  shape[k-offset] = (MultiArrayIndex)dimshape[k];
2081 
2082  vigra_precondition(shape == array.shape(),
2083  "HDF5File::read(): Array shape disagrees with dataset shape.");
2084  if (offset)
2085  vigra_precondition(dimshape[0] == static_cast<hsize_t>(numBandsOfType),
2086  "HDF5File::read(): Band count doesn't match destination array compound type.");
2087 
2088  // simply read in the data as is
2089  H5Dread( datasetHandle, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, array.data() ); // .data() possible since void pointer!
2090  }
2091 
2092  /* Read a single value.
2093  This functions allows to read a single datum of atomic datatype (int, long, double)
2094  from the HDF5 file. So it is not necessary to create a MultiArray
2095  of size 1 to read a single number.
2096 
2097  If the first character of datasetName is a "/", the path will be interpreted as absolute path,
2098  otherwise it will be interpreted as path relative to the current group.
2099  */
2100  template<class T>
2101  inline void readAtomic(std::string datasetName, T & data)
2102  {
2103  // make datasetName clean
2104  datasetName = get_absolute_path(datasetName);
2105 
2106  MultiArray<1,T> array(MultiArrayShape<1>::type(1));
2107  read_(datasetName, array, detail::getH5DataType<T>(), 1);
2108  data = array[0];
2109  }
2110 
2111  inline void readAtomic(std::string datasetName, std::string & data)
2112  {
2113  // make datasetName clean
2114  datasetName = get_absolute_path(datasetName);
2115 
2116  MultiArray<1,const char *> array(MultiArrayShape<1>::type(1));
2117  read_(datasetName, array, detail::getH5DataType<const char *>(), 1);
2118  data = std::string(array[0]);
2119  }
2120 
2121  /* low-level write function to write vigra unstrided MultiArray data into a sub-block of a dataset
2122  */
2123  template<unsigned int N, class T>
2124  inline void writeBlock_(std::string datasetName, typename MultiArrayShape<N>::type &blockOffset, const MultiArrayView<N, T, UnstridedArrayTag> & array, const hid_t datatype, const int numBandsOfType)
2125  {
2126  // open dataset if it exists
2127  std::string errorMessage = "HDF5File::writeBlock(): Error opening dataset '" + datasetName + "'.";
2128  HDF5Handle datasetHandle (getDatasetHandle_(datasetName), &H5Dclose, errorMessage.c_str());
2129 
2130  // hyperslab parameters for position, size, ...
2131  hsize_t boffset [N];
2132  hsize_t bshape [N];
2133  hsize_t bones [N];
2134 
2135  for(int i = 0; i < N; i++){
2136  boffset[i] = blockOffset[N-1-i];
2137  bshape[i] = array.size(N-1-i);
2138  bones[i] = 1;
2139  }
2140 
2141  // create a target dataspace in memory with the shape of the desired block
2142  HDF5Handle memspace_handle (H5Screate_simple(N,bshape,NULL),&H5Sclose,"Unable to get origin dataspace");
2143 
2144  // get file dataspace and select the desired block
2145  HDF5Handle dataspaceHandle (H5Dget_space(datasetHandle),&H5Sclose,"Unable to create target dataspace");
2146  H5Sselect_hyperslab(dataspaceHandle, H5S_SELECT_SET, boffset, bones, bones, bshape);
2147 
2148  // Write the data to the HDF5 dataset as is
2149  H5Dwrite( datasetHandle, datatype, memspace_handle, dataspaceHandle, H5P_DEFAULT, array.data()); // .data() possible since void pointer!
2150  }
2151 
2152  /* low-level read function to read vigra unstrided MultiArray data from a sub-block of a dataset
2153  */
2154  template<unsigned int N, class T>
2155  inline 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)
2156  {
2157  //Prepare to read without using HDF5ImportInfo
2158  //ArrayVector<hsize_t> dimshape = getDatasetShape(datasetName) ;
2159  hssize_t dimensions = getDatasetDimensions(datasetName);
2160 
2161  std::string errorMessage ("HDF5File::readBlock(): Unable to open dataset '" + datasetName + "'.");
2162  HDF5Handle datasetHandle (getDatasetHandle_(datasetName), &H5Dclose, errorMessage.c_str());
2163 
2164  int offset = (numBandsOfType > 1)
2165  ? 1
2166  : 0;
2167 
2168  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
2169  "readHDF5_block(): Array dimension disagrees with data dimension.");
2170 
2171  vigra_precondition(blockShape == array.shape(),
2172  "readHDF5_block(): Array shape disagrees with block size.");
2173 
2174  // hyperslab parameters for position, size, ...
2175  hsize_t boffset [N];
2176  hsize_t bshape [N];
2177  hsize_t bones [N];
2178 
2179  for(int i = 0; i < N; i++){
2180  // vigra and hdf5 use different indexing
2181  boffset[i] = blockOffset[N-1-i];
2182  //bshape[i] = blockShape[i];
2183  bshape[i] = blockShape[N-1-i];
2184  //boffset[i] = blockOffset[N-1-i];
2185  bones[i] = 1;
2186  }
2187 
2188  // create a target dataspace in memory with the shape of the desired block
2189  HDF5Handle memspace_handle(H5Screate_simple(N,bshape,NULL),&H5Sclose,
2190  "Unable to create target dataspace");
2191 
2192  // get file dataspace and select the desired block
2193  HDF5Handle dataspaceHandle(H5Dget_space(datasetHandle),&H5Sclose,
2194  "Unable to get dataspace");
2195  H5Sselect_hyperslab(dataspaceHandle, H5S_SELECT_SET, boffset, bones, bones, bshape);
2196 
2197  // now read the data
2198  H5Dread( datasetHandle, datatype, memspace_handle, dataspaceHandle, H5P_DEFAULT, array.data() ); // .data() possible since void pointer!
2199  }
2200 
2201 }; /* class HDF5File */
2202 
2203 namespace detail {
2204 
2205 template <class Shape>
2206 inline void
2207 selectHyperslabs(HDF5Handle & mid1, HDF5Handle & mid2, Shape const & shape, int & counter, const int elements, const int numBandsOfType)
2208 {
2209  // select hyperslab in HDF5 file
2210  hsize_t shapeHDF5[2];
2211  shapeHDF5[0] = 1;
2212  shapeHDF5[1] = elements;
2213  hsize_t startHDF5[2];
2214  startHDF5[0] = 0;
2215  startHDF5[1] = counter * numBandsOfType * shape[0]; // we have to reserve space for the pixel type channel(s)
2216  hsize_t strideHDF5[2];
2217  strideHDF5[0] = 1;
2218  strideHDF5[1] = 1;
2219  hsize_t countHDF5[2];
2220  countHDF5[0] = 1;
2221  countHDF5[1] = numBandsOfType * shape[0];
2222  hsize_t blockHDF5[2];
2223  blockHDF5[0] = 1;
2224  blockHDF5[1] = 1;
2225  mid1 = HDF5Handle(H5Screate_simple(2, shapeHDF5, NULL),
2226  &H5Sclose, "unable to create hyperslabs.");
2227  H5Sselect_hyperslab(mid1, H5S_SELECT_SET, startHDF5, strideHDF5, countHDF5, blockHDF5);
2228  // select hyperslab in input data object
2229  hsize_t shapeData[2];
2230  shapeData[0] = 1;
2231  shapeData[1] = numBandsOfType * shape[0];
2232  hsize_t startData[2];
2233  startData[0] = 0;
2234  startData[1] = 0;
2235  hsize_t strideData[2];
2236  strideData[0] = 1;
2237  strideData[1] = 1;
2238  hsize_t countData[2];
2239  countData[0] = 1;
2240  countData[1] = numBandsOfType * shape[0];
2241  hsize_t blockData[2];
2242  blockData[0] = 1;
2243  blockData[1] = 1;
2244  mid2 = HDF5Handle(H5Screate_simple(2, shapeData, NULL),
2245  &H5Sclose, "unable to create hyperslabs.");
2246  H5Sselect_hyperslab(mid2, H5S_SELECT_SET, startData, strideData, countData, blockData);
2247 }
2248 
2249 template <class DestIterator, class Shape, class T>
2250 inline void
2251 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>)
2252 {
2253  HDF5Handle mid1, mid2;
2254 
2255  // select hyperslabs
2256  selectHyperslabs(mid1, mid2, shape, counter, elements, numBandsOfType);
2257 
2258  // read from hdf5
2259  herr_t read_status = H5Dread(dataset_id, datatype, mid2, mid1, H5P_DEFAULT, buffer.data());
2260  vigra_precondition(read_status >= 0, "readHDF5Impl(): read from dataset failed.");
2261 
2262  // increase counter
2263  counter++;
2264 
2265  //std::cout << "numBandsOfType: " << numBandsOfType << std::endl;
2266  DestIterator dend = d + shape[0];
2267  int k = 0;
2268  for(; d < dend; ++d, k++)
2269  {
2270  *d = buffer[k];
2271  //std::cout << buffer[k] << "| ";
2272  }
2273 }
2274 
2275 template <class DestIterator, class Shape, class T, int N>
2276 void
2277 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>)
2278 {
2279  DestIterator dend = d + shape[N];
2280  for(; d < dend; ++d)
2281  {
2282  readHDF5Impl(d.begin(), shape, dataset_id, datatype, buffer, counter, elements, numBandsOfType, MetaInt<N-1>());
2283  }
2284 }
2285 
2286 } // namespace detail
2287 
2288 /** \brief Read the data specified by the given \ref vigra::HDF5ImportInfo object
2289  and write the into the given 'array'.
2290 
2291  The array must have the correct number of dimensions and shape for the dataset
2292  represented by 'info'. When the element type of 'array' differs from the stored element
2293  type, HDF5 will convert the type on the fly (except when the HDF5 version is 1.6 or below,
2294  in which case an error will result). Multi-channel element types (i.e. \ref vigra::RGBValue,
2295  \ref vigra::TinyVector, and \ref vigra::FFTWComplex) are recognized and handled correctly.
2296 
2297  <b> Declaration:</b>
2298 
2299  \code
2300  namespace vigra {
2301  template<unsigned int N, class T, class StrideTag>
2302  void
2303  readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, T, StrideTag> array);
2304  }
2305  \endcode
2306 
2307  <b> Usage:</b>
2308 
2309  <b>\#include</b> <vigra/hdf5impex.hxx><br>
2310  Namespace: vigra
2311 
2312  \code
2313 
2314  HDF5ImportInfo info(filename, dataset_name);
2315  vigra_precondition(info.numDimensions() == 3, "Dataset must be 3-dimensional.");
2316 
2317  MultiArrayShape<3>::type shape(info.shape().begin());
2318  MultiArray<3, int> array(shape);
2319 
2320  readHDF5(info, array);
2321  \endcode
2322 */
2323 doxygen_overloaded_function(template <...> void readHDF5)
2324 
2325 // scalar and unstrided target multi array
2326 template<unsigned int N, class T>
2327 inline void readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, T, UnstridedArrayTag> array) // scalar
2328 {
2329  readHDF5(info, array, detail::getH5DataType<T>(), 1);
2330 }
2331 
2332 // non-scalar (TinyVector) and unstrided target multi array
2333 template<unsigned int N, class T, int SIZE>
2334 inline void readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, TinyVector<T, SIZE>, UnstridedArrayTag> array)
2335 {
2336  readHDF5(info, array, detail::getH5DataType<T>(), SIZE);
2337 }
2338 
2339 // non-scalar (RGBValue) and unstrided target multi array
2340 template<unsigned int N, class T>
2341 inline void readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, RGBValue<T>, UnstridedArrayTag> array)
2342 {
2343  readHDF5(info, array, detail::getH5DataType<T>(), 3);
2344 }
2345 
2346 // non-scalar (FFTWComplex) and unstrided target multi array
2347 template<unsigned int N, class T>
2348 inline void readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, FFTWComplex<T>, UnstridedArrayTag> array)
2349 {
2350  readHDF5(info, array, detail::getH5DataType<T>(), 2);
2351 }
2352 
2353 // unstrided target multi array
2354 template<unsigned int N, class T>
2355 void readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, T, UnstridedArrayTag> array, const hid_t datatype, const int numBandsOfType)
2356 {
2357  int offset = (numBandsOfType > 1);
2358 
2359  //std::cout << "offset: " << offset << ", N: " << N << ", dims: " << info.numDimensions() << std::endl;
2360  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
2361  "readHDF5(): Array dimension disagrees with HDF5ImportInfo.numDimensions().");
2362 
2363  typename MultiArrayShape<N>::type shape;
2364  for(int k=offset; k<info.numDimensions(); ++k) {
2365  shape[k-offset] = info.shapeOfDimension(k);
2366  }
2367 
2368  vigra_precondition(shape == array.shape(),
2369  "readHDF5(): Array shape disagrees with HDF5ImportInfo.");
2370 
2371  // simply read in the data as is
2372  H5Dread( info.getDatasetHandle(), datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, array.data() ); // .data() possible since void pointer!
2373 }
2374 
2375 // scalar and strided target multi array
2376 template<unsigned int N, class T>
2377 inline void readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, T, StridedArrayTag> array) // scalar
2378 {
2379  readHDF5(info, array, detail::getH5DataType<T>(), 1);
2380 }
2381 
2382 // non-scalar (TinyVector) and strided target multi array
2383 template<unsigned int N, class T, int SIZE>
2384 inline void readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, TinyVector<T, SIZE>, StridedArrayTag> array)
2385 {
2386  readHDF5(info, array, detail::getH5DataType<T>(), SIZE);
2387 }
2388 
2389 // non-scalar (RGBValue) and strided target multi array
2390 template<unsigned int N, class T>
2391 inline void readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, RGBValue<T>, StridedArrayTag> array)
2392 {
2393  readHDF5(info, array, detail::getH5DataType<T>(), 3);
2394 }
2395 
2396 // strided target multi array
2397 template<unsigned int N, class T>
2398 void readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, T, StridedArrayTag> array, const hid_t datatype, const int numBandsOfType)
2399 {
2400  int offset = (numBandsOfType > 1);
2401 
2402  //std::cout << "offset: " << offset << ", N: " << N << ", dims: " << info.numDimensions() << std::endl;
2403  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
2404  "readHDF5(): Array dimension disagrees with HDF5ImportInfo.numDimensions().");
2405 
2406  typename MultiArrayShape<N>::type shape;
2407  for(int k=offset; k<info.numDimensions(); ++k) {
2408  shape[k-offset] = info.shapeOfDimension(k);
2409  }
2410 
2411  vigra_precondition(shape == array.shape(),
2412  "readHDF5(): Array shape disagrees with HDF5ImportInfo.");
2413 
2414  //Get the data
2415  int counter = 0;
2416  int elements = numBandsOfType;
2417  for(unsigned int i=0;i<N;++i)
2418  elements *= shape[i];
2419  ArrayVector<T> buffer(shape[0]);
2420  detail::readHDF5Impl(array.traverser_begin(), shape, info.getDatasetHandle(), datatype, buffer, counter, elements, numBandsOfType, vigra::MetaInt<N-1>());
2421 }
2422 
2423 inline hid_t openGroup(hid_t parent, std::string group_name)
2424 {
2425  //std::cout << group_name << std::endl;
2426  size_t last_slash = group_name.find_last_of('/');
2427  if (last_slash == std::string::npos || last_slash != group_name.size() - 1)
2428  group_name = group_name + '/';
2429  std::string::size_type begin = 0, end = group_name.find('/');
2430  int ii = 0;
2431  while (end != std::string::npos)
2432  {
2433  std::string group(group_name.begin()+begin, group_name.begin()+end);
2434  hid_t prev_parent = parent;
2435  parent = H5Gopen(prev_parent, group.c_str(), H5P_DEFAULT);
2436 
2437  if(ii != 0) H5Gclose(prev_parent);
2438  if(parent < 0) return parent;
2439  ++ii;
2440  begin = end + 1;
2441  end = group_name.find('/', begin);
2442  }
2443  return parent;
2444 }
2445 
2446 inline hid_t createGroup(hid_t parent, std::string group_name)
2447 {
2448  if(group_name.size() == 0 ||*group_name.rbegin() != '/')
2449  group_name = group_name + '/';
2450  if(group_name == "/")
2451  return H5Gopen(parent, group_name.c_str(), H5P_DEFAULT);
2452 
2453  std::string::size_type begin = 0, end = group_name.find('/');
2454  int ii = 0;
2455  while (end != std::string::npos)
2456  {
2457  std::string group(group_name.begin()+begin, group_name.begin()+end);
2458  hid_t prev_parent = parent;
2459 
2460  if(H5LTfind_dataset(parent, group.c_str()) == 0)
2461  {
2462  parent = H5Gcreate(prev_parent, group.c_str(), H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
2463  } else {
2464  parent = H5Gopen(prev_parent, group.c_str(), H5P_DEFAULT);
2465  }
2466 
2467  if(ii != 0) H5Gclose(prev_parent);
2468  if(parent < 0) return parent;
2469  ++ii;
2470  begin = end + 1;
2471  end = group_name.find('/', begin);
2472  }
2473  return parent;
2474 }
2475 
2476 inline void deleteDataset(hid_t parent, std::string dataset_name)
2477 {
2478  // delete existing data and create new dataset
2479  if(H5LTfind_dataset(parent, dataset_name.c_str()))
2480  {
2481  //std::cout << "dataset already exists" << std::endl;
2482 #if (H5_VERS_MAJOR == 1 && H5_VERS_MINOR <= 6)
2483  if(H5Gunlink(parent, dataset_name.c_str()) < 0)
2484  {
2485  vigra_postcondition(false, "writeToHDF5File(): Unable to delete existing data.");
2486  }
2487 #else
2488  if(H5Ldelete(parent, dataset_name.c_str(), H5P_DEFAULT ) < 0)
2489  {
2490  vigra_postcondition(false, "createDataset(): Unable to delete existing data.");
2491  }
2492 #endif
2493  }
2494 }
2495 
2496 inline hid_t createFile(std::string filePath, bool append_ = true)
2497 {
2498  FILE * pFile;
2499  pFile = fopen ( filePath.c_str(), "r" );
2500  hid_t file_id;
2501  if ( pFile == NULL )
2502  {
2503  file_id = H5Fcreate(filePath.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
2504  }
2505  else if(append_)
2506  {
2507  fclose( pFile );
2508  file_id = H5Fopen(filePath.c_str(), H5F_ACC_RDWR, H5P_DEFAULT);
2509  }
2510  else
2511  {
2512  fclose(pFile);
2513  std::remove(filePath.c_str());
2514  file_id = H5Fcreate(filePath.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
2515  }
2516  return file_id;
2517 }
2518 
2519 template<unsigned int N, class T, class Tag>
2520 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)
2521 {
2522  std::string path_name(pathInFile), group_name, data_set_name, message;
2523  std::string::size_type delimiter = path_name.rfind('/');
2524 
2525  //create or open file
2526  file_handle = HDF5Handle(createFile(filePath), &H5Fclose,
2527  "createDataset(): unable to open output file.");
2528 
2529  // get the groupname and the filename
2530  if(delimiter == std::string::npos)
2531  {
2532  group_name = "/";
2533  data_set_name = path_name;
2534  }
2535  else
2536  {
2537  group_name = std::string(path_name.begin(), path_name.begin()+delimiter);
2538  data_set_name = std::string(path_name.begin()+delimiter+1, path_name.end());
2539  }
2540 
2541  // create all groups
2542  HDF5Handle group(createGroup(file_handle, group_name), &H5Gclose,
2543  "createDataset(): Unable to create and open group. generic v");
2544 
2545  // delete the dataset if it already exists
2546  deleteDataset(group, data_set_name);
2547 
2548  // create dataspace
2549  // add an extra dimension in case that the data is non-scalar
2550  HDF5Handle dataspace_handle;
2551  if(numBandsOfType > 1) {
2552  // invert dimensions to guarantee c-order
2553  hsize_t shape_inv[N+1]; // one additional dimension for pixel type channel(s)
2554  for(unsigned int k=0; k<N; ++k) {
2555  shape_inv[N-1-k] = array.shape(k); // the channels (eg of an RGB image) are represented by the first dimension (before inversion)
2556  //std::cout << shape_inv[N-k] << " (" << N << ")";
2557  }
2558  shape_inv[N] = numBandsOfType;
2559 
2560  // create dataspace
2561  dataspace_handle = HDF5Handle(H5Screate_simple(N+1, shape_inv, NULL),
2562  &H5Sclose, "createDataset(): unable to create dataspace for non-scalar data.");
2563  } else {
2564  // invert dimensions to guarantee c-order
2565  hsize_t shape_inv[N];
2566  for(unsigned int k=0; k<N; ++k)
2567  shape_inv[N-1-k] = array.shape(k);
2568 
2569  // create dataspace
2570  dataspace_handle = HDF5Handle(H5Screate_simple(N, shape_inv, NULL),
2571  &H5Sclose, "createDataset(): unable to create dataspace for scalar data.");
2572  }
2573 
2574  //alloc memory for dataset.
2575  dataset_handle = HDF5Handle(H5Dcreate(group,
2576  data_set_name.c_str(),
2577  datatype,
2578  dataspace_handle,
2579  H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT),
2580  &H5Dclose, "createDataset(): unable to create dataset.");
2581 }
2582 
2583 
2584 
2585 namespace detail {
2586 
2587 template <class DestIterator, class Shape, class T>
2588 inline void
2589 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>)
2590 {
2591  DestIterator dend = d + (typename DestIterator::difference_type)shape[0];
2592  int k = 0;
2593  //std::cout << "new:" << std::endl;
2594  for(; d < dend; ++d, k++)
2595  {
2596  buffer[k] = *d;
2597  //std::cout << buffer[k] << " ";
2598  }
2599  //std::cout << std::endl;
2600  HDF5Handle mid1, mid2;
2601 
2602  // select hyperslabs
2603  selectHyperslabs(mid1, mid2, shape, counter, elements, numBandsOfType);
2604 
2605  // write to hdf5
2606  H5Dwrite(dataset_id, datatype, mid2, mid1, H5P_DEFAULT, buffer.data());
2607  // increase counter
2608  counter++;
2609 }
2610 
2611 template <class DestIterator, class Shape, class T, int N>
2612 void
2613 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>)
2614 {
2615  DestIterator dend = d + (typename DestIterator::difference_type)shape[N];
2616  for(; d < dend; ++d)
2617  {
2618  writeHDF5Impl(d.begin(), shape, dataset_id, datatype, buffer, counter, elements, numBandsOfType, MetaInt<N-1>());
2619  }
2620 }
2621 
2622 } // namespace detail
2623 
2624 /** \brief Store array data in an HDF5 file.
2625 
2626  The number of dimensions, shape and element type of the stored dataset is automatically
2627  determined from the properties of the given \a array. Strided arrays are stored in an
2628  unstrided way, i.e. in contiguous scan-order. Multi-channel element types
2629  (i.e. \ref vigra::RGBValue, \ref vigra::TinyVector and \ref vigra::FFTWComplex)
2630  are recognized and handled correctly
2631  (in particular, the will form the innermost dimension of the stored dataset).
2632  \a pathInFile may contain '/'-separated group names, but must end with the name
2633  of the dataset to be created.
2634 
2635  <b> Declaration:</b>
2636 
2637  \code
2638  namespace vigra {
2639  template<unsigned int N, class T, class StrideTag>
2640  void
2641  writeHDF5(const char* filePath, const char* pathInFile,
2642  MultiArrayView<N, T, StrideTag>const & array);
2643  }
2644  \endcode
2645 
2646  <b> Usage:</b>
2647 
2648  <b>\#include</b> <vigra/hdf5impex.hxx><br>
2649  Namespace: vigra
2650 
2651  \code
2652  MultiArrayShape<3>::type shape(100, 200, 20);
2653  MultiArray<3, int> array(shape);
2654  ... // fill array with data
2655 
2656  writeHDF5("mydata.h5", "/group1/my_dataset", array);
2657  \endcode
2658 */
2659 doxygen_overloaded_function(template <...> void writeHDF5)
2660 
2661 // scalar and unstrided multi arrays
2662 template<unsigned int N, class T>
2663 inline void writeHDF5(const char* filePath, const char* pathInFile, const MultiArrayView<N, T, UnstridedArrayTag> & array) // scalar
2664 {
2665  writeHDF5(filePath, pathInFile, array, detail::getH5DataType<T>(), 1);
2666 }
2667 
2668 // non-scalar (TinyVector) and unstrided multi arrays
2669 template<unsigned int N, class T, int SIZE>
2670 inline void writeHDF5(const char* filePath, const char* pathInFile, const MultiArrayView<N, TinyVector<T, SIZE>, UnstridedArrayTag> & array)
2671 {
2672  writeHDF5(filePath, pathInFile, array, detail::getH5DataType<T>(), SIZE);
2673 }
2674 
2675 // non-scalar (RGBValue) and unstrided multi arrays
2676 template<unsigned int N, class T>
2677 inline void writeHDF5(const char* filePath, const char* pathInFile, const MultiArrayView<N, RGBValue<T>, UnstridedArrayTag> & array)
2678 {
2679  writeHDF5(filePath, pathInFile, array, detail::getH5DataType<T>(), 3);
2680 }
2681 
2682 // non-scalar (FFTWComplex) and unstrided multi arrays
2683 template<unsigned int N, class T>
2684 inline void writeHDF5(const char* filePath, const char* pathInFile, const MultiArrayView<N, FFTWComplex<T>, UnstridedArrayTag> & array)
2685 {
2686  writeHDF5(filePath, pathInFile, array, detail::getH5DataType<T>(), 2);
2687 }
2688 
2689 // unstrided multi arrays
2690 template<unsigned int N, class T>
2691 void writeHDF5(const char* filePath, const char* pathInFile, const MultiArrayView<N, T, UnstridedArrayTag> & array, const hid_t datatype, const int numBandsOfType)
2692 {
2693  HDF5Handle file_handle;
2694  HDF5Handle dataset_handle;
2695  createDataset(filePath, pathInFile, array, datatype, numBandsOfType, file_handle, dataset_handle);
2696 
2697  // Write the data to the HDF5 dataset as is
2698  H5Dwrite( dataset_handle, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, array.data()); // .data() possible since void pointer!
2699 
2700  H5Fflush(file_handle, H5F_SCOPE_GLOBAL);
2701 }
2702 
2703 
2704 // scalar and strided multi arrays
2705 template<unsigned int N, class T>
2706 inline void writeHDF5(const char* filePath, const char* pathInFile, const MultiArrayView<N, T, StridedArrayTag> & array) // scalar
2707 {
2708  writeHDF5(filePath, pathInFile, array, detail::getH5DataType<T>(), 1);
2709 }
2710 
2711 // non-scalar (TinyVector) and strided multi arrays
2712 template<unsigned int N, class T, int SIZE>
2713 inline void writeHDF5(const char* filePath, const char* pathInFile, const MultiArrayView<N, TinyVector<T, SIZE>, StridedArrayTag> & array)
2714 {
2715  writeHDF5(filePath, pathInFile, array, detail::getH5DataType<T>(), SIZE);
2716 }
2717 
2718 // non-scalar (RGBValue) and strided multi arrays
2719 template<unsigned int N, class T>
2720 inline void writeHDF5(const char* filePath, const char* pathInFile, const MultiArrayView<N, RGBValue<T>, StridedArrayTag> & array)
2721 {
2722  writeHDF5(filePath, pathInFile, array, detail::getH5DataType<T>(), 3);
2723 }
2724 
2725 // non-scalar (FFTWComplex) and strided multi arrays
2726 template<unsigned int N, class T>
2727 inline void writeHDF5(const char* filePath, const char* pathInFile, const MultiArrayView<N, FFTWComplex<T>, StridedArrayTag> & array)
2728 {
2729  writeHDF5(filePath, pathInFile, array, detail::getH5DataType<T>(), 2);
2730 }
2731 
2732 // strided multi arrays
2733 template<unsigned int N, class T>
2734 void writeHDF5(const char* filePath, const char* pathInFile, const MultiArrayView<N, T, StridedArrayTag> & array, const hid_t datatype, const int numBandsOfType)
2735 {
2736  HDF5Handle file_handle;
2737  HDF5Handle dataset_handle;
2738  createDataset(filePath, pathInFile, array, datatype, numBandsOfType, file_handle, dataset_handle);
2739 
2741  vigra::TinyVector<int,N> stride;
2742  int elements = numBandsOfType;
2743  for(unsigned int k=0; k<N; ++k)
2744  {
2745  shape[k] = array.shape(k);
2746  stride[k] = array.stride(k);
2747  elements *= (int)shape[k];
2748  }
2749  int counter = 0;
2750 
2751  ArrayVector<T> buffer((int)array.shape(0));
2752  detail::writeHDF5Impl(array.traverser_begin(), shape, dataset_handle, datatype, buffer, counter, elements, numBandsOfType, vigra::MetaInt<N-1>());
2753 
2754  H5Fflush(file_handle, H5F_SCOPE_GLOBAL);
2755 
2756 }
2757 
2758 namespace detail
2759 {
2760 struct MaxSizeFnc
2761 {
2762  size_t size;
2763 
2764  MaxSizeFnc()
2765  : size(0)
2766  {}
2767 
2768  void operator()(std::string const & in)
2769  {
2770  size = in.size() > size ?
2771  in.size() :
2772  size;
2773  }
2774 };
2775 }
2776 
2777 
2778 #if (H5_VERS_MAJOR == 1 && H5_VERS_MINOR == 8) || DOXYGEN
2779 /** Write a numeric MultiArray as an attribute with name \a name
2780  of the dataset specified by the handle \a loc.
2781 
2782  <b>\#include</b> <vigra/hdf5impex.hxx><br>
2783  Namespace: vigra
2784 */
2785 template<size_t N, class T, class C>
2786 void writeHDF5Attr(hid_t loc,
2787  const char* name,
2788  MultiArrayView<N, T, C> const & array)
2789 {
2790  if(H5Aexists(loc, name) > 0)
2791  H5Adelete(loc, name);
2792 
2793  ArrayVector<hsize_t> shape(array.shape().begin(),
2794  array.shape().end());
2795  HDF5Handle
2796  dataspace_handle(H5Screate_simple(N, shape.data(), NULL),
2797  &H5Sclose,
2798  "writeToHDF5File(): unable to create dataspace.");
2799 
2800  HDF5Handle attr(H5Acreate(loc,
2801  name,
2802  detail::getH5DataType<T>(),
2803  dataspace_handle,
2804  H5P_DEFAULT ,H5P_DEFAULT ),
2805  &H5Aclose,
2806  "writeHDF5Attr: unable to create Attribute");
2807 
2808  //copy data - since attributes are small - who cares!
2809  ArrayVector<T> buffer;
2810  for(int ii = 0; ii < array.size(); ++ii)
2811  buffer.push_back(array[ii]);
2812  H5Awrite(attr, detail::getH5DataType<T>(), buffer.data());
2813 }
2814 
2815 /** Write a string MultiArray as an attribute with name \a name
2816  of the dataset specified by the handle \a loc.
2817 
2818  <b>\#include</b> <vigra/hdf5impex.hxx><br>
2819  Namespace: vigra
2820 */
2821 template<size_t N, class C>
2822 void writeHDF5Attr(hid_t loc,
2823  const char* name,
2824  MultiArrayView<N, std::string, C> const & array)
2825 {
2826  if(H5Aexists(loc, name) > 0)
2827  H5Adelete(loc, name);
2828 
2829  ArrayVector<hsize_t> shape(array.shape().begin(),
2830  array.shape().end());
2831  HDF5Handle
2832  dataspace_handle(H5Screate_simple(N, shape.data(), NULL),
2833  &H5Sclose,
2834  "writeToHDF5File(): unable to create dataspace.");
2835 
2836  HDF5Handle atype(H5Tcopy (H5T_C_S1),
2837  &H5Tclose,
2838  "writeToHDF5File(): unable to create type.");
2839 
2840  detail::MaxSizeFnc max_size;
2841  max_size = std::for_each(array.data(),array.data()+ array.size(), max_size);
2842  H5Tset_size (atype, max_size.size);
2843 
2844  HDF5Handle attr(H5Acreate(loc,
2845  name,
2846  atype,
2847  dataspace_handle,
2848  H5P_DEFAULT ,H5P_DEFAULT ),
2849  &H5Aclose,
2850  "writeHDF5Attr: unable to create Attribute");
2851 
2852  std::string buf ="";
2853  for(int ii = 0; ii < array.size(); ++ii)
2854  {
2855  buf = buf + array[ii]
2856  + std::string(max_size.size - array[ii].size(), ' ');
2857  }
2858  H5Awrite(attr, atype, buf.c_str());
2859 }
2860 
2861 /** Write a numeric ArrayVectorView as an attribute with name \a name
2862  of the dataset specified by the handle \a loc.
2863 
2864  <b>\#include</b> <vigra/hdf5impex.hxx><br>
2865  Namespace: vigra
2866 */
2867 template<class T>
2868 inline void writeHDF5Attr( hid_t loc,
2869  const char* name,
2870  ArrayVectorView<T> & array)
2871 {
2872  writeHDF5Attr(loc, name,
2874  array.data()));
2875 }
2876 
2877 /** write an Attribute given a file and a path in the file.
2878  the path in the file should have the format
2879  [attribute] or /[subgroups/]dataset.attribute or
2880  /[subgroups/]group.attribute.
2881  The attribute is written to the root group, a dataset or a subgroup
2882  respectively
2883 */
2884 template<class Arr>
2885 inline void writeHDF5Attr( std::string filePath,
2886  std::string pathInFile,
2887  Arr & ar)
2888 {
2889  std::string path_name(pathInFile), group_name, data_set_name, message, attr_name;
2890  std::string::size_type delimiter = path_name.rfind('/');
2891 
2892  //create or open file
2893  HDF5Handle file_id(createFile(filePath), &H5Fclose,
2894  "writeToHDF5File(): unable to open output file.");
2895 
2896  // get the groupname and the filename
2897  if(delimiter == std::string::npos)
2898  {
2899  group_name = "/";
2900  data_set_name = path_name;
2901  }
2902 
2903  else
2904  {
2905  group_name = std::string(path_name.begin(), path_name.begin()+delimiter);
2906  data_set_name = std::string(path_name.begin()+delimiter+1, path_name.end());
2907  }
2908  delimiter = data_set_name.rfind('.');
2909  if(delimiter == std::string::npos)
2910  {
2911  attr_name = path_name;
2912  data_set_name = "/";
2913  }
2914  else
2915  {
2916  attr_name = std::string(data_set_name.begin()+delimiter+1, data_set_name.end());
2917  data_set_name = std::string(data_set_name.begin(), data_set_name.begin()+delimiter);
2918  }
2919 
2920  HDF5Handle group(openGroup(file_id, group_name), &H5Gclose,
2921  "writeToHDF5File(): Unable to create and open group. attr ver");
2922 
2923  if(data_set_name != "/")
2924  {
2925  HDF5Handle dset(H5Dopen(group, data_set_name.c_str(), H5P_DEFAULT), &H5Dclose,
2926  "writeHDF5Attr():unable to open dataset");
2927  writeHDF5Attr(hid_t(dset), attr_name.c_str(), ar);
2928  }
2929  else
2930  {
2931  writeHDF5Attr(hid_t(group), attr_name.c_str(), ar);
2932  }
2933 
2934 }
2935 #endif
2936 
2937 //@}
2938 
2939 } // namespace vigra
2940 
2941 #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.9.0 (Tue Sep 24 2013)