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

hdf5impex.hxx VIGRA

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 #include <algorithm>
41 #include <utility>
42 
43 #define H5Gcreate_vers 2
44 #define H5Gopen_vers 2
45 #define H5Dopen_vers 2
46 #define H5Dcreate_vers 2
47 #define H5Acreate_vers 2
48 
49 #include <hdf5.h>
50 
51 #if (H5_VERS_MAJOR == 1 && H5_VERS_MINOR <= 6)
52 # ifndef H5Gopen
53 # define H5Gopen(a, b, c) H5Gopen(a, b)
54 # endif
55 # ifndef H5Gcreate
56 # define H5Gcreate(a, b, c, d, e) H5Gcreate(a, b, 1)
57 # endif
58 # ifndef H5Dopen
59 # define H5Dopen(a, b, c) H5Dopen(a, b)
60 # endif
61 # ifndef H5Dcreate
62 # define H5Dcreate(a, b, c, d, e, f, g) H5Dcreate(a, b, c, d, f)
63 # endif
64 # ifndef H5Acreate
65 # define H5Acreate(a, b, c, d, e, f) H5Acreate(a, b, c, d, e)
66 # endif
67 # ifndef H5Pset_obj_track_times
68 # define H5Pset_obj_track_times(a, b) do {} while (0)
69 # endif
70 # include <H5LT.h>
71 #else
72 # include <hdf5_hl.h>
73 #endif
74 
75 #include "impex.hxx"
76 #include "multi_array.hxx"
77 #include "multi_iterator_coupled.hxx"
78 #include "multi_impex.hxx"
79 #include "utilities.hxx"
80 #include "error.hxx"
81 
82 #if defined(_MSC_VER)
83 # include <io.h>
84 #else
85 # include <unistd.h>
86 #endif
87 
88 namespace vigra {
89 
90 /** \addtogroup VigraHDF5Impex Import/Export of Images and Arrays in HDF5 Format
91 
92  Supports arrays with arbitrary element types and arbitrary many dimensions.
93  See the <a href="http://www.hdfgroup.org/HDF5/">HDF5 Website</a> for more
94  information on the HDF5 file format.
95 */
96 //@{
97 
98  /** \brief Check if given filename refers to a HDF5 file.
99  */
100 inline bool isHDF5(char const * filename)
101 {
102 #ifdef _MSC_VER
103  return _access(filename, 0) != -1 && H5Fis_hdf5(filename);
104 #else
105  return access(filename, F_OK) == 0 && H5Fis_hdf5(filename);
106 #endif
107 }
108 
109  /** \brief Temporarily disable HDF5's native error output.
110 
111  This should be used when you want to call an HDF5 function
112  that is known to fail (e.g. during testing), or when you want
113  to use an alternative error reporting mechanism (e.g. exceptions).
114 
115  <b>Usage:</b>
116 
117  <b>\#include</b> <vigra/hdf5impex.hxx><br>
118  Namespace: vigra
119  \code
120  {
121  HDF5DisableErrorOutput hdf5DisableErrorOutput;
122 
123  ... // call some HDF5 function
124 
125  } // restore the original error reporting in the destructor of HDF5DisableErrorOutput
126  \endcode
127  */
129 {
130  H5E_auto2_t old_func_;
131  void *old_client_data_;
132 
134  HDF5DisableErrorOutput & operator=(HDF5DisableErrorOutput const &);
135 
136  public:
138  : old_func_(0)
139  , old_client_data_(0)
140  {
141  H5Eget_auto2(H5E_DEFAULT, &old_func_, &old_client_data_);
142  H5Eset_auto2(H5E_DEFAULT, NULL, NULL);
143  }
144 
146  {
147  H5Eset_auto2(H5E_DEFAULT, old_func_, old_client_data_);
148  }
149 };
150 
151  /** \brief Wrapper for unique hid_t objects.
152 
153  This class offers the functionality of <tt>std::unique_ptr</tt> for HDF5 handles
154  (type <tt>hid_t</tt>). Unfortunately, <tt>std::unique_ptr</tt> cannot be used directly
155  for this purpose because it only works with pointers, whereas <tt>hid_t</tt> is an integer type.
156 
157  Newly created or opened HDF5 handles are stored as objects of type <tt>hid_t</tt>. When the handle
158  is no longer needed, the appropriate close function must be called. However, if a function is
159  aborted by an exception, this is difficult to ensure. Class HDF5Handle is a smart pointer that
160  solves this problem by calling the close function in the destructor (This is analogous to how
161  <tt>std::unique_ptr</tt> calls 'delete' on the contained pointer). A pointer to the close function
162  must be passed to the constructor, along with an error message that is raised when
163  creation/opening fails.
164 
165  When a <tt>HDF5Handle</tt> is created or assigned from another one, ownership passes on to the
166  left-hand-side handle object, and the right-hand-side objects is resest to a NULL handle.
167 
168  Since <tt>HDF5Handle</tt> objects are convertible to <tt>hid_t</tt>, they can be used in the code
169  in place of the latter.
170 
171  <b>Usage:</b>
172 
173  \code
174  HDF5Handle file_id(H5Fopen(filename, H5F_ACC_RDWR, H5P_DEFAULT),
175  &H5Fclose,
176  "Error message when H5Fopen() fails.");
177 
178  ... // use file_id in the same way as a plain hid_t object
179 
180  // pass ownership to a new handle object
181  HDF5Handle new_handle(file_id);
182 
183  assert(file_id.get() == 0);
184  \endcode
185 
186  <b>\#include</b> <vigra/hdf5impex.hxx><br>
187  Namespace: vigra
188  */
190 {
191 public:
192  typedef herr_t (*Destructor)(hid_t);
193 
194 private:
195  hid_t handle_;
196  Destructor destructor_;
197 
198 public:
199 
200  /** \brief Default constructor.
201  Creates a NULL handle.
202  **/
204  : handle_( 0 ),
205  destructor_(0)
206  {}
207 
208  /** \brief Create a wrapper for a hid_t object.
209 
210  The hid_t object \a h is assumed to be the return value of an open or create function.
211  It will be closed with the given close function \a destructor as soon as this
212  HDF5Handle is destructed, except when \a destructor is a NULL pointer (in which
213  case nothing happens at destruction time). If \a h has a value that indicates
214  failed opening or creation (by HDF5 convention, this means that \a h is negative),
215  an exception is raised by calling <tt>vigra_fail(error_message)</tt>.
216 
217  <b>Usage:</b>
218 
219  \code
220  HDF5Handle file_id(H5Fopen(filename, H5F_ACC_RDWR, H5P_DEFAULT),
221  &H5Fclose,
222  "Error message.");
223 
224  ... // use file_id in the same way
225  \endcode
226  */
227  HDF5Handle(hid_t h, Destructor destructor, const char * error_message)
228  : handle_( h ),
229  destructor_(destructor)
230  {
231  if(handle_ < 0)
232  vigra_fail(error_message);
233  }
234 
235  /** \brief Copy constructor.
236 
237  Hands over ownership of the RHS handle (analogous to <tt>std::unique_pt</tt>).
238  */
240  : handle_( h.handle_ ),
241  destructor_(h.destructor_)
242  {
243  const_cast<HDF5Handle &>(h).handle_ = 0;
244  }
245 
246  /** \brief Assignment.
247  Calls close() for the LHS handle and hands over ownership of the
248  RHS handle (analogous to <tt>std::unique_pt</tt>).
249  */
251  {
252  if(h.handle_ != handle_)
253  {
254  close();
255  handle_ = h.handle_;
256  destructor_ = h.destructor_;
257  const_cast<HDF5Handle &>(h).handle_ = 0;
258  }
259  return *this;
260  }
261 
262  /** \brief Destructor.
263  Calls close() for the contained handle.
264  */
266  {
267  close();
268  }
269 
270  /** \brief Explicitly call the stored destructor (if one has been registered in the
271  constructor) for the contained handle and set the wrapper to NULL. Returns
272  a negative value when the destructor call for the handle fails, and
273  a non-negative value otherwise.
274  */
275  herr_t close()
276  {
277  herr_t res = 1;
278  if(handle_ && destructor_)
279  res = (*destructor_)(handle_);
280  handle_ = 0;
281  destructor_ = 0;
282  return res;
283  }
284 
285  /** \brief Return the contained handle and set the wrapper to NULL
286  without calling <tt>close()</tt>.
287  */
288  hid_t release()
289  {
290  hid_t res = handle_;
291  handle_ = 0;
292  destructor_ = 0;
293  return res;
294  }
295 
296  /** \brief Reset the wrapper to a new handle.
297 
298  Equivalent to <tt>handle = HDF5Handle(h, destructor, error_message)</tt>.
299  */
300  void reset(hid_t h, Destructor destructor, const char * error_message)
301  {
302  if(h < 0)
303  vigra_fail(error_message);
304  if(h != handle_)
305  {
306  close();
307  handle_ = h;
308  destructor_ = destructor;
309  }
310  }
311 
312  /** \brief Swap the contents of two handle wrappers.
313 
314  Also available as <tt>std::swap(handle1, handle2)</tt>.
315  */
316  void swap(HDF5Handle & h)
317  {
318  std::swap(handle_, h.handle_);
319  std::swap(destructor_, h.destructor_);
320  }
321 
322  /** \brief Get a temporary hid_t object for the contained handle.
323  Do not call a close function on the return value - a crash will be likely
324  otherwise.
325  */
326  hid_t get() const
327  {
328  return handle_;
329  }
330 
331  /** \brief Convert to a plain hid_t object.
332 
333  This function ensures that hid_t objects can be transparently replaced with
334  HDF5Handle objects in user code. Do not call a close function on the return
335  value - a crash will be likely otherwise.
336  */
337  operator hid_t() const
338  {
339  return handle_;
340  }
341 
342  /** \brief Equality comparison of the contained handle.
343  */
344  bool operator==(HDF5Handle const & h) const
345  {
346  return handle_ == h.handle_;
347  }
348 
349  /** \brief Equality comparison of the contained handle.
350  */
351  bool operator==(hid_t h) const
352  {
353  return handle_ == h;
354  }
355 
356  /** \brief Inequality comparison of the contained handle.
357  */
358  bool operator!=(HDF5Handle const & h) const
359  {
360  return handle_ != h.handle_;
361  }
362 
363  /** \brief Inequality comparison of the contained handle.
364  */
365  bool operator!=(hid_t h) const
366  {
367  return handle_ != h;
368  }
369 };
370 
371 
372  /** \brief Wrapper for shared hid_t objects.
373 
374  This class offers the functionality of <tt>std::shared_ptr</tt> for HDF5 handles
375  (type <tt>hid_t</tt>). Unfortunately, <tt>std::shared_ptr</tt> cannot be used directly
376  for this purpose because it only works with pointers, whereas <tt>hid_t</tt> is an integer type.
377 
378  Newly created or opened HDF5 handles are stored as objects of type <tt>hid_t</tt>. When the handle
379  is no longer needed, the appropriate close function must be called. However, if a function is
380  aborted by an exception, this is difficult to ensure. Class HDF5HandleShared is a smart pointer
381  that solves this problem by calling the close function in the destructor of the handle's last
382  owner (This is analogous to how <tt>std::shared_ptr</tt> calls 'delete' on the contained
383  pointer). A pointer to the close function must be passed to the constructor, along with an error
384  message that is raised when creation/opening fails.
385 
386  When a <tt>HDF5HandleShared</tt> is created or assigned from another one, ownership is shared
387  between the two handles, and the value returned by <tt>use_count()</tt> increases by one.
388 
389  Since <tt>HDF5HandleShared</tt> objects are convertible to <tt>hid_t</tt>, they can be used in the code
390  in place of the latter.
391 
392  <b>Usage:</b>
393 
394  \code
395  HDF5HandleShared file_id(H5Fopen(filename, H5F_ACC_RDWR, H5P_DEFAULT),
396  &H5Fclose,
397  "Error message when H5Fopen() fails.");
398 
399  ... // use file_id in the same way as a plain hid_t object
400 
401  // share ownership between same_id and file_id
402  HDF5HandleShared same_id(file_id);
403  assert(same_id.use_count() == 2);
404  assert(same_id.get() == file_id.get());
405  \endcode
406 
407  <b>\#include</b> <vigra/hdf5impex.hxx><br>
408  Namespace: vigra
409  */
411 {
412 public:
413  typedef herr_t (*Destructor)(hid_t);
414 
415 private:
416  hid_t handle_;
417  Destructor destructor_;
418  size_t * refcount_;
419 
420 public:
421 
422  /** \brief Default constructor.
423  Creates a NULL handle.
424  **/
426  : handle_( 0 ),
427  destructor_(0),
428  refcount_(0)
429  {}
430 
431  /** \brief Create a shared wrapper for a plain hid_t object.
432 
433  The hid_t object \a h is assumed to be the return value of an open or create function.
434  It will be closed with the given close function \a destructor as soon as this
435  HDF5HandleShared is destructed, except when \a destructor is a NULL pointer (in which
436  case nothing happens at destruction time). If \a h has a value that indicates
437  failed opening or creation (by HDF5 convention, this means that \a h is negative),
438  an exception is raised by calling <tt>vigra_fail(error_message)</tt>.
439 
440  <b>Usage:</b>
441 
442  \code
443  HDF5HandleShared file_id(H5Fopen(filename, H5F_ACC_RDWR, H5P_DEFAULT),
444  &H5Fclose,
445  "Error message.");
446 
447  ... // use file_id in the same way
448  \endcode
449  */
450  HDF5HandleShared(hid_t h, Destructor destructor, const char * error_message)
451  : handle_( h ),
452  destructor_(destructor),
453  refcount_(0)
454  {
455  if(handle_ < 0)
456  vigra_fail(error_message);
457  if(handle_ > 0)
458  refcount_ = new size_t(1);
459  }
460 
461  /** \brief Copy constructor.
462  Shares ownership with the RHS handle (analogous to <tt>std::shared_ptr</tt>).
463  */
465  : handle_( h.handle_ ),
466  destructor_(h.destructor_),
467  refcount_(h.refcount_)
468  {
469  if(refcount_)
470  ++(*refcount_);
471  }
472 
473  /** \brief Assignment.
474  Call close() for the present LHS handle and share ownership with the
475  RHS handle (analogous to <tt>std::shared_ptr</tt>).
476  */
478  {
479  if(h.handle_ != handle_)
480  {
481  close();
482  handle_ = h.handle_;
483  destructor_ = h.destructor_;
484  refcount_ = h.refcount_;
485  if(refcount_)
486  ++(*refcount_);
487  }
488  return *this;
489  }
490 
491  /** \brief Destructor (calls close())
492  */
494  {
495  close();
496  }
497 
498  /** \brief Close the handle if this is the unique (i.e. last) owner.
499 
500  Decrements the reference counter and calls the destructor function of
501  the handle (if one has been registered in the constructor) when the counter
502  reaches zero. Sets this wrapper to NULL in any case. Returns
503  a negative value when the destructor call for the handle fails, and
504  a non-negative value otherwise.
505  */
506  herr_t close()
507  {
508  herr_t res = 1;
509  if(refcount_)
510  {
511  --(*refcount_);
512  if(*refcount_ == 0)
513  {
514  if(destructor_)
515  res = (*destructor_)(handle_);
516  delete refcount_;
517  }
518  }
519  handle_ = 0;
520  destructor_ = 0;
521  refcount_ = 0;
522  return res;
523  }
524 
525  /** \brief Reset the handle to a new value.
526 
527  Equivalent to <tt>handle = HDF5HandleShared(h, destructor, error_message)</tt>.
528  */
529  void reset(hid_t h, Destructor destructor, const char * error_message)
530  {
531  if(h < 0)
532  vigra_fail(error_message);
533  if(h != handle_)
534  {
535  close();
536  handle_ = h;
537  destructor_ = destructor;
538  if(handle_ > 0)
539  refcount_ = new size_t(1);
540  }
541  }
542 
543  /** \brief Get the number of owners of the contained handle.
544  */
545  size_t use_count() const
546  {
547  return refcount_
548  ? *refcount_
549  : 0;
550  }
551 
552  /** \brief Check if this is the unique owner of the conatined handle.
553 
554  Equivalent to <tt>handle.use_count() == 1</tt>.
555  */
556  bool unique() const
557  {
558  return use_count() == 1;
559  }
560 
561  /** \brief Swap the contents of two handle wrappers.
562 
563  Also available as <tt>std::swap(handle1, handle2)</tt>.
564  */
566  {
567  std::swap(handle_, h.handle_);
568  std::swap(destructor_, h.destructor_);
569  std::swap(refcount_, h.refcount_);
570  }
571 
572  /** \brief Get a temporary hid_t object for the contained handle.
573  Do not call a close function on the return value - a crash will be likely
574  otherwise.
575  */
576  hid_t get() const
577  {
578  return handle_;
579  }
580 
581  /** \brief Convert to a plain hid_t object.
582 
583  This function ensures that hid_t objects can be transparently replaced with
584  HDF5HandleShared objects in user code. Do not call a close function on the return
585  value - a crash will be likely otherwise.
586  */
587  operator hid_t() const
588  {
589  return handle_;
590  }
591 
592  /** \brief Equality comparison of the contained handle.
593  */
594  bool operator==(HDF5HandleShared const & h) const
595  {
596  return handle_ == h.handle_;
597  }
598 
599  /** \brief Equality comparison of the contained handle.
600  */
601  bool operator==(hid_t h) const
602  {
603  return handle_ == h;
604  }
605 
606  /** \brief Inequality comparison of the contained handle.
607  */
608  bool operator!=(HDF5HandleShared const & h) const
609  {
610  return handle_ != h.handle_;
611  }
612 
613  /** \brief Inequality comparison of the contained handle.
614  */
615  bool operator!=(hid_t h) const
616  {
617  return handle_ != h;
618  }
619 };
620 
621 //@}
622 
623 } // namespace vigra
624 
625 namespace std {
626 
627 inline void swap(vigra::HDF5Handle & l, vigra::HDF5Handle & r)
628 {
629  l.swap(r);
630 }
631 
632 inline void swap(vigra::HDF5HandleShared & l, vigra::HDF5HandleShared & r)
633 {
634  l.swap(r);
635 }
636 
637 } // namespace std
638 
639 namespace vigra {
640 
641 /** \addtogroup VigraHDF5Impex
642 */
643 //@{
644 
645 
646 /********************************************************/
647 /* */
648 /* HDF5ImportInfo */
649 /* */
650 /********************************************************/
651 
652 /** \brief Argument object for the function readHDF5().
653 
654 See \ref readHDF5() for a usage example. This object must be
655 used to read an image or array from an HDF5 file
656 and enquire about its properties.
657 
658 <b>\#include</b> <vigra/hdf5impex.hxx><br>
659 Namespace: vigra
660 */
662 {
663  public:
664  enum PixelType { UINT8, UINT16, UINT32, UINT64,
665  INT8, INT16, INT32, INT64,
666  FLOAT, DOUBLE };
667 
668  /** Construct HDF5ImportInfo object.
669 
670  The dataset \a pathInFile in the HDF5 file \a filename is accessed to
671  read its properties. \a pathInFile may contain '/'-separated group
672  names, but must end with the name of the desired dataset:
673 
674  \code
675  HDF5ImportInfo info(filename, "/group1/group2/my_dataset");
676  \endcode
677  */
678  VIGRA_EXPORT HDF5ImportInfo( const char* filePath, const char* pathInFile );
679 
680  VIGRA_EXPORT ~HDF5ImportInfo();
681 
682  /** Get the filename of this HDF5 object.
683  */
684  VIGRA_EXPORT const std::string& getFilePath() const;
685 
686  /** Get the dataset's full name in the HDF5 file.
687  */
688  VIGRA_EXPORT const std::string& getPathInFile() const;
689 
690  /** Get a handle to the file represented by this info object.
691  */
692  VIGRA_EXPORT hid_t getH5FileHandle() const;
693 
694  /** Get a handle to the dataset represented by this info object.
695  */
696  VIGRA_EXPORT hid_t getDatasetHandle() const;
697 
698  /** Get the number of dimensions of the dataset represented by this info object.
699  */
700  VIGRA_EXPORT MultiArrayIndex numDimensions() const;
701 
702  /** Get the shape of the dataset represented by this info object.
703 
704  Note that the memory order between VIGRA and HDF5 files differs: VIGRA uses
705  Fortran-order, while HDF5 uses C-order. This function therefore reverses the axis
706  order relative to the file contents. That is, when the axes in the file are
707  ordered as 'z', 'y', 'x', this function will return the shape in the order
708  'x', 'y', 'z'.
709  */
710  VIGRA_EXPORT ArrayVector<hsize_t> const & shape() const
711  {
712  return m_dims;
713  }
714 
715  /** Get the shape (length) of the dataset along dimension \a dim.
716 
717  Note that the memory order between VIGRA and HDF5 files differs: VIGRA uses
718  Fortran-order, while HDF5 uses C-order. This function therefore reverses the axis
719  order relative to the file contents. That is, when the axes in the file are
720  ordered as 'z', 'y', 'x', this function will return the shape in the order
721  'x', 'y', 'z'.
722  */
723  VIGRA_EXPORT MultiArrayIndex shapeOfDimension(const int dim) const;
724 
725  /** Query the pixel type of the dataset.
726 
727  Possible values are:
728  <DL>
729  <DT>"INT8"<DD> 8-bit signed integer (unsigned char)
730  <DT>"UINT8"<DD> 8-bit unsigned integer (unsigned char)
731  <DT>"INT16"<DD> 16-bit signed integer (short)
732  <DT>"UINT16"<DD> 16-bit unsigned integer (unsigned short)
733  <DT>"INT32"<DD> 32-bit signed integer (long)
734  <DT>"UINT32"<DD> 32-bit unsigned integer (unsigned long)
735  <DT>"INT64"<DD> 64-bit signed integer (long long)
736  <DT>"UINT64"<DD> 64-bit unsigned integer (unsigned long long)
737  <DT>"FLOAT"<DD> 32-bit floating point (float)
738  <DT>"DOUBLE"<DD> 64-bit floating point (double)
739  </DL>
740  */
741  VIGRA_EXPORT const char * getPixelType() const;
742 
743  /** Query the pixel type of the dataset.
744 
745  Same as getPixelType(), but the result is returned as a
746  ImageImportInfo::PixelType enum. This is useful to implement
747  a switch() on the pixel type.
748 
749  Possible values are:
750  <DL>
751  <DT>UINT8<DD> 8-bit unsigned integer (unsigned char)
752  <DT>INT16<DD> 16-bit signed integer (short)
753  <DT>UINT16<DD> 16-bit unsigned integer (unsigned short)
754  <DT>INT32<DD> 32-bit signed integer (long)
755  <DT>UINT32<DD> 32-bit unsigned integer (unsigned long)
756  <DT>FLOAT<DD> 32-bit floating point (float)
757  <DT>DOUBLE<DD> 64-bit floating point (double)
758  </DL>
759  */
760  VIGRA_EXPORT PixelType pixelType() const;
761 
762  private:
763  HDF5HandleShared m_file_handle, m_dataset_handle;
764  std::string m_filename, m_path, m_pixeltype;
765  hssize_t m_dimensions;
766  ArrayVector<hsize_t> m_dims;
767 };
768 
769 
770 namespace detail {
771 
772 template <class T>
773 struct HDF5TypeTraits
774 {
775  static hid_t getH5DataType()
776  {
777  std::runtime_error("getH5DataType(): invalid type");
778  return 0;
779  }
780 
781  static int numberOfBands()
782  {
783  std::runtime_error("numberOfBands(): invalid type");
784  return 0;
785  }
786 };
787 
788 template<class T>
789 inline hid_t getH5DataType()
790 {
791  return HDF5TypeTraits<T>::getH5DataType();
792 }
793 
794 #define VIGRA_H5_DATATYPE(type, h5type) \
795 template <> \
796 struct HDF5TypeTraits<type> \
797 { \
798  static hid_t getH5DataType() \
799  { \
800  return h5type; \
801  } \
802  static int numberOfBands() \
803  { \
804  return 1; \
805  } \
806  typedef type value_type; \
807 }; \
808 template <int M> \
809 struct HDF5TypeTraits<TinyVector<type, M> > \
810 { \
811  static hid_t getH5DataType() \
812  { \
813  return h5type; \
814  } \
815  static int numberOfBands() \
816  { \
817  return M; \
818  } \
819  typedef type value_type; \
820 }; \
821 template <> \
822 struct HDF5TypeTraits<RGBValue<type> > \
823 { \
824  static hid_t getH5DataType() \
825  { \
826  return h5type; \
827  } \
828  static int numberOfBands() \
829  { \
830  return 3; \
831  } \
832  typedef type value_type; \
833 }; \
834 
835 VIGRA_H5_DATATYPE(char, H5T_NATIVE_CHAR)
836 VIGRA_H5_DATATYPE(signed char, H5T_NATIVE_SCHAR)
837 VIGRA_H5_DATATYPE(unsigned char, H5T_NATIVE_UCHAR)
838 VIGRA_H5_DATATYPE(signed short, H5T_NATIVE_SHORT)
839 VIGRA_H5_DATATYPE(unsigned short, H5T_NATIVE_USHORT)
840 VIGRA_H5_DATATYPE(signed int, H5T_NATIVE_INT)
841 VIGRA_H5_DATATYPE(unsigned int, H5T_NATIVE_UINT)
842 VIGRA_H5_DATATYPE(signed long, H5T_NATIVE_LONG)
843 VIGRA_H5_DATATYPE(unsigned long, H5T_NATIVE_ULONG)
844 VIGRA_H5_DATATYPE(signed long long, H5T_NATIVE_LLONG)
845 VIGRA_H5_DATATYPE(unsigned long long, H5T_NATIVE_ULLONG)
846 VIGRA_H5_DATATYPE(float, H5T_NATIVE_FLOAT)
847 VIGRA_H5_DATATYPE(double, H5T_NATIVE_DOUBLE)
848 VIGRA_H5_DATATYPE(long double, H5T_NATIVE_LDOUBLE)
849 
850 // char arrays with flexible length require 'handcrafted' H5 datatype
851 template <>
852 struct HDF5TypeTraits<char*>
853 {
854  static hid_t getH5DataType()
855  {
856  hid_t stringtype = H5Tcopy (H5T_C_S1);
857  H5Tset_size(stringtype, H5T_VARIABLE);
858  return stringtype;
859  }
860 
861  static int numberOfBands()
862  {
863  return 1;
864  }
865 };
866 
867 template <>
868 struct HDF5TypeTraits<const char*>
869 {
870  static hid_t getH5DataType()
871  {
872  hid_t stringtype = H5Tcopy (H5T_C_S1);
873  H5Tset_size(stringtype, H5T_VARIABLE);
874  return stringtype;
875  }
876 
877  static int numberOfBands()
878  {
879  return 1;
880  }
881 };
882 
883 #undef VIGRA_H5_DATATYPE
884 
885 #if 0
886 template<>
887 inline hid_t getH5DataType<FFTWComplex<float> >()
888 {
889  hid_t complex_id = H5Tcreate (H5T_COMPOUND, sizeof (FFTWComplex<float>));
890  H5Tinsert (complex_id, "real", 0, H5T_NATIVE_FLOAT);
891  H5Tinsert (complex_id, "imaginary", sizeof(float), H5T_NATIVE_FLOAT);
892  return complex_id;
893 }
894 
895 template<>
896 inline hid_t getH5DataType<FFTWComplex<double> >()
897 {
898  hid_t complex_id = H5Tcreate (H5T_COMPOUND, sizeof (FFTWComplex<double>));
899  H5Tinsert (complex_id, "real", 0, H5T_NATIVE_DOUBLE);
900  H5Tinsert (complex_id, "imaginary", sizeof(double), H5T_NATIVE_DOUBLE);
901  return complex_id;
902 }
903 #endif
904 
905 
906 } // namespace detail
907 
908 // helper friend function for callback HDF5_ls_inserter_callback()
909 void HDF5_ls_insert(void*, const std::string &);
910 // callback function for ls(), called via HDF5File::H5Literate()
911 // see http://www.parashift.com/c++-faq-lite/pointers-to-members.html#faq-33.2
912 // for as to why.
913 
914 VIGRA_EXPORT H5O_type_t HDF5_get_type(hid_t, const char*);
915 extern "C" VIGRA_EXPORT herr_t HDF5_ls_inserter_callback(hid_t, const char*, const H5L_info_t*, void*);
916 extern "C" VIGRA_EXPORT herr_t HDF5_listAttributes_inserter_callback(hid_t, const char*, const H5A_info_t*, void*);
917 
918 /********************************************************/
919 /* */
920 /* HDF5File */
921 /* */
922 /********************************************************/
923 
924 
925 /** \brief Access to HDF5 files
926 
927 HDF5File provides a convenient way of accessing data in HDF5 files. vigra::MultiArray
928 structures of any dimension can be stored to / loaded from HDF5 files. Typical
929 HDF5 features like subvolume access, chunks and data compression are available,
930 string attributes can be attached to any dataset or group. Group- or dataset-handles
931 are encapsulated in the class and managed automatically. The internal file-system like
932 structure can be accessed by functions like "cd()" or "mkdir()".
933 
934 Note that the memory order between VIGRA and HDF5 files differs: VIGRA uses
935 Fortran-order, while HDF5 uses C-order. This means that a VIGRA MultiArray,
936 whose indices represent the 'x'-, 'y'-, and 'z'-axis in that order, is reversed
937 upon writing to an HDF5 file, i.e. in the file the axis order is 'z', 'y', 'x'.
938 Likewise, the order is reversed upon reading.
939 
940 <b>Example:</b>
941 Write the MultiArray out_multi_array to file. Change the current directory to
942 "/group" and read in the same MultiArray as in_multi_array.
943 \code
944 HDF5File file("/path/to/file",HDF5File::New);
945 file.mkdir("group");
946 file.write("/group/dataset", out_multi_array);
947 
948 file.cd("/group");
949 file.read("dataset", in_multi_array);
950 
951 \endcode
952 
953 <b>\#include</b> <vigra/hdf5impex.hxx><br>
954 Namespace: vigra
955 */
956 class HDF5File
957 {
958  protected:
959  HDF5HandleShared fileHandle_;
960 
961  // current group handle
962  HDF5Handle cGroupHandle_;
963 
964  private:
965  // time tagging of datasets, turned off (= 0) by default.
966  int track_time;
967 
968  bool read_only_;
969 
970  // helper classes for ls() and listAttributes()
971  struct ls_closure
972  {
973  virtual void insert(const std::string &) = 0;
974  virtual ~ls_closure() {}
975  };
976 
977  // datastructure to hold a std::vector<std::string>
978  struct lsOpData : public ls_closure
979  {
980  std::vector<std::string> & objects;
981  lsOpData(std::vector<std::string> & o) : objects(o) {}
982  void insert(const std::string & x)
983  {
984  objects.push_back(x);
985  }
986  };
987 
988  // datastructure to hold an associative container
989  template<class Container>
990  struct ls_container_data : public ls_closure
991  {
992  Container & objects;
993  ls_container_data(Container & o) : objects(o) {}
994  void insert(const std::string & x)
995  {
996  objects.insert(std::string(x));
997  }
998  };
999 
1000  public:
1001 
1002  // helper for callback HDF5_ls_inserter_callback(), used by ls()
1003  friend void HDF5_ls_insert(void*, const std::string &);
1004 
1005  /** \brief Set how a file is opened.
1006 
1007  OpenMode::New creates a new file. If the file already exists, it is overwritten.
1008 
1009  OpenMode::ReadWrite opens a file for reading/writing. The file will be created if it doesn't exist.
1010 
1011  OpenMode::ReadOnly opens a file for reading. The file as well as any dataset to be accessed must already exist.
1012  */
1013  enum OpenMode {
1014  New, // Create new empty file (existing file will be deleted).
1015  Open, // Open file. Create if not existing.
1016  ReadWrite = Open, // Alias for Open.
1017  OpenReadOnly, // Open file in read-only mode.
1018  ReadOnly = OpenReadOnly, // Alias for OpenReadOnly
1019  Replace, // for ChunkedArrayHDF5: replace dataset if it exists, create otherwise
1020  Default // for ChunkedArrayHDF5: use New if file doesn't exist,
1021  // ReadOnly if file and dataset exist
1022  // Open otherwise
1023  };
1024 
1025  /** \brief Default constructor.
1026 
1027  A file can later be opened via the open() function. Time tagging of datasets is disabled.
1028  */
1030  : track_time(0)
1031  {}
1032 
1033  /** \brief Construct with time tagging of datasets enabled.
1034 
1035  If \a track_creation_times is 'true', time tagging of datasets will be enabled.
1036  */
1037  explicit HDF5File(bool track_creation_times)
1038  : track_time(track_creation_times ? 1 : 0),
1039  read_only_(true)
1040  {}
1041 
1042  /** \brief Open or create an HDF5File object.
1043 
1044  Creates or opens HDF5 file with given filename.
1045  The current group is set to "/".
1046 
1047  Note that the HDF5File class is not copyable (the copy constructor is
1048  private to enforce this).
1049  */
1050  HDF5File(std::string filePath, OpenMode mode, bool track_creation_times = false)
1051  : track_time(track_creation_times ? 1 : 0)
1052  {
1053  open(filePath, mode);
1054  }
1055 
1056  /** \brief Initialize an HDF5File object from HDF5 file handle
1057 
1058  Initializes an HDF5File object corresponding to the HDF5 file
1059  opened elsewhere. If \a fileHandle is constructed with a
1060  <tt>NULL</tt> destructor, ownership is not transferred
1061  to the new HDF5File object, and you must ensure that the file is
1062  not closed while the new HDF5File object is in use. Otherwise,
1063  ownership will be shared.
1064 
1065  The current group is set to the specified \a pathname. If
1066  \a read_only is 'true', you cannot create new datasets or
1067  overwrite data.
1068 
1069  \warning In case the underlying HDF5 library used by Vigra is not
1070  exactly the same library used to open the file with the given id,
1071  this method will lead to crashes.
1072  */
1073  explicit HDF5File(HDF5HandleShared const & fileHandle,
1074  const std::string & pathname = "",
1075  bool read_only = false)
1076  : fileHandle_(fileHandle),
1077  read_only_(read_only)
1078 
1079  {
1080  // get group handle for given pathname
1081  // calling openCreateGroup_ without setting a valid cGroupHandle does
1082  // not work. Starting from root() is a safe bet.
1083  root();
1084  cGroupHandle_ = HDF5Handle(openCreateGroup_(pathname), &H5Gclose,
1085  "HDF5File(fileHandle, pathname): Failed to open group");
1086 
1087  // extract track_time attribute
1088  hbool_t track_times_tmp;
1089  HDF5Handle plist_id(H5Fget_create_plist(fileHandle_), &H5Pclose,
1090  "HDF5File(fileHandle, pathname): Failed to open file creation property list");
1091  herr_t status = H5Pget_obj_track_times(plist_id, &track_times_tmp );
1092  vigra_postcondition(status >= 0,
1093  "HDF5File(fileHandle, pathname): cannot access track time attribute");
1094  track_time = track_times_tmp;
1095  }
1096 
1097  /** \brief Copy a HDF5File object.
1098 
1099  The new object will refer to the same file and group as \a other.
1100  */
1101  HDF5File(HDF5File const & other)
1102  : fileHandle_(other.fileHandle_),
1103  track_time(other.track_time),
1104  read_only_(other.read_only_)
1105  {
1106  cGroupHandle_ = HDF5Handle(openCreateGroup_(other.currentGroupName_()), &H5Gclose,
1107  "HDF5File(HDF5File const &): Failed to open group.");
1108  }
1109 
1110  /** \brief The destructor flushes and closes the file.
1111  */
1113  {
1114  // The members fileHandle_ and cGroupHandle_ are automatically closed
1115  // as they are of type HDF5Handle and are properly initialised.
1116  // The closing of fileHandle_ implies flushing the file to
1117  // the operating system, see
1118  // http://www.hdfgroup.org/HDF5/doc/RM/RM_H5F.html#File-Close .
1119  }
1120 
1121  /** \brief Assign a HDF5File object.
1122 
1123  Calls close() on the present file and The new object will refer to the same file and group as \a other.
1124  */
1125  HDF5File & operator=(HDF5File const & other)
1126  {
1127  if(this != &other)
1128  {
1129  close();
1130  fileHandle_ = other.fileHandle_;
1131  cGroupHandle_ = HDF5Handle(openCreateGroup_(other.currentGroupName_()), &H5Gclose,
1132  "HDF5File::operator=(): Failed to open group.");
1133  track_time = other.track_time;
1134  read_only_ = other.read_only_;
1135  }
1136  return *this;
1137  }
1138 
1139  int file_use_count() const
1140  {
1141  return fileHandle_.use_count();
1142  }
1143 
1144  bool isOpen() const
1145  {
1146  return fileHandle_ != 0;
1147  }
1148 
1149  bool isReadOnly() const
1150  {
1151  return read_only_;
1152  }
1153 
1154  void setReadOnly(bool stat=true)
1155  {
1156  read_only_ = stat;
1157  }
1158 
1159  /** \brief Open or create the given file in the given mode and set the group to "/".
1160  If another file is currently open, it is first closed.
1161  */
1162  void open(std::string filePath, OpenMode mode)
1163  {
1164  close();
1165 
1166  std::string errorMessage = "HDF5File.open(): Could not open or create file '" + filePath + "'.";
1167  fileHandle_ = HDF5HandleShared(createFile_(filePath, mode), &H5Fclose, errorMessage.c_str());
1168  cGroupHandle_ = HDF5Handle(openCreateGroup_("/"), &H5Gclose, "HDF5File.open(): Failed to open root group.");
1169  setReadOnly(mode == OpenReadOnly);
1170  }
1171 
1172  /** \brief Close the current file.
1173  */
1174  void close()
1175  {
1176  bool success = cGroupHandle_.close() >= 0 && fileHandle_.close() >= 0;
1177  vigra_postcondition(success, "HDF5File.close() failed.");
1178  }
1179 
1180  /** \brief Change current group to "/".
1181  */
1182  inline void root()
1183  {
1184  std::string message = "HDF5File::root(): Could not open group '/'.";
1185  cGroupHandle_ = HDF5Handle(H5Gopen(fileHandle_, "/", H5P_DEFAULT),&H5Gclose,message.c_str());
1186  }
1187 
1188  /** \brief Change the current group.
1189  Both absolute and relative group names are allowed.
1190  */
1191  inline void cd(std::string groupName)
1192  {
1193  cGroupHandle_ = getGroupHandle(groupName, "HDF5File::cd()");
1194  }
1195 
1196  /** \brief Change the current group to its parent group.
1197  Returns true if successful, false otherwise. If unsuccessful,
1198  the group will not change.
1199  */
1200  inline bool cd_up()
1201  {
1202  std::string groupName = currentGroupName_();
1203 
1204  //do not try to move up if we already in "/"
1205  if(groupName == "/"){
1206  return false;
1207  }
1208 
1209  size_t lastSlash = groupName.find_last_of('/');
1210 
1211  std::string parentGroup (groupName.begin(), groupName.begin()+lastSlash+1);
1212 
1213  cd(parentGroup);
1214 
1215  return true;
1216  }
1217 
1218  /** \brief Change the current group to its parent group.
1219  Returns true if successful, false otherwise. If unsuccessful,
1220  the group will not change.
1221  */
1222  inline bool cd_up(int levels)
1223  {
1224  std::string groupName = currentGroupName_();
1225 
1226  for(int i = 0; i<levels; i++)
1227  {
1228  if(!cd_up())
1229  {
1230  // restore old group if neccessary
1231  if(groupName != currentGroupName_())
1232  cd(groupName);
1233  return false;
1234  }
1235  }
1236  return true;
1237  }
1238 
1239  /** \brief Create a new group.
1240  If the first character is a "/", the path will be interpreted as absolute path,
1241  otherwise it will be interpreted as path relative to the current group.
1242  */
1243  inline void mkdir(std::string groupName)
1244  {
1245  vigra_precondition(!isReadOnly(),
1246  "HDF5File::mkdir(): file is read-only.");
1247 
1248  std::string message = "HDF5File::mkdir(): Could not create group '" + groupName + "'.\n";
1249 
1250  // make groupName clean
1251  groupName = get_absolute_path(groupName);
1252 
1253  HDF5Handle(openCreateGroup_(groupName.c_str()),&H5Gclose,message.c_str());
1254  }
1255 
1256  /** \brief Change the current group; create it if necessary.
1257  If the first character is a "/", the path will be interpreted as absolute path,
1258  otherwise it will be interpreted as path relative to the current group.
1259  */
1260  inline void cd_mk(std::string groupName)
1261  {
1262  vigra_precondition(!isReadOnly(),
1263  "HDF5File::cd_mk(): file is read-only.");
1264 
1265  std::string message = "HDF5File::cd_mk(): Could not create group '" + groupName + "'.";
1266 
1267  // make groupName clean
1268  groupName = get_absolute_path(groupName);
1269 
1270  cGroupHandle_ = HDF5Handle(openCreateGroup_(groupName.c_str()),&H5Gclose,message.c_str());
1271  }
1272 
1273  // helper function for the various ls() variants.
1274  void ls_H5Literate(ls_closure & data) const
1275  {
1276  H5Literate(cGroupHandle_, H5_INDEX_NAME, H5_ITER_NATIVE, NULL,
1277  HDF5_ls_inserter_callback, static_cast<void*>(&data));
1278  }
1279 
1280  /** \brief List the contents of the current group.
1281  The function returns a vector of strings holding the entries of the
1282  current group. Only datasets and groups are listed, other objects
1283  (e.g. datatypes) are ignored. Group names always have a trailing "/".
1284  */
1285  inline std::vector<std::string> ls() const
1286  {
1287  std::vector<std::string> list;
1288  lsOpData data(list);
1289  ls_H5Literate(data);
1290  return list;
1291  }
1292 
1293  /** \brief List the contents of the current group into a container-like
1294  object via insert().
1295 
1296  Only datasets and groups are inserted, other objects (e.g., datatypes) are ignored.
1297  Group names always have a trailing "/".
1298 
1299  The argument cont is presumably an associative container, however,
1300  only its member function <tt>cont.insert(std::string)</tt> will be
1301  called.
1302  \param cont reference to a container supplying a member function
1303  <tt>insert(const i_type &)</tt>, where <tt>i_type</tt>
1304  is convertible to <tt>std::string</tt>.
1305  */
1306  template<class Container>
1307  void ls(Container & cont) const
1308  {
1309  ls_container_data<Container> data(cont);
1310  ls_H5Literate(data);
1311  }
1312 
1313  /** \brief Get the path of the current group.
1314  */
1315  inline std::string pwd() const
1316  {
1317  return currentGroupName_();
1318  }
1319 
1320  /** \brief Get the name of the associated file.
1321  */
1322  inline std::string filename() const
1323  {
1324  return fileName_();
1325  }
1326 
1327  /** \brief Check if given datasetName exists.
1328  */
1329  inline bool existsDataset(std::string datasetName) const
1330  {
1331  // make datasetName clean
1332  datasetName = get_absolute_path(datasetName);
1333  return (H5Lexists(fileHandle_, datasetName.c_str(), H5P_DEFAULT) > 0);
1334  }
1335 
1336  /** \brief Get the number of dimensions of a certain dataset
1337  If the first character is a "/", the path will be interpreted as absolute path,
1338  otherwise it will be interpreted as path relative to the current group.
1339  */
1340  hssize_t getDatasetDimensions(std::string datasetName) const
1341  {
1342  HDF5Handle datasetHandle = getDatasetHandle(datasetName);
1343 
1344  return getDatasetDimensions_(datasetHandle);
1345  }
1346 
1347  hssize_t getDatasetDimensions_(hid_t dataset) const
1348  {
1349  std::string errorMessage = "HDF5File::getDatasetDimensions(): Unable to access dataspace.";
1350  HDF5Handle dataspaceHandle(H5Dget_space(dataset), &H5Sclose, errorMessage.c_str());
1351 
1352  //return dimension information
1353  return H5Sget_simple_extent_ndims(dataspaceHandle);
1354  }
1355 
1356  /** \brief Get the shape of each dimension of a certain dataset.
1357 
1358  Normally, this function is called after determining the dimension of the
1359  dataset using \ref getDatasetDimensions().
1360  If the first character is a "/", the path will be interpreted as absolute path,
1361  otherwise it will be interpreted as path relative to the current group.
1362 
1363  Note that the memory order between VIGRA and HDF5 files differs: VIGRA uses
1364  Fortran-order, while HDF5 uses C-order. This function therefore reverses the axis
1365  order relative to the file contents. That is, when the axes in the file are
1366  ordered as 'z', 'y', 'x', this function will return the shape in the order
1367  'x', 'y', 'z'.
1368  */
1369  ArrayVector<hsize_t> getDatasetShape(std::string datasetName) const
1370  {
1371  // make datasetName clean
1372  datasetName = get_absolute_path(datasetName);
1373 
1374  //Open dataset and dataspace
1375  std::string errorMessage = "HDF5File::getDatasetShape(): Unable to open dataset '" + datasetName + "'.";
1376  HDF5Handle datasetHandle = HDF5Handle(getDatasetHandle_(datasetName), &H5Dclose, errorMessage.c_str());
1377 
1378  errorMessage = "HDF5File::getDatasetShape(): Unable to access dataspace.";
1379  HDF5Handle dataspaceHandle(H5Dget_space(datasetHandle), &H5Sclose, errorMessage.c_str());
1380 
1381  //get dimension information
1382  ArrayVector<hsize_t>::size_type dimensions = H5Sget_simple_extent_ndims(dataspaceHandle);
1383 
1384  ArrayVector<hsize_t> shape(dimensions);
1385  ArrayVector<hsize_t> maxdims(dimensions);
1386  H5Sget_simple_extent_dims(dataspaceHandle, shape.data(), maxdims.data());
1387 
1388  // invert the dimensions to guarantee VIGRA-compatible order.
1389  std::reverse(shape.begin(), shape.end());
1390  return shape;
1391  }
1392 
1393  /** Query the pixel type of the dataset.
1394 
1395  Possible values are:
1396  <DL>
1397  <DT>"INT8"<DD> 8-bit signed integer (unsigned char)
1398  <DT>"UINT8"<DD> 8-bit unsigned integer (unsigned char)
1399  <DT>"INT16"<DD> 16-bit signed integer (short)
1400  <DT>"UINT16"<DD> 16-bit unsigned integer (unsigned short)
1401  <DT>"INT32"<DD> 32-bit signed integer (long)
1402  <DT>"UINT32"<DD> 32-bit unsigned integer (unsigned long)
1403  <DT>"INT64"<DD> 64-bit signed integer (long long)
1404  <DT>"UINT64"<DD> 64-bit unsigned integer (unsigned long long)
1405  <DT>"FLOAT"<DD> 32-bit floating point (float)
1406  <DT>"DOUBLE"<DD> 64-bit floating point (double)
1407  <DT>"UNKNOWN"<DD> any other type
1408  </DL>
1409  */
1410  std::string getDatasetType(std::string const & datasetName) const
1411  {
1412  HDF5Handle datasetHandle = getDatasetHandle(datasetName);
1413 
1414  hid_t datatype = H5Dget_type(datasetHandle);
1415  H5T_class_t dataclass = H5Tget_class(datatype);
1416  size_t datasize = H5Tget_size(datatype);
1417  H5T_sign_t datasign = H5Tget_sign(datatype);
1418 
1419  if(dataclass == H5T_FLOAT)
1420  {
1421  if(datasize == 4)
1422  return "FLOAT";
1423  else if(datasize == 8)
1424  return "DOUBLE";
1425  }
1426  else if(dataclass == H5T_INTEGER)
1427  {
1428  if(datasign == H5T_SGN_NONE)
1429  {
1430  if(datasize == 1)
1431  return "UINT8";
1432  else if(datasize == 2)
1433  return "UINT16";
1434  else if(datasize == 4)
1435  return "UINT32";
1436  else if(datasize == 8)
1437  return "UINT64";
1438  }
1439  else
1440  {
1441  if(datasize == 1)
1442  return "INT8";
1443  else if(datasize == 2)
1444  return "INT16";
1445  else if(datasize == 4)
1446  return "INT32";
1447  else if(datasize == 8)
1448  return "INT64";
1449  }
1450  }
1451  return "UNKNOWN";
1452  }
1453 
1454  /** \brief Obtain the HDF5 handle of a dataset.
1455  */
1456  HDF5Handle getDatasetHandle(std::string const & datasetName) const
1457  {
1458  std::string errorMessage = "HDF5File::getDatasetHandle(): Unable to open dataset '" + datasetName + "'.";
1459  return HDF5Handle(getDatasetHandle_(get_absolute_path(datasetName)), &H5Dclose, errorMessage.c_str());
1460  }
1461 
1462  /** \brief Obtain a shared HDF5 handle of a dataset.
1463  */
1464  HDF5HandleShared getDatasetHandleShared(std::string const & datasetName) const
1465  {
1466  std::string errorMessage = "HDF5File::getDatasetHandle(): Unable to open dataset '" + datasetName + "'.";
1467  return HDF5HandleShared(getDatasetHandle_(get_absolute_path(datasetName)), &H5Dclose, errorMessage.c_str());
1468  }
1469 
1470  /** \brief Obtain the HDF5 handle of a group (create the group if it doesn't exist).
1471  */
1472  HDF5Handle getGroupHandle(std::string group_name,
1473  std::string function_name = "HDF5File::getGroupHandle()")
1474  {
1475  std::string errorMessage = function_name + ": Group '" + group_name + "' not found.";
1476 
1477  // make group_name clean
1478  group_name = get_absolute_path(group_name);
1479 
1480  // group must exist
1481  vigra_precondition(group_name == "/" || H5Lexists(fileHandle_, group_name.c_str(), H5P_DEFAULT) != 0,
1482  errorMessage.c_str());
1483 
1484  // open group and return group handle
1485  return HDF5Handle(openCreateGroup_(group_name), &H5Gclose, "Internal error");
1486  }
1487 
1488  // helper function for the various listAttributes() variants.
1489  void ls_H5Aiterate(std::string const & group_or_dataset, ls_closure & data) const
1490  {
1491  H5O_type_t h5_type = get_object_type_(group_or_dataset);
1492  vigra_precondition(h5_type == H5O_TYPE_GROUP || h5_type == H5O_TYPE_DATASET,
1493  "HDF5File::listAttributes(): object \"" + group_or_dataset + "\" is neither a group nor a dataset.");
1494  // get object handle
1495  HDF5Handle object_handle(h5_type == H5O_TYPE_GROUP
1496  ? const_cast<HDF5File*>(this)->openCreateGroup_(group_or_dataset)
1497  : getDatasetHandle_(group_or_dataset),
1498  h5_type == H5O_TYPE_GROUP
1499  ? &H5Gclose
1500  : &H5Dclose,
1501  "HDF5File::listAttributes(): unable to open object.");
1502  hsize_t n = 0;
1503  H5Aiterate2(object_handle, H5_INDEX_NAME, H5_ITER_NATIVE, &n,
1504  HDF5_listAttributes_inserter_callback, static_cast<void*>(&data));
1505  }
1506 
1507  /** \brief List the attribute names of the given group or dataset.
1508 
1509  If \a group_or_dataset is empty or <tt>"."</tt> (a dot), the command
1510  refers to the current group of this file object.
1511  */
1512  inline std::vector<std::string> listAttributes(std::string const & group_or_dataset) const
1513  {
1514  std::vector<std::string> list;
1515  lsOpData data(list);
1516  ls_H5Aiterate(group_or_dataset, data);
1517  return list;
1518  }
1519 
1520  /** \brief Insert the attribute names of the given group or dataset into the given
1521  \a container by calling <tt>container.insert(std::string)</tt>.
1522 
1523  If \a group_or_dataset is empty or <tt>"."</tt> (a dot), the command
1524  refers to the current group of this file object.
1525  */
1526  template<class Container>
1527  void listAttributes(std::string const & group_or_dataset, Container & container) const
1528  {
1529  ls_container_data<Container> data(container);
1530  ls_H5Aiterate(group_or_dataset, data);
1531  }
1532 
1533  /** \brief Obtain the HDF5 handle of a attribute.
1534  */
1535  HDF5Handle getAttributeHandle(std::string dataset_name, std::string attribute_name) const
1536  {
1537  std::string message = "HDF5File::getAttributeHandle(): Attribute '" + attribute_name + "' not found.";
1538  return HDF5Handle(H5Aopen(getDatasetHandle(dataset_name), attribute_name.c_str(), H5P_DEFAULT),
1539  &H5Aclose, message.c_str());
1540  }
1541 
1542  /* Writing Attributes */
1543 
1544  /** \brief Write MultiArray Attributes.
1545  * In contrast to datasets, subarray access, chunks and compression are not available.
1546  */
1547  template<unsigned int N, class T, class Stride>
1548  inline void writeAttribute(std::string object_name,
1549  std::string attribute_name,
1550  const MultiArrayView<N, T, Stride> & array)
1551  {
1552  // make object_name clean
1553  object_name = get_absolute_path(object_name);
1554 
1555  write_attribute_(object_name, attribute_name, array, detail::getH5DataType<T>(), 1);
1556  }
1557 
1558  template<unsigned int N, class T, int SIZE, class Stride>
1559  inline void writeAttribute(std::string datasetName,
1560  std::string attributeName,
1561  const MultiArrayView<N, TinyVector<T, SIZE>, Stride> & array)
1562  {
1563  // make datasetName clean
1564  datasetName = get_absolute_path(datasetName);
1565 
1566  write_attribute_(datasetName, attributeName, array, detail::getH5DataType<T>(), SIZE);
1567  }
1568 
1569  template<unsigned int N, class T, class Stride>
1570  inline void writeAttribute(std::string datasetName,
1571  std::string attributeName,
1572  const MultiArrayView<N, RGBValue<T>, Stride> & array)
1573  {
1574  // make datasetName clean
1575  datasetName = get_absolute_path(datasetName);
1576 
1577  write_attribute_(datasetName, attributeName, array, detail::getH5DataType<T>(), 3);
1578  }
1579 
1580  /** \brief Write a single value.
1581  Specialization of the write function for simple datatypes
1582  */
1583  inline void writeAttribute(std::string object_name, std::string attribute_name, char data)
1584  { writeAtomicAttribute(object_name,attribute_name,data); }
1585  inline void writeAttribute(std::string datasetName, std::string attributeName, signed char data)
1586  { writeAtomicAttribute(datasetName,attributeName,data); }
1587  inline void writeAttribute(std::string datasetName, std::string attributeName, signed short data)
1588  { writeAtomicAttribute(datasetName,attributeName,data); }
1589  inline void writeAttribute(std::string datasetName, std::string attributeName, signed int data)
1590  { writeAtomicAttribute(datasetName,attributeName,data); }
1591  inline void writeAttribute(std::string datasetName, std::string attributeName, signed long data)
1592  { writeAtomicAttribute(datasetName,attributeName,data); }
1593  inline void writeAttribute(std::string datasetName, std::string attributeName, signed long long data)
1594  { writeAtomicAttribute(datasetName,attributeName,data); }
1595  inline void writeAttribute(std::string datasetName, std::string attributeName, unsigned char data)
1596  { writeAtomicAttribute(datasetName,attributeName,data); }
1597  inline void writeAttribute(std::string datasetName, std::string attributeName, unsigned short data)
1598  { writeAtomicAttribute(datasetName,attributeName,data); }
1599  inline void writeAttribute(std::string datasetName, std::string attributeName, unsigned int data)
1600  { writeAtomicAttribute(datasetName,attributeName,data); }
1601  inline void writeAttribute(std::string datasetName, std::string attributeName, unsigned long data)
1602  { writeAtomicAttribute(datasetName,attributeName,data); }
1603  inline void writeAttribute(std::string datasetName, std::string attributeName, unsigned long long data)
1604  { writeAtomicAttribute(datasetName,attributeName,data); }
1605  inline void writeAttribute(std::string datasetName, std::string attributeName, float data)
1606  { writeAtomicAttribute(datasetName,attributeName,data); }
1607  inline void writeAttribute(std::string datasetName, std::string attributeName, double data)
1608  { writeAtomicAttribute(datasetName,attributeName,data); }
1609  inline void writeAttribute(std::string datasetName, std::string attributeName, long double data)
1610  { writeAtomicAttribute(datasetName,attributeName,data); }
1611  inline void writeAttribute(std::string datasetName, std::string attributeName, const char* data)
1612  { writeAtomicAttribute(datasetName,attributeName,data); }
1613  inline void writeAttribute(std::string datasetName, std::string attributeName, std::string const & data)
1614  { writeAtomicAttribute(datasetName,attributeName,data.c_str()); }
1615 
1616  /** \brief Test if attribute exists.
1617  */
1618  bool existsAttribute(std::string object_name, std::string attribute_name)
1619  {
1620  std::string obj_path = get_absolute_path(object_name);
1621  htri_t exists = H5Aexists_by_name(fileHandle_, obj_path.c_str(),
1622  attribute_name.c_str(), H5P_DEFAULT);
1623  vigra_precondition(exists >= 0, "HDF5File::existsAttribute(): "
1624  "object '" + object_name + "' "
1625  "not found.");
1626  return exists != 0;
1627  }
1628 
1629  // Reading Attributes
1630 
1631  /** \brief Read MultiArray Attributes.
1632  * In contrast to datasets, subarray access is not available.
1633  */
1634  template<unsigned int N, class T, class Stride>
1635  inline void readAttribute(std::string object_name,
1636  std::string attribute_name,
1638  {
1639  // make object_name clean
1640  object_name = get_absolute_path(object_name);
1641 
1642  read_attribute_(object_name, attribute_name, array, detail::getH5DataType<T>(), 1);
1643  }
1644 
1645  template<unsigned int N, class T, int SIZE, class Stride>
1646  inline void readAttribute(std::string datasetName,
1647  std::string attributeName,
1648  MultiArrayView<N, TinyVector<T, SIZE>, Stride> array)
1649  {
1650  // make datasetName clean
1651  datasetName = get_absolute_path(datasetName);
1652 
1653  read_attribute_(datasetName, attributeName, array, detail::getH5DataType<T>(), SIZE);
1654  }
1655 
1656  template<unsigned int N, class T, class Stride>
1657  inline void readAttribute(std::string datasetName,
1658  std::string attributeName,
1659  MultiArrayView<N, RGBValue<T>, Stride> array)
1660  {
1661  // make datasetName clean
1662  datasetName = get_absolute_path(datasetName);
1663 
1664  read_attribute_(datasetName, attributeName, array, detail::getH5DataType<T>(), 3);
1665  }
1666 
1667  /** \brief Read a single value.
1668  Specialization of the read function for simple datatypes
1669  */
1670  inline void readAttribute(std::string object_name, std::string attribute_name, char &data)
1671  { readAtomicAttribute(object_name,attribute_name,data); }
1672  inline void readAttribute(std::string datasetName, std::string attributeName, signed char &data)
1673  { readAtomicAttribute(datasetName,attributeName,data); }
1674  inline void readAttribute(std::string datasetName, std::string attributeName, signed short &data)
1675  { readAtomicAttribute(datasetName,attributeName,data); }
1676  inline void readAttribute(std::string datasetName, std::string attributeName, signed int &data)
1677  { readAtomicAttribute(datasetName,attributeName,data); }
1678  inline void readAttribute(std::string datasetName, std::string attributeName, signed long &data)
1679  { readAtomicAttribute(datasetName,attributeName,data); }
1680  inline void readAttribute(std::string datasetName, std::string attributeName, signed long long &data)
1681  { readAtomicAttribute(datasetName,attributeName,data); }
1682  inline void readAttribute(std::string datasetName, std::string attributeName, unsigned char &data)
1683  { readAtomicAttribute(datasetName,attributeName,data); }
1684  inline void readAttribute(std::string datasetName, std::string attributeName, unsigned short &data)
1685  { readAtomicAttribute(datasetName,attributeName,data); }
1686  inline void readAttribute(std::string datasetName, std::string attributeName, unsigned int &data)
1687  { readAtomicAttribute(datasetName,attributeName,data); }
1688  inline void readAttribute(std::string datasetName, std::string attributeName, unsigned long &data)
1689  { readAtomicAttribute(datasetName,attributeName,data); }
1690  inline void readAttribute(std::string datasetName, std::string attributeName, unsigned long long &data)
1691  { readAtomicAttribute(datasetName,attributeName,data); }
1692  inline void readAttribute(std::string datasetName, std::string attributeName, float &data)
1693  { readAtomicAttribute(datasetName,attributeName,data); }
1694  inline void readAttribute(std::string datasetName, std::string attributeName, double &data)
1695  { readAtomicAttribute(datasetName,attributeName,data); }
1696  inline void readAttribute(std::string datasetName, std::string attributeName, long double &data)
1697  { readAtomicAttribute(datasetName,attributeName,data); }
1698  inline void readAttribute(std::string datasetName, std::string attributeName, std::string &data)
1699  { readAtomicAttribute(datasetName,attributeName,data); }
1700 
1701  // Writing data
1702 
1703  /** \brief Write multi arrays.
1704 
1705  Chunks can be activated by setting
1706  \code iChunkSize = size; //size > 0
1707  \endcode .
1708  The chunks will be hypercubes with edge length size. When <tt>iChunkSize == 0</tt>
1709  (default), the behavior depends on the <tt>compression</tt> setting: If no
1710  compression is requested, the data is written without chunking. Otherwise,
1711  chuning is required, and the chunk size is automatically selected such that
1712  each chunk contains about 300k pixels.
1713 
1714  Compression can be activated by setting
1715  \code compression = parameter; // 0 < parameter <= 9
1716  \endcode
1717  where 0 stands for no compression and 9 for maximum compression.
1718 
1719  If the first character of datasetName is a "/", the path will be interpreted as absolute path,
1720  otherwise it will be interpreted as path relative to the current group.
1721 
1722  Note that the memory order between VIGRA and HDF5 files differs: VIGRA uses
1723  Fortran-order, while HDF5 uses C-order. This means that a VIGRA MultiArray,
1724  whose indices represent the 'x'-, 'y'-, and 'z'-axis in that order, is reversed
1725  upon writing to an HDF5 file, i.e. in the file the axis order is 'z', 'y', 'x'.
1726  */
1727  template<unsigned int N, class T, class Stride>
1728  inline void write(std::string datasetName,
1729  const MultiArrayView<N, T, Stride> & array,
1730  int iChunkSize = 0, int compression = 0)
1731  {
1732  // make datasetName clean
1733  datasetName = get_absolute_path(datasetName);
1734 
1735  typename MultiArrayShape<N>::type chunkSize;
1736  for(unsigned int i = 0; i < N; i++){
1737  chunkSize[i] = iChunkSize;
1738  }
1739  write_(datasetName, array, detail::getH5DataType<T>(), 1, chunkSize, compression);
1740  }
1741 
1742  /** \brief Write multi arrays.
1743  Chunks can be activated by providing a MultiArrayShape as chunkSize.
1744  chunkSize must have equal dimension as array.
1745 
1746  Compression can be activated by setting
1747  \code compression = parameter; // 0 < parameter <= 9
1748  \endcode
1749  where 0 stands for no compression and 9 for maximum compression.
1750 
1751  If the first character of datasetName is a "/", the path will be interpreted as absolute path,
1752  otherwise it will be interpreted as path relative to the current group.
1753 
1754  Note that the memory order between VIGRA and HDF5 files differs: VIGRA uses
1755  Fortran-order, while HDF5 uses C-order. This means that a VIGRA MultiArray,
1756  whose indices represent the 'x'-, 'y'-, and 'z'-axis in that order, is reversed
1757  upon writing to an HDF5 file, i.e. in the file the axis order is 'z', 'y', 'x'.
1758  */
1759  template<unsigned int N, class T, class Stride>
1760  inline void write(std::string datasetName,
1761  const MultiArrayView<N, T, Stride> & array,
1762  typename MultiArrayShape<N>::type chunkSize, int compression = 0)
1763  {
1764  // make datasetName clean
1765  datasetName = get_absolute_path(datasetName);
1766 
1767  write_(datasetName, array, detail::getH5DataType<T>(), 1, chunkSize, compression);
1768  }
1769 
1770  /** \brief Write a multi array into a larger volume.
1771  blockOffset determines the position, where array is written.
1772 
1773  If the first character of datasetName is a "/", the path will be interpreted as absolute path,
1774  otherwise it will be interpreted as path relative to the current group.
1775 
1776  Note that the memory order between VIGRA and HDF5 files differs: VIGRA uses
1777  Fortran-order, while HDF5 uses C-order. This means that a VIGRA MultiArray,
1778  whose indices represent the 'x'-, 'y'-, and 'z'-axis in that order, is reversed
1779  upon writing to an HDF5 file, i.e. in the file the axis order is 'z', 'y', 'x'.
1780  */
1781  template<unsigned int N, class T, class Stride>
1782  inline void writeBlock(std::string datasetName,
1783  typename MultiArrayShape<N>::type blockOffset,
1784  const MultiArrayView<N, T, Stride> & array)
1785  {
1786  // make datasetName clean
1787  datasetName = get_absolute_path(datasetName);
1788  typedef detail::HDF5TypeTraits<T> TypeTraits;
1789  writeBlock_(datasetName, blockOffset, array,
1790  TypeTraits::getH5DataType(), TypeTraits::numberOfBands());
1791  }
1792 
1793  template<unsigned int N, class T, class Stride>
1794  inline herr_t writeBlock(HDF5HandleShared dataset,
1795  typename MultiArrayShape<N>::type blockOffset,
1796  const MultiArrayView<N, T, Stride> & array)
1797  {
1798  typedef detail::HDF5TypeTraits<T> TypeTraits;
1799  return writeBlock_(dataset, blockOffset, array,
1800  TypeTraits::getH5DataType(), TypeTraits::numberOfBands());
1801  }
1802 
1803  // non-scalar (TinyVector) and unstrided multi arrays
1804  template<unsigned int N, class T, int SIZE, class Stride>
1805  inline void write(std::string datasetName,
1806  const MultiArrayView<N, TinyVector<T, SIZE>, Stride> & array,
1807  int iChunkSize = 0, int compression = 0)
1808  {
1809  // make datasetName clean
1810  datasetName = get_absolute_path(datasetName);
1811 
1812  typename MultiArrayShape<N>::type chunkSize;
1813  for(int i = 0; i < N; i++){
1814  chunkSize[i] = iChunkSize;
1815  }
1816  write_(datasetName, array, detail::getH5DataType<T>(), SIZE, chunkSize, compression);
1817  }
1818 
1819  template<unsigned int N, class T, int SIZE, class Stride>
1820  inline void write(std::string datasetName,
1821  const MultiArrayView<N, TinyVector<T, SIZE>, Stride> & array,
1822  typename MultiArrayShape<N>::type chunkSize, int compression = 0)
1823  {
1824  // make datasetName clean
1825  datasetName = get_absolute_path(datasetName);
1826 
1827  write_(datasetName, array, detail::getH5DataType<T>(), SIZE, chunkSize, compression);
1828  }
1829 
1830  /** \brief Write array vectors.
1831 
1832  Compression can be activated by setting
1833  \code compression = parameter; // 0 < parameter <= 9
1834  \endcode
1835  where 0 stands for no compression and 9 for maximum compression.
1836 
1837  If the first character of datasetName is a "/", the path will be interpreted as absolute path,
1838  otherwise it will be interpreted as path relative to the current group.
1839  */
1840  template<class T>
1841  void write(const std::string & datasetName,
1842  const ArrayVectorView<T> & array,
1843  int compression = 0)
1844  {
1845  // convert to a (trivial) MultiArrayView and forward.
1846  MultiArrayShape<1>::type shape(static_cast<MultiArrayIndex>(array.size()));
1847  const MultiArrayView<1, T> m_array(shape, const_cast<T*>(array.data()));
1848  write(datasetName, m_array, compression);
1849  }
1850 
1851  // non-scalar (RGBValue) and unstrided multi arrays
1852  template<unsigned int N, class T, class Stride>
1853  inline void write(std::string datasetName,
1854  const MultiArrayView<N, RGBValue<T>, Stride> & array,
1855  int iChunkSize = 0, int compression = 0)
1856  {
1857  // make datasetName clean
1858  datasetName = get_absolute_path(datasetName);
1859 
1860  typename MultiArrayShape<N>::type chunkSize;
1861  for(int i = 0; i < N; i++){
1862  chunkSize[i] = iChunkSize;
1863  }
1864  write_(datasetName, array, detail::getH5DataType<T>(), 3, chunkSize, compression);
1865  }
1866 
1867  template<unsigned int N, class T, class Stride>
1868  inline void write(std::string datasetName,
1869  const MultiArrayView<N, RGBValue<T>, Stride> & array,
1870  typename MultiArrayShape<N>::type chunkSize, int compression = 0)
1871  {
1872  // make datasetName clean
1873  datasetName = get_absolute_path(datasetName);
1874 
1875  write_(datasetName, array, detail::getH5DataType<T>(), 3, chunkSize, compression);
1876  }
1877 
1878  /** \brief Write a single value.
1879  Specialization of the write function for simple datatypes
1880  */
1881  inline void write(std::string datasetName, char data) { writeAtomic(datasetName,data); }
1882  inline void write(std::string datasetName, signed char data) { writeAtomic(datasetName,data); }
1883  inline void write(std::string datasetName, signed short data) { writeAtomic(datasetName,data); }
1884  inline void write(std::string datasetName, signed int data) { writeAtomic(datasetName,data); }
1885  inline void write(std::string datasetName, signed long data) { writeAtomic(datasetName,data); }
1886  inline void write(std::string datasetName, signed long long data) { writeAtomic(datasetName,data); }
1887  inline void write(std::string datasetName, unsigned char data) { writeAtomic(datasetName,data); }
1888  inline void write(std::string datasetName, unsigned short data) { writeAtomic(datasetName,data); }
1889  inline void write(std::string datasetName, unsigned int data) { writeAtomic(datasetName,data); }
1890  inline void write(std::string datasetName, unsigned long data) { writeAtomic(datasetName,data); }
1891  inline void write(std::string datasetName, unsigned long long data) { writeAtomic(datasetName,data); }
1892  inline void write(std::string datasetName, float data) { writeAtomic(datasetName,data); }
1893  inline void write(std::string datasetName, double data) { writeAtomic(datasetName,data); }
1894  inline void write(std::string datasetName, long double data) { writeAtomic(datasetName,data); }
1895  inline void write(std::string datasetName, const char* data) { writeAtomic(datasetName,data); }
1896  inline void write(std::string datasetName, std::string const & data) { writeAtomic(datasetName,data.c_str()); }
1897 
1898  // Reading data
1899 
1900  /** \brief Read data into a multi array.
1901  If the first character of datasetName is a "/", the path will be interpreted as absolute path,
1902  otherwise it will be interpreted as path relative to the current group.
1903 
1904  Note that the memory order between VIGRA and HDF5 files differs: VIGRA uses
1905  Fortran-order, while HDF5 uses C-order. This means that a HDF5 dataset,
1906  whose indices represent the 'z'-, 'y'-, and 'x'-axis in that order, is reversed
1907  upon reading into a MultiArrayView, i.e. in the array axis order must be 'x', 'y', 'z'.
1908  */
1909  template<unsigned int N, class T, class Stride>
1910  inline void read(std::string datasetName, MultiArrayView<N, T, Stride> array)
1911  {
1912  // make datasetName clean
1913  datasetName = get_absolute_path(datasetName);
1914 
1915  read_(datasetName, array, detail::getH5DataType<T>(), 1);
1916  }
1917 
1918  /** \brief Read data into a MultiArray. Resize MultiArray to the correct size.
1919  If the first character of datasetName is a "/", the path will be interpreted as absolute path,
1920  otherwise it will be interpreted as path relative to the current group.
1921 
1922  Note that the memory order between VIGRA and HDF5 files differs: VIGRA uses
1923  Fortran-order, while HDF5 uses C-order. This means that a HDF5 dataset,
1924  whose indices represent the 'z'-, 'y'-, and 'x'-axis in that order, is reversed
1925  upon reading into a MultiArray, i.e. in the array axis order will be 'x', 'y', 'z'.
1926  */
1927  template<unsigned int N, class T, class Alloc>
1928  inline void readAndResize(std::string datasetName, MultiArray<N, T, Alloc> & array)
1929  {
1930  // make datasetName clean
1931  datasetName = get_absolute_path(datasetName);
1932 
1933  // get dataset dimension
1934  ArrayVector<hsize_t> dimshape = getDatasetShape(datasetName);
1935 
1936  // check if dimensions are correct
1937  vigra_precondition(N == MultiArrayIndex(dimshape.size()), // the object in the HDF5 file may have one additional dimension which we then interpret as the pixel type bands
1938  "HDF5File::readAndResize(): Array dimension disagrees with dataset dimension.");
1939 
1940  // reshape target MultiArray
1941  typename MultiArrayShape<N>::type shape;
1942  for(int k=0; k < static_cast<int>(dimshape.size()); ++k)
1943  shape[k] = static_cast<MultiArrayIndex>(dimshape[k]);
1944  array.reshape(shape);
1945 
1946  read_(datasetName, array, detail::getH5DataType<T>(), 1);
1947  }
1948 
1949  /** \brief Read data into an array vector.
1950  If the first character of datasetName is a "/", the path will be interpreted as absolute path,
1951  otherwise it will be interpreted as path relative to the current group.
1952  */
1953  template<class T>
1954  inline void read(const std::string & datasetName, ArrayVectorView<T> array)
1955  {
1956  // convert to a (trivial) MultiArrayView and forward.
1957  MultiArrayShape<1>::type shape(array.size());
1958  MultiArrayView<1, T> m_array(shape, (array.data()));
1959  read(datasetName, m_array);
1960  }
1961 
1962  /** \brief Read data into an array vector. Resize the array vector to the correct size.
1963  If the first character of datasetName is a "/", the path will be interpreted as absolute path,
1964  otherwise it will be interpreted as path relative to the current group.
1965  */
1966  template<class T>
1967  inline void readAndResize(std::string datasetName,
1968  ArrayVector<T> & array)
1969  {
1970  // make dataset name clean
1971  datasetName = get_absolute_path(datasetName);
1972 
1973  // get dataset dimension
1974  ArrayVector<hsize_t> dimshape = getDatasetShape(datasetName);
1975 
1976  // check if dimensions are correct
1977  vigra_precondition(1 == MultiArrayIndex(dimshape.size()),
1978  "HDF5File::readAndResize(): Array dimension disagrees with Dataset dimension must equal one for vigra::ArrayVector.");
1979 
1980  // resize target array vector
1981  array.resize((typename ArrayVector<T>::size_type)dimshape[0]);
1982  // convert to a (trivial) MultiArrayView and forward.
1983  MultiArrayShape<1>::type shape(static_cast<MultiArrayIndex>(array.size()));
1984  MultiArrayView<1, T> m_array(shape, (array.data()));
1985 
1986  read_(datasetName, m_array, detail::getH5DataType<T>(), 1);
1987  }
1988 
1989  /** \brief Read a block of data into a multi array.
1990  This function allows to read a small block out of a larger volume stored
1991  in an HDF5 dataset.
1992 
1993  blockOffset determines the position of the block.
1994  blockSize determines the size in each dimension of the block.
1995 
1996  If the first character of datasetName is a "/", the path will be interpreted as absolute path,
1997  otherwise it will be interpreted as path relative to the current group.
1998 
1999  Note that the memory order between VIGRA and HDF5 files differs: VIGRA uses
2000  Fortran-order, while HDF5 uses C-order. This means that a HDF5 dataset,
2001  whose indices represent the 'z'-, 'y'-, and 'x'-axis in that order, is reversed
2002  upon reading into a MultiArray, i.e. in the array axis order will be 'x', 'y', 'z'.
2003  */
2004  template<unsigned int N, class T, class Stride>
2005  inline void readBlock(std::string datasetName,
2006  typename MultiArrayShape<N>::type blockOffset,
2007  typename MultiArrayShape<N>::type blockShape,
2009  {
2010  // make datasetName clean
2011  datasetName = get_absolute_path(datasetName);
2012  typedef detail::HDF5TypeTraits<T> TypeTraits;
2013  readBlock_(datasetName, blockOffset, blockShape, array,
2014  TypeTraits::getH5DataType(), TypeTraits::numberOfBands());
2015  }
2016 
2017  template<unsigned int N, class T, class Stride>
2018  inline herr_t readBlock(HDF5HandleShared dataset,
2019  typename MultiArrayShape<N>::type blockOffset,
2020  typename MultiArrayShape<N>::type blockShape,
2022  {
2023  typedef detail::HDF5TypeTraits<T> TypeTraits;
2024  return readBlock_(dataset, blockOffset, blockShape, array,
2025  TypeTraits::getH5DataType(), TypeTraits::numberOfBands());
2026  }
2027 
2028  // non-scalar (TinyVector) and unstrided target MultiArrayView
2029  template<unsigned int N, class T, int SIZE, class Stride>
2030  inline void read(std::string datasetName, MultiArrayView<N, TinyVector<T, SIZE>, Stride> array)
2031  {
2032  // make datasetName clean
2033  datasetName = get_absolute_path(datasetName);
2034 
2035  read_(datasetName, array, detail::getH5DataType<T>(), SIZE);
2036  }
2037 
2038  // non-scalar (TinyVector) MultiArray
2039  template<unsigned int N, class T, int SIZE, class Alloc>
2040  inline void readAndResize(std::string datasetName, MultiArray<N, TinyVector<T, SIZE>, Alloc> & array)
2041  {
2042  // make datasetName clean
2043  datasetName = get_absolute_path(datasetName);
2044 
2045  // get dataset dimension
2046  ArrayVector<hsize_t> dimshape = getDatasetShape(datasetName);
2047 
2048  // check if dimensions are correct
2049  vigra_precondition((N+1) == MultiArrayIndex(dimshape.size()) &&
2050  SIZE == dimshape[0], // the object in the HDF5 file must have one additional dimension which we interpret as the pixel type bands
2051  "HDF5File::readAndResize(): Array dimension disagrees with dataset dimension.");
2052 
2053  // reshape target MultiArray
2054  typename MultiArrayShape<N>::type shape;
2055  for(int k=1; k < static_cast<int>(dimshape.size()); ++k)
2056  shape[k-1] = static_cast<MultiArrayIndex>(dimshape[k]);
2057  array.reshape(shape);
2058 
2059  read_(datasetName, array, detail::getH5DataType<T>(), SIZE);
2060  }
2061 
2062  // non-scalar (RGBValue) and unstrided target MultiArrayView
2063  template<unsigned int N, class T, class Stride>
2064  inline void read(std::string datasetName, MultiArrayView<N, RGBValue<T>, Stride> array)
2065  {
2066  // make datasetName clean
2067  datasetName = get_absolute_path(datasetName);
2068 
2069  read_(datasetName, array, detail::getH5DataType<T>(), 3);
2070  }
2071 
2072  // non-scalar (RGBValue) MultiArray
2073  template<unsigned int N, class T, class Alloc>
2074  inline void readAndResize(std::string datasetName, MultiArray<N, RGBValue<T>, Alloc> & array)
2075  {
2076  // make datasetName clean
2077  datasetName = get_absolute_path(datasetName);
2078 
2079  // get dataset dimension
2080  ArrayVector<hsize_t> dimshape = getDatasetShape(datasetName);
2081 
2082  // check if dimensions are correct
2083  vigra_precondition((N+1) == MultiArrayIndex(dimshape.size()) &&
2084  3 == dimshape[0], // the object in the HDF5 file must have one additional dimension which we interpret as the pixel type bands
2085  "HDF5File::readAndResize(): Array dimension disagrees with dataset dimension.");
2086 
2087  // reshape target MultiArray
2088  typename MultiArrayShape<N>::type shape;
2089  for(int k=1; k < static_cast<int>(dimshape.size()); ++k)
2090  shape[k-1] = static_cast<MultiArrayIndex>(dimshape[k]);
2091  array.reshape(shape);
2092 
2093  read_(datasetName, array, detail::getH5DataType<T>(), 3);
2094  }
2095 
2096  /** \brief Read a single value.
2097  Specialization of the read function for simple datatypes
2098  */
2099  inline void read(std::string datasetName, char &data) { readAtomic(datasetName,data); }
2100  inline void read(std::string datasetName, signed char &data) { readAtomic(datasetName,data); }
2101  inline void read(std::string datasetName, signed short &data) { readAtomic(datasetName,data); }
2102  inline void read(std::string datasetName, signed int &data) { readAtomic(datasetName,data); }
2103  inline void read(std::string datasetName, signed long &data) { readAtomic(datasetName,data); }
2104  inline void read(std::string datasetName, signed long long &data) { readAtomic(datasetName,data); }
2105  inline void read(std::string datasetName, unsigned char &data) { readAtomic(datasetName,data); }
2106  inline void read(std::string datasetName, unsigned short &data) { readAtomic(datasetName,data); }
2107  inline void read(std::string datasetName, unsigned int &data) { readAtomic(datasetName,data); }
2108  inline void read(std::string datasetName, unsigned long &data) { readAtomic(datasetName,data); }
2109  inline void read(std::string datasetName, unsigned long long &data) { readAtomic(datasetName,data); }
2110  inline void read(std::string datasetName, float &data) { readAtomic(datasetName,data); }
2111  inline void read(std::string datasetName, double &data) { readAtomic(datasetName,data); }
2112  inline void read(std::string datasetName, long double &data) { readAtomic(datasetName,data); }
2113  inline void read(std::string datasetName, std::string &data) { readAtomic(datasetName,data); }
2114 
2115  /** \brief Create a new dataset.
2116  This function can be used to create a dataset filled with a default value \a init,
2117  for example before writing data into it using \ref writeBlock().
2118 
2119  shape determines the dimension and the size of the dataset.
2120 
2121  Chunks can be activated by providing a MultiArrayShape as chunkSize.
2122  chunkSize must have equal dimension as array.
2123 
2124  Compression can be activated by setting
2125  \code compression = parameter; // 0 < parameter <= 9
2126  \endcode
2127  where 0 stands for no compression and 9 for maximum compression. If
2128  a non-zero compression level is specified, but the chunk size is zero,
2129  a default chunk size will be chosen (compression always requires chunks).
2130 
2131  If the first character of datasetName is a "/", the path will be interpreted as absolute path,
2132  otherwise it will be interpreted as path relative to the current group.
2133 
2134  Note that the memory order between VIGRA and HDF5 files differs: VIGRA uses
2135  Fortran-order, while HDF5 uses C-order. This means that a VIGRA MultiArray,
2136  whose indices represent the 'x'-, 'y'-, and 'z'-axis in that order, is reversed
2137  upon writing to an HDF5 file, i.e. in the file the axis order is 'z', 'y', 'x'.
2138  */
2139  template<int N, class T>
2141  createDataset(std::string datasetName,
2142  TinyVector<MultiArrayIndex, N> const & shape,
2143  typename detail::HDF5TypeTraits<T>::value_type init =
2144  typename detail::HDF5TypeTraits<T>::value_type(),
2145 #ifdef _MSC_VER
2147 #else
2149 #endif
2150  int compressionParameter = 0);
2151 
2152  // for backwards compatibility
2153  template<int N, class T>
2155  createDataset(std::string datasetName,
2156  TinyVector<MultiArrayIndex, N> const & shape,
2157  T init,
2158  int iChunkSize,
2159  int compressionParameter = 0)
2160  {
2161  typename MultiArrayShape<N>::type chunkSize;
2162  for(int i = 0; i < N; i++){
2163  chunkSize[i] = iChunkSize;
2164  }
2165  return this->template createDataset<N, T>(datasetName, shape, init,
2166  chunkSize, compressionParameter);
2167  }
2168 
2169  /** \brief Immediately write all data to disk
2170  */
2171  inline void flushToDisk()
2172  {
2173  if(fileHandle_)
2174  H5Fflush(fileHandle_, H5F_SCOPE_GLOBAL);
2175  }
2176 
2177  private:
2178 
2179  /* Simple extension of std::string for splitting into two parts
2180  *
2181  * Strings (in particular: file/dataset paths) will be split into two
2182  * parts. The split is made at the last occurrence of the delimiter.
2183  *
2184  * For example, "/path/to/some/file" will be split (delimiter = "/") into
2185  * first() = "/path/to/some" and last() = "file".
2186  */
2187  class SplitString: public std::string {
2188  public:
2189  SplitString(std::string &sstring): std::string(sstring) {};
2190 
2191  // return the part of the string before the delimiter
2192  std::string first(char delimiter = '/')
2193  {
2194  size_t lastPos = find_last_of(delimiter);
2195  if(lastPos == std::string::npos) // delimiter not found --> no first
2196  return "";
2197 
2198  return std::string(begin(), begin()+lastPos+1);
2199  }
2200 
2201  // return the part of the string after the delimiter
2202  std::string last(char delimiter = '/')
2203  {
2204  size_t lastPos = find_last_of(delimiter);
2205  if(lastPos == std::string::npos) // delimiter not found --> only last
2206  return std::string(*this);
2207  return std::string(begin()+lastPos+1, end());
2208  }
2209  };
2210 
2211  template <class Shape>
2213  defineChunks(Shape chunks, Shape const & shape, int numBands, int compression = 0)
2214  {
2215  if(prod(chunks) > 0)
2216  {
2217  ArrayVector<hsize_t> res(chunks.begin(), chunks.end());
2218  if(numBands > 1)
2219  res.insert(res.begin(), static_cast<hsize_t>(numBands));
2220  return res;
2221  }
2222  else if(compression > 0)
2223  {
2224  // set default chunks to enable compression
2225  chunks = min(detail::ChunkShape<Shape::static_size>::defaultShape(), shape);
2226  ArrayVector<hsize_t> res(chunks.begin(), chunks.end());
2227  if(numBands > 1)
2228  res.insert(res.begin(), static_cast<hsize_t>(numBands));
2229  return res;
2230  }
2231  else
2232  {
2233  return ArrayVector<hsize_t>();
2234  }
2235  }
2236 
2237  public:
2238 
2239  /** \brief takes any path and converts it into an absolute path
2240  in the current file.
2241 
2242  Elements like "." and ".." are treated as expected.
2243  Links are not supported or resolved.
2244  */
2245  inline std::string get_absolute_path(std::string path) const {
2246  // check for empty input or "." and return the current folder
2247  if(path.length() == 0 || path == "."){
2248  return currentGroupName_();
2249  }
2250 
2251  std::string str;
2252  // convert to absolute path
2253  if(relativePath_(path)){
2254  std::string cname = currentGroupName_();
2255  if (cname == "/")
2256  str = currentGroupName_()+path;
2257  else
2258  str = currentGroupName_()+"/"+path;
2259  }else{
2260  str = path;
2261  }
2262 
2263  // cut out "./"
2264  std::string::size_type startpos = 0;
2265  while(str.find(std::string("./"), startpos) != std::string::npos){
2266  std::string::size_type pos = str.find(std::string("./"), startpos);
2267  startpos = pos+1;
2268  // only cut if "./" is not part of "../" (see below)
2269  if(str.substr(pos-1,3) != "../"){
2270  // cut out part of the string
2271  str = str.substr(0,pos) + str.substr(pos+2,str.length()-pos-2);
2272  startpos = pos;
2273  }
2274  }
2275 
2276  // cut out pairs of "bla/../"
2277  while(str.find(std::string("..")) != std::string::npos){
2278  std::string::size_type pos = str.find(std::string(".."));
2279 
2280  // find first slash after ".."
2281  std::string::size_type end = str.find("/",pos);
2282  if(end != std::string::npos){
2283  // also include slash
2284  end++;
2285  }else{
2286  // no "/" after ".." --> this is a group, add a "/"
2287  str = str + "/";
2288  end = str.length();
2289  }
2290 
2291  // find first slash before ".."
2292  std::string::size_type prev_slash = str.rfind("/",pos);
2293  // if the root slash is the first before ".." --> Error
2294  vigra_invariant(prev_slash != 0 && prev_slash != std::string::npos,
2295  "Error parsing path: "+str);
2296  // find second slash before ".."
2297  std::string::size_type begin = str.rfind("/",prev_slash-1);
2298 
2299  // cut out part of the string
2300  str = str.substr(0,begin+1) + str.substr(end,str.length()-end);
2301  }
2302 
2303  return str;
2304  }
2305 
2306  protected:
2307 
2308  /* checks if the given path is a relative path.
2309  */
2310  inline bool relativePath_(std::string & path) const
2311  {
2312  std::string::size_type pos = path.find('/') ;
2313  if(pos == 0)
2314  return false;
2315 
2316  return true;
2317  }
2318 
2319  /* return the name of the current group
2320  */
2321  inline std::string currentGroupName_() const
2322  {
2323  int len = H5Iget_name(cGroupHandle_,NULL,1000);
2324  ArrayVector<char> name (len+1,0);
2325  H5Iget_name(cGroupHandle_,name.begin(),len+1);
2326 
2327  return std::string(name.begin());
2328  }
2329 
2330  /* return the name of the current file
2331  */
2332  inline std::string fileName_() const
2333  {
2334  int len = H5Fget_name(fileHandle_,NULL,1000);
2335  ArrayVector<char> name (len+1,0);
2336  H5Fget_name(fileHandle_,name.begin(),len+1);
2337 
2338  return std::string(name.begin());
2339  }
2340 
2341  /* create an empty file or open an existing one
2342  */
2343  inline hid_t createFile_(std::string filePath, OpenMode mode = Open)
2344  {
2345  // try to open file
2346  FILE * pFile;
2347  pFile = fopen ( filePath.c_str(), "r" );
2348  hid_t fileId;
2349 
2350  // check if opening was successful (= file exists)
2351  if ( pFile == NULL )
2352  {
2353  vigra_precondition(mode != OpenReadOnly,
2354  "HDF5File::open(): cannot open non-existing file in read-only mode.");
2355  fileId = H5Fcreate(filePath.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
2356  }
2357  else
2358  {
2359  fclose(pFile);
2360  if(mode == OpenReadOnly)
2361  {
2362  fileId = H5Fopen(filePath.c_str(), H5F_ACC_RDONLY, H5P_DEFAULT);
2363  }
2364  else if(mode == New)
2365  {
2366  std::remove(filePath.c_str());
2367  fileId = H5Fcreate(filePath.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
2368  }
2369  else
2370  {
2371  fileId = H5Fopen(filePath.c_str(), H5F_ACC_RDWR, H5P_DEFAULT);
2372  }
2373  }
2374  return fileId;
2375  }
2376 
2377  /* \brief Open a group.
2378 
2379  A negative value is returned when the group does not exist or when opening
2380  fails for other reasons.
2381  */
2382  hid_t openGroup_(std::string groupName) const
2383  {
2384  return const_cast<HDF5File *>(this)->openCreateGroup_(groupName, false);
2385  }
2386 
2387  /* \brief Open or create a group.
2388 
2389  If \a create is <tt>true</tt> and the group does not exist, it will be created,
2390  including all necessary parent groups. If group creation fails, a negative
2391  value is returned. Likewise, a negative value is returned when \a create
2392  is <tt>false</tt> and the group does not exist or when opening of the group
2393  fails for other reasons.
2394  */
2395  hid_t openCreateGroup_(std::string groupName, bool create = true)
2396  {
2397  // make groupName clean
2398  groupName = get_absolute_path(groupName);
2399 
2400  // open root group
2401  hid_t parent = H5Gopen(fileHandle_, "/", H5P_DEFAULT);
2402  if(groupName == "/")
2403  {
2404  return parent;
2405  }
2406 
2407  // remove leading /
2408  groupName = std::string(groupName.begin()+1, groupName.end());
2409 
2410  // check if the groupName has finishing slash
2411  if( groupName.size() != 0 && *groupName.rbegin() != '/')
2412  {
2413  groupName = groupName + '/';
2414  }
2415 
2416  // open or create subgroups one by one
2417  std::string::size_type begin = 0, end = groupName.find('/');
2418  while (end != std::string::npos)
2419  {
2420  std::string group(groupName.begin()+begin, groupName.begin()+end);
2421  hid_t prevParent = parent;
2422 
2423  if(H5LTfind_dataset(parent, group.c_str()) == 0)
2424  {
2425  if(create)
2426  parent = H5Gcreate(prevParent, group.c_str(), H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
2427  else
2428  parent = -1;
2429  }
2430  else
2431  {
2432  parent = H5Gopen(prevParent, group.c_str(), H5P_DEFAULT);
2433  }
2434  H5Gclose(prevParent);
2435 
2436  if(parent < 0)
2437  {
2438  return parent;
2439  }
2440  begin = end + 1;
2441  end = groupName.find('/', begin);
2442  }
2443 
2444  return parent;
2445  }
2446 
2447  /* delete a dataset by unlinking it from the file structure. This does not
2448  delete the data!
2449  */
2450  inline void deleteDataset_(hid_t parent, std::string datasetName)
2451  {
2452  // delete existing data and create new dataset
2453  if(H5LTfind_dataset(parent, datasetName.c_str()))
2454  {
2455 
2456  #if (H5_VERS_MAJOR == 1 && H5_VERS_MINOR <= 6)
2457  if(H5Gunlink(parent, datasetName.c_str()) < 0)
2458  {
2459  vigra_postcondition(false, "HDF5File::deleteDataset_(): Unable to delete existing data.");
2460  }
2461  #else
2462  if(H5Ldelete(parent, datasetName.c_str(), H5P_DEFAULT ) < 0)
2463  {
2464  vigra_postcondition(false, "HDF5File::deleteDataset_(): Unable to delete existing data.");
2465  }
2466  #endif
2467  }
2468  }
2469 
2470  /* get the handle of a dataset specified by a string
2471  */
2472  hid_t getDatasetHandle_(std::string datasetName) const
2473  {
2474  // make datasetName clean
2475  datasetName = get_absolute_path(datasetName);
2476 
2477  std::string groupname = SplitString(datasetName).first();
2478  std::string setname = SplitString(datasetName).last();
2479 
2480  if(H5Lexists(fileHandle_, datasetName.c_str(), H5P_DEFAULT) <= 0)
2481  {
2482  std::cerr << "HDF5File::getDatasetHandle_(): Dataset '" << datasetName << "' does not exist.\n";
2483  return -1;
2484  }
2485 
2486  // Open parent group
2487  HDF5Handle groupHandle(openGroup_(groupname), &H5Gclose, "HDF5File::getDatasetHandle_(): Internal error");
2488 
2489  return H5Dopen(groupHandle, setname.c_str(), H5P_DEFAULT);
2490  }
2491 
2492  /* get the type of an object specified by a string
2493  */
2494  H5O_type_t get_object_type_(std::string name) const
2495  {
2496  name = get_absolute_path(name);
2497  std::string group_name = SplitString(name).first();
2498  std::string object_name = SplitString(name).last();
2499  if (!object_name.size())
2500  return H5O_TYPE_GROUP;
2501 
2502  htri_t exists = H5Lexists(fileHandle_, name.c_str(), H5P_DEFAULT);
2503  vigra_precondition(exists > 0, "HDF5File::get_object_type_(): "
2504  "object \"" + name + "\" "
2505  "not found.");
2506  // open parent group
2507  HDF5Handle group_handle(openGroup_(group_name), &H5Gclose, "Internal error");
2508  return HDF5_get_type(group_handle, name.c_str());
2509  }
2510 
2511  /* low-level write function to write vigra MultiArray data as an attribute
2512  */
2513  template<unsigned int N, class T, class Stride>
2514  void write_attribute_(std::string name,
2515  const std::string & attribute_name,
2516  const MultiArrayView<N, T, Stride> & array,
2517  const hid_t datatype,
2518  const int numBandsOfType);
2519 
2520  /* Write single value attribute
2521  This function allows to write data of atomic datatypes (int, long, double)
2522  as an attribute in the HDF5 file. So it is not necessary to create a MultiArray
2523  of size 1 to write a single number.
2524  */
2525  template<class T>
2526  inline void writeAtomicAttribute(std::string datasetName, std::string attributeName, const T data)
2527  {
2528  // make datasetName clean
2529  datasetName = get_absolute_path(datasetName);
2530 
2531  typename MultiArrayShape<1>::type chunkSize;
2532  chunkSize[0] = 0;
2534  array[0] = data;
2535  write_attribute_(datasetName, attributeName, array, detail::getH5DataType<T>(), 1);
2536  }
2537 
2538  /* low-level read function to read vigra MultiArray data from attributes
2539  */
2540  template<unsigned int N, class T, class Stride>
2541  void read_attribute_(std::string datasetName,
2542  std::string attributeName,
2544  const hid_t datatype, const int numBandsOfType);
2545 
2546  /* Read a single value attribute.
2547  This functions allows to read a single value attribute of atomic datatype (int, long, double)
2548  from the HDF5 file. So it is not necessary to create a MultiArray
2549  of size 1 to read a single number.
2550  */
2551  template<class T>
2552  inline void readAtomicAttribute(std::string datasetName, std::string attributeName, T & data)
2553  {
2554  // make datasetName clean
2555  datasetName = get_absolute_path(datasetName);
2556 
2558  read_attribute_(datasetName, attributeName, array, detail::getH5DataType<T>(), 1);
2559  data = array[0];
2560  }
2561 
2562  inline void readAtomicAttribute(std::string datasetName, std::string attributeName, std::string & data)
2563  {
2564  // make datasetName clean
2565  datasetName = get_absolute_path(datasetName);
2566 
2568  read_attribute_(datasetName, attributeName, array, detail::getH5DataType<const char *>(), 1);
2569  data = std::string(array[0]);
2570  }
2571 
2572  /* low-level write function to write vigra unstrided MultiArray data
2573  */
2574  template<unsigned int N, class T, class Stride>
2575  void write_(std::string &datasetName,
2576  const MultiArrayView<N, T, Stride> & array,
2577  const hid_t datatype,
2578  const int numBandsOfType,
2579  typename MultiArrayShape<N>::type &chunkSize,
2580  int compressionParameter = 0);
2581 
2582  /* Write single value as dataset.
2583  This functions allows to write data of atomic datatypes (int, long, double)
2584  as a dataset in the HDF5 file. So it is not necessary to create a MultiArray
2585  of size 1 to write a single number.
2586 
2587  If the first character of datasetName is a "/", the path will be interpreted as absolute path,
2588  otherwise it will be interpreted as path relative to the current group.
2589  */
2590  template<class T>
2591  inline void writeAtomic(std::string datasetName, const T data)
2592  {
2593  // make datasetName clean
2594  datasetName = get_absolute_path(datasetName);
2595 
2596  typename MultiArrayShape<1>::type chunkSize;
2597  chunkSize[0] = 0;
2599  array[0] = data;
2600  write_(datasetName, array, detail::getH5DataType<T>(), 1, chunkSize,0);
2601  }
2602 
2603  /* low-level read function to read vigra unstrided MultiArray data
2604  */
2605  template<unsigned int N, class T, class Stride>
2606  void read_(std::string datasetName,
2608  const hid_t datatype, const int numBandsOfType);
2609 
2610  /* Read a single value.
2611  This functions allows to read a single datum of atomic datatype (int, long, double)
2612  from the HDF5 file. So it is not necessary to create a MultiArray
2613  of size 1 to read a single number.
2614 
2615  If the first character of datasetName is a "/", the path will be interpreted as absolute path,
2616  otherwise it will be interpreted as path relative to the current group.
2617  */
2618  template<class T>
2619  inline void readAtomic(std::string datasetName, T & data)
2620  {
2621  // make datasetName clean
2622  datasetName = get_absolute_path(datasetName);
2623 
2625  read_(datasetName, array, detail::getH5DataType<T>(), 1);
2626  data = array[0];
2627  }
2628 
2629  inline void readAtomic(std::string datasetName, std::string & data)
2630  {
2631  // make datasetName clean
2632  datasetName = get_absolute_path(datasetName);
2633 
2635  read_(datasetName, array, detail::getH5DataType<const char *>(), 1);
2636  data = std::string(array[0]);
2637  }
2638 
2639  /* low-level write function to write vigra unstrided MultiArray data into a sub-block of a dataset
2640  */
2641  template<unsigned int N, class T, class Stride>
2642  void writeBlock_(std::string datasetName,
2643  typename MultiArrayShape<N>::type &blockOffset,
2644  const MultiArrayView<N, T, Stride> & array,
2645  const hid_t datatype,
2646  const int numBandsOfType)
2647  {
2648  // open dataset if it exists
2649  std::string errorMessage = "HDF5File::writeBlock(): Error opening dataset '" + datasetName + "'.";
2650  HDF5HandleShared dataset(getDatasetHandle_(datasetName), &H5Dclose, errorMessage.c_str());
2651  herr_t status = writeBlock_(dataset, blockOffset, array, datatype, numBandsOfType);
2652  vigra_postcondition(status >= 0,
2653  "HDF5File::writeBlock(): write to dataset '" + datasetName + "' via H5Dwrite() failed.");
2654  }
2655 
2656  /* low-level write function to write vigra unstrided MultiArray data into a
2657  sub-block of a dataset. Returns the result of the internal call
2658  to <tt>H5Dwrite()</tt>.
2659  */
2660  template<unsigned int N, class T, class Stride>
2661  herr_t writeBlock_(HDF5HandleShared dataset,
2662  typename MultiArrayShape<N>::type &blockOffset,
2663  const MultiArrayView<N, T, Stride> & array,
2664  const hid_t datatype,
2665  const int numBandsOfType);
2666 
2667  /* low-level read function to read vigra unstrided MultiArray data from a sub-block of a dataset.
2668 
2669  The array must have the same shape as the block.
2670  */
2671  template<unsigned int N, class T, class Stride>
2672  void readBlock_(std::string datasetName,
2673  typename MultiArrayShape<N>::type &blockOffset,
2674  typename MultiArrayShape<N>::type &blockShape,
2676  const hid_t datatype, const int numBandsOfType)
2677  {
2678  std::string errorMessage ("HDF5File::readBlock(): Unable to open dataset '" + datasetName + "'.");
2679  HDF5HandleShared dataset(getDatasetHandle_(datasetName), &H5Dclose, errorMessage.c_str());
2680  herr_t status = readBlock_(dataset, blockOffset, blockShape, array, datatype, numBandsOfType);
2681  vigra_postcondition(status >= 0,
2682  "HDF5File::readBlock(): read from dataset '" + datasetName + "' via H5Dread() failed.");
2683  }
2684 
2685  /* low-level read function to read vigra unstrided MultiArray data from a sub-block of a dataset.
2686 
2687  The array must have the same shape as the block. Returns the result of the internal call
2688  to <tt>H5Dread()</tt>.
2689  */
2690  template<unsigned int N, class T, class Stride>
2691  herr_t readBlock_(HDF5HandleShared dataset,
2692  typename MultiArrayShape<N>::type &blockOffset,
2693  typename MultiArrayShape<N>::type &blockShape,
2695  const hid_t datatype, const int numBandsOfType);
2696 }; /* class HDF5File */
2697 
2698 /********************************************************************/
2699 
2700 template<int N, class T>
2702 HDF5File::createDataset(std::string datasetName,
2703  TinyVector<MultiArrayIndex, N> const & shape,
2704  typename detail::HDF5TypeTraits<T>::value_type init,
2705  TinyVector<MultiArrayIndex, N> const & chunkSize,
2706  int compressionParameter)
2707 {
2708  vigra_precondition(!isReadOnly(),
2709  "HDF5File::createDataset(): file is read-only.");
2710 
2711  // make datasetName clean
2712  datasetName = get_absolute_path(datasetName);
2713 
2714  std::string groupname = SplitString(datasetName).first();
2715  std::string setname = SplitString(datasetName).last();
2716 
2717  hid_t parent = openCreateGroup_(groupname);
2718 
2719  // delete the dataset if it already exists
2720  deleteDataset_(parent, setname);
2721 
2722  // invert dimensions to guarantee c-order
2723  // add an extra dimension in case that the data is non-scalar
2724  typedef detail::HDF5TypeTraits<T> TypeTraits;
2725  ArrayVector<hsize_t> shape_inv;
2726  if(TypeTraits::numberOfBands() > 1)
2727  {
2728  shape_inv.resize(N+1);
2729  shape_inv[N] = TypeTraits::numberOfBands();
2730  }
2731  else
2732  {
2733  shape_inv.resize(N);
2734  }
2735  for(int k=0; k<N; ++k)
2736  shape_inv[N-1-k] = shape[k];
2737 
2738  // create dataspace
2739  HDF5Handle
2740  dataspaceHandle = HDF5Handle(H5Screate_simple(shape_inv.size(), shape_inv.data(), NULL),
2741  &H5Sclose, "HDF5File::createDataset(): unable to create dataspace for scalar data.");
2742 
2743  // set fill value
2744  HDF5Handle plist ( H5Pcreate(H5P_DATASET_CREATE), &H5Pclose, "HDF5File::createDataset(): unable to create property list." );
2745  H5Pset_fill_value(plist, TypeTraits::getH5DataType(), &init);
2746 
2747  // turn off time tagging of datasets by default.
2748  H5Pset_obj_track_times(plist, track_time);
2749 
2750  // enable chunks
2751  ArrayVector<hsize_t> chunks(defineChunks(chunkSize, shape, TypeTraits::numberOfBands(), compressionParameter));
2752  if(chunks.size() > 0)
2753  {
2754  std::reverse(chunks.begin(), chunks.end());
2755  H5Pset_chunk (plist, chunks.size(), chunks.begin());
2756  }
2757 
2758  // enable compression
2759  if(compressionParameter > 0)
2760  {
2761  H5Pset_deflate(plist, compressionParameter);
2762  }
2763 
2764  //create the dataset.
2765  HDF5HandleShared datasetHandle(H5Dcreate(parent, setname.c_str(),
2766  TypeTraits::getH5DataType(),
2767  dataspaceHandle, H5P_DEFAULT, plist, H5P_DEFAULT),
2768  &H5Dclose,
2769  "HDF5File::createDataset(): unable to create dataset.");
2770  if(parent != cGroupHandle_)
2771  H5Gclose(parent);
2772 
2773  return datasetHandle;
2774 }
2775 
2776 /********************************************************************/
2777 
2778 template<unsigned int N, class T, class Stride>
2779 void HDF5File::write_(std::string &datasetName,
2780  const MultiArrayView<N, T, Stride> & array,
2781  const hid_t datatype,
2782  const int numBandsOfType,
2783  typename MultiArrayShape<N>::type &chunkSize,
2784  int compressionParameter)
2785 {
2786  vigra_precondition(!isReadOnly(),
2787  "HDF5File::write(): file is read-only.");
2788 
2789  std::string groupname = SplitString(datasetName).first();
2790  std::string setname = SplitString(datasetName).last();
2791 
2792  // shape of the array. Add one dimension, if array contains non-scalars.
2793  ArrayVector<hsize_t> shape(array.shape().begin(), array.shape().end());
2794  std::reverse(shape.begin(), shape.end());
2795 
2796  if(numBandsOfType > 1)
2797  shape.push_back(numBandsOfType);
2798 
2799  HDF5Handle dataspace(H5Screate_simple(shape.size(), shape.begin(), NULL), &H5Sclose,
2800  "HDF5File::write(): Can not create dataspace.");
2801 
2802  // create and open group:
2803  std::string errorMessage ("HDF5File::write(): can not create group '" + groupname + "'.");
2804  HDF5Handle groupHandle(openCreateGroup_(groupname), &H5Gclose, errorMessage.c_str());
2805 
2806  // delete dataset, if it already exists
2807  deleteDataset_(groupHandle, setname.c_str());
2808 
2809  // set up properties list
2810  HDF5Handle plist(H5Pcreate(H5P_DATASET_CREATE), &H5Pclose,
2811  "HDF5File::write(): unable to create property list." );
2812 
2813  // turn off time tagging of datasets by default.
2814  H5Pset_obj_track_times(plist, track_time);
2815 
2816  // enable chunks
2817  ArrayVector<hsize_t> chunks(defineChunks(chunkSize, array.shape(), numBandsOfType, compressionParameter));
2818  if(chunks.size() > 0)
2819  {
2820  std::reverse(chunks.begin(), chunks.end());
2821  H5Pset_chunk (plist, chunks.size(), chunks.begin());
2822  }
2823 
2824  // enable compression
2825  if(compressionParameter > 0)
2826  {
2827  H5Pset_deflate(plist, compressionParameter);
2828  }
2829 
2830  // create dataset
2831  HDF5Handle datasetHandle(H5Dcreate(groupHandle, setname.c_str(), datatype, dataspace,H5P_DEFAULT, plist, H5P_DEFAULT),
2832  &H5Dclose, "HDF5File::write(): Can not create dataset.");
2833 
2834  herr_t status = 0;
2835  if(array.isUnstrided())
2836  {
2837  // Write the data directly from the array data buffer
2838  status = H5Dwrite(datasetHandle, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, array.data());
2839  }
2840  else
2841  {
2842  // otherwise, we need an intermediate buffer
2843  // FIXME: right now, the buffer has the same size as the array to be read
2844  // incomplete code for better solutions is below
2845  // MultiArray<N, T> buffer(array);
2846  // status = H5Dwrite(datasetHandle, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, buffer.data());
2847 
2848  int offset = numBandsOfType > 1 ? 1 : 0;
2849  std::reverse(shape.begin(), shape.end());
2850  if(chunks.size() > 0)
2851  {
2852  // if the file is chunked, we use a buffer that matches the chunk size.
2853  std::reverse(chunks.begin(), chunks.end());
2854  }
2855  else
2856  {
2857  // otherwise, we compute a suitable chunk size.
2858  ArrayVector<hsize_t>(shape.size(), 1).swap(chunks);
2859  chunks[0] = numBandsOfType;
2860  MultiArrayIndex prod = 1;
2861  for(unsigned int k=0; k<N; ++k)
2862  {
2863  chunks[k+offset] = array.shape(k);
2864  prod *= array.shape(k);
2865  if(prod > 300000)
2866  break;
2867  }
2868  }
2869 
2870  ArrayVector<hsize_t> null(shape.size(), 0),
2871  start(shape.size(), 0),
2872  count(shape.size(), 1);
2873 
2874  count[N-1-offset] = numBandsOfType;
2875 
2876  typedef typename MultiArrayShape<N>::type Shape;
2877  Shape chunkCount, chunkMaxShape;
2878  for(unsigned int k=offset; k<chunks.size(); ++k)
2879  {
2880  chunkMaxShape[k-offset] = chunks[k];
2881  chunkCount[k-offset] = static_cast<MultiArrayIndex>(std::ceil(double(shape[k]) / chunks[k]));
2882  }
2883 
2884  typename CoupledIteratorType<N>::type chunkIter = createCoupledIterator(chunkCount),
2885  chunkEnd = chunkIter.getEndIterator();
2886  for(; chunkIter != chunkEnd; ++chunkIter)
2887  {
2888  Shape chunkStart(chunkIter.point() * chunkMaxShape),
2889  chunkStop(min(chunkStart + chunkMaxShape, array.shape()));
2890  MultiArray<N, T> buffer(array.subarray(chunkStart, chunkStop));
2891 
2892  for(unsigned int k=0; k<N; ++k)
2893  {
2894  start[N-1-k] = chunkStart[k];
2895  count[N-1-k] = buffer.shape(k);
2896  }
2897  if(offset == 1)
2898  {
2899  start[N] = 0;
2900  count[N] = numBandsOfType;
2901  }
2902  HDF5Handle filespace(H5Dget_space(datasetHandle),
2903  &H5Sclose, "HDF5File::write(): unable to create hyperslabs.");
2904  status = H5Sselect_hyperslab(filespace, H5S_SELECT_SET, start.data(), NULL, count.data(), NULL);
2905  if(status < 0)
2906  break;
2907 
2908  HDF5Handle dataspace2(H5Screate_simple(count.size(), count.data(), NULL),
2909  &H5Sclose, "HDF5File::write(): unable to create hyperslabs.");
2910  status = H5Sselect_hyperslab(dataspace2, H5S_SELECT_SET, null.data(), NULL, count.data(), NULL);
2911  if(status < 0)
2912  break;
2913 
2914  status = H5Dwrite(datasetHandle, datatype, dataspace2, filespace, H5P_DEFAULT, buffer.data());
2915  if(status < 0)
2916  break;
2917  }
2918  }
2919  vigra_postcondition(status >= 0,
2920  "HDF5File::write(): write to dataset '" + datasetName + "' via H5Dwrite() failed.");
2921 }
2922 
2923 /********************************************************************/
2924 
2925 template<unsigned int N, class T, class Stride>
2926 herr_t HDF5File::writeBlock_(HDF5HandleShared datasetHandle,
2927  typename MultiArrayShape<N>::type &blockOffset,
2928  const MultiArrayView<N, T, Stride> & array,
2929  const hid_t datatype,
2930  const int numBandsOfType)
2931 {
2932  vigra_precondition(!isReadOnly(),
2933  "HDF5File::writeBlock(): file is read-only.");
2934 
2935  ArrayVector<hsize_t> boffset, bshape, bones(N+1, 1);
2936  hssize_t dimensions = getDatasetDimensions_(datasetHandle);
2937  if(numBandsOfType > 1)
2938  {
2939  vigra_precondition(N+1 == dimensions,
2940  "HDF5File::readBlock(): Array dimension disagrees with data dimension.");
2941  bshape.resize(N+1);
2942  boffset.resize(N+1);
2943  bshape[N] = numBandsOfType;
2944  boffset[N] = 0;
2945  }
2946  else
2947  {
2948  vigra_precondition(N == dimensions,
2949  "HDF5File::readBlock(): Array dimension disagrees with data dimension.");
2950  bshape.resize(N);
2951  boffset.resize(N);
2952  }
2953 
2954  for(int i = 0; i < N; ++i)
2955  {
2956  // vigra and hdf5 use different indexing
2957  bshape[N-1-i] = array.shape(i);
2958  boffset[N-1-i] = blockOffset[i];
2959  }
2960 
2961  // create a target dataspace in memory with the shape of the desired block
2962  HDF5Handle memspace_handle (H5Screate_simple(bshape.size(), bshape.data(), NULL),
2963  &H5Sclose,
2964  "Unable to get origin dataspace");
2965 
2966  // get file dataspace and select the desired block
2967  HDF5Handle dataspaceHandle (H5Dget_space(datasetHandle),&H5Sclose,"Unable to create target dataspace");
2968  H5Sselect_hyperslab(dataspaceHandle, H5S_SELECT_SET,
2969  boffset.data(), bones.data(), bones.data(), bshape.data());
2970 
2971  herr_t status = 0;
2972  if(array.isUnstrided())
2973  {
2974  // when the array is unstrided, we can read the data directly from the array buffer
2975  status = H5Dwrite( datasetHandle, datatype, memspace_handle, dataspaceHandle, H5P_DEFAULT, array.data());
2976  }
2977  else
2978  {
2979  // otherwise, we must copy the data into an unstrided extra buffer
2980  MultiArray<N, T> buffer(array);
2981  status = H5Dwrite( datasetHandle, datatype, memspace_handle, dataspaceHandle, H5P_DEFAULT, buffer.data());
2982  }
2983  return status;
2984 }
2985 
2986 /********************************************************************/
2987 
2988 template<unsigned int N, class T, class Stride>
2989 void HDF5File::write_attribute_(std::string name,
2990  const std::string & attribute_name,
2991  const MultiArrayView<N, T, Stride> & array,
2992  const hid_t datatype,
2993  const int numBandsOfType)
2994 {
2995  vigra_precondition(!isReadOnly(),
2996  "HDF5File::writeAttribute(): file is read-only.");
2997 
2998  // shape of the array. Add one dimension, if array contains non-scalars.
2999  ArrayVector<hsize_t> shape(array.shape().begin(), array.shape().end());
3000  std::reverse(shape.begin(), shape.end());
3001  if(numBandsOfType > 1)
3002  shape.push_back(numBandsOfType);
3003 
3004  HDF5Handle dataspace(H5Screate_simple(shape.size(),
3005  shape.begin(), NULL),
3006  &H5Sclose, "HDF5File::writeAttribute(): Can not"
3007  " create dataspace.");
3008 
3009  std::string errorMessage ("HDF5File::writeAttribute(): can not find "
3010  "object '" + name + "'.");
3011 
3012  H5O_type_t h5_type = get_object_type_(name);
3013  bool is_group = h5_type == H5O_TYPE_GROUP;
3014  if (!is_group && h5_type != H5O_TYPE_DATASET)
3015  vigra_precondition(0, "HDF5File::writeAttribute(): object \""
3016  + name + "\" is neither a group nor a "
3017  "dataset.");
3018  // get parent object handle
3019  HDF5Handle object_handle(is_group
3020  ? openCreateGroup_(name)
3021  : getDatasetHandle_(name),
3022  is_group
3023  ? &H5Gclose
3024  : &H5Dclose,
3025  errorMessage.c_str());
3026  // create / open attribute
3027  bool exists = existsAttribute(name, attribute_name);
3028  HDF5Handle attributeHandle(exists
3029  ? H5Aopen(object_handle,
3030  attribute_name.c_str(),
3031  H5P_DEFAULT)
3032  : H5Acreate(object_handle,
3033  attribute_name.c_str(), datatype,
3034  dataspace, H5P_DEFAULT,
3035  H5P_DEFAULT),
3036  &H5Aclose,
3037  "HDF5File::writeAttribute(): Can not create"
3038  " attribute.");
3039  herr_t status = 0;
3040  if(array.isUnstrided())
3041  {
3042  // write the data directly from the array data buffer
3043  status = H5Awrite(attributeHandle, datatype, array.data());
3044  }
3045  else
3046  {
3047  // write the data via an unstrided copy
3048  // (we assume that attributes are small arrays, so that the wasted memory is uncritical)
3049  MultiArray<N, T> buffer(array);
3050  status = H5Awrite(attributeHandle, datatype, buffer.data());
3051  }
3052  vigra_postcondition(status >= 0,
3053  "HDF5File::writeAttribute(): write to attribute '" + attribute_name + "' via H5Awrite() failed.");
3054 }
3055 
3056 /********************************************************************/
3057 
3058 template<unsigned int N, class T, class Stride>
3059 void HDF5File::read_(std::string datasetName,
3061  const hid_t datatype, const int numBandsOfType)
3062 {
3063  //Prepare to read without using HDF5ImportInfo
3064  ArrayVector<hsize_t> dimshape = getDatasetShape(datasetName);
3065 
3066  std::string errorMessage ("HDF5File::read(): Unable to open dataset '" + datasetName + "'.");
3067  HDF5Handle datasetHandle(getDatasetHandle_(datasetName), &H5Dclose, errorMessage.c_str());
3068 
3069  // the object in the HDF5 file may have one additional dimension which we
3070  // interprete as the pixel type's bands
3071  int offset = (numBandsOfType > 1)
3072  ? 1
3073  : 0;
3074 
3075  vigra_precondition(MultiArrayIndex(N + offset) == MultiArrayIndex(dimshape.size()),
3076  "HDF5File::read(): Array dimension disagrees with dataset dimension.");
3077 
3078  typename MultiArrayShape<N>::type shape;
3079  for(int k=offset; k < (int)dimshape.size(); ++k)
3080  shape[k-offset] = (MultiArrayIndex)dimshape[k];
3081 
3082  vigra_precondition(shape == array.shape(),
3083  "HDF5File::read(): Array shape disagrees with dataset shape.");
3084  if (offset)
3085  vigra_precondition(dimshape[0] == static_cast<hsize_t>(numBandsOfType),
3086  "HDF5File::read(): Band count doesn't match destination array compound type.");
3087 
3088  herr_t status = 0;
3089  if(array.isUnstrided())
3090  {
3091  // when the array is unstrided, we can read the data directly into the array buffer
3092  status = H5Dread(datasetHandle, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, array.data() );
3093  }
3094  else
3095  {
3096  // otherwise, we need an intermediate buffer
3097 
3098  ArrayVector<hsize_t> null(dimshape.size(), 0),
3099  chunks(dimshape.size(), 1),
3100  start(dimshape.size(), 0),
3101  count(dimshape.size(), 1);
3102 
3103  HDF5Handle properties(H5Dget_create_plist(datasetHandle),
3104  &H5Pclose, "HDF5File::read(): failed to get property list");
3105  if(H5D_CHUNKED == H5Pget_layout(properties))
3106  {
3107  // if the file is chunked, we use a buffer that matches the chunk size.
3108  H5Pget_chunk(properties, static_cast<int>(chunks.size()), chunks.data());
3109  std::reverse(chunks.begin(), chunks.end());
3110  }
3111  else
3112  {
3113  // otherwise, we compute a suitable chunk size.
3114  chunks[0] = numBandsOfType;
3115  MultiArrayIndex prod = 1;
3116  for(unsigned int k=0; k<N; ++k)
3117  {
3118  chunks[k+offset] = array.shape(k);
3119  prod *= array.shape(k);
3120  if(prod > 300000)
3121  break;
3122  }
3123  }
3124 
3125  count[N-1-offset] = static_cast<hsize_t>(numBandsOfType);
3126 
3127  typedef typename MultiArrayShape<N>::type Shape;
3128  Shape chunkCount, chunkMaxShape;
3129  for(unsigned int k=offset; k<chunks.size(); ++k)
3130  {
3131  chunkMaxShape[k-offset] = chunks[k];
3132  chunkCount[k-offset] = (MultiArrayIndex)std::ceil(double(dimshape[k]) / chunks[k]);
3133  }
3134 
3135  typename CoupledIteratorType<N>::type chunkIter = createCoupledIterator(chunkCount),
3136  chunkEnd = chunkIter.getEndIterator();
3137  for(; chunkIter != chunkEnd; ++chunkIter)
3138  {
3139  Shape chunkStart(chunkIter.point() * chunkMaxShape),
3140  chunkStop(min(chunkStart + chunkMaxShape, array.shape()));
3141  MultiArray<N, T> buffer(chunkStop - chunkStart);
3142 
3143  for(unsigned int k=0; k<N; ++k)
3144  {
3145  start[N-1-k] = chunkStart[k];
3146  count[N-1-k] = buffer.shape(k);
3147  }
3148  if(offset == 1)
3149  {
3150  start[N] = 0;
3151  count[N] = numBandsOfType;
3152  }
3153  HDF5Handle filespace(H5Dget_space(datasetHandle),
3154  &H5Sclose, "HDF5File::read(): unable to create hyperslabs.");
3155  status = H5Sselect_hyperslab(filespace, H5S_SELECT_SET, start.data(), NULL, count.data(), NULL);
3156  if(status < 0)
3157  break;
3158 
3159  HDF5Handle dataspace(H5Screate_simple(count.size(), count.data(), NULL),
3160  &H5Sclose, "HDF5File::read(): unable to create hyperslabs.");
3161  status = H5Sselect_hyperslab(dataspace, H5S_SELECT_SET, null.data(), NULL, count.data(), NULL);
3162  if(status < 0)
3163  break;
3164 
3165  status = H5Dread(datasetHandle, datatype, dataspace, filespace, H5P_DEFAULT, buffer.data());
3166  if(status < 0)
3167  break;
3168 
3169  array.subarray(chunkStart, chunkStop) = buffer;
3170  }
3171  }
3172  vigra_postcondition(status >= 0,
3173  "HDF5File::read(): read from dataset '" + datasetName + "' via H5Dread() failed.");
3174 }
3175 
3176 /********************************************************************/
3177 
3178 template<unsigned int N, class T, class Stride>
3179 herr_t HDF5File::readBlock_(HDF5HandleShared datasetHandle,
3180  typename MultiArrayShape<N>::type &blockOffset,
3181  typename MultiArrayShape<N>::type &blockShape,
3183  const hid_t datatype, const int numBandsOfType)
3184 {
3185  vigra_precondition(blockShape == array.shape(),
3186  "HDF5File::readBlock(): Array shape disagrees with block size.");
3187 
3188  ArrayVector<hsize_t> boffset, bshape, bones(N+1, 1);
3189  hssize_t dimensions = getDatasetDimensions_(datasetHandle);
3190  if(numBandsOfType > 1)
3191  {
3192  vigra_precondition(N+1 == dimensions,
3193  "HDF5File::readBlock(): Array dimension disagrees with data dimension.");
3194  bshape.resize(N+1);
3195  boffset.resize(N+1);
3196  bshape[N] = numBandsOfType;
3197  boffset[N] = 0;
3198  }
3199  else
3200  {
3201  vigra_precondition(N == dimensions,
3202  "HDF5File::readBlock(): Array dimension disagrees with data dimension.");
3203  bshape.resize(N);
3204  boffset.resize(N);
3205  }
3206 
3207  for(int i = 0; i < N; ++i)
3208  {
3209  // vigra and hdf5 use different indexing
3210  bshape[N-1-i] = blockShape[i];
3211  boffset[N-1-i] = blockOffset[i];
3212  }
3213 
3214  // create a target dataspace in memory with the shape of the desired block
3215  HDF5Handle memspace_handle(H5Screate_simple(bshape.size(), bshape.data(), NULL),
3216  &H5Sclose,
3217  "Unable to create target dataspace");
3218 
3219  // get file dataspace and select the desired block
3220  HDF5Handle dataspaceHandle(H5Dget_space(datasetHandle), &H5Sclose,
3221  "Unable to get dataspace");
3222  H5Sselect_hyperslab(dataspaceHandle, H5S_SELECT_SET,
3223  boffset.data(), bones.data(), bones.data(), bshape.data());
3224 
3225  herr_t status = 0;
3226  if(array.isUnstrided())
3227  {
3228  // when the array is unstrided, we can read the data directly into the array buffer
3229  status = H5Dread( datasetHandle, datatype, memspace_handle, dataspaceHandle, H5P_DEFAULT, array.data());
3230  }
3231  else
3232  {
3233  // otherwise, we need an unstrided extra buffer ...
3234  MultiArray<N, T> buffer(array.shape());
3235  status = H5Dread( datasetHandle, datatype, memspace_handle, dataspaceHandle, H5P_DEFAULT, buffer.data());
3236  // ... and must copy the values
3237  if(status >= 0)
3238  array = buffer;
3239  }
3240  return status;
3241 }
3242 
3243 /********************************************************************/
3244 
3245 template<unsigned int N, class T, class Stride>
3246 void HDF5File::read_attribute_(std::string datasetName,
3247  std::string attributeName,
3249  const hid_t datatype, const int numBandsOfType)
3250 {
3251  std::string dataset_path = get_absolute_path(datasetName);
3252  // open Attribute handle
3253  std::string message = "HDF5File::readAttribute(): could not get handle for attribute '"+attributeName+"'' of object '"+dataset_path+"'.";
3254  HDF5Handle attr_handle (H5Aopen_by_name(fileHandle_,dataset_path.c_str(),attributeName.c_str(),H5P_DEFAULT,H5P_DEFAULT),&H5Aclose, message.c_str());
3255 
3256  // get Attribute dataspace
3257  message = "HDF5File::readAttribute(): could not get dataspace for attribute '"+attributeName+"'' of object '"+dataset_path+"'.";
3258  HDF5Handle attr_dataspace_handle (H5Aget_space(attr_handle),&H5Sclose,message.c_str());
3259 
3260  // obtain Attribute shape
3261  int raw_dims = H5Sget_simple_extent_ndims(attr_dataspace_handle);
3262  int dims = std::max(raw_dims, 1); // scalar attributes may be stored with raw_dims==0
3263  ArrayVector<hsize_t> dimshape(dims);
3264  if(raw_dims > 0)
3265  H5Sget_simple_extent_dims(attr_dataspace_handle, dimshape.data(), NULL);
3266  else
3267  dimshape[0] = 1;
3268 
3269  // invert the dimensions to guarantee VIGRA-compatible order
3270  std::reverse(dimshape.begin(), dimshape.end());
3271 
3272  int offset = (numBandsOfType > 1)
3273  ? 1
3274  : 0;
3275  message = "HDF5File::readAttribute(): Array dimension disagrees with dataset dimension.";
3276  // the object in the HDF5 file may have one additional dimension which we then interpret as the pixel type bands
3277  vigra_precondition(MultiArrayIndex(N + offset) == MultiArrayIndex(dims), message);
3278 
3279  for(int k=offset; k < (int)dimshape.size(); ++k)
3280  vigra_precondition(array.shape()[k-offset] == (MultiArrayIndex)dimshape[k],
3281  "HDF5File::readAttribute(): Array shape disagrees with dataset shape");
3282 
3283  herr_t status = 0;
3284  if(array.isUnstrided())
3285  {
3286  // when the array is unstrided, we can read the data directly into the array buffer
3287  status = H5Aread( attr_handle, datatype, array.data());
3288  }
3289  else
3290  {
3291  // otherwise, we need an unstrided extra buffer ...
3292  // (we assume that attributes are small arrays, so that the wasted memory is uncritical)
3293  MultiArray<N, T> buffer(array.shape());
3294  status = H5Aread( attr_handle, datatype, buffer.data() );
3295  // ... and must copy the values
3296  if(status >= 0)
3297  array = buffer;
3298  }
3299  vigra_postcondition(status >= 0,
3300  "HDF5File::readAttribute(): read from attribute '" + attributeName + "' via H5Aread() failed.");
3301 }
3302 
3303 /********************************************************************/
3304 
3305 /** \brief Read the data specified by the given \ref vigra::HDF5ImportInfo object
3306  and write the into the given 'array'.
3307 
3308  The array must have the correct number of dimensions and shape for the dataset
3309  represented by 'info'. When the element type of 'array' differs from the stored element
3310  type, HDF5 will convert the type on the fly (except when the HDF5 version is 1.6 or below,
3311  in which case an error will result). Multi-channel element types (i.e. \ref vigra::RGBValue,
3312  \ref vigra::TinyVector, and \ref vigra::FFTWComplex) are recognized and handled correctly.
3313 
3314  <b> Declaration:</b>
3315 
3316  \code
3317  namespace vigra {
3318  template<unsigned int N, class T, class StrideTag>
3319  void
3320  readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, T, StrideTag> array);
3321  }
3322  \endcode
3323 
3324  <b> Usage:</b>
3325 
3326  <b>\#include</b> <vigra/hdf5impex.hxx><br>
3327  Namespace: vigra
3328 
3329  \code
3330 
3331  HDF5ImportInfo info(filename, dataset_name);
3332  vigra_precondition(info.numDimensions() == 3, "Dataset must be 3-dimensional.");
3333 
3334  MultiArrayShape<3>::type shape(info.shape().begin());
3335  MultiArray<3, int> array(shape);
3336 
3337  readHDF5(info, array);
3338  \endcode
3339 */
3340 doxygen_overloaded_function(template <...> void readHDF5)
3341 
3342 template<unsigned int N, class T, class StrideTag>
3343 inline void readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, T, StrideTag> array)
3344 {
3345  readHDF5(info, array, 0, 0); // last two arguments are not used
3346 }
3347 
3348 template<unsigned int N, class T, class StrideTag>
3349 void readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, T, StrideTag> array, const hid_t datatype, const int numBandsOfType)
3350 {
3351  HDF5File file(info.getFilePath(), HDF5File::OpenReadOnly);
3352  file.read(info.getPathInFile(), array);
3353  file.close();
3354 }
3355 
3356 inline hid_t openGroup(hid_t parent, std::string group_name)
3357 {
3358  //std::cout << group_name << std::endl;
3359  size_t last_slash = group_name.find_last_of('/');
3360  if (last_slash == std::string::npos || last_slash != group_name.size() - 1)
3361  group_name = group_name + '/';
3362  std::string::size_type begin = 0, end = group_name.find('/');
3363  int ii = 0;
3364  while (end != std::string::npos)
3365  {
3366  std::string group(group_name.begin()+begin, group_name.begin()+end);
3367  hid_t prev_parent = parent;
3368  parent = H5Gopen(prev_parent, group.c_str(), H5P_DEFAULT);
3369 
3370  if(ii != 0) H5Gclose(prev_parent);
3371  if(parent < 0) return parent;
3372  ++ii;
3373  begin = end + 1;
3374  end = group_name.find('/', begin);
3375  }
3376  return parent;
3377 }
3378 
3379 inline hid_t createGroup(hid_t parent, std::string group_name)
3380 {
3381  if(group_name.size() == 0 ||*group_name.rbegin() != '/')
3382  group_name = group_name + '/';
3383  if(group_name == "/")
3384  return H5Gopen(parent, group_name.c_str(), H5P_DEFAULT);
3385 
3386  std::string::size_type begin = 0, end = group_name.find('/');
3387  int ii = 0;
3388  while (end != std::string::npos)
3389  {
3390  std::string group(group_name.begin()+begin, group_name.begin()+end);
3391  hid_t prev_parent = parent;
3392 
3393  if(H5LTfind_dataset(parent, group.c_str()) == 0)
3394  {
3395  parent = H5Gcreate(prev_parent, group.c_str(), H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
3396  } else {
3397  parent = H5Gopen(prev_parent, group.c_str(), H5P_DEFAULT);
3398  }
3399 
3400  if(ii != 0) H5Gclose(prev_parent);
3401  if(parent < 0) return parent;
3402  ++ii;
3403  begin = end + 1;
3404  end = group_name.find('/', begin);
3405  }
3406  return parent;
3407 }
3408 
3409 inline void deleteDataset(hid_t parent, std::string dataset_name)
3410 {
3411  // delete existing data and create new dataset
3412  if(H5LTfind_dataset(parent, dataset_name.c_str()))
3413  {
3414  //std::cout << "dataset already exists" << std::endl;
3415 #if (H5_VERS_MAJOR == 1 && H5_VERS_MINOR <= 6)
3416  if(H5Gunlink(parent, dataset_name.c_str()) < 0)
3417  {
3418  vigra_postcondition(false, "writeToHDF5File(): Unable to delete existing data.");
3419  }
3420 #else
3421  if(H5Ldelete(parent, dataset_name.c_str(), H5P_DEFAULT ) < 0)
3422  {
3423  vigra_postcondition(false, "createDataset(): Unable to delete existing data.");
3424  }
3425 #endif
3426  }
3427 }
3428 
3429 inline hid_t createFile(std::string filePath, bool append_ = true)
3430 {
3431  FILE * pFile;
3432  pFile = fopen ( filePath.c_str(), "r" );
3433  hid_t file_id;
3434  if ( pFile == NULL )
3435  {
3436  file_id = H5Fcreate(filePath.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
3437  }
3438  else if(append_)
3439  {
3440  fclose( pFile );
3441  file_id = H5Fopen(filePath.c_str(), H5F_ACC_RDWR, H5P_DEFAULT);
3442  }
3443  else
3444  {
3445  fclose(pFile);
3446  std::remove(filePath.c_str());
3447  file_id = H5Fcreate(filePath.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
3448  }
3449  return file_id;
3450 }
3451 
3452 template<unsigned int N, class T, class Tag>
3453 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)
3454 {
3455  std::string path_name(pathInFile), group_name, data_set_name, message;
3456  std::string::size_type delimiter = path_name.rfind('/');
3457 
3458  //create or open file
3459  file_handle = HDF5Handle(createFile(filePath), &H5Fclose,
3460  "createDataset(): unable to open output file.");
3461 
3462  // get the groupname and the filename
3463  if(delimiter == std::string::npos)
3464  {
3465  group_name = "/";
3466  data_set_name = path_name;
3467  }
3468  else
3469  {
3470  group_name = std::string(path_name.begin(), path_name.begin()+delimiter);
3471  data_set_name = std::string(path_name.begin()+delimiter+1, path_name.end());
3472  }
3473 
3474  // create all groups
3475  HDF5Handle group(createGroup(file_handle, group_name), &H5Gclose,
3476  "createDataset(): Unable to create and open group. generic v");
3477 
3478  // delete the dataset if it already exists
3479  deleteDataset(group, data_set_name);
3480 
3481  // create dataspace
3482  // add an extra dimension in case that the data is non-scalar
3483  HDF5Handle dataspace_handle;
3484  if(numBandsOfType > 1) {
3485  // invert dimensions to guarantee c-order
3486  hsize_t shape_inv[N+1]; // one additional dimension for pixel type channel(s)
3487  for(unsigned int k=0; k<N; ++k) {
3488  shape_inv[N-1-k] = array.shape(k); // the channels (eg of an RGB image) are represented by the first dimension (before inversion)
3489  //std::cout << shape_inv[N-k] << " (" << N << ")";
3490  }
3491  shape_inv[N] = numBandsOfType;
3492 
3493  // create dataspace
3494  dataspace_handle = HDF5Handle(H5Screate_simple(N+1, shape_inv, NULL),
3495  &H5Sclose, "createDataset(): unable to create dataspace for non-scalar data.");
3496  } else {
3497  // invert dimensions to guarantee c-order
3498  hsize_t shape_inv[N];
3499  for(unsigned int k=0; k<N; ++k)
3500  shape_inv[N-1-k] = array.shape(k);
3501 
3502  // create dataspace
3503  dataspace_handle = HDF5Handle(H5Screate_simple(N, shape_inv, NULL),
3504  &H5Sclose, "createDataset(): unable to create dataspace for scalar data.");
3505  }
3506 
3507  //alloc memory for dataset.
3508  dataset_handle = HDF5Handle(H5Dcreate(group,
3509  data_set_name.c_str(),
3510  datatype,
3511  dataspace_handle,
3512  H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT),
3513  &H5Dclose, "createDataset(): unable to create dataset.");
3514 }
3515 
3516 
3517 
3518 
3519 /** \brief Store array data in an HDF5 file.
3520 
3521  The number of dimensions, shape and element type of the stored dataset is automatically
3522  determined from the properties of the given \a array. Strided arrays are stored in an
3523  unstrided way, i.e. in contiguous scan-order. Multi-channel element types
3524  (i.e. \ref vigra::RGBValue, \ref vigra::TinyVector and \ref vigra::FFTWComplex)
3525  are recognized and handled correctly
3526  (in particular, the will form the innermost dimension of the stored dataset).
3527  \a pathInFile may contain '/'-separated group names, but must end with the name
3528  of the dataset to be created.
3529 
3530  <b> Declaration:</b>
3531 
3532  \code
3533  namespace vigra {
3534  template<unsigned int N, class T, class StrideTag>
3535  void
3536  writeHDF5(const char* filePath, const char* pathInFile,
3537  MultiArrayView<N, T, StrideTag>const & array);
3538  }
3539  \endcode
3540 
3541  <b> Usage:</b>
3542 
3543  <b>\#include</b> <vigra/hdf5impex.hxx><br>
3544  Namespace: vigra
3545 
3546  \code
3547  MultiArrayShape<3>::type shape(100, 200, 20);
3548  MultiArray<3, int> array(shape);
3549  ... // fill array with data
3550 
3551  writeHDF5("mydata.h5", "/group1/my_dataset", array);
3552  \endcode
3553 */
3554 doxygen_overloaded_function(template <...> void writeHDF5)
3555 
3556 template<unsigned int N, class T, class StrideTag>
3557 inline void writeHDF5(const char* filePath, const char* pathInFile, const MultiArrayView<N, T, StrideTag> & array)
3558 {
3559  //last two arguments are not used
3560  writeHDF5(filePath, pathInFile, array, 0, 0);
3561 }
3562 
3563 template<unsigned int N, class T, class StrideTag>
3564 void writeHDF5(const char* filePath, const char* pathInFile, const MultiArrayView<N, T, StrideTag> & array, const hid_t datatype, const int numBandsOfType)
3565 {
3566  HDF5File file(filePath, HDF5File::Open);
3567  file.write(pathInFile, array);
3568  file.close();
3569 }
3570 
3571 
3572 namespace detail
3573 {
3574 struct MaxSizeFnc
3575 {
3576  size_t size;
3577 
3578  MaxSizeFnc()
3579  : size(0)
3580  {}
3581 
3582  void operator()(std::string const & in)
3583  {
3584  size = in.size() > size ?
3585  in.size() :
3586  size;
3587  }
3588 };
3589 }
3590 
3591 
3592 #if (H5_VERS_MAJOR == 1 && H5_VERS_MINOR == 8) || DOXYGEN
3593 /** Write a numeric MultiArray as an attribute with name \a name
3594  of the dataset specified by the handle \a loc.
3595 
3596  <b>\#include</b> <vigra/hdf5impex.hxx><br>
3597  Namespace: vigra
3598 */
3599 template<size_t N, class T, class C>
3600 void writeHDF5Attr(hid_t loc,
3601  const char* name,
3602  MultiArrayView<N, T, C> const & array)
3603 {
3604  if(H5Aexists(loc, name) > 0)
3605  H5Adelete(loc, name);
3606 
3607  ArrayVector<hsize_t> shape(array.shape().begin(),
3608  array.shape().end());
3609  HDF5Handle
3610  dataspace_handle(H5Screate_simple(N, shape.data(), NULL),
3611  &H5Sclose,
3612  "writeToHDF5File(): unable to create dataspace.");
3613 
3614  HDF5Handle attr(H5Acreate(loc,
3615  name,
3616  detail::getH5DataType<T>(),
3617  dataspace_handle,
3618  H5P_DEFAULT ,H5P_DEFAULT ),
3619  &H5Aclose,
3620  "writeHDF5Attr: unable to create Attribute");
3621 
3622  //copy data - since attributes are small - who cares!
3623  ArrayVector<T> buffer;
3624  for(int ii = 0; ii < array.size(); ++ii)
3625  buffer.push_back(array[ii]);
3626  H5Awrite(attr, detail::getH5DataType<T>(), buffer.data());
3627 }
3628 
3629 /** Write a string MultiArray as an attribute with name \a name
3630  of the dataset specified by the handle \a loc.
3631 
3632  <b>\#include</b> <vigra/hdf5impex.hxx><br>
3633  Namespace: vigra
3634 */
3635 template<size_t N, class C>
3636 void writeHDF5Attr(hid_t loc,
3637  const char* name,
3638  MultiArrayView<N, std::string, C> const & array)
3639 {
3640  if(H5Aexists(loc, name) > 0)
3641  H5Adelete(loc, name);
3642 
3643  ArrayVector<hsize_t> shape(array.shape().begin(),
3644  array.shape().end());
3645  HDF5Handle
3646  dataspace_handle(H5Screate_simple(N, shape.data(), NULL),
3647  &H5Sclose,
3648  "writeToHDF5File(): unable to create dataspace.");
3649 
3650  HDF5Handle atype(H5Tcopy (H5T_C_S1),
3651  &H5Tclose,
3652  "writeToHDF5File(): unable to create type.");
3653 
3654  detail::MaxSizeFnc max_size;
3655  max_size = std::for_each(array.data(),array.data()+ array.size(), max_size);
3656  H5Tset_size (atype, max_size.size);
3657 
3658  HDF5Handle attr(H5Acreate(loc,
3659  name,
3660  atype,
3661  dataspace_handle,
3662  H5P_DEFAULT ,H5P_DEFAULT ),
3663  &H5Aclose,
3664  "writeHDF5Attr: unable to create Attribute");
3665 
3666  std::string buf ="";
3667  for(int ii = 0; ii < array.size(); ++ii)
3668  {
3669  buf = buf + array[ii]
3670  + std::string(max_size.size - array[ii].size(), ' ');
3671  }
3672  H5Awrite(attr, atype, buf.c_str());
3673 }
3674 
3675 /** Write a numeric ArrayVectorView as an attribute with name \a name
3676  of the dataset specified by the handle \a loc.
3677 
3678  <b>\#include</b> <vigra/hdf5impex.hxx><br>
3679  Namespace: vigra
3680 */
3681 template<class T>
3682 inline void writeHDF5Attr( hid_t loc,
3683  const char* name,
3684  ArrayVectorView<T> & array)
3685 {
3686  writeHDF5Attr(loc, name,
3688  array.data()));
3689 }
3690 
3691 /** write an Attribute given a file and a path in the file.
3692  the path in the file should have the format
3693  [attribute] or /[subgroups/]dataset.attribute or
3694  /[subgroups/]group.attribute.
3695  The attribute is written to the root group, a dataset or a subgroup
3696  respectively
3697 */
3698 template<class Arr>
3699 inline void writeHDF5Attr( std::string filePath,
3700  std::string pathInFile,
3701  Arr & ar)
3702 {
3703  std::string path_name(pathInFile), group_name, data_set_name, message, attr_name;
3704  std::string::size_type delimiter = path_name.rfind('/');
3705 
3706  //create or open file
3707  HDF5Handle file_id(createFile(filePath), &H5Fclose,
3708  "writeToHDF5File(): unable to open output file.");
3709 
3710  // get the groupname and the filename
3711  if(delimiter == std::string::npos)
3712  {
3713  group_name = "/";
3714  data_set_name = path_name;
3715  }
3716 
3717  else
3718  {
3719  group_name = std::string(path_name.begin(), path_name.begin()+delimiter);
3720  data_set_name = std::string(path_name.begin()+delimiter+1, path_name.end());
3721  }
3722  delimiter = data_set_name.rfind('.');
3723  if(delimiter == std::string::npos)
3724  {
3725  attr_name = path_name;
3726  data_set_name = "/";
3727  }
3728  else
3729  {
3730  attr_name = std::string(data_set_name.begin()+delimiter+1, data_set_name.end());
3731  data_set_name = std::string(data_set_name.begin(), data_set_name.begin()+delimiter);
3732  }
3733 
3734  HDF5Handle group(openGroup(file_id, group_name), &H5Gclose,
3735  "writeToHDF5File(): Unable to create and open group. attr ver");
3736 
3737  if(data_set_name != "/")
3738  {
3739  HDF5Handle dset(H5Dopen(group, data_set_name.c_str(), H5P_DEFAULT), &H5Dclose,
3740  "writeHDF5Attr():unable to open dataset");
3741  writeHDF5Attr(hid_t(dset), attr_name.c_str(), ar);
3742  }
3743  else
3744  {
3745  writeHDF5Attr(hid_t(group), attr_name.c_str(), ar);
3746  }
3747 
3748 }
3749 #endif
3750 
3751 //@}
3752 
3753 } // namespace vigra
3754 
3755 #endif // VIGRA_HDF5IMPEX_HXX
ArrayVector< hsize_t > getDatasetShape(std::string datasetName) const
Get the shape of each dimension of a certain dataset.
Definition: hdf5impex.hxx:1369
HDF5File & operator=(HDF5File const &other)
Assign a HDF5File object.
Definition: hdf5impex.hxx:1125
hssize_t getDatasetDimensions(std::string datasetName) const
Get the number of dimensions of a certain dataset If the first character is a "/", the path will be interpreted as absolute path, otherwise it will be interpreted as path relative to the current group.
Definition: hdf5impex.hxx:1340
void read(const std::string &datasetName, ArrayVectorView< T > array)
Read data into an array vector. If the first character of datasetName is a "/", the path will be inte...
Definition: hdf5impex.hxx:1954
const std::string & getFilePath() const
HDF5Handle()
Default constructor. Creates a NULL handle.
Definition: hdf5impex.hxx:203
void write(const std::string &datasetName, const ArrayVectorView< T > &array, int compression=0)
Write array vectors.
Definition: hdf5impex.hxx:1841
ArrayVector< hsize_t > const & shape() const
Definition: hdf5impex.hxx:710
HDF5Handle getAttributeHandle(std::string dataset_name, std::string attribute_name) const
Obtain the HDF5 handle of a attribute.
Definition: hdf5impex.hxx:1535
bool cd_up(int levels)
Change the current group to its parent group. Returns true if successful, false otherwise. If unsuccessful, the group will not change.
Definition: hdf5impex.hxx:1222
bool operator!=(HDF5Handle const &h) const
Inequality comparison of the contained handle.
Definition: hdf5impex.hxx:358
Temporarily disable HDF5&#39;s native error output.
Definition: hdf5impex.hxx:128
Wrapper for unique hid_t objects.
Definition: hdf5impex.hxx:189
HDF5File(std::string filePath, OpenMode mode, bool track_creation_times=false)
Open or create an HDF5File object.
Definition: hdf5impex.hxx:1050
bool operator==(hid_t h) const
Equality comparison of the contained handle.
Definition: hdf5impex.hxx:351
HDF5HandleShared()
Default constructor. Creates a NULL handle.
Definition: hdf5impex.hxx:425
bool existsDataset(std::string datasetName) const
Check if given datasetName exists.
Definition: hdf5impex.hxx:1329
void readAttribute(std::string object_name, std::string attribute_name, MultiArrayView< N, T, Stride > array)
Read MultiArray Attributes. In contrast to datasets, subarray access is not available.
Definition: hdf5impex.hxx:1635
void cd_mk(std::string groupName)
Change the current group; create it if necessary. If the first character is a "/", the path will be interpreted as absolute path, otherwise it will be interpreted as path relative to the current group.
Definition: hdf5impex.hxx:1260
void listAttributes(std::string const &group_or_dataset, Container &container) const
Insert the attribute names of the given group or dataset into the given container by calling containe...
Definition: hdf5impex.hxx:1527
bool unique() const
Check if this is the unique owner of the conatined handle.
Definition: hdf5impex.hxx:556
void ls(Container &cont) const
List the contents of the current group into a container-like object via insert(). ...
Definition: hdf5impex.hxx:1307
bool operator==(hid_t h) const
Equality comparison of the contained handle.
Definition: hdf5impex.hxx:601
Definition: array_vector.hxx:76
std::vector< std::string > ls() const
List the contents of the current group. The function returns a vector of strings holding the entries ...
Definition: hdf5impex.hxx:1285
std::vector< std::string > listAttributes(std::string const &group_or_dataset) const
List the attribute names of the given group or dataset.
Definition: hdf5impex.hxx:1512
Definition: array_vector.hxx:954
HDF5Handle(hid_t h, Destructor destructor, const char *error_message)
Create a wrapper for a hid_t object.
Definition: hdf5impex.hxx:227
void swap(HDF5HandleShared &h)
Swap the contents of two handle wrappers.
Definition: hdf5impex.hxx:565
void reshape(const difference_type &shape)
Definition: multi_array.hxx:2809
void mkdir(std::string groupName)
Create a new group. If the first character is a "/", the path will be interpreted as absolute path...
Definition: hdf5impex.hxx:1243
bool isUnstrided(unsigned int dimension=N-1) const
Definition: multi_array.hxx:1234
MultiArrayView subarray(difference_type p, difference_type q) const
Definition: multi_array.hxx:1476
const std::string & getPathInFile() const
bool existsAttribute(std::string object_name, std::string attribute_name)
Test if attribute exists.
Definition: hdf5impex.hxx:1618
HDF5Handle getDatasetHandle(std::string const &datasetName) const
Obtain the HDF5 handle of a dataset.
Definition: hdf5impex.hxx:1456
difference_type_1 size() const
Definition: multi_array.hxx:1589
std::ptrdiff_t MultiArrayIndex
Definition: multi_fwd.hxx:60
void writeHDF5Attr(hid_t loc, const char *name, MultiArrayView< N, T, C > const &array)
Definition: hdf5impex.hxx:3600
HDF5HandleShared createDataset(std::string datasetName, TinyVector< MultiArrayIndex, N > const &shape, typename detail::HDF5TypeTraits< T >::value_type init=typename detail::HDF5TypeTraits< T >::value_type(), TinyVector< MultiArrayIndex, N > const &chunkSize=(TinyVector< MultiArrayIndex, N >()), int compressionParameter=0)
Create a new dataset. This function can be used to create a dataset filled with a default value init...
Definition: hdf5impex.hxx:2702
Definition: accessor.hxx:43
hid_t release()
Return the contained handle and set the wrapper to NULL without calling close().
Definition: hdf5impex.hxx:288
herr_t close()
Close the handle if this is the unique (i.e. last) owner.
Definition: hdf5impex.hxx:506
void write(std::string datasetName, const MultiArrayView< N, T, Stride > &array, typename MultiArrayShape< N >::type chunkSize, int compression=0)
Write multi arrays. Chunks can be activated by providing a MultiArrayShape as chunkSize. chunkSize must have equal dimension as array.
Definition: hdf5impex.hxx:1760
Argument object for the function readHDF5().
Definition: hdf5impex.hxx:661
bool isHDF5(char const *filename)
Check if given filename refers to a HDF5 file.
Definition: hdf5impex.hxx:100
void reset(hid_t h, Destructor destructor, const char *error_message)
Reset the handle to a new value.
Definition: hdf5impex.hxx:529
doxygen_overloaded_function(template<... > void separableConvolveBlockwise) template< unsigned int N
Separated convolution on ChunkedArrays.
HDF5File(HDF5File const &other)
Copy a HDF5File object.
Definition: hdf5impex.hxx:1101
HDF5HandleShared & operator=(HDF5HandleShared const &h)
Assignment. Call close() for the present LHS handle and share ownership with the RHS handle (analogou...
Definition: hdf5impex.hxx:477
HDF5HandleShared(HDF5HandleShared const &h)
Copy constructor. Shares ownership with the RHS handle (analogous to std::shared_ptr).
Definition: hdf5impex.hxx:464
Wrapper for shared hid_t objects.
Definition: hdf5impex.hxx:410
HDF5File()
Default constructor.
Definition: hdf5impex.hxx:1029
HDF5Handle & operator=(HDF5Handle const &h)
Assignment. Calls close() for the LHS handle and hands over ownership of the RHS handle (analogous to...
Definition: hdf5impex.hxx:250
bool operator==(HDF5Handle const &h) const
Equality comparison of the contained handle.
Definition: hdf5impex.hxx:344
~HDF5File()
The destructor flushes and closes the file.
Definition: hdf5impex.hxx:1112
NumericTraits< V >::Promote prod(TinyVectorBase< V, SIZE, D1, D2 > const &l)
product of the vector&#39;s elements
Definition: tinyvector.hxx:2097
const difference_type & shape() const
Definition: multi_array.hxx:1596
HDF5File(HDF5HandleShared const &fileHandle, const std::string &pathname="", bool read_only=false)
Initialize an HDF5File object from HDF5 file handle.
Definition: hdf5impex.hxx:1073
void readAndResize(std::string datasetName, MultiArray< N, T, Alloc > &array)
Read data into a MultiArray. Resize MultiArray to the correct size. If the first character of dataset...
Definition: hdf5impex.hxx:1928
size_t use_count() const
Get the number of owners of the contained handle.
Definition: hdf5impex.hxx:545
void readHDF5(...)
Read the data specified by the given vigra::HDF5ImportInfo object and write the into the given &#39;array...
void readAndResize(std::string datasetName, ArrayVector< T > &array)
Read data into an array vector. Resize the array vector to the correct size. If the first character o...
Definition: hdf5impex.hxx:1967
~HDF5Handle()
Destructor. Calls close() for the contained handle.
Definition: hdf5impex.hxx:265
const_pointer data() const
Definition: array_vector.hxx:209
void read(std::string datasetName, char &data)
Read a single value. Specialization of the read function for simple datatypes.
Definition: hdf5impex.hxx:2099
void open(std::string filePath, OpenMode mode)
Open or create the given file in the given mode and set the group to "/". If another file is currentl...
Definition: hdf5impex.hxx:1162
OpenMode
Set how a file is opened.
Definition: hdf5impex.hxx:1013
void readAttribute(std::string object_name, std::string attribute_name, char &data)
Read a single value. Specialization of the read function for simple datatypes.
Definition: hdf5impex.hxx:1670
void writeBlock(std::string datasetName, typename MultiArrayShape< N >::type blockOffset, const MultiArrayView< N, T, Stride > &array)
Write a multi array into a larger volume. blockOffset determines the position, where array is written...
Definition: hdf5impex.hxx:1782
void flushToDisk()
Immediately write all data to disk.
Definition: hdf5impex.hxx:2171
HDF5Handle(HDF5Handle const &h)
Copy constructor.
Definition: hdf5impex.hxx:239
bool operator!=(hid_t h) const
Inequality comparison of the contained handle.
Definition: hdf5impex.hxx:615
void reset(hid_t h, Destructor destructor, const char *error_message)
Reset the wrapper to a new handle.
Definition: hdf5impex.hxx:300
Class for fixed size vectors.This class contains an array of size SIZE of the specified VALUETYPE...
Definition: accessor.hxx:940
void writeHDF5(...)
Store array data in an HDF5 file.
HDF5Handle getGroupHandle(std::string group_name, std::string function_name="HDF5File::getGroupHandle()")
Obtain the HDF5 handle of a group (create the group if it doesn&#39;t exist).
Definition: hdf5impex.hxx:1472
void read(std::string datasetName, MultiArrayView< N, T, Stride > array)
Read data into a multi array. If the first character of datasetName is a "/", the path will be interp...
Definition: hdf5impex.hxx:1910
std::string filename() const
Get the name of the associated file.
Definition: hdf5impex.hxx:1322
void write(std::string datasetName, char data)
Write a single value. Specialization of the write function for simple datatypes.
Definition: hdf5impex.hxx:1881
const_iterator begin() const
Definition: array_vector.hxx:223
void writeAttribute(std::string object_name, std::string attribute_name, char data)
Write a single value. Specialization of the write function for simple datatypes.
Definition: hdf5impex.hxx:1583
void writeAttribute(std::string object_name, std::string attribute_name, const MultiArrayView< N, T, Stride > &array)
Write MultiArray Attributes. In contrast to datasets, subarray access, chunks and compression are not...
Definition: hdf5impex.hxx:1548
herr_t close()
Explicitly call the stored destructor (if one has been registered in the constructor) for the contain...
Definition: hdf5impex.hxx:275
void write(std::string datasetName, const MultiArrayView< N, T, Stride > &array, int iChunkSize=0, int compression=0)
Write multi arrays.
Definition: hdf5impex.hxx:1728
image import and export functions
bool operator==(HDF5HandleShared const &h) const
Equality comparison of the contained handle.
Definition: hdf5impex.hxx:594
void close()
Close the current file.
Definition: hdf5impex.hxx:1174
bool cd_up()
Change the current group to its parent group. Returns true if successful, false otherwise. If unsuccessful, the group will not change.
Definition: hdf5impex.hxx:1200
Base class for, and view to, vigra::MultiArray.
Definition: multi_array.hxx:652
CoupledScanOrderIterator getEndIterator() const
Definition: multi_iterator_coupled.hxx:282
HDF5HandleShared getDatasetHandleShared(std::string const &datasetName) const
Obtain a shared HDF5 handle of a dataset.
Definition: hdf5impex.hxx:1464
bool operator!=(HDF5HandleShared const &h) const
Inequality comparison of the contained handle.
Definition: hdf5impex.hxx:608
Iterate over multiple images simultaneously in scan order.
Definition: multi_fwd.hxx:167
size_type size() const
Definition: array_vector.hxx:358
bool operator!=(hid_t h) const
Inequality comparison of the contained handle.
Definition: hdf5impex.hxx:365
void readBlock(std::string datasetName, typename MultiArrayShape< N >::type blockOffset, typename MultiArrayShape< N >::type blockShape, MultiArrayView< N, T, Stride > array)
Read a block of data into a multi array. This function allows to read a small block out of a larger v...
Definition: hdf5impex.hxx:2005
Class for a single RGB value.
Definition: accessor.hxx:938
int ceil(FixedPoint< IntBits, FracBits > v)
rounding up.
Definition: fixedpoint.hxx:675
std::string get_absolute_path(std::string path) const
takes any path and converts it into an absolute path in the current file.
Definition: hdf5impex.hxx:2245
HDF5HandleShared(hid_t h, Destructor destructor, const char *error_message)
Create a shared wrapper for a plain hid_t object.
Definition: hdf5impex.hxx:450
const_iterator end() const
Definition: array_vector.hxx:237
~HDF5HandleShared()
Destructor (calls close())
Definition: hdf5impex.hxx:493
pointer data() const
Definition: multi_array.hxx:1846
Wrapper class for the FFTW complex types &#39;fftw_complex&#39;.
Definition: fftw3.hxx:131
void root()
Change current group to "/".
Definition: hdf5impex.hxx:1182
HDF5File(bool track_creation_times)
Construct with time tagging of datasets enabled.
Definition: hdf5impex.hxx:1037
void cd(std::string groupName)
Change the current group. Both absolute and relative group names are allowed.
Definition: hdf5impex.hxx:1191
std::string pwd() const
Get the path of the current group.
Definition: hdf5impex.hxx:1315
void swap(HDF5Handle &h)
Swap the contents of two handle wrappers.
Definition: hdf5impex.hxx:316
Access to HDF5 files.
Definition: hdf5impex.hxx:956
std::string getDatasetType(std::string const &datasetName) const
Definition: hdf5impex.hxx:1410

© 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.11.0