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

hdf5impex.hxx |

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

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