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