comparison armadillo-2.4.4/include/armadillo_bits/diskio_meat.hpp @ 0:8b6102e2a9b0

Armadillo Library
author maxzanoni76 <max.zanoni@eecs.qmul.ac.uk>
date Wed, 11 Apr 2012 09:27:06 +0100
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:8b6102e2a9b0
1 // Copyright (C) 2008-2011 NICTA (www.nicta.com.au)
2 // Copyright (C) 2008-2011 Conrad Sanderson
3 // Copyright (C) 2009-2010 Ian Cullinan
4 //
5 // This file is part of the Armadillo C++ library.
6 // It is provided without any warranty of fitness
7 // for any purpose. You can redistribute this file
8 // and/or modify it under the terms of the GNU
9 // Lesser General Public License (LGPL) as published
10 // by the Free Software Foundation, either version 3
11 // of the License or (at your option) any later version.
12 // (see http://www.opensource.org/licenses for more info)
13
14
15 //! \addtogroup diskio
16 //! @{
17
18
19 //! Generate the first line of the header used for saving matrices in text format.
20 //! Format: "ARMA_MAT_TXT_ABXYZ".
21 //! A is one of: I (for integral types) or F (for floating point types).
22 //! B is one of: U (for unsigned types), S (for signed types), N (for not appliable) or C (for complex types).
23 //! XYZ specifies the width of each element in terms of bytes, e.g. "008" indicates eight bytes.
24 template<typename eT>
25 inline
26 std::string
27 diskio::gen_txt_header(const Mat<eT>& x)
28 {
29 arma_type_check(( is_supported_elem_type<eT>::value == false ));
30
31 arma_ignore(x);
32
33 if(is_u8<eT>::value == true)
34 {
35 return std::string("ARMA_MAT_TXT_IU001");
36 }
37 else
38 if(is_s8<eT>::value == true)
39 {
40 return std::string("ARMA_MAT_TXT_IS001");
41 }
42 else
43 if(is_u16<eT>::value == true)
44 {
45 return std::string("ARMA_MAT_TXT_IU002");
46 }
47 else
48 if(is_s16<eT>::value == true)
49 {
50 return std::string("ARMA_MAT_TXT_IS002");
51 }
52 else
53 if(is_u32<eT>::value == true)
54 {
55 return std::string("ARMA_MAT_TXT_IU004");
56 }
57 else
58 if(is_s32<eT>::value == true)
59 {
60 return std::string("ARMA_MAT_TXT_IS004");
61 }
62 #if defined(ARMA_64BIT_WORD)
63 else
64 if(is_u64<eT>::value == true)
65 {
66 return std::string("ARMA_MAT_TXT_IU008");
67 }
68 else
69 if(is_s64<eT>::value == true)
70 {
71 return std::string("ARMA_MAT_TXT_IS008");
72 }
73 #endif
74 else
75 if(is_float<eT>::value == true)
76 {
77 return std::string("ARMA_MAT_TXT_FN004");
78 }
79 else
80 if(is_double<eT>::value == true)
81 {
82 return std::string("ARMA_MAT_TXT_FN008");
83 }
84 else
85 if(is_complex_float<eT>::value == true)
86 {
87 return std::string("ARMA_MAT_TXT_FC008");
88 }
89 else
90 if(is_complex_double<eT>::value == true)
91 {
92 return std::string("ARMA_MAT_TXT_FC016");
93 }
94 else
95 {
96 return std::string();
97 }
98
99 }
100
101
102
103 //! Generate the first line of the header used for saving matrices in binary format.
104 //! Format: "ARMA_MAT_BIN_ABXYZ".
105 //! A is one of: I (for integral types) or F (for floating point types).
106 //! B is one of: U (for unsigned types), S (for signed types), N (for not appliable) or C (for complex types).
107 //! XYZ specifies the width of each element in terms of bytes, e.g. "008" indicates eight bytes.
108 template<typename eT>
109 inline
110 std::string
111 diskio::gen_bin_header(const Mat<eT>& x)
112 {
113 arma_type_check(( is_supported_elem_type<eT>::value == false ));
114
115 arma_ignore(x);
116
117 if(is_u8<eT>::value == true)
118 {
119 return std::string("ARMA_MAT_BIN_IU001");
120 }
121 else
122 if(is_s8<eT>::value == true)
123 {
124 return std::string("ARMA_MAT_BIN_IS001");
125 }
126 else
127 if(is_u16<eT>::value == true)
128 {
129 return std::string("ARMA_MAT_BIN_IU002");
130 }
131 else
132 if(is_s16<eT>::value == true)
133 {
134 return std::string("ARMA_MAT_BIN_IS002");
135 }
136 else
137 if(is_u32<eT>::value == true)
138 {
139 return std::string("ARMA_MAT_BIN_IU004");
140 }
141 else
142 if(is_s32<eT>::value == true)
143 {
144 return std::string("ARMA_MAT_BIN_IS004");
145 }
146 #if defined(ARMA_64BIT_WORD)
147 else
148 if(is_u64<eT>::value == true)
149 {
150 return std::string("ARMA_MAT_BIN_IU008");
151 }
152 else
153 if(is_s64<eT>::value == true)
154 {
155 return std::string("ARMA_MAT_BIN_IS008");
156 }
157 #endif
158 else
159 if(is_float<eT>::value == true)
160 {
161 return std::string("ARMA_MAT_BIN_FN004");
162 }
163 else
164 if(is_double<eT>::value == true)
165 {
166 return std::string("ARMA_MAT_BIN_FN008");
167 }
168 else
169 if(is_complex_float<eT>::value == true)
170 {
171 return std::string("ARMA_MAT_BIN_FC008");
172 }
173 else
174 if(is_complex_double<eT>::value == true)
175 {
176 return std::string("ARMA_MAT_BIN_FC016");
177 }
178 else
179 {
180 return std::string();
181 }
182
183 }
184
185
186
187 //! Generate the first line of the header used for saving cubes in text format.
188 //! Format: "ARMA_CUB_TXT_ABXYZ".
189 //! A is one of: I (for integral types) or F (for floating point types).
190 //! B is one of: U (for unsigned types), S (for signed types), N (for not appliable) or C (for complex types).
191 //! XYZ specifies the width of each element in terms of bytes, e.g. "008" indicates eight bytes.
192 template<typename eT>
193 inline
194 std::string
195 diskio::gen_txt_header(const Cube<eT>& x)
196 {
197 arma_type_check(( is_supported_elem_type<eT>::value == false ));
198
199 arma_ignore(x);
200
201 if(is_u8<eT>::value == true)
202 {
203 return std::string("ARMA_CUB_TXT_IU001");
204 }
205 else
206 if(is_s8<eT>::value == true)
207 {
208 return std::string("ARMA_CUB_TXT_IS001");
209 }
210 else
211 if(is_u16<eT>::value == true)
212 {
213 return std::string("ARMA_CUB_TXT_IU002");
214 }
215 else
216 if(is_s16<eT>::value == true)
217 {
218 return std::string("ARMA_CUB_TXT_IS002");
219 }
220 else
221 if(is_u32<eT>::value == true)
222 {
223 return std::string("ARMA_CUB_TXT_IU004");
224 }
225 else
226 if(is_s32<eT>::value == true)
227 {
228 return std::string("ARMA_CUB_TXT_IS004");
229 }
230 #if defined(ARMA_64BIT_WORD)
231 else
232 if(is_u64<eT>::value == true)
233 {
234 return std::string("ARMA_CUB_TXT_IU008");
235 }
236 else
237 if(is_s64<eT>::value == true)
238 {
239 return std::string("ARMA_CUB_TXT_IS008");
240 }
241 #endif
242 else
243 if(is_float<eT>::value == true)
244 {
245 return std::string("ARMA_CUB_TXT_FN004");
246 }
247 else
248 if(is_double<eT>::value == true)
249 {
250 return std::string("ARMA_CUB_TXT_FN008");
251 }
252 else
253 if(is_complex_float<eT>::value == true)
254 {
255 return std::string("ARMA_CUB_TXT_FC008");
256 }
257 else
258 if(is_complex_double<eT>::value == true)
259 {
260 return std::string("ARMA_CUB_TXT_FC016");
261 }
262 else
263 {
264 return std::string();
265 }
266
267 }
268
269
270
271 //! Generate the first line of the header used for saving cubes in binary format.
272 //! Format: "ARMA_CUB_BIN_ABXYZ".
273 //! A is one of: I (for integral types) or F (for floating point types).
274 //! B is one of: U (for unsigned types), S (for signed types), N (for not appliable) or C (for complex types).
275 //! XYZ specifies the width of each element in terms of bytes, e.g. "008" indicates eight bytes.
276 template<typename eT>
277 inline
278 std::string
279 diskio::gen_bin_header(const Cube<eT>& x)
280 {
281 arma_type_check(( is_supported_elem_type<eT>::value == false ));
282
283 arma_ignore(x);
284
285 if(is_u8<eT>::value == true)
286 {
287 return std::string("ARMA_CUB_BIN_IU001");
288 }
289 else
290 if(is_s8<eT>::value == true)
291 {
292 return std::string("ARMA_CUB_BIN_IS001");
293 }
294 else
295 if(is_u16<eT>::value == true)
296 {
297 return std::string("ARMA_CUB_BIN_IU002");
298 }
299 else
300 if(is_s16<eT>::value == true)
301 {
302 return std::string("ARMA_CUB_BIN_IS002");
303 }
304 else
305 if(is_u32<eT>::value == true)
306 {
307 return std::string("ARMA_CUB_BIN_IU004");
308 }
309 else
310 if(is_s32<eT>::value == true)
311 {
312 return std::string("ARMA_CUB_BIN_IS004");
313 }
314 #if defined(ARMA_64BIT_WORD)
315 else
316 if(is_u64<eT>::value == true)
317 {
318 return std::string("ARMA_CUB_BIN_IU008");
319 }
320 else
321 if(is_s64<eT>::value == true)
322 {
323 return std::string("ARMA_CUB_BIN_IS008");
324 }
325 #endif
326 else
327 if(is_float<eT>::value == true)
328 {
329 return std::string("ARMA_CUB_BIN_FN004");
330 }
331 else
332 if(is_double<eT>::value == true)
333 {
334 return std::string("ARMA_CUB_BIN_FN008");
335 }
336 else
337 if(is_complex_float<eT>::value == true)
338 {
339 return std::string("ARMA_CUB_BIN_FC008");
340 }
341 else
342 if(is_complex_double<eT>::value == true)
343 {
344 return std::string("ARMA_CUB_BIN_FC016");
345 }
346 else
347 {
348 return std::string();
349 }
350
351 }
352
353
354
355 inline
356 file_type
357 diskio::guess_file_type(std::istream& f)
358 {
359 arma_extra_debug_sigprint();
360
361 f.clear();
362 const std::fstream::pos_type pos1 = f.tellg();
363
364 f.clear();
365 f.seekg(0, ios::end);
366
367 f.clear();
368 const std::fstream::pos_type pos2 = f.tellg();
369
370 const uword N = ( (pos1 >= 0) && (pos2 >= 0) ) ? uword(pos2 - pos1) : 0;
371
372 f.clear();
373 f.seekg(pos1);
374
375 podarray<unsigned char> data(N);
376
377 unsigned char* ptr = data.memptr();
378
379 f.clear();
380 f.read( reinterpret_cast<char*>(ptr), std::streamsize(N) );
381
382 const bool load_okay = f.good();
383
384 f.clear();
385 f.seekg(pos1);
386
387 bool has_binary = false;
388 bool has_comma = false;
389
390 if(load_okay == true)
391 {
392 uword i = 0;
393 uword j = (N >= 2) ? 1 : 0;
394
395 for(; j<N; i+=2, j+=2)
396 {
397 const unsigned char val_i = ptr[i];
398 const unsigned char val_j = ptr[j];
399
400 // the range checking can be made more elaborate
401 if( ((val_i <= 8) || (val_i >= 123)) || ((val_j <= 8) || (val_j >= 123)) )
402 {
403 has_binary = true;
404 break;
405 }
406
407 if( (val_i == ',') || (val_j == ',') )
408 {
409 has_comma = true;
410 break;
411 }
412 }
413 }
414 else
415 {
416 return file_type_unknown;
417 }
418
419 if(has_binary)
420 {
421 return raw_binary;
422 }
423
424 if(has_comma)
425 {
426 return csv_ascii;
427 }
428
429 return raw_ascii;
430 }
431
432
433
434 inline
435 char
436 diskio::conv_to_hex_char(const u8 x)
437 {
438 char out;
439
440 switch(x)
441 {
442 case 0: out = '0'; break;
443 case 1: out = '1'; break;
444 case 2: out = '2'; break;
445 case 3: out = '3'; break;
446 case 4: out = '4'; break;
447 case 5: out = '5'; break;
448 case 6: out = '6'; break;
449 case 7: out = '7'; break;
450 case 8: out = '8'; break;
451 case 9: out = '9'; break;
452 case 10: out = 'a'; break;
453 case 11: out = 'b'; break;
454 case 12: out = 'c'; break;
455 case 13: out = 'd'; break;
456 case 14: out = 'e'; break;
457 case 15: out = 'f'; break;
458 default: out = '-'; break;
459 }
460
461 return out;
462 }
463
464
465
466 inline
467 void
468 diskio::conv_to_hex(char* out, const u8 x)
469 {
470 const u8 a = x / 16;
471 const u8 b = x - 16*a;
472
473 out[0] = conv_to_hex_char(a);
474 out[1] = conv_to_hex_char(b);
475 }
476
477
478
479 //! Append a quasi-random string to the given filename.
480 //! The rand() function is deliberately not used,
481 //! as rand() has an internal state that changes
482 //! from call to call. Such states should not be
483 //! modified in scientific applications, where the
484 //! results should be reproducable and not affected
485 //! by saving data.
486 inline
487 std::string
488 diskio::gen_tmp_name(const std::string& x)
489 {
490 const std::string* ptr_x = &x;
491 const u8* ptr_ptr_x = reinterpret_cast<const u8*>(&ptr_x);
492
493 const char* extra = ".tmp_";
494 const uword extra_size = 5;
495
496 const uword tmp_size = 2*sizeof(u8*) + 2*2;
497 char tmp[tmp_size];
498
499 uword char_count = 0;
500
501 for(uword i=0; i<sizeof(u8*); ++i)
502 {
503 conv_to_hex(&tmp[char_count], ptr_ptr_x[i]);
504 char_count += 2;
505 }
506
507 const uword x_size = static_cast<uword>(x.size());
508 u8 sum = 0;
509
510 for(uword i=0; i<x_size; ++i)
511 {
512 sum += u8(x[i]);
513 }
514
515 conv_to_hex(&tmp[char_count], sum);
516 char_count += 2;
517
518 conv_to_hex(&tmp[char_count], u8(x_size));
519
520
521 std::string out;
522 out.resize(x_size + extra_size + tmp_size);
523
524
525 for(uword i=0; i<x_size; ++i)
526 {
527 out[i] = x[i];
528 }
529
530 for(uword i=0; i<extra_size; ++i)
531 {
532 out[x_size + i] = extra[i];
533 }
534
535 for(uword i=0; i<tmp_size; ++i)
536 {
537 out[x_size + extra_size + i] = tmp[i];
538 }
539
540 return out;
541 }
542
543
544
545 //! Safely rename a file.
546 //! Before renaming, test if we can write to the final file.
547 //! This should prevent:
548 //! (i) overwriting files that are write protected,
549 //! (ii) overwriting directories.
550 inline
551 bool
552 diskio::safe_rename(const std::string& old_name, const std::string& new_name)
553 {
554 std::fstream f(new_name.c_str(), std::fstream::out | std::fstream::app);
555 f.put(' ');
556
557 bool save_okay = f.good();
558 f.close();
559
560 if(save_okay == true)
561 {
562 std::remove(new_name.c_str());
563
564 const int mv_result = std::rename(old_name.c_str(), new_name.c_str());
565
566 save_okay = (mv_result == 0);
567 }
568
569 return save_okay;
570 }
571
572
573
574 //! Save a matrix as raw text (no header, human readable).
575 //! Matrices can be loaded in Matlab and Octave, as long as they don't have complex elements.
576 template<typename eT>
577 inline
578 bool
579 diskio::save_raw_ascii(const Mat<eT>& x, const std::string& final_name)
580 {
581 arma_extra_debug_sigprint();
582
583 const std::string tmp_name = diskio::gen_tmp_name(final_name);
584
585 std::fstream f(tmp_name.c_str(), std::fstream::out);
586
587 bool save_okay = f.is_open();
588
589 if(save_okay == true)
590 {
591 save_okay = diskio::save_raw_ascii(x, f);
592
593 f.flush();
594 f.close();
595
596 if(save_okay == true)
597 {
598 save_okay = diskio::safe_rename(tmp_name, final_name);
599 }
600 }
601
602 return save_okay;
603 }
604
605
606
607 //! Save a matrix as raw text (no header, human readable).
608 //! Matrices can be loaded in Matlab and Octave, as long as they don't have complex elements.
609 template<typename eT>
610 inline
611 bool
612 diskio::save_raw_ascii(const Mat<eT>& x, std::ostream& f)
613 {
614 arma_extra_debug_sigprint();
615
616 uword cell_width;
617
618 // TODO: need sane values for complex numbers
619
620 if( (is_float<eT>::value == true) || (is_double<eT>::value == true) )
621 {
622 f.setf(ios::scientific);
623 f.precision(10);
624 cell_width = 18;
625 }
626
627 for(uword row=0; row < x.n_rows; ++row)
628 {
629 for(uword col=0; col < x.n_cols; ++col)
630 {
631 f.put(' ');
632
633 if( (is_float<eT>::value == true) || (is_double<eT>::value == true) )
634 {
635 f.width(cell_width);
636 }
637
638 f << x.at(row,col);
639 }
640
641 f.put('\n');
642 }
643
644 return f.good();
645 }
646
647
648
649 //! Save a matrix as raw binary (no header)
650 template<typename eT>
651 inline
652 bool
653 diskio::save_raw_binary(const Mat<eT>& x, const std::string& final_name)
654 {
655 arma_extra_debug_sigprint();
656
657 const std::string tmp_name = diskio::gen_tmp_name(final_name);
658
659 std::ofstream f(tmp_name.c_str(), std::fstream::binary);
660
661 bool save_okay = f.is_open();
662
663 if(save_okay == true)
664 {
665 save_okay = diskio::save_raw_binary(x, f);
666
667 f.flush();
668 f.close();
669
670 if(save_okay == true)
671 {
672 save_okay = diskio::safe_rename(tmp_name, final_name);
673 }
674 }
675
676 return save_okay;
677 }
678
679
680
681 template<typename eT>
682 inline
683 bool
684 diskio::save_raw_binary(const Mat<eT>& x, std::ostream& f)
685 {
686 arma_extra_debug_sigprint();
687
688 f.write( reinterpret_cast<const char*>(x.mem), std::streamsize(x.n_elem*sizeof(eT)) );
689
690 return f.good();
691 }
692
693
694
695 //! Save a matrix in text format (human readable),
696 //! with a header that indicates the matrix type as well as its dimensions
697 template<typename eT>
698 inline
699 bool
700 diskio::save_arma_ascii(const Mat<eT>& x, const std::string& final_name)
701 {
702 arma_extra_debug_sigprint();
703
704 const std::string tmp_name = diskio::gen_tmp_name(final_name);
705
706 std::ofstream f(tmp_name.c_str());
707
708 bool save_okay = f.is_open();
709
710 if(save_okay == true)
711 {
712 save_okay = diskio::save_arma_ascii(x, f);
713
714 f.flush();
715 f.close();
716
717 if(save_okay == true)
718 {
719 save_okay = diskio::safe_rename(tmp_name, final_name);
720 }
721 }
722
723 return save_okay;
724 }
725
726
727
728 //! Save a matrix in text format (human readable),
729 //! with a header that indicates the matrix type as well as its dimensions
730 template<typename eT>
731 inline
732 bool
733 diskio::save_arma_ascii(const Mat<eT>& x, std::ostream& f)
734 {
735 arma_extra_debug_sigprint();
736
737 const ios::fmtflags orig_flags = f.flags();
738
739 f << diskio::gen_txt_header(x) << '\n';
740 f << x.n_rows << ' ' << x.n_cols << '\n';
741
742 uword cell_width;
743
744 // TODO: need sane values for complex numbers
745
746 if( (is_float<eT>::value == true) || (is_double<eT>::value == true) )
747 {
748 f.setf(ios::scientific);
749 f.precision(10);
750 cell_width = 18;
751 }
752
753 for(uword row=0; row < x.n_rows; ++row)
754 {
755 for(uword col=0; col < x.n_cols; ++col)
756 {
757 f.put(' ');
758
759 if( (is_float<eT>::value == true) || (is_double<eT>::value == true) )
760 {
761 f.width(cell_width);
762 }
763
764 f << x.at(row,col);
765 }
766
767 f.put('\n');
768 }
769
770 const bool save_okay = f.good();
771
772 f.flags(orig_flags);
773
774 return save_okay;
775 }
776
777
778
779 //! Save a matrix in CSV text format (human readable)
780 template<typename eT>
781 inline
782 bool
783 diskio::save_csv_ascii(const Mat<eT>& x, const std::string& final_name)
784 {
785 arma_extra_debug_sigprint();
786
787 const std::string tmp_name = diskio::gen_tmp_name(final_name);
788
789 std::ofstream f(tmp_name.c_str());
790
791 bool save_okay = f.is_open();
792
793 if(save_okay == true)
794 {
795 save_okay = diskio::save_csv_ascii(x, f);
796
797 f.flush();
798 f.close();
799
800 if(save_okay == true)
801 {
802 save_okay = diskio::safe_rename(tmp_name, final_name);
803 }
804 }
805
806 return save_okay;
807 }
808
809
810
811 //! Save a matrix in CSV text format (human readable)
812 template<typename eT>
813 inline
814 bool
815 diskio::save_csv_ascii(const Mat<eT>& x, std::ostream& f)
816 {
817 arma_extra_debug_sigprint();
818
819 const ios::fmtflags orig_flags = f.flags();
820
821 // TODO: need sane values for complex numbers
822
823 if( (is_float<eT>::value == true) || (is_double<eT>::value == true) )
824 {
825 f.setf(ios::scientific);
826 f.precision(10);
827 }
828
829 uword x_n_rows = x.n_rows;
830 uword x_n_cols = x.n_cols;
831
832 for(uword row=0; row < x_n_rows; ++row)
833 {
834 for(uword col=0; col < x_n_cols; ++col)
835 {
836 f << x.at(row,col);
837
838 if( col < (x_n_cols-1) )
839 {
840 f.put(',');
841 }
842 }
843
844 f.put('\n');
845 }
846
847 const bool save_okay = f.good();
848
849 f.flags(orig_flags);
850
851 return save_okay;
852 }
853
854
855
856 //! Save a matrix in binary format,
857 //! with a header that stores the matrix type as well as its dimensions
858 template<typename eT>
859 inline
860 bool
861 diskio::save_arma_binary(const Mat<eT>& x, const std::string& final_name)
862 {
863 arma_extra_debug_sigprint();
864
865 const std::string tmp_name = diskio::gen_tmp_name(final_name);
866
867 std::ofstream f(tmp_name.c_str(), std::fstream::binary);
868
869 bool save_okay = f.is_open();
870
871 if(save_okay == true)
872 {
873 save_okay = diskio::save_arma_binary(x, f);
874
875 f.flush();
876 f.close();
877
878 if(save_okay == true)
879 {
880 save_okay = diskio::safe_rename(tmp_name, final_name);
881 }
882 }
883
884 return save_okay;
885 }
886
887
888
889 //! Save a matrix in binary format,
890 //! with a header that stores the matrix type as well as its dimensions
891 template<typename eT>
892 inline
893 bool
894 diskio::save_arma_binary(const Mat<eT>& x, std::ostream& f)
895 {
896 arma_extra_debug_sigprint();
897
898 f << diskio::gen_bin_header(x) << '\n';
899 f << x.n_rows << ' ' << x.n_cols << '\n';
900
901 f.write( reinterpret_cast<const char*>(x.mem), std::streamsize(x.n_elem*sizeof(eT)) );
902
903 return f.good();
904 }
905
906
907
908 //! Save a matrix as a PGM greyscale image
909 template<typename eT>
910 inline
911 bool
912 diskio::save_pgm_binary(const Mat<eT>& x, const std::string& final_name)
913 {
914 arma_extra_debug_sigprint();
915
916 const std::string tmp_name = diskio::gen_tmp_name(final_name);
917
918 std::fstream f(tmp_name.c_str(), std::fstream::out | std::fstream::binary);
919
920 bool save_okay = f.is_open();
921
922 if(save_okay == true)
923 {
924 save_okay = diskio::save_pgm_binary(x, f);
925
926 f.flush();
927 f.close();
928
929 if(save_okay == true)
930 {
931 save_okay = diskio::safe_rename(tmp_name, final_name);
932 }
933 }
934
935 return save_okay;
936 }
937
938
939
940 //
941 // TODO:
942 // add functionality to save the image in a normalised format,
943 // i.e. scaled so that every value falls in the [0,255] range.
944
945 //! Save a matrix as a PGM greyscale image
946 template<typename eT>
947 inline
948 bool
949 diskio::save_pgm_binary(const Mat<eT>& x, std::ostream& f)
950 {
951 arma_extra_debug_sigprint();
952
953 f << "P5" << '\n';
954 f << x.n_cols << ' ' << x.n_rows << '\n';
955 f << 255 << '\n';
956
957 const uword n_elem = x.n_rows * x.n_cols;
958 podarray<u8> tmp(n_elem);
959
960 uword i = 0;
961
962 for(uword row=0; row < x.n_rows; ++row)
963 {
964 for(uword col=0; col < x.n_cols; ++col)
965 {
966 tmp[i] = u8( x.at(row,col) ); // TODO: add round() ?
967 ++i;
968 }
969 }
970
971 f.write(reinterpret_cast<const char*>(tmp.mem), std::streamsize(n_elem) );
972
973 return f.good();
974 }
975
976
977
978 //! Save a matrix as a PGM greyscale image
979 template<typename T>
980 inline
981 bool
982 diskio::save_pgm_binary(const Mat< std::complex<T> >& x, const std::string& final_name)
983 {
984 arma_extra_debug_sigprint();
985
986 const uchar_mat tmp = conv_to<uchar_mat>::from(x);
987
988 return diskio::save_pgm_binary(tmp, final_name);
989 }
990
991
992
993 //! Save a matrix as a PGM greyscale image
994 template<typename T>
995 inline
996 bool
997 diskio::save_pgm_binary(const Mat< std::complex<T> >& x, std::ostream& f)
998 {
999 arma_extra_debug_sigprint();
1000
1001 const uchar_mat tmp = conv_to<uchar_mat>::from(x);
1002
1003 return diskio::save_pgm_binary(tmp, f);
1004 }
1005
1006
1007
1008 //! Load a matrix as raw text (no header, human readable).
1009 //! Can read matrices saved as text in Matlab and Octave.
1010 //! NOTE: this is much slower than reading a file with a header.
1011 template<typename eT>
1012 inline
1013 bool
1014 diskio::load_raw_ascii(Mat<eT>& x, const std::string& name, std::string& err_msg)
1015 {
1016 arma_extra_debug_sigprint();
1017
1018 std::fstream f;
1019 f.open(name.c_str(), std::fstream::in);
1020
1021 bool load_okay = f.is_open();
1022
1023 if(load_okay == true)
1024 {
1025 load_okay = diskio::load_raw_ascii(x, f, err_msg);
1026 f.close();
1027 }
1028
1029 return load_okay;
1030 }
1031
1032
1033
1034 //! Load a matrix as raw text (no header, human readable).
1035 //! Can read matrices saved as text in Matlab and Octave.
1036 //! NOTE: this is much slower than reading a file with a header.
1037 template<typename eT>
1038 inline
1039 bool
1040 diskio::load_raw_ascii(Mat<eT>& x, std::istream& f, std::string& err_msg)
1041 {
1042 arma_extra_debug_sigprint();
1043
1044 bool load_okay = f.good();
1045
1046 f.clear();
1047 const std::fstream::pos_type pos1 = f.tellg();
1048
1049 //
1050 // work out the size
1051
1052 uword f_n_rows = 0;
1053 uword f_n_cols = 0;
1054
1055 bool f_n_cols_found = false;
1056
1057 std::string line_string;
1058 std::string token;
1059
1060 while( (f.good() == true) && (load_okay == true) )
1061 {
1062 std::getline(f, line_string);
1063
1064 if(line_string.size() == 0)
1065 {
1066 break;
1067 }
1068
1069 std::stringstream line_stream(line_string);
1070
1071 uword line_n_cols = 0;
1072
1073 while (line_stream >> token)
1074 {
1075 ++line_n_cols;
1076 }
1077
1078 if(f_n_cols_found == false)
1079 {
1080 f_n_cols = line_n_cols;
1081 f_n_cols_found = true;
1082 }
1083 else
1084 {
1085 if(line_n_cols != f_n_cols)
1086 {
1087 err_msg = "inconsistent number of columns in ";
1088 load_okay = false;
1089 }
1090 }
1091
1092 ++f_n_rows;
1093 }
1094
1095 if(load_okay == true)
1096 {
1097 f.clear();
1098 f.seekg(pos1);
1099
1100 x.set_size(f_n_rows, f_n_cols);
1101
1102 eT val;
1103
1104 for(uword row=0; (row < x.n_rows) && (load_okay == true); ++row)
1105 {
1106 for(uword col=0; (col < x.n_cols) && (load_okay == true); ++col)
1107 {
1108 f >> val;
1109
1110 if(f.fail() == false)
1111 {
1112 x.at(row,col) = val;
1113 }
1114 else
1115 {
1116 load_okay = false;
1117 err_msg = "couldn't interpret data in ";
1118 //break;
1119 }
1120 }
1121 }
1122 }
1123
1124
1125 // an empty file indicates an empty matrix
1126 if( (f_n_cols_found == false) && (load_okay == true) )
1127 {
1128 x.reset();
1129 }
1130
1131
1132 return load_okay;
1133 }
1134
1135
1136
1137 //! Load a matrix in binary format (no header);
1138 //! the matrix is assumed to have one column
1139 template<typename eT>
1140 inline
1141 bool
1142 diskio::load_raw_binary(Mat<eT>& x, const std::string& name, std::string& err_msg)
1143 {
1144 arma_extra_debug_sigprint();
1145
1146 std::ifstream f;
1147 f.open(name.c_str(), std::fstream::binary);
1148
1149 bool load_okay = f.is_open();
1150
1151 if(load_okay == true)
1152 {
1153 load_okay = diskio::load_raw_binary(x, f, err_msg);
1154 f.close();
1155 }
1156
1157 return load_okay;
1158 }
1159
1160
1161
1162 template<typename eT>
1163 inline
1164 bool
1165 diskio::load_raw_binary(Mat<eT>& x, std::istream& f, std::string& err_msg)
1166 {
1167 arma_extra_debug_sigprint();
1168 arma_ignore(err_msg);
1169
1170 f.clear();
1171 const std::streampos pos1 = f.tellg();
1172
1173 f.clear();
1174 f.seekg(0, ios::end);
1175
1176 f.clear();
1177 const std::streampos pos2 = f.tellg();
1178
1179 const uword N = ( (pos1 >= 0) && (pos2 >= 0) ) ? uword(pos2 - pos1) : 0;
1180
1181 f.clear();
1182 //f.seekg(0, ios::beg);
1183 f.seekg(pos1);
1184
1185 x.set_size(N / sizeof(eT), 1);
1186
1187 f.clear();
1188 f.read( reinterpret_cast<char *>(x.memptr()), std::streamsize(N) );
1189
1190 return f.good();
1191 }
1192
1193
1194
1195 //! Load a matrix in text format (human readable),
1196 //! with a header that indicates the matrix type as well as its dimensions
1197 template<typename eT>
1198 inline
1199 bool
1200 diskio::load_arma_ascii(Mat<eT>& x, const std::string& name, std::string& err_msg)
1201 {
1202 arma_extra_debug_sigprint();
1203
1204 std::ifstream f(name.c_str());
1205
1206 bool load_okay = f.is_open();
1207
1208 if(load_okay == true)
1209 {
1210 load_okay = diskio::load_arma_ascii(x, f, err_msg);
1211 f.close();
1212 }
1213
1214 return load_okay;
1215 }
1216
1217
1218
1219 //! Load a matrix in text format (human readable),
1220 //! with a header that indicates the matrix type as well as its dimensions
1221 template<typename eT>
1222 inline
1223 bool
1224 diskio::load_arma_ascii(Mat<eT>& x, std::istream& f, std::string& err_msg)
1225 {
1226 arma_extra_debug_sigprint();
1227
1228 bool load_okay = true;
1229
1230 std::string f_header;
1231 uword f_n_rows;
1232 uword f_n_cols;
1233
1234 f >> f_header;
1235 f >> f_n_rows;
1236 f >> f_n_cols;
1237
1238 if(f_header == diskio::gen_txt_header(x))
1239 {
1240 x.set_size(f_n_rows, f_n_cols);
1241
1242 for(uword row=0; row < x.n_rows; ++row)
1243 {
1244 for(uword col=0; col < x.n_cols; ++col)
1245 {
1246 f >> x.at(row,col);
1247 }
1248 }
1249
1250 load_okay = f.good();
1251 }
1252 else
1253 {
1254 load_okay = false;
1255 err_msg = "incorrect header in ";
1256 }
1257
1258 return load_okay;
1259 }
1260
1261
1262
1263 //! Load a matrix in CSV text format (human readable)
1264 template<typename eT>
1265 inline
1266 bool
1267 diskio::load_csv_ascii(Mat<eT>& x, const std::string& name, std::string& err_msg)
1268 {
1269 arma_extra_debug_sigprint();
1270
1271 std::fstream f;
1272 f.open(name.c_str(), std::fstream::in);
1273
1274 bool load_okay = f.is_open();
1275
1276 if(load_okay == true)
1277 {
1278 load_okay = diskio::load_csv_ascii(x, f, err_msg);
1279 f.close();
1280 }
1281
1282 return load_okay;
1283 }
1284
1285
1286
1287 //! Load a matrix in CSV text format (human readable)
1288 template<typename eT>
1289 inline
1290 bool
1291 diskio::load_csv_ascii(Mat<eT>& x, std::istream& f, std::string& err_msg)
1292 {
1293 arma_extra_debug_sigprint();
1294
1295 bool load_okay = f.good();
1296
1297 f.clear();
1298 const std::fstream::pos_type pos1 = f.tellg();
1299
1300 //
1301 // work out the size
1302
1303 uword f_n_rows = 0;
1304 uword f_n_cols = 0;
1305
1306 std::string line_string;
1307 std::string token;
1308
1309 while( (f.good() == true) && (load_okay == true) )
1310 {
1311 std::getline(f, line_string);
1312
1313 if(line_string.size() == 0)
1314 {
1315 break;
1316 }
1317
1318 std::stringstream line_stream(line_string);
1319
1320 uword line_n_cols = 0;
1321
1322 while(line_stream.good() == true)
1323 {
1324 getline(line_stream, token, ',');
1325 ++line_n_cols;
1326 }
1327
1328 if(f_n_cols < line_n_cols)
1329 {
1330 f_n_cols = line_n_cols;
1331 }
1332
1333 ++f_n_rows;
1334 }
1335
1336 f.clear();
1337 f.seekg(pos1);
1338
1339 x.zeros(f_n_rows, f_n_cols);
1340
1341 uword row = 0;
1342
1343 while(f.good() == true)
1344 {
1345 std::getline(f, line_string);
1346
1347 if(line_string.size() == 0)
1348 {
1349 break;
1350 }
1351
1352 std::stringstream line_stream(line_string);
1353
1354 uword col = 0;
1355
1356 while(line_stream.good() == true)
1357 {
1358 getline(line_stream, token, ',');
1359
1360 eT val;
1361
1362 std::stringstream ss(token);
1363
1364 ss >> val;
1365
1366 if(ss.fail() == false)
1367 {
1368 x.at(row,col) = val;
1369 }
1370
1371 ++col;
1372 }
1373
1374 ++row;
1375 }
1376
1377 return load_okay;
1378 }
1379
1380
1381
1382 //! Load a matrix in binary format,
1383 //! with a header that indicates the matrix type as well as its dimensions
1384 template<typename eT>
1385 inline
1386 bool
1387 diskio::load_arma_binary(Mat<eT>& x, const std::string& name, std::string& err_msg)
1388 {
1389 arma_extra_debug_sigprint();
1390
1391 std::ifstream f;
1392 f.open(name.c_str(), std::fstream::binary);
1393
1394 bool load_okay = f.is_open();
1395
1396 if(load_okay == true)
1397 {
1398 load_okay = diskio::load_arma_binary(x, f, err_msg);
1399 f.close();
1400 }
1401
1402 return load_okay;
1403 }
1404
1405
1406
1407 template<typename eT>
1408 inline
1409 bool
1410 diskio::load_arma_binary(Mat<eT>& x, std::istream& f, std::string& err_msg)
1411 {
1412 arma_extra_debug_sigprint();
1413
1414 bool load_okay = true;
1415
1416 std::string f_header;
1417 uword f_n_rows;
1418 uword f_n_cols;
1419
1420 f >> f_header;
1421 f >> f_n_rows;
1422 f >> f_n_cols;
1423
1424 if(f_header == diskio::gen_bin_header(x))
1425 {
1426 //f.seekg(1, ios::cur); // NOTE: this may not be portable, as on a Windows machine a newline could be two characters
1427 f.get();
1428
1429 x.set_size(f_n_rows,f_n_cols);
1430 f.read( reinterpret_cast<char *>(x.memptr()), std::streamsize(x.n_elem*sizeof(eT)) );
1431
1432 load_okay = f.good();
1433 }
1434 else
1435 {
1436 load_okay = false;
1437 err_msg = "incorrect header in ";
1438 }
1439
1440 return load_okay;
1441 }
1442
1443
1444
1445 inline
1446 void
1447 diskio::pnm_skip_comments(std::istream& f)
1448 {
1449 while( isspace(f.peek()) )
1450 {
1451 while( isspace(f.peek()) )
1452 {
1453 f.get();
1454 }
1455
1456 if(f.peek() == '#')
1457 {
1458 while( (f.peek() != '\r') && (f.peek()!='\n') )
1459 {
1460 f.get();
1461 }
1462 }
1463 }
1464 }
1465
1466
1467
1468 //! Load a PGM greyscale image as a matrix
1469 template<typename eT>
1470 inline
1471 bool
1472 diskio::load_pgm_binary(Mat<eT>& x, const std::string& name, std::string& err_msg)
1473 {
1474 arma_extra_debug_sigprint();
1475
1476 std::fstream f;
1477 f.open(name.c_str(), std::fstream::in | std::fstream::binary);
1478
1479 bool load_okay = f.is_open();
1480
1481 if(load_okay == true)
1482 {
1483 load_okay = diskio::load_pgm_binary(x, f, err_msg);
1484 f.close();
1485 }
1486
1487 return load_okay;
1488 }
1489
1490
1491
1492 //! Load a PGM greyscale image as a matrix
1493 template<typename eT>
1494 inline
1495 bool
1496 diskio::load_pgm_binary(Mat<eT>& x, std::istream& f, std::string& err_msg)
1497 {
1498 bool load_okay = true;
1499
1500 std::string f_header;
1501 f >> f_header;
1502
1503 if(f_header == "P5")
1504 {
1505 uword f_n_rows = 0;
1506 uword f_n_cols = 0;
1507 int f_maxval = 0;
1508
1509 diskio::pnm_skip_comments(f);
1510
1511 f >> f_n_cols;
1512 diskio::pnm_skip_comments(f);
1513
1514 f >> f_n_rows;
1515 diskio::pnm_skip_comments(f);
1516
1517 f >> f_maxval;
1518 f.get();
1519
1520 if( (f_maxval > 0) || (f_maxval <= 65535) )
1521 {
1522 x.set_size(f_n_rows,f_n_cols);
1523
1524 if(f_maxval <= 255)
1525 {
1526 const uword n_elem = f_n_cols*f_n_rows;
1527 podarray<u8> tmp(n_elem);
1528
1529 f.read( reinterpret_cast<char*>(tmp.memptr()), std::streamsize(n_elem) );
1530
1531 uword i = 0;
1532
1533 //cout << "f_n_cols = " << f_n_cols << endl;
1534 //cout << "f_n_rows = " << f_n_rows << endl;
1535
1536
1537 for(uword row=0; row < f_n_rows; ++row)
1538 {
1539 for(uword col=0; col < f_n_cols; ++col)
1540 {
1541 x.at(row,col) = eT(tmp[i]);
1542 ++i;
1543 }
1544 }
1545
1546 }
1547 else
1548 {
1549 const uword n_elem = f_n_cols*f_n_rows;
1550 podarray<u16> tmp(n_elem);
1551
1552 f.read( reinterpret_cast<char *>(tmp.memptr()), std::streamsize(n_elem*2) );
1553
1554 uword i = 0;
1555
1556 for(uword row=0; row < f_n_rows; ++row)
1557 {
1558 for(uword col=0; col < f_n_cols; ++col)
1559 {
1560 x.at(row,col) = eT(tmp[i]);
1561 ++i;
1562 }
1563 }
1564
1565 }
1566
1567 }
1568 else
1569 {
1570 load_okay = false;
1571 err_msg = "currently no code available to handle loading ";
1572 }
1573
1574 if(f.good() == false)
1575 {
1576 load_okay = false;
1577 }
1578 }
1579 else
1580 {
1581 load_okay = false;
1582 err_msg = "unsupported header in ";
1583 }
1584
1585 return load_okay;
1586 }
1587
1588
1589
1590 //! Load a PGM greyscale image as a matrix
1591 template<typename T>
1592 inline
1593 bool
1594 diskio::load_pgm_binary(Mat< std::complex<T> >& x, const std::string& name, std::string& err_msg)
1595 {
1596 arma_extra_debug_sigprint();
1597
1598 uchar_mat tmp;
1599 const bool load_okay = diskio::load_pgm_binary(tmp, name, err_msg);
1600
1601 x = conv_to< Mat< std::complex<T> > >::from(tmp);
1602
1603 return load_okay;
1604 }
1605
1606
1607
1608 //! Load a PGM greyscale image as a matrix
1609 template<typename T>
1610 inline
1611 bool
1612 diskio::load_pgm_binary(Mat< std::complex<T> >& x, std::istream& is, std::string& err_msg)
1613 {
1614 arma_extra_debug_sigprint();
1615
1616 uchar_mat tmp;
1617 const bool load_okay = diskio::load_pgm_binary(tmp, is, err_msg);
1618
1619 x = conv_to< Mat< std::complex<T> > >::from(tmp);
1620
1621 return load_okay;
1622 }
1623
1624
1625
1626 //! Try to load a matrix by automatically determining its type
1627 template<typename eT>
1628 inline
1629 bool
1630 diskio::load_auto_detect(Mat<eT>& x, const std::string& name, std::string& err_msg)
1631 {
1632 arma_extra_debug_sigprint();
1633
1634 std::fstream f;
1635 f.open(name.c_str(), std::fstream::in | std::fstream::binary);
1636
1637 bool load_okay = f.is_open();
1638
1639 if(load_okay == true)
1640 {
1641 load_okay = diskio::load_auto_detect(x, f, err_msg);
1642 f.close();
1643 }
1644
1645 return load_okay;
1646 }
1647
1648
1649
1650 //! Try to load a matrix by automatically determining its type
1651 template<typename eT>
1652 inline
1653 bool
1654 diskio::load_auto_detect(Mat<eT>& x, std::istream& f, std::string& err_msg)
1655 {
1656 arma_extra_debug_sigprint();
1657
1658 static const std::string ARMA_MAT_TXT = "ARMA_MAT_TXT";
1659 static const std::string ARMA_MAT_BIN = "ARMA_MAT_BIN";
1660 static const std::string P5 = "P5";
1661
1662 podarray<char> raw_header(ARMA_MAT_TXT.length() + 1);
1663
1664 std::streampos pos = f.tellg();
1665
1666 f.read( raw_header.memptr(), std::streamsize(ARMA_MAT_TXT.length()) );
1667 raw_header[ARMA_MAT_TXT.length()] = '\0';
1668
1669 f.clear();
1670 f.seekg(pos);
1671
1672 const std::string header = raw_header.mem;
1673
1674 if(ARMA_MAT_TXT == header.substr(0,ARMA_MAT_TXT.length()))
1675 {
1676 return load_arma_ascii(x, f, err_msg);
1677 }
1678 else
1679 if(ARMA_MAT_BIN == header.substr(0,ARMA_MAT_BIN.length()))
1680 {
1681 return load_arma_binary(x, f, err_msg);
1682 }
1683 else
1684 if(P5 == header.substr(0,P5.length()))
1685 {
1686 return load_pgm_binary(x, f, err_msg);
1687 }
1688 else
1689 {
1690 const file_type ft = guess_file_type(f);
1691
1692 switch(ft)
1693 {
1694 case csv_ascii:
1695 return load_csv_ascii(x, f, err_msg);
1696 break;
1697
1698 case raw_binary:
1699 return load_raw_binary(x, f, err_msg);
1700 break;
1701
1702 case raw_ascii:
1703 return load_raw_ascii(x, f, err_msg);
1704 break;
1705
1706 default:
1707 err_msg = "unknown data in ";
1708 return false;
1709 }
1710 }
1711
1712 return false;
1713 }
1714
1715
1716
1717 // cubes
1718
1719
1720
1721 //! Save a cube as raw text (no header, human readable).
1722 template<typename eT>
1723 inline
1724 bool
1725 diskio::save_raw_ascii(const Cube<eT>& x, const std::string& final_name)
1726 {
1727 arma_extra_debug_sigprint();
1728
1729 const std::string tmp_name = diskio::gen_tmp_name(final_name);
1730
1731 std::fstream f(tmp_name.c_str(), std::fstream::out);
1732
1733 bool save_okay = f.is_open();
1734
1735 if(save_okay == true)
1736 {
1737 save_okay = save_raw_ascii(x, f);
1738
1739 f.flush();
1740 f.close();
1741
1742 if(save_okay == true)
1743 {
1744 save_okay = diskio::safe_rename(tmp_name, final_name);
1745 }
1746 }
1747
1748 return save_okay;
1749 }
1750
1751
1752
1753 //! Save a cube as raw text (no header, human readable).
1754 template<typename eT>
1755 inline
1756 bool
1757 diskio::save_raw_ascii(const Cube<eT>& x, std::ostream& f)
1758 {
1759 arma_extra_debug_sigprint();
1760
1761 uword cell_width;
1762
1763 // TODO: need sane values for complex numbers
1764
1765 if( (is_float<eT>::value == true) || (is_double<eT>::value == true) )
1766 {
1767 f.setf(ios::scientific);
1768 f.precision(10);
1769 cell_width = 18;
1770 }
1771
1772 for(uword slice=0; slice < x.n_slices; ++slice)
1773 {
1774 for(uword row=0; row < x.n_rows; ++row)
1775 {
1776 for(uword col=0; col < x.n_cols; ++col)
1777 {
1778 f.put(' ');
1779
1780 if( (is_float<eT>::value == true) || (is_double<eT>::value == true) )
1781 {
1782 f.width(cell_width);
1783 }
1784
1785 f << x.at(row,col,slice);
1786 }
1787
1788 f.put('\n');
1789 }
1790 }
1791
1792 return f.good();
1793 }
1794
1795
1796
1797 //! Save a cube as raw binary (no header)
1798 template<typename eT>
1799 inline
1800 bool
1801 diskio::save_raw_binary(const Cube<eT>& x, const std::string& final_name)
1802 {
1803 arma_extra_debug_sigprint();
1804
1805 const std::string tmp_name = diskio::gen_tmp_name(final_name);
1806
1807 std::ofstream f(tmp_name.c_str(), std::fstream::binary);
1808
1809 bool save_okay = f.is_open();
1810
1811 if(save_okay == true)
1812 {
1813 save_okay = diskio::save_raw_binary(x, f);
1814
1815 f.flush();
1816 f.close();
1817
1818 if(save_okay == true)
1819 {
1820 save_okay = diskio::safe_rename(tmp_name, final_name);
1821 }
1822 }
1823
1824 return save_okay;
1825 }
1826
1827
1828
1829 template<typename eT>
1830 inline
1831 bool
1832 diskio::save_raw_binary(const Cube<eT>& x, std::ostream& f)
1833 {
1834 arma_extra_debug_sigprint();
1835
1836 f.write( reinterpret_cast<const char*>(x.mem), std::streamsize(x.n_elem*sizeof(eT)) );
1837
1838 return f.good();
1839 }
1840
1841
1842
1843 //! Save a cube in text format (human readable),
1844 //! with a header that indicates the cube type as well as its dimensions
1845 template<typename eT>
1846 inline
1847 bool
1848 diskio::save_arma_ascii(const Cube<eT>& x, const std::string& final_name)
1849 {
1850 arma_extra_debug_sigprint();
1851
1852 const std::string tmp_name = diskio::gen_tmp_name(final_name);
1853
1854 std::ofstream f(tmp_name.c_str());
1855
1856 bool save_okay = f.is_open();
1857
1858 if(save_okay == true)
1859 {
1860 save_okay = diskio::save_arma_ascii(x, f);
1861
1862 f.flush();
1863 f.close();
1864
1865 if(save_okay == true)
1866 {
1867 save_okay = diskio::safe_rename(tmp_name, final_name);
1868 }
1869 }
1870
1871 return save_okay;
1872 }
1873
1874
1875
1876 //! Save a cube in text format (human readable),
1877 //! with a header that indicates the cube type as well as its dimensions
1878 template<typename eT>
1879 inline
1880 bool
1881 diskio::save_arma_ascii(const Cube<eT>& x, std::ostream& f)
1882 {
1883 arma_extra_debug_sigprint();
1884
1885 const ios::fmtflags orig_flags = f.flags();
1886
1887 f << diskio::gen_txt_header(x) << '\n';
1888 f << x.n_rows << ' ' << x.n_cols << ' ' << x.n_slices << '\n';
1889
1890 uword cell_width;
1891
1892 // TODO: need sane values for complex numbers
1893
1894 if( (is_float<eT>::value == true) || (is_double<eT>::value == true) )
1895 {
1896 f.setf(ios::scientific);
1897 f.precision(10);
1898 cell_width = 18;
1899 }
1900
1901 for(uword slice=0; slice < x.n_slices; ++slice)
1902 {
1903 for(uword row=0; row < x.n_rows; ++row)
1904 {
1905 for(uword col=0; col < x.n_cols; ++col)
1906 {
1907 f.put(' ');
1908
1909 if( (is_float<eT>::value == true) || (is_double<eT>::value == true) )
1910 {
1911 f.width(cell_width);
1912 }
1913
1914 f << x.at(row,col,slice);
1915 }
1916
1917 f.put('\n');
1918 }
1919 }
1920
1921 const bool save_okay = f.good();
1922
1923 f.flags(orig_flags);
1924
1925 return save_okay;
1926 }
1927
1928
1929
1930 //! Save a cube in binary format,
1931 //! with a header that stores the cube type as well as its dimensions
1932 template<typename eT>
1933 inline
1934 bool
1935 diskio::save_arma_binary(const Cube<eT>& x, const std::string& final_name)
1936 {
1937 arma_extra_debug_sigprint();
1938
1939 const std::string tmp_name = diskio::gen_tmp_name(final_name);
1940
1941 std::ofstream f(tmp_name.c_str(), std::fstream::binary);
1942
1943 bool save_okay = f.is_open();
1944
1945 if(save_okay == true)
1946 {
1947 save_okay = diskio::save_arma_binary(x, f);
1948
1949 f.flush();
1950 f.close();
1951
1952 if(save_okay == true)
1953 {
1954 save_okay = diskio::safe_rename(tmp_name, final_name);
1955 }
1956 }
1957
1958 return save_okay;
1959 }
1960
1961
1962
1963 //! Save a cube in binary format,
1964 //! with a header that stores the cube type as well as its dimensions
1965 template<typename eT>
1966 inline
1967 bool
1968 diskio::save_arma_binary(const Cube<eT>& x, std::ostream& f)
1969 {
1970 arma_extra_debug_sigprint();
1971
1972 f << diskio::gen_bin_header(x) << '\n';
1973 f << x.n_rows << ' ' << x.n_cols << ' ' << x.n_slices << '\n';
1974
1975 f.write( reinterpret_cast<const char*>(x.mem), std::streamsize(x.n_elem*sizeof(eT)) );
1976
1977 return f.good();
1978 }
1979
1980
1981
1982 //! Load a cube as raw text (no header, human readable).
1983 //! NOTE: this is much slower than reading a file with a header.
1984 template<typename eT>
1985 inline
1986 bool
1987 diskio::load_raw_ascii(Cube<eT>& x, const std::string& name, std::string& err_msg)
1988 {
1989 arma_extra_debug_sigprint();
1990
1991 Mat<eT> tmp;
1992 const bool load_okay = diskio::load_raw_ascii(tmp, name, err_msg);
1993
1994 if(load_okay == true)
1995 {
1996 if(tmp.is_empty() == false)
1997 {
1998 x.set_size(tmp.n_rows, tmp.n_cols, 1);
1999
2000 x.slice(0) = tmp;
2001 }
2002 else
2003 {
2004 x.reset();
2005 }
2006 }
2007
2008 return load_okay;
2009 }
2010
2011
2012
2013 //! Load a cube as raw text (no header, human readable).
2014 //! NOTE: this is much slower than reading a file with a header.
2015 template<typename eT>
2016 inline
2017 bool
2018 diskio::load_raw_ascii(Cube<eT>& x, std::istream& f, std::string& err_msg)
2019 {
2020 arma_extra_debug_sigprint();
2021
2022 Mat<eT> tmp;
2023 const bool load_okay = diskio::load_raw_ascii(tmp, f, err_msg);
2024
2025 if(load_okay == true)
2026 {
2027 if(tmp.is_empty() == false)
2028 {
2029 x.set_size(tmp.n_rows, tmp.n_cols, 1);
2030
2031 x.slice(0) = tmp;
2032 }
2033 else
2034 {
2035 x.reset();
2036 }
2037 }
2038
2039 return load_okay;
2040 }
2041
2042
2043
2044 //! Load a cube in binary format (no header);
2045 //! the cube is assumed to have one slice with one column
2046 template<typename eT>
2047 inline
2048 bool
2049 diskio::load_raw_binary(Cube<eT>& x, const std::string& name, std::string& err_msg)
2050 {
2051 arma_extra_debug_sigprint();
2052
2053 std::ifstream f;
2054 f.open(name.c_str(), std::fstream::binary);
2055
2056 bool load_okay = f.is_open();
2057
2058 if(load_okay == true)
2059 {
2060 load_okay = diskio::load_raw_binary(x, f, err_msg);
2061 f.close();
2062 }
2063
2064 return load_okay;
2065 }
2066
2067
2068
2069 template<typename eT>
2070 inline
2071 bool
2072 diskio::load_raw_binary(Cube<eT>& x, std::istream& f, std::string& err_msg)
2073 {
2074 arma_extra_debug_sigprint();
2075 arma_ignore(err_msg);
2076
2077 f.clear();
2078 const std::streampos pos1 = f.tellg();
2079
2080 f.clear();
2081 f.seekg(0, ios::end);
2082
2083 f.clear();
2084 const std::streampos pos2 = f.tellg();
2085
2086 const uword N = ( (pos1 >= 0) && (pos2 >= 0) ) ? uword(pos2 - pos1) : 0;
2087
2088 f.clear();
2089 //f.seekg(0, ios::beg);
2090 f.seekg(pos1);
2091
2092 x.set_size(N / sizeof(eT), 1, 1);
2093
2094 f.clear();
2095 f.read( reinterpret_cast<char *>(x.memptr()), std::streamsize(N) );
2096
2097 return f.good();
2098 }
2099
2100
2101
2102 //! Load a cube in text format (human readable),
2103 //! with a header that indicates the cube type as well as its dimensions
2104 template<typename eT>
2105 inline
2106 bool
2107 diskio::load_arma_ascii(Cube<eT>& x, const std::string& name, std::string& err_msg)
2108 {
2109 arma_extra_debug_sigprint();
2110
2111 std::ifstream f(name.c_str());
2112
2113 bool load_okay = f.is_open();
2114
2115 if(load_okay == true)
2116 {
2117 load_okay = diskio::load_arma_ascii(x, f, err_msg);
2118 f.close();
2119 }
2120
2121 return load_okay;
2122 }
2123
2124
2125
2126 //! Load a cube in text format (human readable),
2127 //! with a header that indicates the cube type as well as its dimensions
2128 template<typename eT>
2129 inline
2130 bool
2131 diskio::load_arma_ascii(Cube<eT>& x, std::istream& f, std::string& err_msg)
2132 {
2133 arma_extra_debug_sigprint();
2134
2135 bool load_okay = true;
2136
2137 std::string f_header;
2138 uword f_n_rows;
2139 uword f_n_cols;
2140 uword f_n_slices;
2141
2142 f >> f_header;
2143 f >> f_n_rows;
2144 f >> f_n_cols;
2145 f >> f_n_slices;
2146
2147 if(f_header == diskio::gen_txt_header(x))
2148 {
2149 x.set_size(f_n_rows, f_n_cols, f_n_slices);
2150
2151 for(uword slice=0; slice < x.n_slices; ++slice)
2152 {
2153 for(uword row=0; row < x.n_rows; ++row)
2154 {
2155 for(uword col=0; col < x.n_cols; ++col)
2156 {
2157 f >> x.at(row,col,slice);
2158 }
2159 }
2160 }
2161
2162 load_okay = f.good();
2163 }
2164 else
2165 {
2166 load_okay = false;
2167 err_msg = "incorrect header in ";
2168 }
2169
2170 return load_okay;
2171 }
2172
2173
2174
2175 //! Load a cube in binary format,
2176 //! with a header that indicates the cube type as well as its dimensions
2177 template<typename eT>
2178 inline
2179 bool
2180 diskio::load_arma_binary(Cube<eT>& x, const std::string& name, std::string& err_msg)
2181 {
2182 arma_extra_debug_sigprint();
2183
2184 std::ifstream f;
2185 f.open(name.c_str(), std::fstream::binary);
2186
2187 bool load_okay = f.is_open();
2188
2189 if(load_okay == true)
2190 {
2191 load_okay = diskio::load_arma_binary(x, f, err_msg);
2192 f.close();
2193 }
2194
2195 return load_okay;
2196 }
2197
2198
2199
2200 template<typename eT>
2201 inline
2202 bool
2203 diskio::load_arma_binary(Cube<eT>& x, std::istream& f, std::string& err_msg)
2204 {
2205 arma_extra_debug_sigprint();
2206
2207 bool load_okay = true;
2208
2209 std::string f_header;
2210 uword f_n_rows;
2211 uword f_n_cols;
2212 uword f_n_slices;
2213
2214 f >> f_header;
2215 f >> f_n_rows;
2216 f >> f_n_cols;
2217 f >> f_n_slices;
2218
2219 if(f_header == diskio::gen_bin_header(x))
2220 {
2221 //f.seekg(1, ios::cur); // NOTE: this may not be portable, as on a Windows machine a newline could be two characters
2222 f.get();
2223
2224 x.set_size(f_n_rows, f_n_cols, f_n_slices);
2225 f.read( reinterpret_cast<char *>(x.memptr()), std::streamsize(x.n_elem*sizeof(eT)) );
2226
2227 load_okay = f.good();
2228 }
2229 else
2230 {
2231 load_okay = false;
2232 err_msg = "incorrect header in ";
2233 }
2234
2235 return load_okay;
2236 }
2237
2238
2239
2240 //! Try to load a cube by automatically determining its type
2241 template<typename eT>
2242 inline
2243 bool
2244 diskio::load_auto_detect(Cube<eT>& x, const std::string& name, std::string& err_msg)
2245 {
2246 arma_extra_debug_sigprint();
2247
2248 std::fstream f;
2249 f.open(name.c_str(), std::fstream::in | std::fstream::binary);
2250
2251 bool load_okay = f.is_open();
2252
2253 if(load_okay == true)
2254 {
2255 load_okay = diskio::load_auto_detect(x, f, err_msg);
2256 f.close();
2257 }
2258
2259 return load_okay;
2260 }
2261
2262
2263
2264 //! Try to load a cube by automatically determining its type
2265 template<typename eT>
2266 inline
2267 bool
2268 diskio::load_auto_detect(Cube<eT>& x, std::istream& f, std::string& err_msg)
2269 {
2270 arma_extra_debug_sigprint();
2271
2272 static const std::string ARMA_CUB_TXT = "ARMA_CUB_TXT";
2273 static const std::string ARMA_CUB_BIN = "ARMA_CUB_BIN";
2274 static const std::string P6 = "P6";
2275
2276 podarray<char> raw_header(ARMA_CUB_TXT.length() + 1);
2277
2278 std::streampos pos = f.tellg();
2279
2280 f.read( raw_header.memptr(), std::streamsize(ARMA_CUB_TXT.length()) );
2281 raw_header[ARMA_CUB_TXT.length()] = '\0';
2282
2283 f.clear();
2284 f.seekg(pos);
2285
2286 const std::string header = raw_header.mem;
2287
2288 if(ARMA_CUB_TXT == header.substr(0, ARMA_CUB_TXT.length()))
2289 {
2290 return load_arma_ascii(x, f, err_msg);
2291 }
2292 else
2293 if(ARMA_CUB_BIN == header.substr(0, ARMA_CUB_BIN.length()))
2294 {
2295 return load_arma_binary(x, f, err_msg);
2296 }
2297 else
2298 if(P6 == header.substr(0, P6.length()))
2299 {
2300 return load_ppm_binary(x, f, err_msg);
2301 }
2302 else
2303 {
2304 const file_type ft = guess_file_type(f);
2305
2306 switch(ft)
2307 {
2308 // case csv_ascii:
2309 // return load_csv_ascii(x, f, err_msg);
2310 // break;
2311
2312 case raw_binary:
2313 return load_raw_binary(x, f, err_msg);
2314 break;
2315
2316 case raw_ascii:
2317 return load_raw_ascii(x, f, err_msg);
2318 break;
2319
2320 default:
2321 err_msg = "unknown data in ";
2322 return false;
2323 }
2324 }
2325
2326 return false;
2327 }
2328
2329
2330
2331
2332
2333 // fields
2334
2335
2336
2337 template<typename T1>
2338 inline
2339 bool
2340 diskio::save_arma_binary(const field<T1>& x, const std::string& final_name)
2341 {
2342 arma_extra_debug_sigprint();
2343
2344 const std::string tmp_name = diskio::gen_tmp_name(final_name);
2345
2346 std::ofstream f( tmp_name.c_str(), std::fstream::binary );
2347
2348 bool save_okay = f.is_open();
2349
2350 if(save_okay == true)
2351 {
2352 save_okay = diskio::save_arma_binary(x, f);
2353
2354 f.flush();
2355 f.close();
2356
2357 if(save_okay == true)
2358 {
2359 save_okay = diskio::safe_rename(tmp_name, final_name);
2360 }
2361 }
2362
2363 return save_okay;
2364 }
2365
2366
2367
2368 template<typename T1>
2369 inline
2370 bool
2371 diskio::save_arma_binary(const field<T1>& x, std::ostream& f)
2372 {
2373 arma_extra_debug_sigprint();
2374
2375 arma_type_check(( (is_Mat<T1>::value == false) && (is_Cube<T1>::value == false) ));
2376
2377 f << "ARMA_FLD_BIN" << '\n';
2378 f << x.n_rows << '\n';
2379 f << x.n_cols << '\n';
2380
2381 bool save_okay = true;
2382
2383 for(uword i=0; i<x.n_elem; ++i)
2384 {
2385 save_okay = diskio::save_arma_binary(x[i], f);
2386
2387 if(save_okay == false)
2388 {
2389 break;
2390 }
2391 }
2392
2393 return save_okay;
2394 }
2395
2396
2397
2398 template<typename T1>
2399 inline
2400 bool
2401 diskio::load_arma_binary(field<T1>& x, const std::string& name, std::string& err_msg)
2402 {
2403 arma_extra_debug_sigprint();
2404
2405 std::ifstream f( name.c_str(), std::fstream::binary );
2406
2407 bool load_okay = f.is_open();
2408
2409 if(load_okay == true)
2410 {
2411 load_okay = diskio::load_arma_binary(x, f, err_msg);
2412 f.close();
2413 }
2414
2415 return load_okay;
2416 }
2417
2418
2419
2420 template<typename T1>
2421 inline
2422 bool
2423 diskio::load_arma_binary(field<T1>& x, std::istream& f, std::string& err_msg)
2424 {
2425 arma_extra_debug_sigprint();
2426
2427 arma_type_check(( (is_Mat<T1>::value == false) && (is_Cube<T1>::value == false) ));
2428
2429 bool load_okay = true;
2430
2431 std::string f_type;
2432 f >> f_type;
2433
2434 if(f_type != "ARMA_FLD_BIN")
2435 {
2436 load_okay = false;
2437 err_msg = "unsupported field type in ";
2438 }
2439 else
2440 {
2441 uword f_n_rows;
2442 uword f_n_cols;
2443
2444 f >> f_n_rows;
2445 f >> f_n_cols;
2446
2447 x.set_size(f_n_rows, f_n_cols);
2448
2449 f.get();
2450
2451 for(uword i=0; i<x.n_elem; ++i)
2452 {
2453 load_okay = diskio::load_arma_binary(x[i], f, err_msg);
2454
2455 if(load_okay == false)
2456 {
2457 break;
2458 }
2459 }
2460 }
2461
2462 return load_okay;
2463 }
2464
2465
2466
2467 inline
2468 bool
2469 diskio::save_std_string(const field<std::string>& x, const std::string& final_name)
2470 {
2471 arma_extra_debug_sigprint();
2472
2473 const std::string tmp_name = diskio::gen_tmp_name(final_name);
2474
2475 std::ofstream f( tmp_name.c_str(), std::fstream::binary );
2476
2477 bool save_okay = f.is_open();
2478
2479 if(save_okay == true)
2480 {
2481 save_okay = diskio::save_std_string(x, f);
2482
2483 f.flush();
2484 f.close();
2485
2486 if(save_okay == true)
2487 {
2488 save_okay = diskio::safe_rename(tmp_name, final_name);
2489 }
2490 }
2491
2492 return save_okay;
2493 }
2494
2495
2496
2497 inline
2498 bool
2499 diskio::save_std_string(const field<std::string>& x, std::ostream& f)
2500 {
2501 arma_extra_debug_sigprint();
2502
2503 for(uword row=0; row<x.n_rows; ++row)
2504 for(uword col=0; col<x.n_cols; ++col)
2505 {
2506 f << x.at(row,col);
2507
2508 if(col < x.n_cols-1)
2509 {
2510 f << ' ';
2511 }
2512 else
2513 {
2514 f << '\n';
2515 }
2516 }
2517
2518 return f.good();
2519 }
2520
2521
2522
2523 inline
2524 bool
2525 diskio::load_std_string(field<std::string>& x, const std::string& name, std::string& err_msg)
2526 {
2527 arma_extra_debug_sigprint();
2528
2529 std::ifstream f( name.c_str() );
2530
2531 bool load_okay = f.is_open();
2532
2533 if(load_okay == true)
2534 {
2535 load_okay = diskio::load_std_string(x, f, err_msg);
2536 f.close();
2537 }
2538
2539 return load_okay;
2540 }
2541
2542
2543
2544 inline
2545 bool
2546 diskio::load_std_string(field<std::string>& x, std::istream& f, std::string& err_msg)
2547 {
2548 arma_extra_debug_sigprint();
2549
2550 bool load_okay = true;
2551
2552 //
2553 // work out the size
2554
2555 uword f_n_rows = 0;
2556 uword f_n_cols = 0;
2557
2558 bool f_n_cols_found = false;
2559
2560 std::string line_string;
2561 std::string token;
2562
2563 while( (f.good() == true) && (load_okay == true) )
2564 {
2565 std::getline(f, line_string);
2566 if(line_string.size() == 0)
2567 break;
2568
2569 std::stringstream line_stream(line_string);
2570
2571 uword line_n_cols = 0;
2572 while (line_stream >> token)
2573 line_n_cols++;
2574
2575 if(f_n_cols_found == false)
2576 {
2577 f_n_cols = line_n_cols;
2578 f_n_cols_found = true;
2579 }
2580 else
2581 {
2582 if(line_n_cols != f_n_cols)
2583 {
2584 load_okay = false;
2585 err_msg = "inconsistent number of columns in ";
2586 }
2587 }
2588
2589 ++f_n_rows;
2590 }
2591
2592 if(load_okay == true)
2593 {
2594 f.clear();
2595 f.seekg(0, ios::beg);
2596 //f.seekg(start);
2597
2598 x.set_size(f_n_rows, f_n_cols);
2599
2600 for(uword row=0; row < x.n_rows; ++row)
2601 {
2602 for(uword col=0; col < x.n_cols; ++col)
2603 {
2604 f >> x.at(row,col);
2605 }
2606 }
2607 }
2608
2609 if(f.good() == false)
2610 {
2611 load_okay = false;
2612 }
2613
2614 return load_okay;
2615 }
2616
2617
2618
2619 //! Try to load a field by automatically determining its type
2620 template<typename T1>
2621 inline
2622 bool
2623 diskio::load_auto_detect(field<T1>& x, const std::string& name, std::string& err_msg)
2624 {
2625 arma_extra_debug_sigprint();
2626
2627 std::fstream f;
2628 f.open(name.c_str(), std::fstream::in | std::fstream::binary);
2629
2630 bool load_okay = f.is_open();
2631
2632 if(load_okay == true)
2633 {
2634 load_okay = diskio::load_auto_detect(x, f, err_msg);
2635 f.close();
2636 }
2637
2638 return load_okay;
2639 }
2640
2641
2642
2643 //! Try to load a field by automatically determining its type
2644 template<typename T1>
2645 inline
2646 bool
2647 diskio::load_auto_detect(field<T1>& x, std::istream& f, std::string& err_msg)
2648 {
2649 arma_extra_debug_sigprint();
2650
2651 arma_type_check(( is_Mat<T1>::value == false ));
2652
2653 static const std::string ARMA_FLD_BIN = "ARMA_FLD_BIN";
2654 static const std::string P6 = "P6";
2655
2656 podarray<char> raw_header(ARMA_FLD_BIN.length() + 1);
2657
2658 std::streampos pos = f.tellg();
2659
2660 f.read( raw_header.memptr(), std::streamsize(ARMA_FLD_BIN.length()) );
2661
2662 f.clear();
2663 f.seekg(pos);
2664
2665 raw_header[ARMA_FLD_BIN.length()] = '\0';
2666
2667 const std::string header = raw_header.mem;
2668
2669 if(ARMA_FLD_BIN == header.substr(0, ARMA_FLD_BIN.length()))
2670 {
2671 return load_arma_binary(x, f, err_msg);
2672 }
2673 else
2674 if(P6 == header.substr(0, P6.length()))
2675 {
2676 return load_ppm_binary(x, f, err_msg);
2677 }
2678 else
2679 {
2680 err_msg = "unsupported header in ";
2681 return false;
2682 }
2683 }
2684
2685
2686
2687 //
2688 // handling of PPM images by cubes
2689
2690
2691 template<typename eT>
2692 inline
2693 bool
2694 diskio::load_ppm_binary(Cube<eT>& x, const std::string& name, std::string& err_msg)
2695 {
2696 arma_extra_debug_sigprint();
2697
2698 std::fstream f;
2699 f.open(name.c_str(), std::fstream::in | std::fstream::binary);
2700
2701 bool load_okay = f.is_open();
2702
2703 if(load_okay == true)
2704 {
2705 load_okay = diskio::load_ppm_binary(x, f, err_msg);
2706 f.close();
2707 }
2708
2709 return load_okay;
2710 }
2711
2712
2713
2714 template<typename eT>
2715 inline
2716 bool
2717 diskio::load_ppm_binary(Cube<eT>& x, std::istream& f, std::string& err_msg)
2718 {
2719 arma_extra_debug_sigprint();
2720
2721 bool load_okay = true;
2722
2723 std::string f_header;
2724 f >> f_header;
2725
2726 if(f_header == "P6")
2727 {
2728 uword f_n_rows = 0;
2729 uword f_n_cols = 0;
2730 int f_maxval = 0;
2731
2732 diskio::pnm_skip_comments(f);
2733
2734 f >> f_n_cols;
2735 diskio::pnm_skip_comments(f);
2736
2737 f >> f_n_rows;
2738 diskio::pnm_skip_comments(f);
2739
2740 f >> f_maxval;
2741 f.get();
2742
2743 if( (f_maxval > 0) || (f_maxval <= 65535) )
2744 {
2745 x.set_size(f_n_rows, f_n_cols, 3);
2746
2747 if(f_maxval <= 255)
2748 {
2749 const uword n_elem = 3*f_n_cols*f_n_rows;
2750 podarray<u8> tmp(n_elem);
2751
2752 f.read( reinterpret_cast<char*>(tmp.memptr()), std::streamsize(n_elem) );
2753
2754 uword i = 0;
2755
2756 //cout << "f_n_cols = " << f_n_cols << endl;
2757 //cout << "f_n_rows = " << f_n_rows << endl;
2758
2759
2760 for(uword row=0; row < f_n_rows; ++row)
2761 {
2762 for(uword col=0; col < f_n_cols; ++col)
2763 {
2764 x.at(row,col,0) = eT(tmp[i+0]);
2765 x.at(row,col,1) = eT(tmp[i+1]);
2766 x.at(row,col,2) = eT(tmp[i+2]);
2767 i+=3;
2768 }
2769
2770 }
2771 }
2772 else
2773 {
2774 const uword n_elem = 3*f_n_cols*f_n_rows;
2775 podarray<u16> tmp(n_elem);
2776
2777 f.read( reinterpret_cast<char *>(tmp.memptr()), std::streamsize(2*n_elem) );
2778
2779 uword i = 0;
2780
2781 for(uword row=0; row < f_n_rows; ++row)
2782 {
2783 for(uword col=0; col < f_n_cols; ++col)
2784 {
2785 x.at(row,col,0) = eT(tmp[i+0]);
2786 x.at(row,col,1) = eT(tmp[i+1]);
2787 x.at(row,col,2) = eT(tmp[i+2]);
2788 i+=3;
2789 }
2790
2791 }
2792
2793 }
2794
2795 }
2796 else
2797 {
2798 load_okay = false;
2799 err_msg = "currently no code available to handle loading ";
2800 }
2801
2802 if(f.good() == false)
2803 {
2804 load_okay = false;
2805 }
2806
2807 }
2808 else
2809 {
2810 load_okay = false;
2811 err_msg = "unsupported header in ";
2812 }
2813
2814 return load_okay;
2815 }
2816
2817
2818
2819 template<typename eT>
2820 inline
2821 bool
2822 diskio::save_ppm_binary(const Cube<eT>& x, const std::string& final_name)
2823 {
2824 arma_extra_debug_sigprint();
2825
2826 const std::string tmp_name = diskio::gen_tmp_name(final_name);
2827
2828 std::ofstream f( tmp_name.c_str(), std::fstream::binary );
2829
2830 bool save_okay = f.is_open();
2831
2832 if(save_okay == true)
2833 {
2834 save_okay = diskio::save_ppm_binary(x, f);
2835
2836 f.flush();
2837 f.close();
2838
2839 if(save_okay == true)
2840 {
2841 save_okay = diskio::safe_rename(tmp_name, final_name);
2842 }
2843 }
2844
2845 return save_okay;
2846 }
2847
2848
2849
2850 template<typename eT>
2851 inline
2852 bool
2853 diskio::save_ppm_binary(const Cube<eT>& x, std::ostream& f)
2854 {
2855 arma_extra_debug_sigprint();
2856
2857 arma_debug_check( (x.n_slices != 3), "diskio::save_ppm_binary(): given cube must have exactly 3 slices" );
2858
2859 const uword n_elem = 3 * x.n_rows * x.n_cols;
2860 podarray<u8> tmp(n_elem);
2861
2862 uword i = 0;
2863 for(uword row=0; row < x.n_rows; ++row)
2864 {
2865 for(uword col=0; col < x.n_cols; ++col)
2866 {
2867 tmp[i+0] = u8( access::tmp_real( x.at(row,col,0) ) );
2868 tmp[i+1] = u8( access::tmp_real( x.at(row,col,1) ) );
2869 tmp[i+2] = u8( access::tmp_real( x.at(row,col,2) ) );
2870
2871 i+=3;
2872 }
2873 }
2874
2875 f << "P6" << '\n';
2876 f << x.n_cols << '\n';
2877 f << x.n_rows << '\n';
2878 f << 255 << '\n';
2879
2880 f.write( reinterpret_cast<const char*>(tmp.mem), std::streamsize(n_elem) );
2881
2882 return f.good();
2883 }
2884
2885
2886
2887 //
2888 // handling of PPM images by fields
2889
2890
2891
2892 template<typename T1>
2893 inline
2894 bool
2895 diskio::load_ppm_binary(field<T1>& x, const std::string& name, std::string& err_msg)
2896 {
2897 arma_extra_debug_sigprint();
2898
2899 std::fstream f;
2900 f.open(name.c_str(), std::fstream::in | std::fstream::binary);
2901
2902 bool load_okay = f.is_open();
2903
2904 if(load_okay == true)
2905 {
2906 load_okay = diskio::load_ppm_binary(x, f, err_msg);
2907 f.close();
2908 }
2909
2910 return load_okay;
2911 }
2912
2913
2914
2915 template<typename T1>
2916 inline
2917 bool
2918 diskio::load_ppm_binary(field<T1>& x, std::istream& f, std::string& err_msg)
2919 {
2920 arma_extra_debug_sigprint();
2921
2922 arma_type_check(( is_Mat<T1>::value == false ));
2923 typedef typename T1::elem_type eT;
2924
2925 bool load_okay = true;
2926
2927 std::string f_header;
2928 f >> f_header;
2929
2930 if(f_header == "P6")
2931 {
2932 uword f_n_rows = 0;
2933 uword f_n_cols = 0;
2934 int f_maxval = 0;
2935
2936 diskio::pnm_skip_comments(f);
2937
2938 f >> f_n_cols;
2939 diskio::pnm_skip_comments(f);
2940
2941 f >> f_n_rows;
2942 diskio::pnm_skip_comments(f);
2943
2944 f >> f_maxval;
2945 f.get();
2946
2947 if( (f_maxval > 0) || (f_maxval <= 65535) )
2948 {
2949 x.set_size(3);
2950 Mat<eT>& R = x(0);
2951 Mat<eT>& G = x(1);
2952 Mat<eT>& B = x(2);
2953
2954 R.set_size(f_n_rows,f_n_cols);
2955 G.set_size(f_n_rows,f_n_cols);
2956 B.set_size(f_n_rows,f_n_cols);
2957
2958 if(f_maxval <= 255)
2959 {
2960 const uword n_elem = 3*f_n_cols*f_n_rows;
2961 podarray<u8> tmp(n_elem);
2962
2963 f.read( reinterpret_cast<char*>(tmp.memptr()), std::streamsize(n_elem) );
2964
2965 uword i = 0;
2966
2967 //cout << "f_n_cols = " << f_n_cols << endl;
2968 //cout << "f_n_rows = " << f_n_rows << endl;
2969
2970
2971 for(uword row=0; row < f_n_rows; ++row)
2972 {
2973 for(uword col=0; col < f_n_cols; ++col)
2974 {
2975 R.at(row,col) = eT(tmp[i+0]);
2976 G.at(row,col) = eT(tmp[i+1]);
2977 B.at(row,col) = eT(tmp[i+2]);
2978 i+=3;
2979 }
2980
2981 }
2982 }
2983 else
2984 {
2985 const uword n_elem = 3*f_n_cols*f_n_rows;
2986 podarray<u16> tmp(n_elem);
2987
2988 f.read( reinterpret_cast<char *>(tmp.memptr()), std::streamsize(2*n_elem) );
2989
2990 uword i = 0;
2991
2992 for(uword row=0; row < f_n_rows; ++row)
2993 {
2994 for(uword col=0; col < f_n_cols; ++col)
2995 {
2996 R.at(row,col) = eT(tmp[i+0]);
2997 G.at(row,col) = eT(tmp[i+1]);
2998 B.at(row,col) = eT(tmp[i+2]);
2999 i+=3;
3000 }
3001
3002 }
3003
3004 }
3005
3006 }
3007 else
3008 {
3009 load_okay = false;
3010 err_msg = "currently no code available to handle loading ";
3011 }
3012
3013 if(f.good() == false)
3014 {
3015 load_okay = false;
3016 }
3017
3018 }
3019 else
3020 {
3021 load_okay = false;
3022 err_msg = "unsupported header in ";
3023 }
3024
3025 return load_okay;
3026 }
3027
3028
3029
3030 template<typename T1>
3031 inline
3032 bool
3033 diskio::save_ppm_binary(const field<T1>& x, const std::string& final_name)
3034 {
3035 arma_extra_debug_sigprint();
3036
3037 const std::string tmp_name = diskio::gen_tmp_name(final_name);
3038 std::ofstream f( tmp_name.c_str(), std::fstream::binary );
3039
3040 bool save_okay = f.is_open();
3041
3042 if(save_okay == true)
3043 {
3044 save_okay = diskio::save_ppm_binary(x, f);
3045
3046 f.flush();
3047 f.close();
3048
3049 if(save_okay == true)
3050 {
3051 save_okay = diskio::safe_rename(tmp_name, final_name);
3052 }
3053 }
3054
3055 return save_okay;
3056 }
3057
3058
3059
3060 template<typename T1>
3061 inline
3062 bool
3063 diskio::save_ppm_binary(const field<T1>& x, std::ostream& f)
3064 {
3065 arma_extra_debug_sigprint();
3066
3067 arma_type_check(( is_Mat<T1>::value == false ));
3068
3069 typedef typename T1::elem_type eT;
3070
3071 arma_debug_check( (x.n_elem != 3), "diskio::save_ppm_binary(): given field must have exactly 3 matrices of equal size" );
3072
3073 bool same_size = true;
3074 for(uword i=1; i<3; ++i)
3075 {
3076 if( (x(0).n_rows != x(i).n_rows) || (x(0).n_cols != x(i).n_cols) )
3077 {
3078 same_size = false;
3079 break;
3080 }
3081 }
3082
3083 arma_debug_check( (same_size != true), "diskio::save_ppm_binary(): given field must have exactly 3 matrices of equal size" );
3084
3085 const Mat<eT>& R = x(0);
3086 const Mat<eT>& G = x(1);
3087 const Mat<eT>& B = x(2);
3088
3089 f << "P6" << '\n';
3090 f << R.n_cols << '\n';
3091 f << R.n_rows << '\n';
3092 f << 255 << '\n';
3093
3094 const uword n_elem = 3 * R.n_rows * R.n_cols;
3095 podarray<u8> tmp(n_elem);
3096
3097 uword i = 0;
3098 for(uword row=0; row < R.n_rows; ++row)
3099 {
3100 for(uword col=0; col < R.n_cols; ++col)
3101 {
3102 tmp[i+0] = u8( access::tmp_real( R.at(row,col) ) );
3103 tmp[i+1] = u8( access::tmp_real( G.at(row,col) ) );
3104 tmp[i+2] = u8( access::tmp_real( B.at(row,col) ) );
3105
3106 i+=3;
3107 }
3108 }
3109
3110 f.write( reinterpret_cast<const char*>(tmp.mem), std::streamsize(n_elem) );
3111
3112 return f.good();
3113 }
3114
3115
3116
3117 //! @}
3118