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

© 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.1 (Fri May 19 2017)