[ 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  H5Fflush(fileHandle_, H5F_SCOPE_GLOBAL);
2174  }
2175 
2176  private:
2177 
2178  /* Simple extension of std::string for splitting into two parts
2179  *
2180  * Strings (in particular: file/dataset paths) will be split into two
2181  * parts. The split is made at the last occurrence of the delimiter.
2182  *
2183  * For example, "/path/to/some/file" will be split (delimiter = "/") into
2184  * first() = "/path/to/some" and last() = "file".
2185  */
2186  class SplitString: public std::string {
2187  public:
2188  SplitString(std::string &sstring): std::string(sstring) {};
2189 
2190  // return the part of the string before the delimiter
2191  std::string first(char delimiter = '/')
2192  {
2193  size_t lastPos = find_last_of(delimiter);
2194  if(lastPos == std::string::npos) // delimiter not found --> no first
2195  return "";
2196 
2197  return std::string(begin(), begin()+lastPos+1);
2198  }
2199 
2200  // return the part of the string after the delimiter
2201  std::string last(char delimiter = '/')
2202  {
2203  size_t lastPos = find_last_of(delimiter);
2204  if(lastPos == std::string::npos) // delimiter not found --> only last
2205  return std::string(*this);
2206  return std::string(begin()+lastPos+1, end());
2207  }
2208  };
2209 
2210  template <class Shape>
2212  defineChunks(Shape chunks, Shape const & shape, int numBands, int compression = 0)
2213  {
2214  if(prod(chunks) > 0)
2215  {
2216  ArrayVector<hsize_t> res(chunks.begin(), chunks.end());
2217  if(numBands > 1)
2218  res.insert(res.begin(), static_cast<hsize_t>(numBands));
2219  return res;
2220  }
2221  else if(compression > 0)
2222  {
2223  // set default chunks to enable compression
2224  chunks = min(detail::ChunkShape<Shape::static_size>::defaultShape(), shape);
2225  ArrayVector<hsize_t> res(chunks.begin(), chunks.end());
2226  if(numBands > 1)
2227  res.insert(res.begin(), static_cast<hsize_t>(numBands));
2228  return res;
2229  }
2230  else
2231  {
2232  return ArrayVector<hsize_t>();
2233  }
2234  }
2235 
2236  public:
2237 
2238  /** \brief takes any path and converts it into an absolute path
2239  in the current file.
2240 
2241  Elements like "." and ".." are treated as expected.
2242  Links are not supported or resolved.
2243  */
2244  inline std::string get_absolute_path(std::string path) const {
2245  // check for empty input or "." and return the current folder
2246  if(path.length() == 0 || path == "."){
2247  return currentGroupName_();
2248  }
2249 
2250  std::string str;
2251  // convert to absolute path
2252  if(relativePath_(path)){
2253  std::string cname = currentGroupName_();
2254  if (cname == "/")
2255  str = currentGroupName_()+path;
2256  else
2257  str = currentGroupName_()+"/"+path;
2258  }else{
2259  str = path;
2260  }
2261 
2262  // cut out "./"
2263  std::string::size_type startpos = 0;
2264  while(str.find(std::string("./"), startpos) != std::string::npos){
2265  std::string::size_type pos = str.find(std::string("./"), startpos);
2266  startpos = pos+1;
2267  // only cut if "./" is not part of "../" (see below)
2268  if(str.substr(pos-1,3) != "../"){
2269  // cut out part of the string
2270  str = str.substr(0,pos) + str.substr(pos+2,str.length()-pos-2);
2271  startpos = pos;
2272  }
2273  }
2274 
2275  // cut out pairs of "bla/../"
2276  while(str.find(std::string("..")) != std::string::npos){
2277  std::string::size_type pos = str.find(std::string(".."));
2278 
2279  // find first slash after ".."
2280  std::string::size_type end = str.find("/",pos);
2281  if(end != std::string::npos){
2282  // also include slash
2283  end++;
2284  }else{
2285  // no "/" after ".." --> this is a group, add a "/"
2286  str = str + "/";
2287  end = str.length();
2288  }
2289 
2290  // find first slash before ".."
2291  std::string::size_type prev_slash = str.rfind("/",pos);
2292  // if the root slash is the first before ".." --> Error
2293  vigra_invariant(prev_slash != 0 && prev_slash != std::string::npos,
2294  "Error parsing path: "+str);
2295  // find second slash before ".."
2296  std::string::size_type begin = str.rfind("/",prev_slash-1);
2297 
2298  // cut out part of the string
2299  str = str.substr(0,begin+1) + str.substr(end,str.length()-end);
2300  }
2301 
2302  return str;
2303  }
2304 
2305  protected:
2306 
2307  /* checks if the given path is a relative path.
2308  */
2309  inline bool relativePath_(std::string & path) const
2310  {
2311  std::string::size_type pos = path.find('/') ;
2312  if(pos == 0)
2313  return false;
2314 
2315  return true;
2316  }
2317 
2318  /* return the name of the current group
2319  */
2320  inline std::string currentGroupName_() const
2321  {
2322  int len = H5Iget_name(cGroupHandle_,NULL,1000);
2323  ArrayVector<char> name (len+1,0);
2324  H5Iget_name(cGroupHandle_,name.begin(),len+1);
2325 
2326  return std::string(name.begin());
2327  }
2328 
2329  /* return the name of the current file
2330  */
2331  inline std::string fileName_() const
2332  {
2333  int len = H5Fget_name(fileHandle_,NULL,1000);
2334  ArrayVector<char> name (len+1,0);
2335  H5Fget_name(fileHandle_,name.begin(),len+1);
2336 
2337  return std::string(name.begin());
2338  }
2339 
2340  /* create an empty file or open an existing one
2341  */
2342  inline hid_t createFile_(std::string filePath, OpenMode mode = Open)
2343  {
2344  // try to open file
2345  FILE * pFile;
2346  pFile = fopen ( filePath.c_str(), "r" );
2347  hid_t fileId;
2348 
2349  // check if opening was successful (= file exists)
2350  if ( pFile == NULL )
2351  {
2352  vigra_precondition(mode != OpenReadOnly,
2353  "HDF5File::open(): cannot open non-existing file in read-only mode.");
2354  fileId = H5Fcreate(filePath.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
2355  }
2356  else
2357  {
2358  fclose(pFile);
2359  if(mode == OpenReadOnly)
2360  {
2361  fileId = H5Fopen(filePath.c_str(), H5F_ACC_RDONLY, H5P_DEFAULT);
2362  }
2363  else if(mode == New)
2364  {
2365  std::remove(filePath.c_str());
2366  fileId = H5Fcreate(filePath.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
2367  }
2368  else
2369  {
2370  fileId = H5Fopen(filePath.c_str(), H5F_ACC_RDWR, H5P_DEFAULT);
2371  }
2372  }
2373  return fileId;
2374  }
2375 
2376  /* \brief Open a group.
2377 
2378  A negative value is returned when the group does not exist or when opening
2379  fails for other reasons.
2380  */
2381  hid_t openGroup_(std::string groupName) const
2382  {
2383  return const_cast<HDF5File *>(this)->openCreateGroup_(groupName, false);
2384  }
2385 
2386  /* \brief Open or create a group.
2387 
2388  If \a create is <tt>true</tt> and the group does not exist, it will be created,
2389  including all necessary parent groups. If group creation fails, a negative
2390  value is returned. Likewise, a negative value is returned when \a create
2391  is <tt>false</tt> and the group does not exist or when opening of the group
2392  fails for other reasons.
2393  */
2394  hid_t openCreateGroup_(std::string groupName, bool create = true)
2395  {
2396  // make groupName clean
2397  groupName = get_absolute_path(groupName);
2398 
2399  // open root group
2400  hid_t parent = H5Gopen(fileHandle_, "/", H5P_DEFAULT);
2401  if(groupName == "/")
2402  {
2403  return parent;
2404  }
2405 
2406  // remove leading /
2407  groupName = std::string(groupName.begin()+1, groupName.end());
2408 
2409  // check if the groupName has finishing slash
2410  if( groupName.size() != 0 && *groupName.rbegin() != '/')
2411  {
2412  groupName = groupName + '/';
2413  }
2414 
2415  // open or create subgroups one by one
2416  std::string::size_type begin = 0, end = groupName.find('/');
2417  while (end != std::string::npos)
2418  {
2419  std::string group(groupName.begin()+begin, groupName.begin()+end);
2420  hid_t prevParent = parent;
2421 
2422  if(H5LTfind_dataset(parent, group.c_str()) == 0)
2423  {
2424  if(create)
2425  parent = H5Gcreate(prevParent, group.c_str(), H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
2426  else
2427  parent = -1;
2428  }
2429  else
2430  {
2431  parent = H5Gopen(prevParent, group.c_str(), H5P_DEFAULT);
2432  }
2433  H5Gclose(prevParent);
2434 
2435  if(parent < 0)
2436  {
2437  return parent;
2438  }
2439  begin = end + 1;
2440  end = groupName.find('/', begin);
2441  }
2442 
2443  return parent;
2444  }
2445 
2446  /* delete a dataset by unlinking it from the file structure. This does not
2447  delete the data!
2448  */
2449  inline void deleteDataset_(hid_t parent, std::string datasetName)
2450  {
2451  // delete existing data and create new dataset
2452  if(H5LTfind_dataset(parent, datasetName.c_str()))
2453  {
2454 
2455  #if (H5_VERS_MAJOR == 1 && H5_VERS_MINOR <= 6)
2456  if(H5Gunlink(parent, datasetName.c_str()) < 0)
2457  {
2458  vigra_postcondition(false, "HDF5File::deleteDataset_(): Unable to delete existing data.");
2459  }
2460  #else
2461  if(H5Ldelete(parent, datasetName.c_str(), H5P_DEFAULT ) < 0)
2462  {
2463  vigra_postcondition(false, "HDF5File::deleteDataset_(): Unable to delete existing data.");
2464  }
2465  #endif
2466  }
2467  }
2468 
2469  /* get the handle of a dataset specified by a string
2470  */
2471  hid_t getDatasetHandle_(std::string datasetName) const
2472  {
2473  // make datasetName clean
2474  datasetName = get_absolute_path(datasetName);
2475 
2476  std::string groupname = SplitString(datasetName).first();
2477  std::string setname = SplitString(datasetName).last();
2478 
2479  if(H5Lexists(fileHandle_, datasetName.c_str(), H5P_DEFAULT) <= 0)
2480  {
2481  std::cerr << "HDF5File::getDatasetHandle_(): Dataset '" << datasetName << "' does not exist.\n";
2482  return -1;
2483  }
2484 
2485  // Open parent group
2486  HDF5Handle groupHandle(openGroup_(groupname), &H5Gclose, "HDF5File::getDatasetHandle_(): Internal error");
2487 
2488  return H5Dopen(groupHandle, setname.c_str(), H5P_DEFAULT);
2489  }
2490 
2491  /* get the type of an object specified by a string
2492  */
2493  H5O_type_t get_object_type_(std::string name) const
2494  {
2495  name = get_absolute_path(name);
2496  std::string group_name = SplitString(name).first();
2497  std::string object_name = SplitString(name).last();
2498  if (!object_name.size())
2499  return H5O_TYPE_GROUP;
2500 
2501  htri_t exists = H5Lexists(fileHandle_, name.c_str(), H5P_DEFAULT);
2502  vigra_precondition(exists > 0, "HDF5File::get_object_type_(): "
2503  "object \"" + name + "\" "
2504  "not found.");
2505  // open parent group
2506  HDF5Handle group_handle(openGroup_(group_name), &H5Gclose, "Internal error");
2507  return HDF5_get_type(group_handle, name.c_str());
2508  }
2509 
2510  /* low-level write function to write vigra MultiArray data as an attribute
2511  */
2512  template<unsigned int N, class T, class Stride>
2513  void write_attribute_(std::string name,
2514  const std::string & attribute_name,
2515  const MultiArrayView<N, T, Stride> & array,
2516  const hid_t datatype,
2517  const int numBandsOfType);
2518 
2519  /* Write single value attribute
2520  This function allows to write data of atomic datatypes (int, long, double)
2521  as an attribute in the HDF5 file. So it is not necessary to create a MultiArray
2522  of size 1 to write a single number.
2523  */
2524  template<class T>
2525  inline void writeAtomicAttribute(std::string datasetName, std::string attributeName, const T data)
2526  {
2527  // make datasetName clean
2528  datasetName = get_absolute_path(datasetName);
2529 
2530  typename MultiArrayShape<1>::type chunkSize;
2531  chunkSize[0] = 0;
2533  array[0] = data;
2534  write_attribute_(datasetName, attributeName, array, detail::getH5DataType<T>(), 1);
2535  }
2536 
2537  /* low-level read function to read vigra MultiArray data from attributes
2538  */
2539  template<unsigned int N, class T, class Stride>
2540  void read_attribute_(std::string datasetName,
2541  std::string attributeName,
2543  const hid_t datatype, const int numBandsOfType);
2544 
2545  /* Read a single value attribute.
2546  This functions allows to read a single value attribute of atomic datatype (int, long, double)
2547  from the HDF5 file. So it is not necessary to create a MultiArray
2548  of size 1 to read a single number.
2549  */
2550  template<class T>
2551  inline void readAtomicAttribute(std::string datasetName, std::string attributeName, T & data)
2552  {
2553  // make datasetName clean
2554  datasetName = get_absolute_path(datasetName);
2555 
2557  read_attribute_(datasetName, attributeName, array, detail::getH5DataType<T>(), 1);
2558  data = array[0];
2559  }
2560 
2561  inline void readAtomicAttribute(std::string datasetName, std::string attributeName, std::string & data)
2562  {
2563  // make datasetName clean
2564  datasetName = get_absolute_path(datasetName);
2565 
2567  read_attribute_(datasetName, attributeName, array, detail::getH5DataType<const char *>(), 1);
2568  data = std::string(array[0]);
2569  }
2570 
2571  /* low-level write function to write vigra unstrided MultiArray data
2572  */
2573  template<unsigned int N, class T, class Stride>
2574  void write_(std::string &datasetName,
2575  const MultiArrayView<N, T, Stride> & array,
2576  const hid_t datatype,
2577  const int numBandsOfType,
2578  typename MultiArrayShape<N>::type &chunkSize,
2579  int compressionParameter = 0);
2580 
2581  /* Write single value as dataset.
2582  This functions allows to write data of atomic datatypes (int, long, double)
2583  as a dataset in the HDF5 file. So it is not necessary to create a MultiArray
2584  of size 1 to write a single number.
2585 
2586  If the first character of datasetName is a "/", the path will be interpreted as absolute path,
2587  otherwise it will be interpreted as path relative to the current group.
2588  */
2589  template<class T>
2590  inline void writeAtomic(std::string datasetName, const T data)
2591  {
2592  // make datasetName clean
2593  datasetName = get_absolute_path(datasetName);
2594 
2595  typename MultiArrayShape<1>::type chunkSize;
2596  chunkSize[0] = 0;
2598  array[0] = data;
2599  write_(datasetName, array, detail::getH5DataType<T>(), 1, chunkSize,0);
2600  }
2601 
2602  /* low-level read function to read vigra unstrided MultiArray data
2603  */
2604  template<unsigned int N, class T, class Stride>
2605  void read_(std::string datasetName,
2607  const hid_t datatype, const int numBandsOfType);
2608 
2609  /* Read a single value.
2610  This functions allows to read a single datum of atomic datatype (int, long, double)
2611  from the HDF5 file. So it is not necessary to create a MultiArray
2612  of size 1 to read a single number.
2613 
2614  If the first character of datasetName is a "/", the path will be interpreted as absolute path,
2615  otherwise it will be interpreted as path relative to the current group.
2616  */
2617  template<class T>
2618  inline void readAtomic(std::string datasetName, T & data)
2619  {
2620  // make datasetName clean
2621  datasetName = get_absolute_path(datasetName);
2622 
2624  read_(datasetName, array, detail::getH5DataType<T>(), 1);
2625  data = array[0];
2626  }
2627 
2628  inline void readAtomic(std::string datasetName, std::string & data)
2629  {
2630  // make datasetName clean
2631  datasetName = get_absolute_path(datasetName);
2632 
2634  read_(datasetName, array, detail::getH5DataType<const char *>(), 1);
2635  data = std::string(array[0]);
2636  }
2637 
2638  /* low-level write function to write vigra unstrided MultiArray data into a sub-block of a dataset
2639  */
2640  template<unsigned int N, class T, class Stride>
2641  void writeBlock_(std::string datasetName,
2642  typename MultiArrayShape<N>::type &blockOffset,
2643  const MultiArrayView<N, T, Stride> & array,
2644  const hid_t datatype,
2645  const int numBandsOfType)
2646  {
2647  // open dataset if it exists
2648  std::string errorMessage = "HDF5File::writeBlock(): Error opening dataset '" + datasetName + "'.";
2649  HDF5HandleShared dataset(getDatasetHandle_(datasetName), &H5Dclose, errorMessage.c_str());
2650  herr_t status = writeBlock_(dataset, blockOffset, array, datatype, numBandsOfType);
2651  vigra_postcondition(status >= 0,
2652  "HDF5File::writeBlock(): write to dataset '" + datasetName + "' via H5Dwrite() failed.");
2653  }
2654 
2655  /* low-level write function to write vigra unstrided MultiArray data into a
2656  sub-block of a dataset. Returns the result of the internal call
2657  to <tt>H5Dwrite()</tt>.
2658  */
2659  template<unsigned int N, class T, class Stride>
2660  herr_t writeBlock_(HDF5HandleShared dataset,
2661  typename MultiArrayShape<N>::type &blockOffset,
2662  const MultiArrayView<N, T, Stride> & array,
2663  const hid_t datatype,
2664  const int numBandsOfType);
2665 
2666  /* low-level read function to read vigra unstrided MultiArray data from a sub-block of a dataset.
2667 
2668  The array must have the same shape as the block.
2669  */
2670  template<unsigned int N, class T, class Stride>
2671  void readBlock_(std::string datasetName,
2672  typename MultiArrayShape<N>::type &blockOffset,
2673  typename MultiArrayShape<N>::type &blockShape,
2675  const hid_t datatype, const int numBandsOfType)
2676  {
2677  std::string errorMessage ("HDF5File::readBlock(): Unable to open dataset '" + datasetName + "'.");
2678  HDF5HandleShared dataset(getDatasetHandle_(datasetName), &H5Dclose, errorMessage.c_str());
2679  herr_t status = readBlock_(dataset, blockOffset, blockShape, array, datatype, numBandsOfType);
2680  vigra_postcondition(status >= 0,
2681  "HDF5File::readBlock(): read from dataset '" + datasetName + "' via H5Dread() failed.");
2682  }
2683 
2684  /* low-level read function to read vigra unstrided MultiArray data from a sub-block of a dataset.
2685 
2686  The array must have the same shape as the block. Returns the result of the internal call
2687  to <tt>H5Dread()</tt>.
2688  */
2689  template<unsigned int N, class T, class Stride>
2690  herr_t readBlock_(HDF5HandleShared dataset,
2691  typename MultiArrayShape<N>::type &blockOffset,
2692  typename MultiArrayShape<N>::type &blockShape,
2694  const hid_t datatype, const int numBandsOfType);
2695 }; /* class HDF5File */
2696 
2697 /********************************************************************/
2698 
2699 template<int N, class T>
2701 HDF5File::createDataset(std::string datasetName,
2702  TinyVector<MultiArrayIndex, N> const & shape,
2703  typename detail::HDF5TypeTraits<T>::value_type init,
2704  TinyVector<MultiArrayIndex, N> const & chunkSize,
2705  int compressionParameter)
2706 {
2707  vigra_precondition(!isReadOnly(),
2708  "HDF5File::createDataset(): file is read-only.");
2709 
2710  // make datasetName clean
2711  datasetName = get_absolute_path(datasetName);
2712 
2713  std::string groupname = SplitString(datasetName).first();
2714  std::string setname = SplitString(datasetName).last();
2715 
2716  hid_t parent = openCreateGroup_(groupname);
2717 
2718  // delete the dataset if it already exists
2719  deleteDataset_(parent, setname);
2720 
2721  // invert dimensions to guarantee c-order
2722  // add an extra dimension in case that the data is non-scalar
2723  typedef detail::HDF5TypeTraits<T> TypeTraits;
2724  ArrayVector<hsize_t> shape_inv;
2725  if(TypeTraits::numberOfBands() > 1)
2726  {
2727  shape_inv.resize(N+1);
2728  shape_inv[N] = TypeTraits::numberOfBands();
2729  }
2730  else
2731  {
2732  shape_inv.resize(N);
2733  }
2734  for(int k=0; k<N; ++k)
2735  shape_inv[N-1-k] = shape[k];
2736 
2737  // create dataspace
2738  HDF5Handle
2739  dataspaceHandle = HDF5Handle(H5Screate_simple(shape_inv.size(), shape_inv.data(), NULL),
2740  &H5Sclose, "HDF5File::createDataset(): unable to create dataspace for scalar data.");
2741 
2742  // set fill value
2743  HDF5Handle plist ( H5Pcreate(H5P_DATASET_CREATE), &H5Pclose, "HDF5File::createDataset(): unable to create property list." );
2744  H5Pset_fill_value(plist, TypeTraits::getH5DataType(), &init);
2745 
2746  // turn off time tagging of datasets by default.
2747  H5Pset_obj_track_times(plist, track_time);
2748 
2749  // enable chunks
2750  ArrayVector<hsize_t> chunks(defineChunks(chunkSize, shape, TypeTraits::numberOfBands(), compressionParameter));
2751  if(chunks.size() > 0)
2752  {
2753  std::reverse(chunks.begin(), chunks.end());
2754  H5Pset_chunk (plist, chunks.size(), chunks.begin());
2755  }
2756 
2757  // enable compression
2758  if(compressionParameter > 0)
2759  {
2760  H5Pset_deflate(plist, compressionParameter);
2761  }
2762 
2763  //create the dataset.
2764  HDF5HandleShared datasetHandle(H5Dcreate(parent, setname.c_str(),
2765  TypeTraits::getH5DataType(),
2766  dataspaceHandle, H5P_DEFAULT, plist, H5P_DEFAULT),
2767  &H5Dclose,
2768  "HDF5File::createDataset(): unable to create dataset.");
2769  if(parent != cGroupHandle_)
2770  H5Gclose(parent);
2771 
2772  return datasetHandle;
2773 }
2774 
2775 /********************************************************************/
2776 
2777 template<unsigned int N, class T, class Stride>
2778 void HDF5File::write_(std::string &datasetName,
2779  const MultiArrayView<N, T, Stride> & array,
2780  const hid_t datatype,
2781  const int numBandsOfType,
2782  typename MultiArrayShape<N>::type &chunkSize,
2783  int compressionParameter)
2784 {
2785  vigra_precondition(!isReadOnly(),
2786  "HDF5File::write(): file is read-only.");
2787 
2788  std::string groupname = SplitString(datasetName).first();
2789  std::string setname = SplitString(datasetName).last();
2790 
2791  // shape of the array. Add one dimension, if array contains non-scalars.
2792  ArrayVector<hsize_t> shape(array.shape().begin(), array.shape().end());
2793  std::reverse(shape.begin(), shape.end());
2794 
2795  if(numBandsOfType > 1)
2796  shape.push_back(numBandsOfType);
2797 
2798  HDF5Handle dataspace(H5Screate_simple(shape.size(), shape.begin(), NULL), &H5Sclose,
2799  "HDF5File::write(): Can not create dataspace.");
2800 
2801  // create and open group:
2802  std::string errorMessage ("HDF5File::write(): can not create group '" + groupname + "'.");
2803  HDF5Handle groupHandle(openCreateGroup_(groupname), &H5Gclose, errorMessage.c_str());
2804 
2805  // delete dataset, if it already exists
2806  deleteDataset_(groupHandle, setname.c_str());
2807 
2808  // set up properties list
2809  HDF5Handle plist(H5Pcreate(H5P_DATASET_CREATE), &H5Pclose,
2810  "HDF5File::write(): unable to create property list." );
2811 
2812  // turn off time tagging of datasets by default.
2813  H5Pset_obj_track_times(plist, track_time);
2814 
2815  // enable chunks
2816  ArrayVector<hsize_t> chunks(defineChunks(chunkSize, array.shape(), numBandsOfType, compressionParameter));
2817  if(chunks.size() > 0)
2818  {
2819  std::reverse(chunks.begin(), chunks.end());
2820  H5Pset_chunk (plist, chunks.size(), chunks.begin());
2821  }
2822 
2823  // enable compression
2824  if(compressionParameter > 0)
2825  {
2826  H5Pset_deflate(plist, compressionParameter);
2827  }
2828 
2829  // create dataset
2830  HDF5Handle datasetHandle(H5Dcreate(groupHandle, setname.c_str(), datatype, dataspace,H5P_DEFAULT, plist, H5P_DEFAULT),
2831  &H5Dclose, "HDF5File::write(): Can not create dataset.");
2832 
2833  herr_t status = 0;
2834  if(array.isUnstrided())
2835  {
2836  // Write the data directly from the array data buffer
2837  status = H5Dwrite(datasetHandle, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, array.data());
2838  }
2839  else
2840  {
2841  // otherwise, we need an intermediate buffer
2842  // FIXME: right now, the buffer has the same size as the array to be read
2843  // incomplete code for better solutions is below
2844  // MultiArray<N, T> buffer(array);
2845  // status = H5Dwrite(datasetHandle, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, buffer.data());
2846 
2847  int offset = numBandsOfType > 1 ? 1 : 0;
2848  std::reverse(shape.begin(), shape.end());
2849  if(chunks.size() > 0)
2850  {
2851  // if the file is chunked, we use a buffer that matches the chunk size.
2852  std::reverse(chunks.begin(), chunks.end());
2853  }
2854  else
2855  {
2856  // otherwise, we compute a suitable chunk size.
2857  ArrayVector<hsize_t>(shape.size(), 1).swap(chunks);
2858  chunks[0] = numBandsOfType;
2859  MultiArrayIndex prod = 1;
2860  for(unsigned int k=0; k<N; ++k)
2861  {
2862  chunks[k+offset] = array.shape(k);
2863  prod *= array.shape(k);
2864  if(prod > 300000)
2865  break;
2866  }
2867  }
2868 
2869  ArrayVector<hsize_t> null(shape.size(), 0),
2870  start(shape.size(), 0),
2871  count(shape.size(), 1);
2872 
2873  count[N-1-offset] = numBandsOfType;
2874 
2875  typedef typename MultiArrayShape<N>::type Shape;
2876  Shape chunkCount, chunkMaxShape;
2877  for(unsigned int k=offset; k<chunks.size(); ++k)
2878  {
2879  chunkMaxShape[k-offset] = chunks[k];
2880  chunkCount[k-offset] = static_cast<MultiArrayIndex>(std::ceil(double(shape[k]) / chunks[k]));
2881  }
2882 
2883  typename CoupledIteratorType<N>::type chunkIter = createCoupledIterator(chunkCount),
2884  chunkEnd = chunkIter.getEndIterator();
2885  for(; chunkIter != chunkEnd; ++chunkIter)
2886  {
2887  Shape chunkStart(chunkIter.point() * chunkMaxShape),
2888  chunkStop(min(chunkStart + chunkMaxShape, array.shape()));
2889  MultiArray<N, T> buffer(array.subarray(chunkStart, chunkStop));
2890 
2891  for(unsigned int k=0; k<N; ++k)
2892  {
2893  start[N-1-k] = chunkStart[k];
2894  count[N-1-k] = buffer.shape(k);
2895  }
2896  if(offset == 1)
2897  {
2898  start[N] = 0;
2899  count[N] = numBandsOfType;
2900  }
2901  HDF5Handle filespace(H5Dget_space(datasetHandle),
2902  &H5Sclose, "HDF5File::write(): unable to create hyperslabs.");
2903  status = H5Sselect_hyperslab(filespace, H5S_SELECT_SET, start.data(), NULL, count.data(), NULL);
2904  if(status < 0)
2905  break;
2906 
2907  HDF5Handle dataspace2(H5Screate_simple(count.size(), count.data(), NULL),
2908  &H5Sclose, "HDF5File::write(): unable to create hyperslabs.");
2909  status = H5Sselect_hyperslab(dataspace2, H5S_SELECT_SET, null.data(), NULL, count.data(), NULL);
2910  if(status < 0)
2911  break;
2912 
2913  status = H5Dwrite(datasetHandle, datatype, dataspace2, filespace, H5P_DEFAULT, buffer.data());
2914  if(status < 0)
2915  break;
2916  }
2917  }
2918  vigra_postcondition(status >= 0,
2919  "HDF5File::write(): write to dataset '" + datasetName + "' via H5Dwrite() failed.");
2920 }
2921 
2922 /********************************************************************/
2923 
2924 template<unsigned int N, class T, class Stride>
2925 herr_t HDF5File::writeBlock_(HDF5HandleShared datasetHandle,
2926  typename MultiArrayShape<N>::type &blockOffset,
2927  const MultiArrayView<N, T, Stride> & array,
2928  const hid_t datatype,
2929  const int numBandsOfType)
2930 {
2931  vigra_precondition(!isReadOnly(),
2932  "HDF5File::writeBlock(): file is read-only.");
2933 
2934  ArrayVector<hsize_t> boffset, bshape, bones(N+1, 1);
2935  hssize_t dimensions = getDatasetDimensions_(datasetHandle);
2936  if(numBandsOfType > 1)
2937  {
2938  vigra_precondition(N+1 == dimensions,
2939  "HDF5File::readBlock(): Array dimension disagrees with data dimension.");
2940  bshape.resize(N+1);
2941  boffset.resize(N+1);
2942  bshape[N] = numBandsOfType;
2943  boffset[N] = 0;
2944  }
2945  else
2946  {
2947  vigra_precondition(N == dimensions,
2948  "HDF5File::readBlock(): Array dimension disagrees with data dimension.");
2949  bshape.resize(N);
2950  boffset.resize(N);
2951  }
2952 
2953  for(int i = 0; i < N; ++i)
2954  {
2955  // vigra and hdf5 use different indexing
2956  bshape[N-1-i] = array.shape(i);
2957  boffset[N-1-i] = blockOffset[i];
2958  }
2959 
2960  // create a target dataspace in memory with the shape of the desired block
2961  HDF5Handle memspace_handle (H5Screate_simple(bshape.size(), bshape.data(), NULL),
2962  &H5Sclose,
2963  "Unable to get origin dataspace");
2964 
2965  // get file dataspace and select the desired block
2966  HDF5Handle dataspaceHandle (H5Dget_space(datasetHandle),&H5Sclose,"Unable to create target dataspace");
2967  H5Sselect_hyperslab(dataspaceHandle, H5S_SELECT_SET,
2968  boffset.data(), bones.data(), bones.data(), bshape.data());
2969 
2970  herr_t status = 0;
2971  if(array.isUnstrided())
2972  {
2973  // when the array is unstrided, we can read the data directly from the array buffer
2974  status = H5Dwrite( datasetHandle, datatype, memspace_handle, dataspaceHandle, H5P_DEFAULT, array.data());
2975  }
2976  else
2977  {
2978  // otherwise, we must copy the data into an unstrided extra buffer
2979  MultiArray<N, T> buffer(array);
2980  status = H5Dwrite( datasetHandle, datatype, memspace_handle, dataspaceHandle, H5P_DEFAULT, buffer.data());
2981  }
2982  return status;
2983 }
2984 
2985 /********************************************************************/
2986 
2987 template<unsigned int N, class T, class Stride>
2988 void HDF5File::write_attribute_(std::string name,
2989  const std::string & attribute_name,
2990  const MultiArrayView<N, T, Stride> & array,
2991  const hid_t datatype,
2992  const int numBandsOfType)
2993 {
2994  vigra_precondition(!isReadOnly(),
2995  "HDF5File::writeAttribute(): file is read-only.");
2996 
2997  // shape of the array. Add one dimension, if array contains non-scalars.
2998  ArrayVector<hsize_t> shape(array.shape().begin(), array.shape().end());
2999  std::reverse(shape.begin(), shape.end());
3000  if(numBandsOfType > 1)
3001  shape.push_back(numBandsOfType);
3002 
3003  HDF5Handle dataspace(H5Screate_simple(shape.size(),
3004  shape.begin(), NULL),
3005  &H5Sclose, "HDF5File::writeAttribute(): Can not"
3006  " create dataspace.");
3007 
3008  std::string errorMessage ("HDF5File::writeAttribute(): can not find "
3009  "object '" + name + "'.");
3010 
3011  H5O_type_t h5_type = get_object_type_(name);
3012  bool is_group = h5_type == H5O_TYPE_GROUP;
3013  if (!is_group && h5_type != H5O_TYPE_DATASET)
3014  vigra_precondition(0, "HDF5File::writeAttribute(): object \""
3015  + name + "\" is neither a group nor a "
3016  "dataset.");
3017  // get parent object handle
3018  HDF5Handle object_handle(is_group
3019  ? openCreateGroup_(name)
3020  : getDatasetHandle_(name),
3021  is_group
3022  ? &H5Gclose
3023  : &H5Dclose,
3024  errorMessage.c_str());
3025  // create / open attribute
3026  bool exists = existsAttribute(name, attribute_name);
3027  HDF5Handle attributeHandle(exists
3028  ? H5Aopen(object_handle,
3029  attribute_name.c_str(),
3030  H5P_DEFAULT)
3031  : H5Acreate(object_handle,
3032  attribute_name.c_str(), datatype,
3033  dataspace, H5P_DEFAULT,
3034  H5P_DEFAULT),
3035  &H5Aclose,
3036  "HDF5File::writeAttribute(): Can not create"
3037  " attribute.");
3038  herr_t status = 0;
3039  if(array.isUnstrided())
3040  {
3041  // write the data directly from the array data buffer
3042  status = H5Awrite(attributeHandle, datatype, array.data());
3043  }
3044  else
3045  {
3046  // write the data via an unstrided copy
3047  // (we assume that attributes are small arrays, so that the wasted memory is uncritical)
3048  MultiArray<N, T> buffer(array);
3049  status = H5Awrite(attributeHandle, datatype, buffer.data());
3050  }
3051  vigra_postcondition(status >= 0,
3052  "HDF5File::writeAttribute(): write to attribute '" + attribute_name + "' via H5Awrite() failed.");
3053 }
3054 
3055 /********************************************************************/
3056 
3057 template<unsigned int N, class T, class Stride>
3058 void HDF5File::read_(std::string datasetName,
3060  const hid_t datatype, const int numBandsOfType)
3061 {
3062  //Prepare to read without using HDF5ImportInfo
3063  ArrayVector<hsize_t> dimshape = getDatasetShape(datasetName);
3064 
3065  std::string errorMessage ("HDF5File::read(): Unable to open dataset '" + datasetName + "'.");
3066  HDF5Handle datasetHandle(getDatasetHandle_(datasetName), &H5Dclose, errorMessage.c_str());
3067 
3068  // the object in the HDF5 file may have one additional dimension which we
3069  // interprete as the pixel type's bands
3070  int offset = (numBandsOfType > 1)
3071  ? 1
3072  : 0;
3073 
3074  vigra_precondition(MultiArrayIndex(N + offset) == MultiArrayIndex(dimshape.size()),
3075  "HDF5File::read(): Array dimension disagrees with dataset dimension.");
3076 
3077  typename MultiArrayShape<N>::type shape;
3078  for(int k=offset; k < (int)dimshape.size(); ++k)
3079  shape[k-offset] = (MultiArrayIndex)dimshape[k];
3080 
3081  vigra_precondition(shape == array.shape(),
3082  "HDF5File::read(): Array shape disagrees with dataset shape.");
3083  if (offset)
3084  vigra_precondition(dimshape[0] == static_cast<hsize_t>(numBandsOfType),
3085  "HDF5File::read(): Band count doesn't match destination array compound type.");
3086 
3087  herr_t status = 0;
3088  if(array.isUnstrided())
3089  {
3090  // when the array is unstrided, we can read the data directly into the array buffer
3091  status = H5Dread(datasetHandle, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, array.data() );
3092  }
3093  else
3094  {
3095  // otherwise, we need an intermediate buffer
3096 
3097  ArrayVector<hsize_t> null(dimshape.size(), 0),
3098  chunks(dimshape.size(), 1),
3099  start(dimshape.size(), 0),
3100  count(dimshape.size(), 1);
3101 
3102  HDF5Handle properties(H5Dget_create_plist(datasetHandle),
3103  &H5Pclose, "HDF5File::read(): failed to get property list");
3104  if(H5D_CHUNKED == H5Pget_layout(properties))
3105  {
3106  // if the file is chunked, we use a buffer that matches the chunk size.
3107  H5Pget_chunk(properties, static_cast<int>(chunks.size()), chunks.data());
3108  std::reverse(chunks.begin(), chunks.end());
3109  }
3110  else
3111  {
3112  // otherwise, we compute a suitable chunk size.
3113  chunks[0] = numBandsOfType;
3114  MultiArrayIndex prod = 1;
3115  for(unsigned int k=0; k<N; ++k)
3116  {
3117  chunks[k+offset] = array.shape(k);
3118  prod *= array.shape(k);
3119  if(prod > 300000)
3120  break;
3121  }
3122  }
3123 
3124  count[N-1-offset] = static_cast<hsize_t>(numBandsOfType);
3125 
3126  typedef typename MultiArrayShape<N>::type Shape;
3127  Shape chunkCount, chunkMaxShape;
3128  for(unsigned int k=offset; k<chunks.size(); ++k)
3129  {
3130  chunkMaxShape[k-offset] = chunks[k];
3131  chunkCount[k-offset] = (MultiArrayIndex)std::ceil(double(dimshape[k]) / chunks[k]);
3132  }
3133 
3134  typename CoupledIteratorType<N>::type chunkIter = createCoupledIterator(chunkCount),
3135  chunkEnd = chunkIter.getEndIterator();
3136  for(; chunkIter != chunkEnd; ++chunkIter)
3137  {
3138  Shape chunkStart(chunkIter.point() * chunkMaxShape),
3139  chunkStop(min(chunkStart + chunkMaxShape, array.shape()));
3140  MultiArray<N, T> buffer(chunkStop - chunkStart);
3141 
3142  for(unsigned int k=0; k<N; ++k)
3143  {
3144  start[N-1-k] = chunkStart[k];
3145  count[N-1-k] = buffer.shape(k);
3146  }
3147  if(offset == 1)
3148  {
3149  start[N] = 0;
3150  count[N] = numBandsOfType;
3151  }
3152  HDF5Handle filespace(H5Dget_space(datasetHandle),
3153  &H5Sclose, "HDF5File::read(): unable to create hyperslabs.");
3154  status = H5Sselect_hyperslab(filespace, H5S_SELECT_SET, start.data(), NULL, count.data(), NULL);
3155  if(status < 0)
3156  break;
3157 
3158  HDF5Handle dataspace(H5Screate_simple(count.size(), count.data(), NULL),
3159  &H5Sclose, "HDF5File::read(): unable to create hyperslabs.");
3160  status = H5Sselect_hyperslab(dataspace, H5S_SELECT_SET, null.data(), NULL, count.data(), NULL);
3161  if(status < 0)
3162  break;
3163 
3164  status = H5Dread(datasetHandle, datatype, dataspace, filespace, H5P_DEFAULT, buffer.data());
3165  if(status < 0)
3166  break;
3167 
3168  array.subarray(chunkStart, chunkStop) = buffer;
3169  }
3170  }
3171  vigra_postcondition(status >= 0,
3172  "HDF5File::read(): read from dataset '" + datasetName + "' via H5Dread() failed.");
3173 }
3174 
3175 /********************************************************************/
3176 
3177 template<unsigned int N, class T, class Stride>
3178 herr_t HDF5File::readBlock_(HDF5HandleShared datasetHandle,
3179  typename MultiArrayShape<N>::type &blockOffset,
3180  typename MultiArrayShape<N>::type &blockShape,
3182  const hid_t datatype, const int numBandsOfType)
3183 {
3184  vigra_precondition(blockShape == array.shape(),
3185  "HDF5File::readBlock(): Array shape disagrees with block size.");
3186 
3187  ArrayVector<hsize_t> boffset, bshape, bones(N+1, 1);
3188  hssize_t dimensions = getDatasetDimensions_(datasetHandle);
3189  if(numBandsOfType > 1)
3190  {
3191  vigra_precondition(N+1 == dimensions,
3192  "HDF5File::readBlock(): Array dimension disagrees with data dimension.");
3193  bshape.resize(N+1);
3194  boffset.resize(N+1);
3195  bshape[N] = numBandsOfType;
3196  boffset[N] = 0;
3197  }
3198  else
3199  {
3200  vigra_precondition(N == dimensions,
3201  "HDF5File::readBlock(): Array dimension disagrees with data dimension.");
3202  bshape.resize(N);
3203  boffset.resize(N);
3204  }
3205 
3206  for(int i = 0; i < N; ++i)
3207  {
3208  // vigra and hdf5 use different indexing
3209  bshape[N-1-i] = blockShape[i];
3210  boffset[N-1-i] = blockOffset[i];
3211  }
3212 
3213  // create a target dataspace in memory with the shape of the desired block
3214  HDF5Handle memspace_handle(H5Screate_simple(bshape.size(), bshape.data(), NULL),
3215  &H5Sclose,
3216  "Unable to create target dataspace");
3217 
3218  // get file dataspace and select the desired block
3219  HDF5Handle dataspaceHandle(H5Dget_space(datasetHandle), &H5Sclose,
3220  "Unable to get dataspace");
3221  H5Sselect_hyperslab(dataspaceHandle, H5S_SELECT_SET,
3222  boffset.data(), bones.data(), bones.data(), bshape.data());
3223 
3224  herr_t status = 0;
3225  if(array.isUnstrided())
3226  {
3227  // when the array is unstrided, we can read the data directly into the array buffer
3228  status = H5Dread( datasetHandle, datatype, memspace_handle, dataspaceHandle, H5P_DEFAULT, array.data());
3229  }
3230  else
3231  {
3232  // otherwise, we need an unstrided extra buffer ...
3233  MultiArray<N, T> buffer(array.shape());
3234  status = H5Dread( datasetHandle, datatype, memspace_handle, dataspaceHandle, H5P_DEFAULT, buffer.data());
3235  // ... and must copy the values
3236  if(status >= 0)
3237  array = buffer;
3238  }
3239  return status;
3240 }
3241 
3242 /********************************************************************/
3243 
3244 template<unsigned int N, class T, class Stride>
3245 void HDF5File::read_attribute_(std::string datasetName,
3246  std::string attributeName,
3248  const hid_t datatype, const int numBandsOfType)
3249 {
3250  std::string dataset_path = get_absolute_path(datasetName);
3251  // open Attribute handle
3252  std::string message = "HDF5File::readAttribute(): could not get handle for attribute '"+attributeName+"'' of object '"+dataset_path+"'.";
3253  HDF5Handle attr_handle (H5Aopen_by_name(fileHandle_,dataset_path.c_str(),attributeName.c_str(),H5P_DEFAULT,H5P_DEFAULT),&H5Aclose, message.c_str());
3254 
3255  // get Attribute dataspace
3256  message = "HDF5File::readAttribute(): could not get dataspace for attribute '"+attributeName+"'' of object '"+dataset_path+"'.";
3257  HDF5Handle attr_dataspace_handle (H5Aget_space(attr_handle),&H5Sclose,message.c_str());
3258 
3259  // obtain Attribute shape
3260  int raw_dims = H5Sget_simple_extent_ndims(attr_dataspace_handle);
3261  int dims = std::max(raw_dims, 1); // scalar attributes may be stored with raw_dims==0
3262  ArrayVector<hsize_t> dimshape(dims);
3263  if(raw_dims > 0)
3264  H5Sget_simple_extent_dims(attr_dataspace_handle, dimshape.data(), NULL);
3265  else
3266  dimshape[0] = 1;
3267 
3268  // invert the dimensions to guarantee VIGRA-compatible order
3269  std::reverse(dimshape.begin(), dimshape.end());
3270 
3271  int offset = (numBandsOfType > 1)
3272  ? 1
3273  : 0;
3274  message = "HDF5File::readAttribute(): Array dimension disagrees with dataset dimension.";
3275  // the object in the HDF5 file may have one additional dimension which we then interpret as the pixel type bands
3276  vigra_precondition(MultiArrayIndex(N + offset) == MultiArrayIndex(dims), message);
3277 
3278  for(int k=offset; k < (int)dimshape.size(); ++k)
3279  vigra_precondition(array.shape()[k-offset] == (MultiArrayIndex)dimshape[k],
3280  "HDF5File::readAttribute(): Array shape disagrees with dataset shape");
3281 
3282  herr_t status = 0;
3283  if(array.isUnstrided())
3284  {
3285  // when the array is unstrided, we can read the data directly into the array buffer
3286  status = H5Aread( attr_handle, datatype, array.data());
3287  }
3288  else
3289  {
3290  // otherwise, we need an unstrided extra buffer ...
3291  // (we assume that attributes are small arrays, so that the wasted memory is uncritical)
3292  MultiArray<N, T> buffer(array.shape());
3293  status = H5Aread( attr_handle, datatype, buffer.data() );
3294  // ... and must copy the values
3295  if(status >= 0)
3296  array = buffer;
3297  }
3298  vigra_postcondition(status >= 0,
3299  "HDF5File::readAttribute(): read from attribute '" + attributeName + "' via H5Aread() failed.");
3300 }
3301 
3302 /********************************************************************/
3303 
3304 /** \brief Read the data specified by the given \ref vigra::HDF5ImportInfo object
3305  and write the into the given 'array'.
3306 
3307  The array must have the correct number of dimensions and shape for the dataset
3308  represented by 'info'. When the element type of 'array' differs from the stored element
3309  type, HDF5 will convert the type on the fly (except when the HDF5 version is 1.6 or below,
3310  in which case an error will result). Multi-channel element types (i.e. \ref vigra::RGBValue,
3311  \ref vigra::TinyVector, and \ref vigra::FFTWComplex) are recognized and handled correctly.
3312 
3313  <b> Declaration:</b>
3314 
3315  \code
3316  namespace vigra {
3317  template<unsigned int N, class T, class StrideTag>
3318  void
3319  readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, T, StrideTag> array);
3320  }
3321  \endcode
3322 
3323  <b> Usage:</b>
3324 
3325  <b>\#include</b> <vigra/hdf5impex.hxx><br>
3326  Namespace: vigra
3327 
3328  \code
3329 
3330  HDF5ImportInfo info(filename, dataset_name);
3331  vigra_precondition(info.numDimensions() == 3, "Dataset must be 3-dimensional.");
3332 
3333  MultiArrayShape<3>::type shape(info.shape().begin());
3334  MultiArray<3, int> array(shape);
3335 
3336  readHDF5(info, array);
3337  \endcode
3338 */
3339 doxygen_overloaded_function(template <...> void readHDF5)
3340 
3341 template<unsigned int N, class T, class StrideTag>
3342 inline void readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, T, StrideTag> array)
3343 {
3344  readHDF5(info, array, 0, 0); // last two arguments are not used
3345 }
3346 
3347 template<unsigned int N, class T, class StrideTag>
3348 void readHDF5(const HDF5ImportInfo &info, MultiArrayView<N, T, StrideTag> array, const hid_t datatype, const int numBandsOfType)
3349 {
3350  HDF5File file(info.getFilePath(), HDF5File::OpenReadOnly);
3351  file.read(info.getPathInFile(), array);
3352  file.close();
3353 }
3354 
3355 inline hid_t openGroup(hid_t parent, std::string group_name)
3356 {
3357  //std::cout << group_name << std::endl;
3358  size_t last_slash = group_name.find_last_of('/');
3359  if (last_slash == std::string::npos || last_slash != group_name.size() - 1)
3360  group_name = group_name + '/';
3361  std::string::size_type begin = 0, end = group_name.find('/');
3362  int ii = 0;
3363  while (end != std::string::npos)
3364  {
3365  std::string group(group_name.begin()+begin, group_name.begin()+end);
3366  hid_t prev_parent = parent;
3367  parent = H5Gopen(prev_parent, group.c_str(), H5P_DEFAULT);
3368 
3369  if(ii != 0) H5Gclose(prev_parent);
3370  if(parent < 0) return parent;
3371  ++ii;
3372  begin = end + 1;
3373  end = group_name.find('/', begin);
3374  }
3375  return parent;
3376 }
3377 
3378 inline hid_t createGroup(hid_t parent, std::string group_name)
3379 {
3380  if(group_name.size() == 0 ||*group_name.rbegin() != '/')
3381  group_name = group_name + '/';
3382  if(group_name == "/")
3383  return H5Gopen(parent, group_name.c_str(), H5P_DEFAULT);
3384 
3385  std::string::size_type begin = 0, end = group_name.find('/');
3386  int ii = 0;
3387  while (end != std::string::npos)
3388  {
3389  std::string group(group_name.begin()+begin, group_name.begin()+end);
3390  hid_t prev_parent = parent;
3391 
3392  if(H5LTfind_dataset(parent, group.c_str()) == 0)
3393  {
3394  parent = H5Gcreate(prev_parent, group.c_str(), H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
3395  } else {
3396  parent = H5Gopen(prev_parent, group.c_str(), H5P_DEFAULT);
3397  }
3398 
3399  if(ii != 0) H5Gclose(prev_parent);
3400  if(parent < 0) return parent;
3401  ++ii;
3402  begin = end + 1;
3403  end = group_name.find('/', begin);
3404  }
3405  return parent;
3406 }
3407 
3408 inline void deleteDataset(hid_t parent, std::string dataset_name)
3409 {
3410  // delete existing data and create new dataset
3411  if(H5LTfind_dataset(parent, dataset_name.c_str()))
3412  {
3413  //std::cout << "dataset already exists" << std::endl;
3414 #if (H5_VERS_MAJOR == 1 && H5_VERS_MINOR <= 6)
3415  if(H5Gunlink(parent, dataset_name.c_str()) < 0)
3416  {
3417  vigra_postcondition(false, "writeToHDF5File(): Unable to delete existing data.");
3418  }
3419 #else
3420  if(H5Ldelete(parent, dataset_name.c_str(), H5P_DEFAULT ) < 0)
3421  {
3422  vigra_postcondition(false, "createDataset(): Unable to delete existing data.");
3423  }
3424 #endif
3425  }
3426 }
3427 
3428 inline hid_t createFile(std::string filePath, bool append_ = true)
3429 {
3430  FILE * pFile;
3431  pFile = fopen ( filePath.c_str(), "r" );
3432  hid_t file_id;
3433  if ( pFile == NULL )
3434  {
3435  file_id = H5Fcreate(filePath.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
3436  }
3437  else if(append_)
3438  {
3439  fclose( pFile );
3440  file_id = H5Fopen(filePath.c_str(), H5F_ACC_RDWR, H5P_DEFAULT);
3441  }
3442  else
3443  {
3444  fclose(pFile);
3445  std::remove(filePath.c_str());
3446  file_id = H5Fcreate(filePath.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
3447  }
3448  return file_id;
3449 }
3450 
3451 template<unsigned int N, class T, class Tag>
3452 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)
3453 {
3454  std::string path_name(pathInFile), group_name, data_set_name, message;
3455  std::string::size_type delimiter = path_name.rfind('/');
3456 
3457  //create or open file
3458  file_handle = HDF5Handle(createFile(filePath), &H5Fclose,
3459  "createDataset(): unable to open output file.");
3460 
3461  // get the groupname and the filename
3462  if(delimiter == std::string::npos)
3463  {
3464  group_name = "/";
3465  data_set_name = path_name;
3466  }
3467  else
3468  {
3469  group_name = std::string(path_name.begin(), path_name.begin()+delimiter);
3470  data_set_name = std::string(path_name.begin()+delimiter+1, path_name.end());
3471  }
3472 
3473  // create all groups
3474  HDF5Handle group(createGroup(file_handle, group_name), &H5Gclose,
3475  "createDataset(): Unable to create and open group. generic v");
3476 
3477  // delete the dataset if it already exists
3478  deleteDataset(group, data_set_name);
3479 
3480  // create dataspace
3481  // add an extra dimension in case that the data is non-scalar
3482  HDF5Handle dataspace_handle;
3483  if(numBandsOfType > 1) {
3484  // invert dimensions to guarantee c-order
3485  hsize_t shape_inv[N+1]; // one additional dimension for pixel type channel(s)
3486  for(unsigned int k=0; k<N; ++k) {
3487  shape_inv[N-1-k] = array.shape(k); // the channels (eg of an RGB image) are represented by the first dimension (before inversion)
3488  //std::cout << shape_inv[N-k] << " (" << N << ")";
3489  }
3490  shape_inv[N] = numBandsOfType;
3491 
3492  // create dataspace
3493  dataspace_handle = HDF5Handle(H5Screate_simple(N+1, shape_inv, NULL),
3494  &H5Sclose, "createDataset(): unable to create dataspace for non-scalar data.");
3495  } else {
3496  // invert dimensions to guarantee c-order
3497  hsize_t shape_inv[N];
3498  for(unsigned int k=0; k<N; ++k)
3499  shape_inv[N-1-k] = array.shape(k);
3500 
3501  // create dataspace
3502  dataspace_handle = HDF5Handle(H5Screate_simple(N, shape_inv, NULL),
3503  &H5Sclose, "createDataset(): unable to create dataspace for scalar data.");
3504  }
3505 
3506  //alloc memory for dataset.
3507  dataset_handle = HDF5Handle(H5Dcreate(group,
3508  data_set_name.c_str(),
3509  datatype,
3510  dataspace_handle,
3511  H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT),
3512  &H5Dclose, "createDataset(): unable to create dataset.");
3513 }
3514 
3515 
3516 
3517 
3518 /** \brief Store array data in an HDF5 file.
3519 
3520  The number of dimensions, shape and element type of the stored dataset is automatically
3521  determined from the properties of the given \a array. Strided arrays are stored in an
3522  unstrided way, i.e. in contiguous scan-order. Multi-channel element types
3523  (i.e. \ref vigra::RGBValue, \ref vigra::TinyVector and \ref vigra::FFTWComplex)
3524  are recognized and handled correctly
3525  (in particular, the will form the innermost dimension of the stored dataset).
3526  \a pathInFile may contain '/'-separated group names, but must end with the name
3527  of the dataset to be created.
3528 
3529  <b> Declaration:</b>
3530 
3531  \code
3532  namespace vigra {
3533  template<unsigned int N, class T, class StrideTag>
3534  void
3535  writeHDF5(const char* filePath, const char* pathInFile,
3536  MultiArrayView<N, T, StrideTag>const & array);
3537  }
3538  \endcode
3539 
3540  <b> Usage:</b>
3541 
3542  <b>\#include</b> <vigra/hdf5impex.hxx><br>
3543  Namespace: vigra
3544 
3545  \code
3546  MultiArrayShape<3>::type shape(100, 200, 20);
3547  MultiArray<3, int> array(shape);
3548  ... // fill array with data
3549 
3550  writeHDF5("mydata.h5", "/group1/my_dataset", array);
3551  \endcode
3552 */
3553 doxygen_overloaded_function(template <...> void writeHDF5)
3554 
3555 template<unsigned int N, class T, class StrideTag>
3556 inline void writeHDF5(const char* filePath, const char* pathInFile, const MultiArrayView<N, T, StrideTag> & array)
3557 {
3558  //last two arguments are not used
3559  writeHDF5(filePath, pathInFile, array, 0, 0);
3560 }
3561 
3562 template<unsigned int N, class T, class StrideTag>
3563 void writeHDF5(const char* filePath, const char* pathInFile, const MultiArrayView<N, T, StrideTag> & array, const hid_t datatype, const int numBandsOfType)
3564 {
3565  HDF5File file(filePath, HDF5File::Open);
3566  file.write(pathInFile, array);
3567  file.close();
3568 }
3569 
3570 
3571 namespace detail
3572 {
3573 struct MaxSizeFnc
3574 {
3575  size_t size;
3576 
3577  MaxSizeFnc()
3578  : size(0)
3579  {}
3580 
3581  void operator()(std::string const & in)
3582  {
3583  size = in.size() > size ?
3584  in.size() :
3585  size;
3586  }
3587 };
3588 }
3589 
3590 
3591 #if (H5_VERS_MAJOR == 1 && H5_VERS_MINOR == 8) || DOXYGEN
3592 /** Write a numeric MultiArray as an attribute with name \a name
3593  of the dataset specified by the handle \a loc.
3594 
3595  <b>\#include</b> <vigra/hdf5impex.hxx><br>
3596  Namespace: vigra
3597 */
3598 template<size_t N, class T, class C>
3599 void writeHDF5Attr(hid_t loc,
3600  const char* name,
3601  MultiArrayView<N, T, C> const & array)
3602 {
3603  if(H5Aexists(loc, name) > 0)
3604  H5Adelete(loc, name);
3605 
3606  ArrayVector<hsize_t> shape(array.shape().begin(),
3607  array.shape().end());
3608  HDF5Handle
3609  dataspace_handle(H5Screate_simple(N, shape.data(), NULL),
3610  &H5Sclose,
3611  "writeToHDF5File(): unable to create dataspace.");
3612 
3613  HDF5Handle attr(H5Acreate(loc,
3614  name,
3615  detail::getH5DataType<T>(),
3616  dataspace_handle,
3617  H5P_DEFAULT ,H5P_DEFAULT ),
3618  &H5Aclose,
3619  "writeHDF5Attr: unable to create Attribute");
3620 
3621  //copy data - since attributes are small - who cares!
3622  ArrayVector<T> buffer;
3623  for(int ii = 0; ii < array.size(); ++ii)
3624  buffer.push_back(array[ii]);
3625  H5Awrite(attr, detail::getH5DataType<T>(), buffer.data());
3626 }
3627 
3628 /** Write a string MultiArray as an attribute with name \a name
3629  of the dataset specified by the handle \a loc.
3630 
3631  <b>\#include</b> <vigra/hdf5impex.hxx><br>
3632  Namespace: vigra
3633 */
3634 template<size_t N, class C>
3635 void writeHDF5Attr(hid_t loc,
3636  const char* name,
3637  MultiArrayView<N, std::string, C> const & array)
3638 {
3639  if(H5Aexists(loc, name) > 0)
3640  H5Adelete(loc, name);
3641 
3642  ArrayVector<hsize_t> shape(array.shape().begin(),
3643  array.shape().end());
3644  HDF5Handle
3645  dataspace_handle(H5Screate_simple(N, shape.data(), NULL),
3646  &H5Sclose,
3647  "writeToHDF5File(): unable to create dataspace.");
3648 
3649  HDF5Handle atype(H5Tcopy (H5T_C_S1),
3650  &H5Tclose,
3651  "writeToHDF5File(): unable to create type.");
3652 
3653  detail::MaxSizeFnc max_size;
3654  max_size = std::for_each(array.data(),array.data()+ array.size(), max_size);
3655  H5Tset_size (atype, max_size.size);
3656 
3657  HDF5Handle attr(H5Acreate(loc,
3658  name,
3659  atype,
3660  dataspace_handle,
3661  H5P_DEFAULT ,H5P_DEFAULT ),
3662  &H5Aclose,
3663  "writeHDF5Attr: unable to create Attribute");
3664 
3665  std::string buf ="";
3666  for(int ii = 0; ii < array.size(); ++ii)
3667  {
3668  buf = buf + array[ii]
3669  + std::string(max_size.size - array[ii].size(), ' ');
3670  }
3671  H5Awrite(attr, atype, buf.c_str());
3672 }
3673 
3674 /** Write a numeric ArrayVectorView as an attribute with name \a name
3675  of the dataset specified by the handle \a loc.
3676 
3677  <b>\#include</b> <vigra/hdf5impex.hxx><br>
3678  Namespace: vigra
3679 */
3680 template<class T>
3681 inline void writeHDF5Attr( hid_t loc,
3682  const char* name,
3683  ArrayVectorView<T> & array)
3684 {
3685  writeHDF5Attr(loc, name,
3687  array.data()));
3688 }
3689 
3690 /** write an Attribute given a file and a path in the file.
3691  the path in the file should have the format
3692  [attribute] or /[subgroups/]dataset.attribute or
3693  /[subgroups/]group.attribute.
3694  The attribute is written to the root group, a dataset or a subgroup
3695  respectively
3696 */
3697 template<class Arr>
3698 inline void writeHDF5Attr( std::string filePath,
3699  std::string pathInFile,
3700  Arr & ar)
3701 {
3702  std::string path_name(pathInFile), group_name, data_set_name, message, attr_name;
3703  std::string::size_type delimiter = path_name.rfind('/');
3704 
3705  //create or open file
3706  HDF5Handle file_id(createFile(filePath), &H5Fclose,
3707  "writeToHDF5File(): unable to open output file.");
3708 
3709  // get the groupname and the filename
3710  if(delimiter == std::string::npos)
3711  {
3712  group_name = "/";
3713  data_set_name = path_name;
3714  }
3715 
3716  else
3717  {
3718  group_name = std::string(path_name.begin(), path_name.begin()+delimiter);
3719  data_set_name = std::string(path_name.begin()+delimiter+1, path_name.end());
3720  }
3721  delimiter = data_set_name.rfind('.');
3722  if(delimiter == std::string::npos)
3723  {
3724  attr_name = path_name;
3725  data_set_name = "/";
3726  }
3727  else
3728  {
3729  attr_name = std::string(data_set_name.begin()+delimiter+1, data_set_name.end());
3730  data_set_name = std::string(data_set_name.begin(), data_set_name.begin()+delimiter);
3731  }
3732 
3733  HDF5Handle group(openGroup(file_id, group_name), &H5Gclose,
3734  "writeToHDF5File(): Unable to create and open group. attr ver");
3735 
3736  if(data_set_name != "/")
3737  {
3738  HDF5Handle dset(H5Dopen(group, data_set_name.c_str(), H5P_DEFAULT), &H5Dclose,
3739  "writeHDF5Attr():unable to open dataset");
3740  writeHDF5Attr(hid_t(dset), attr_name.c_str(), ar);
3741  }
3742  else
3743  {
3744  writeHDF5Attr(hid_t(group), attr_name.c_str(), ar);
3745  }
3746 
3747 }
3748 #endif
3749 
3750 //@}
3751 
3752 } // namespace vigra
3753 
3754 #endif // VIGRA_HDF5IMPEX_HXX
HDF5File & operator=(HDF5File const &other)
Assign a HDF5File object.
Definition: hdf5impex.hxx:1125
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
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
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
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
bool operator==(HDF5Handle const &h) const
Equality comparison of the contained handle.
Definition: hdf5impex.hxx:344
Temporarily disable HDF5&#39;s native error output.
Definition: hdf5impex.hxx:128
ArrayVector< hsize_t > getDatasetShape(std::string datasetName) const
Get the shape of each dimension of a certain dataset.
Definition: hdf5impex.hxx:1369
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
Inequality comparison of the contained handle.
Definition: hdf5impex.hxx:615
HDF5HandleShared()
Default constructor. Creates a NULL handle.
Definition: hdf5impex.hxx:425
const difference_type & shape() const
Definition: multi_array.hxx:1596
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
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
Definition: array_vector.hxx:76
const_iterator begin() const
Definition: array_vector.hxx:223
pointer data() const
Definition: multi_array.hxx:1846
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
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:2244
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
HDF5HandleShared getDatasetHandleShared(std::string const &datasetName) const
Obtain a shared HDF5 handle of a dataset.
Definition: hdf5impex.hxx:1464
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 existsAttribute(std::string object_name, std::string attribute_name)
Test if attribute exists.
Definition: hdf5impex.hxx:1618
const std::string & getFilePath() const
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:3599
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:2701
bool operator==(hid_t h) const
Equality comparison of the contained handle.
Definition: hdf5impex.hxx:351
Definition: accessor.hxx:43
hid_t release()
Return the contained handle and set the wrapper to NULL without calling close().
Definition: hdf5impex.hxx:288
const std::string & getPathInFile() const
herr_t close()
Close the handle if this is the unique (i.e. last) owner.
Definition: hdf5impex.hxx:506
void ls(Container &cont) const
List the contents of the current group into a container-like object via insert(). ...
Definition: hdf5impex.hxx:1307
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
bool operator!=(hid_t h) const
Inequality comparison of the contained handle.
Definition: hdf5impex.hxx:365
bool operator!=(HDF5Handle const &h) const
Inequality comparison of the contained handle.
Definition: hdf5impex.hxx:358
difference_type_1 size() const
Definition: multi_array.hxx:1589
Wrapper for shared hid_t objects.
Definition: hdf5impex.hxx:410
std::string filename() const
Get the name of the associated file.
Definition: hdf5impex.hxx:1322
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
~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
bool operator==(HDF5HandleShared const &h) const
Equality comparison of the contained handle.
Definition: hdf5impex.hxx:594
CoupledScanOrderIterator getEndIterator() const
Definition: multi_iterator_coupled.hxx:282
HDF5File(HDF5HandleShared const &fileHandle, const std::string &pathname="", bool read_only=false)
Initialize an HDF5File object from HDF5 file handle.
Definition: hdf5impex.hxx:1073
HDF5Handle getAttributeHandle(std::string dataset_name, std::string attribute_name) const
Obtain the HDF5 handle of a attribute.
Definition: hdf5impex.hxx:1535
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
bool operator==(hid_t h) const
Equality comparison of the contained handle.
Definition: hdf5impex.hxx:601
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
bool operator!=(HDF5HandleShared const &h) const
Inequality comparison of the contained handle.
Definition: hdf5impex.hxx:608
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
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
std::string pwd() const
Get the path of the current group.
Definition: hdf5impex.hxx:1315
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
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 write(std::string datasetName, char data)
Write a single value. Specialization of the write function for simple datatypes.
Definition: hdf5impex.hxx:1881
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 isUnstrided(unsigned int dimension=N-1) const
Definition: multi_array.hxx:1234
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
std::string getDatasetType(std::string const &datasetName) const
Definition: hdf5impex.hxx:1410
bool existsDataset(std::string datasetName) const
Check if given datasetName exists.
Definition: hdf5impex.hxx:1329
const_iterator end() const
Definition: array_vector.hxx:237
const_pointer data() const
Definition: array_vector.hxx:209
ArrayVector< hsize_t > const & shape() const
Definition: hdf5impex.hxx:710
size_type size() const
Definition: array_vector.hxx:358
Iterate over multiple images simultaneously in scan order.
Definition: multi_fwd.hxx:167
MultiArrayView subarray(difference_type p, difference_type q) const
Definition: multi_array.hxx:1476
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
HDF5HandleShared(hid_t h, Destructor destructor, const char *error_message)
Create a shared wrapper for a plain hid_t object.
Definition: hdf5impex.hxx:450
~HDF5HandleShared()
Destructor (calls close())
Definition: hdf5impex.hxx:493
HDF5Handle getDatasetHandle(std::string const &datasetName) const
Obtain the HDF5 handle of a dataset.
Definition: hdf5impex.hxx:1456
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
size_t use_count() const
Get the number of owners of the contained handle.
Definition: hdf5impex.hxx:545
void swap(HDF5Handle &h)
Swap the contents of two handle wrappers.
Definition: hdf5impex.hxx:316
Access to HDF5 files.
Definition: hdf5impex.hxx:956
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

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