Commit 43dec7889fc305d2dab2e19da474e33c27774061

Authored by David Mayerich
1 parent b3a38641

added code for sifting BSQ files in memory, updated CImg

@@ -26,7 +26,7 @@ class bsq: public binary<T> { @@ -26,7 +26,7 @@ class bsq: public binary<T> {
26 26
27 27
28 protected: 28 protected:
29 - 29 +
30 std::vector<double> w; //band wavelengths 30 std::vector<double> w; //band wavelengths
31 unsigned int offset; 31 unsigned int offset;
32 32
@@ -51,7 +51,7 @@ public: @@ -51,7 +51,7 @@ public:
51 using binary<T>::read_line_01; 51 using binary<T>::read_line_01;
52 using binary<T>::read_plane_2; 52 using binary<T>::read_plane_2;
53 //using binary<T>::getSlice; 53 //using binary<T>::getSlice;
54 - 54 +
55 55
56 /// Open a data file for reading using the class interface. 56 /// Open a data file for reading using the class interface.
57 57
@@ -60,7 +60,7 @@ public: @@ -60,7 +60,7 @@ public:
60 /// @param Y is the number of samples (lines) along dimension 2 60 /// @param Y is the number of samples (lines) along dimension 2
61 /// @param B is the number of samples (bands) along dimension 3 61 /// @param B is the number of samples (bands) along dimension 3
62 /// @param header_offset is the number of bytes (if any) in the binary header 62 /// @param header_offset is the number of bytes (if any) in the binary header
63 - /// @param wavelengths is an optional STL vector of size B specifying a numerical label for each band 63 + /// @param wavelengths is an STL vector of size B specifying a numerical label for each band
64 bool open(std::string filename, unsigned int X, unsigned int Y, unsigned int B, unsigned int header_offset, std::vector<double> wavelengths){ 64 bool open(std::string filename, unsigned int X, unsigned int Y, unsigned int B, unsigned int header_offset, std::vector<double> wavelengths){
65 65
66 //copy the wavelengths to the BSQ file structure 66 //copy the wavelengths to the BSQ file structure
@@ -69,7 +69,6 @@ public: @@ -69,7 +69,6 @@ public:
69 offset = header_offset; 69 offset = header_offset;
70 70
71 return open(filename, vec<unsigned int>(X, Y, B), header_offset); 71 return open(filename, vec<unsigned int>(X, Y, B), header_offset);
72 -  
73 } 72 }
74 73
75 /// Retrieve a single band (based on index) and stores it in pre-allocated memory. 74 /// Retrieve a single band (based on index) and stores it in pre-allocated memory.
@@ -91,7 +90,7 @@ public: @@ -91,7 +90,7 @@ public:
91 return band_index(p, (unsigned int)wavelength); 90 return band_index(p, (unsigned int)wavelength);
92 91
93 unsigned int XY = X() * Y(); //calculate the number of pixels in a band 92 unsigned int XY = X() * Y(); //calculate the number of pixels in a band
94 - unsigned page = 0; 93 + unsigned page = 0;
95 94
96 95
97 //get the two neighboring bands (above and below 'wavelength') 96 //get the two neighboring bands (above and below 'wavelength')
@@ -165,13 +164,13 @@ public: @@ -165,13 +164,13 @@ public:
165 file.seekg((bandnum - 1) * sizeof(T), std::ios::cur); //go to the next band 164 file.seekg((bandnum - 1) * sizeof(T), std::ios::cur); //go to the next band
166 } 165 }
167 166
168 - return true; 167 + return true;
169 } 168 }
170 169
171 /// Perform baseline correction given a list of baseline points and stores the result in a new BSQ file. 170 /// Perform baseline correction given a list of baseline points and stores the result in a new BSQ file.
172 171
173 /// @param outname is the name of the output file used to store the resulting baseline-corrected data. 172 /// @param outname is the name of the output file used to store the resulting baseline-corrected data.
174 - /// @param wls is the list of baseline points based on band labels. 173 + /// @param wls is the list of baseline points based on band labels.
175 bool baseline(std::string outname, std::vector<double> wls ) 174 bool baseline(std::string outname, std::vector<double> wls )
176 { 175 {
177 unsigned N = wls.size(); //get the number of baseline points 176 unsigned N = wls.size(); //get the number of baseline points
@@ -194,8 +193,8 @@ public: @@ -194,8 +193,8 @@ public:
194 T * c; //pointer to the current image 193 T * c; //pointer to the current image
195 194
196 a = (T*)malloc( S ); //memory allocation 195 a = (T*)malloc( S ); //memory allocation
197 - b = (T*)malloc( S );  
198 - c = (T*)malloc( S ); 196 + b = (T*)malloc( S );
  197 + c = (T*)malloc( S );
199 198
200 if (a == NULL || b == NULL || c == NULL){ 199 if (a == NULL || b == NULL || c == NULL){
201 std::cout<<"ERROR: error allocating memory"; 200 std::cout<<"ERROR: error allocating memory";
@@ -203,13 +202,13 @@ public: @@ -203,13 +202,13 @@ public:
203 } 202 }
204 203
205 204
206 - //initialize lownum, highnum, low, high 205 + //initialize lownum, highnum, low, high
207 ai=w[0]; 206 ai=w[0];
208 207
209 //if no baseline point is specified at band 0, 208 //if no baseline point is specified at band 0,
210 //set the baseline point at band 0 to 0 209 //set the baseline point at band 0 to 0
211 if(wls[0] != w[0]){ 210 if(wls[0] != w[0]){
212 - bi = wls[control]; 211 + bi = wls[control];
213 memset(a, (char)0, S); 212 memset(a, (char)0, S);
214 } 213 }
215 //else get the low band 214 //else get the low band
@@ -221,7 +220,7 @@ public: @@ -221,7 +220,7 @@ public:
221 //get the high band 220 //get the high band
222 band(b, bi); 221 band(b, bi);
223 222
224 - //correct every band 223 + //correct every band
225 for(unsigned cii = 0; cii < B; cii++){ 224 for(unsigned cii = 0; cii < B; cii++){
226 225
227 //update baseline points, if necessary 226 //update baseline points, if necessary
@@ -253,21 +252,21 @@ public: @@ -253,21 +252,21 @@ public:
253 //get the current band 252 //get the current band
254 band_index(c, cii); 253 band_index(c, cii);
255 ci = w[cii]; 254 ci = w[cii];
256 - 255 +
257 //perform the baseline correction 256 //perform the baseline correction
258 for(unsigned i=0; i < XY; i++){ 257 for(unsigned i=0; i < XY; i++){
259 double r = (double) (ci - ai) / (double) (bi - ai); 258 double r = (double) (ci - ai) / (double) (bi - ai);
260 c[i] =(T) ( c[i] - (b[i] - a[i]) * r - a[i] ); 259 c[i] =(T) ( c[i] - (b[i] - a[i]) * r - a[i] );
261 } 260 }
262 - 261 +
263 target.write(reinterpret_cast<const char*>(c), S); //write the corrected data into destination 262 target.write(reinterpret_cast<const char*>(c), S); //write the corrected data into destination
264 263
265 thread_data = (double)cii / B * 100; 264 thread_data = (double)cii / B * 100;
266 -  
267 - } 265 +
  266 + }
268 267
269 //header.save(headername); //save the new header file 268 //header.save(headername); //save the new header file
270 - 269 +
271 free(a); 270 free(a);
272 free(b); 271 free(b);
273 free(c); 272 free(c);
@@ -295,7 +294,7 @@ public: @@ -295,7 +294,7 @@ public:
295 T * c; //pointer to the current image 294 T * c; //pointer to the current image
296 295
297 b = (T*)malloc( S ); //memory allocation 296 b = (T*)malloc( S ); //memory allocation
298 - c = (T*)malloc( S ); 297 + c = (T*)malloc( S );
299 298
300 band(b, w); //get the certain band into memory 299 band(b, w); //get the certain band into memory
301 300
@@ -314,17 +313,17 @@ public: @@ -314,17 +313,17 @@ public:
314 thread_data = (double)j / B * 100; 313 thread_data = (double)j / B * 100;
315 } 314 }
316 315
317 - 316 +
318 317
319 //header.save(headername); //save the new header file 318 //header.save(headername); //save the new header file
320 - 319 +
321 free(b); 320 free(b);
322 free(c); 321 free(c);
323 target.close(); 322 target.close();
324 thread_data = 100; //make sure that the progress bar is full 323 thread_data = 100; //make sure that the progress bar is full
325 return true; 324 return true;
326 } 325 }
327 - 326 +
328 /// Convert the current BSQ file to a BIP file with the specified file name. 327 /// Convert the current BSQ file to a BIP file with the specified file name.
329 328
330 /// @param outname is the name of the output BIP file to be saved to disk. 329 /// @param outname is the name of the output BIP file to be saved to disk.
@@ -356,10 +355,10 @@ public: @@ -356,10 +355,10 @@ public:
356 //simplify image resolution 355 //simplify image resolution
357 unsigned int L = X() * Z() * sizeof(T); //calculate the number of bytes of a ZX slice 356 unsigned int L = X() * Z() * sizeof(T); //calculate the number of bytes of a ZX slice
358 unsigned int jump = (Y() - 1) * X() * sizeof(T); 357 unsigned int jump = (Y() - 1) * X() * sizeof(T);
359 - 358 +
360 std::ofstream target(outname.c_str(), std::ios::binary); 359 std::ofstream target(outname.c_str(), std::ios::binary);
361 std::string headername = outname + ".hdr"; 360 std::string headername = outname + ".hdr";
362 - 361 +
363 unsigned int xz_bytes = X() * Z() * sizeof(T); 362 unsigned int xz_bytes = X() * Z() * sizeof(T);
364 T * xz_slice; //pointer to the current spectrum 363 T * xz_slice; //pointer to the current spectrum
365 xz_slice = (T*)malloc(xz_bytes); 364 xz_slice = (T*)malloc(xz_bytes);
@@ -372,16 +371,16 @@ public: @@ -372,16 +371,16 @@ public:
372 file.read((char *)(xz_slice + z * X()), sizeof(T) * X()); //read a line 371 file.read((char *)(xz_slice + z * X()), sizeof(T) * X()); //read a line
373 file.seekg(jump, std::ios::cur); //seek to the next band 372 file.seekg(jump, std::ios::cur); //seek to the next band
374 373
375 - 374 +
376 thread_data = (double)(y * Z() + z) / (Z() * Y()) * 100; //update the progress counter 375 thread_data = (double)(y * Z() + z) / (Z() * Y()) * 100; //update the progress counter
377 - }  
378 - target.write(reinterpret_cast<const char*>(xz_slice), xz_bytes); //write the generated XZ slice to the target file 376 + }
  377 + target.write(reinterpret_cast<const char*>(xz_slice), xz_bytes); //write the generated XZ slice to the target file
379 } 378 }
380 379
381 380
382 - 381 +
383 thread_data = 100; 382 thread_data = 100;
384 - 383 +
385 free(xz_slice); 384 free(xz_slice);
386 target.close(); 385 target.close();
387 386
@@ -425,7 +424,7 @@ public: @@ -425,7 +424,7 @@ public:
425 rp = (T*) malloc(S); 424 rp = (T*) malloc(S);
426 425
427 band(lp, lb); 426 band(lp, lb);
428 - band(rp, rb); 427 + band(rp, rb);
429 428
430 baseline_band(lb, rb, lp, rp, bandwavelength, result); 429 baseline_band(lb, rb, lp, rp, bandwavelength, result);
431 430
@@ -496,7 +495,7 @@ public: @@ -496,7 +495,7 @@ public:
496 } 495 }
497 baseline_band(lb, rb, lp, rp, lab, cur2); //beginnning part 496 baseline_band(lb, rb, lp, rp, lab, cur2); //beginnning part
498 baseline_band(lb, rb, lp, rp, w[ai], cur); 497 baseline_band(lb, rb, lp, rp, w[ai], cur);
499 - for(unsigned j = 0; j < XY; j++){ 498 + for(unsigned j = 0; j < XY; j++){
500 result[j] += (w[ai] - lab) * (cur[j] + cur2[j]) / 2.0; 499 result[j] += (w[ai] - lab) * (cur[j] + cur2[j]) / 2.0;
501 } 500 }
502 501
@@ -507,7 +506,7 @@ public: @@ -507,7 +506,7 @@ public:
507 baseline_band(lb, rb, lp, rp, w[ai], cur2); 506 baseline_band(lb, rb, lp, rp, w[ai], cur2);
508 for(unsigned j = 0; j < XY; j++) 507 for(unsigned j = 0; j < XY; j++)
509 { 508 {
510 - result[j] += (w[ai] - w[ai-1]) * (cur[j] + cur2[j]) / 2.0; 509 + result[j] += (w[ai] - w[ai-1]) * (cur[j] + cur2[j]) / 2.0;
511 } 510 }
512 std::swap(cur,cur2); //swap the band pointers 511 std::swap(cur,cur2); //swap the band pointers
513 } 512 }
@@ -530,9 +529,9 @@ public: @@ -530,9 +529,9 @@ public:
530 /// @param result is a pointer to a pre-allocated array at least X * Y * sizeof(T) in size 529 /// @param result is a pointer to a pre-allocated array at least X * Y * sizeof(T) in size
531 bool ph_to_ph(double lb1, double rb1, double pos1, double lb2, double rb2, double pos2, T * result){ 530 bool ph_to_ph(double lb1, double rb1, double pos1, double lb2, double rb2, double pos2, T * result){
532 531
533 - T* p1 = (T*)malloc(X() * Y() * sizeof(T));  
534 - T* p2 = (T*)malloc(X() * Y() * sizeof(T));  
535 - 532 + T* p1 = (T*)malloc(X() * Y() * sizeof(T));
  533 + T* p2 = (T*)malloc(X() * Y() * sizeof(T));
  534 +
536 //get the two peak band 535 //get the two peak band
537 height(lb1, rb1, pos1, p1); 536 height(lb1, rb1, pos1, p1);
538 height(lb2, rb2, pos2, p2); 537 height(lb2, rb2, pos2, p2);
@@ -546,9 +545,9 @@ public: @@ -546,9 +545,9 @@ public:
546 545
547 free(p1); 546 free(p1);
548 free(p2); 547 free(p2);
549 - return true; 548 + return true;
550 } 549 }
551 - 550 +
552 /// Compute the ratio between a peak area and peak height. 551 /// Compute the ratio between a peak area and peak height.
553 552
554 /// @param lb1 is the label value for the left baseline point for the first peak (numerator) 553 /// @param lb1 is the label value for the left baseline point for the first peak (numerator)
@@ -560,10 +559,10 @@ public: @@ -560,10 +559,10 @@ public:
560 /// @param result is a pointer to a pre-allocated array at least X * Y * sizeof(T) in size 559 /// @param result is a pointer to a pre-allocated array at least X * Y * sizeof(T) in size
561 bool pa_to_ph(double lb1, double rb1, double lab1, double rab1, 560 bool pa_to_ph(double lb1, double rb1, double lab1, double rab1,
562 double lb2, double rb2, double pos, T* result){ 561 double lb2, double rb2, double pos, T* result){
563 -  
564 - T* p1 = (T*)malloc(X() * Y() * sizeof(T));  
565 - T* p2 = (T*)malloc(X() * Y() * sizeof(T));  
566 - 562 +
  563 + T* p1 = (T*)malloc(X() * Y() * sizeof(T));
  564 + T* p2 = (T*)malloc(X() * Y() * sizeof(T));
  565 +
567 //get the area and the peak band 566 //get the area and the peak band
568 area(lb1, rb1, lab1, rab1, p1); 567 area(lb1, rb1, lab1, rab1, p1);
569 height(lb2, rb2, pos, p2); 568 height(lb2, rb2, pos, p2);
@@ -577,9 +576,9 @@ public: @@ -577,9 +576,9 @@ public:
577 576
578 free(p1); 577 free(p1);
579 free(p2); 578 free(p2);
580 - return true;  
581 - }  
582 - 579 + return true;
  580 + }
  581 +
583 /// Compute the ratio between two peak areas. 582 /// Compute the ratio between two peak areas.
584 583
585 /// @param lb1 is the label value for the left baseline point for the first peak (numerator) 584 /// @param lb1 is the label value for the left baseline point for the first peak (numerator)
@@ -589,14 +588,14 @@ public: @@ -589,14 +588,14 @@ public:
589 /// @param lb2 is the label value for the left baseline point for the second peak (denominator) 588 /// @param lb2 is the label value for the left baseline point for the second peak (denominator)
590 /// @param rb2 is the label value for the right baseline point for the second peak (denominator) 589 /// @param rb2 is the label value for the right baseline point for the second peak (denominator)
591 /// @param lab2 is the label value for the left bound (start of the integration) of the second peak (denominator) 590 /// @param lab2 is the label value for the left bound (start of the integration) of the second peak (denominator)
592 - /// @param rab2 is the label value for the right bound (end of the integration) of the second peak (denominator) 591 + /// @param rab2 is the label value for the right bound (end of the integration) of the second peak (denominator)
593 /// @param result is a pointer to a pre-allocated array at least X * Y * sizeof(T) in size 592 /// @param result is a pointer to a pre-allocated array at least X * Y * sizeof(T) in size
594 bool pa_to_pa(double lb1, double rb1, double lab1, double rab1, 593 bool pa_to_pa(double lb1, double rb1, double lab1, double rab1,
595 double lb2, double rb2, double lab2, double rab2, T* result){ 594 double lb2, double rb2, double lab2, double rab2, T* result){
596 -  
597 - T* p1 = (T*)malloc(X() * Y() * sizeof(T));  
598 - T* p2 = (T*)malloc(X() * Y() * sizeof(T));  
599 - 595 +
  596 + T* p1 = (T*)malloc(X() * Y() * sizeof(T));
  597 + T* p2 = (T*)malloc(X() * Y() * sizeof(T));
  598 +
600 //get the area and the peak band 599 //get the area and the peak band
601 area(lb1, rb1, lab1, rab1, p1); 600 area(lb1, rb1, lab1, rab1, p1);
602 area(lb2, rb2, lab2, rab2, p2); 601 area(lb2, rb2, lab2, rab2, p2);
@@ -610,8 +609,8 @@ public: @@ -610,8 +609,8 @@ public:
610 609
611 free(p1); 610 free(p1);
612 free(p2); 611 free(p2);
613 - return true;  
614 - } 612 + return true;
  613 + }
615 614
616 /// Compute the definite integral of a baseline corrected peak. 615 /// Compute the definite integral of a baseline corrected peak.
617 616
@@ -671,7 +670,7 @@ public: @@ -671,7 +670,7 @@ public:
671 } 670 }
672 baseline_band(lb, rb, lp, rp, lab, cur2); //beginnning part 671 baseline_band(lb, rb, lp, rp, lab, cur2); //beginnning part
673 baseline_band(lb, rb, lp, rp, w[ai], cur); 672 baseline_band(lb, rb, lp, rp, w[ai], cur);
674 - for(unsigned j = 0; j < XY; j++){ 673 + for(unsigned j = 0; j < XY; j++){
675 result[j] += (w[ai] - lab) * (w[ai] + lab) * (cur[j] + cur2[j]) / 4.0; 674 result[j] += (w[ai] - lab) * (w[ai] + lab) * (cur[j] + cur2[j]) / 4.0;
676 } 675 }
677 676
@@ -682,7 +681,7 @@ public: @@ -682,7 +681,7 @@ public:
682 baseline_band(lb, rb, lp, rp, w[ai], cur2); 681 baseline_band(lb, rb, lp, rp, w[ai], cur2);
683 for(unsigned j = 0; j < XY; j++) 682 for(unsigned j = 0; j < XY; j++)
684 { 683 {
685 - result[j] += (w[ai] - w[ai-1]) * (w[ai] + w[ai-1]) * (cur[j] + cur2[j]) / 4.0; 684 + result[j] += (w[ai] - w[ai-1]) * (w[ai] + w[ai-1]) * (cur[j] + cur2[j]) / 4.0;
686 } 685 }
687 std::swap(cur,cur2); //swap the band pointers 686 std::swap(cur,cur2); //swap the band pointers
688 } 687 }
@@ -702,9 +701,9 @@ public: @@ -702,9 +701,9 @@ public:
702 /// @param rab is the label for the end of the peak 701 /// @param rab is the label for the end of the peak
703 /// @param result is a pointer to a pre-allocated array at least X * Y * sizeof(T) in size 702 /// @param result is a pointer to a pre-allocated array at least X * Y * sizeof(T) in size
704 bool cpoint(double lb, double rb, double lab, double rab, T* result){ 703 bool cpoint(double lb, double rb, double lab, double rab, T* result){
705 - T* p1 = (T*)malloc(X() * Y() * sizeof(T));  
706 - T* p2 = (T*)malloc(X() * Y() * sizeof(T));  
707 - 704 + T* p1 = (T*)malloc(X() * Y() * sizeof(T));
  705 + T* p2 = (T*)malloc(X() * Y() * sizeof(T));
  706 +
708 //get the area and the peak band 707 //get the area and the peak band
709 x_area(lb, rb, lab, rab, p1); 708 x_area(lb, rb, lab, rab, p1);
710 area(lb, rb, lab, rab, p2); 709 area(lb, rb, lab, rab, p2);
@@ -718,7 +717,7 @@ public: @@ -718,7 +717,7 @@ public:
718 717
719 free(p1); 718 free(p1);
720 free(p2); 719 free(p2);
721 - return true; 720 + return true;
722 } 721 }
723 722
724 /// Create a mask based on a given band and threshold value. 723 /// Create a mask based on a given band and threshold value.
@@ -777,7 +776,80 @@ public: @@ -777,7 +776,80 @@ public:
777 return true; 776 return true;
778 } 777 }
779 778
  779 + /// Saves only those pixels in a band corresponding to the mask value != 0
  780 + /// @param array is a pointer to the destination array used to store the data
  781 + /// @param i is the band index
  782 + /// @p is a pointer to the mask data
  783 + bool sift_band(T* values, unsigned long b, unsigned char* p){
  784 + unsigned long long XY = X() * Y(); //Number of XY pixels
  785 + unsigned long long L = XY * sizeof(T); //size of XY plane (in bytes)
  786 +
  787 + unsigned long long vi = 0; //create an index into the values array
  788 +
  789 + unsigned long long start, end; //start and end indices of a block of masked pixels in the band
  790 + bool reading = false;
  791 + unsigned long long l, i; //length of the masked region
  792 +
  793 + for(unsigned long long xy = 0; xy < XY; xy++){ //for each pixel in the band
  794 +
  795 + if(reading){ //if we are currently iterating through a block of masked pixels
  796 + if(p[xy]) end++; //if the current pixel is part of that block, increment the end index
  797 + else{ //otherwise, terminate the block
  798 + reading = false; //stop reading
  799 + i = b * XY + start;
  800 + file.seekg( i * sizeof(T) + header); //skip all of the unmasked pixels up to this point
  801 + l = (end - start);
  802 + file.read((char *)&values[vi], l * sizeof(T)); //write the values between start and end to the values array
  803 + vi += l; //increment the pointer into the values array
  804 + }
  805 + }
  806 + else{ //if we are currently iterating through a block of empty pixels
  807 + if(p[xy]){ //if the next pixel is masked, start a new block for reading
  808 + reading = true;
  809 + start = xy; //set the start and end indices to the beginning of this new block
  810 + end = start + 1;
  811 + }
  812 + }
  813 + }
  814 +
  815 + return true;
  816 + }
  817 +
  818 + /// Saves only those spectra corresponding to mask value != 0 to pre-allocated memory
  819 + /// @param matrix is the destination for the sifted pixels
  820 + /// @param p is the mask file used for sifting
  821 + bool sift(T* matrix, unsigned char* p){
  822 +
  823 + // open a band (XY plane)
  824 + unsigned long XY = X() * Y(); //Number of XY pixels
  825 + unsigned long L = XY * sizeof(T); //size of XY pixels
  826 +
  827 + //count the number of masked pixels
  828 + unsigned long P = 0; //allocate space for the number of pixels
  829 + for(unsigned long xy = 0; xy < XY; xy++){ //count the number of pixels
  830 + if(p[xy] != 0) P++;
  831 + }
  832 +
  833 + T* bandvals = (T*) malloc(sizeof(T) * P); //allocate a temporary array to store the pixels for a single band
  834 + memset(matrix, 0, sizeof(T) * P * Z());
  835 + for (unsigned long z = 0; z < Z(); z++){ //for each band
  836 +
  837 + if(!sift_band(bandvals, z, p)){
  838 + std::cout<<"ERROR sifting band index "<<z<<std::endl;
  839 + exit(1);
  840 + }
  841 +
  842 + for(unsigned long p = 0; p < P; p++) //for each pixel in the array representing a single band
  843 + matrix[p * Z() + z] = bandvals[p]; //copy it to the appropriate location in the matrix
  844 + }
  845 +
  846 + free(bandvals); //clean up temporary memory
  847 + return true;
  848 + }
  849 +
780 /// Saves to disk only those spectra corresponding to mask values != 0 850 /// Saves to disk only those spectra corresponding to mask values != 0
  851 + /// @param outfile is the name of the sifted ENVI file to be written to disk
  852 + /// @param unsigned char* p is the mask file used for sifting
781 bool sift(std::string outfile, unsigned char* p){ 853 bool sift(std::string outfile, unsigned char* p){
782 std::ofstream target(outfile.c_str(), std::ios::binary); 854 std::ofstream target(outfile.c_str(), std::ios::binary);
783 // open a band (XY plane) 855 // open a band (XY plane)
@@ -912,7 +984,7 @@ public: @@ -912,7 +984,7 @@ public:
912 for (unsigned j = 0; j < XY; j++){ //loop through temp, averaging valid pixels 984 for (unsigned j = 0; j < XY; j++){ //loop through temp, averaging valid pixels
913 if (mask[j] != 0){ 985 if (mask[j] != 0){
914 p[i] += temp[j] / (T)count; 986 p[i] += temp[j] / (T)count;
915 - } 987 + }
916 } 988 }
917 } 989 }
918 free(temp); 990 free(temp);
@@ -930,7 +1002,7 @@ public: @@ -930,7 +1002,7 @@ public:
930 unsigned int B = Z(); 1002 unsigned int B = Z();
931 T* bandi = (T*)malloc(sizeof(T) * xy); 1003 T* bandi = (T*)malloc(sizeof(T) * xy);
932 T* bandj = (T*)malloc(sizeof(T) * xy); 1004 T* bandj = (T*)malloc(sizeof(T) * xy);
933 - 1005 +
934 //count vaild pixels in a band 1006 //count vaild pixels in a band
935 unsigned count = 0; 1007 unsigned count = 0;
936 for (unsigned j = 0; j < xy; j++){ 1008 for (unsigned j = 0; j < xy; j++){
@@ -1004,11 +1076,11 @@ public: @@ -1004,11 +1076,11 @@ public:
1004 for (unsigned y = 0; y < lines; y++) 1076 for (unsigned y = 0; y < lines; y++)
1005 { 1077 {
1006 file.read((char *)(temp + y * samples), sizeof(T) * samples); 1078 file.read((char *)(temp + y * samples), sizeof(T) * samples);
1007 - file.seekg(jumpl, std::ios::cur); //go to the next band 1079 + file.seekg(jumpl, std::ios::cur); //go to the next band
1008 1080
1009 thread_data = (double)(z * lines + y) / (Z() * lines) * 100; 1081 thread_data = (double)(z * lines + y) / (Z() * lines) * 100;
1010 } 1082 }
1011 - out.write(reinterpret_cast<const char*>(temp), L); //write slice data into target file 1083 + out.write(reinterpret_cast<const char*>(temp), L); //write slice data into target file
1012 file.seekg(jumpb, std::ios::cur); 1084 file.seekg(jumpb, std::ios::cur);
1013 } 1085 }
1014 free(temp); 1086 free(temp);
@@ -1030,4 +1102,4 @@ public: @@ -1030,4 +1102,4 @@ public:
1030 1102
1031 #endif 1103 #endif
1032 1104
1033 - 1105 +
@@ -465,7 +465,26 @@ public: @@ -465,7 +465,26 @@ public:
465 return false; 465 return false;
466 } 466 }
467 467
  468 + /// sift copies all spectra corresponding to nonzero values of a mask into a pre-allocated matrix
  469 + /// @param matrix is the destination for the pixel data
  470 + /// @param p is the mask
  471 + bool sift(void* matrix, unsigned char* p){
  472 +
  473 + if (header.interleave == envi_header::BSQ){ //if the infile is bsq file
  474 + if (header.data_type == envi_header::float32)
  475 + return ((bsq<float>*)file)->sift((float*)matrix, p);
  476 + else if (header.data_type == envi_header::float64)
  477 + return ((bsq<double>*)file)->sift((double*)matrix, p);
  478 + else
  479 + std::cout << "ERROR: unidentified data type" << std::endl;
  480 + }
  481 + return false;
  482 +
  483 + }
  484 +
468 /// sift-mask saves in an array only those spectra corresponding to nonzero values of the mask. 485 /// sift-mask saves in an array only those spectra corresponding to nonzero values of the mask.
  486 + /// @param outfile is the name of the sifted output file
  487 + /// @param p is the mask
469 bool sift(std::string outfile, unsigned char* p) 488 bool sift(std::string outfile, unsigned char* p)
470 { 489 {
471 490
@@ -54,7 +54,7 @@ @@ -54,7 +54,7 @@
54 54
55 // Set version number of the library. 55 // Set version number of the library.
56 #ifndef cimg_version 56 #ifndef cimg_version
57 -#define cimg_version 165 57 +#define cimg_version 169
58 58
59 /*----------------------------------------------------------- 59 /*-----------------------------------------------------------
60 # 60 #
@@ -75,6 +75,7 @@ @@ -75,6 +75,7 @@
75 #include <cstdarg> 75 #include <cstdarg>
76 #include <cstring> 76 #include <cstring>
77 #include <cmath> 77 #include <cmath>
  78 +#include <cfloat>
78 #include <climits> 79 #include <climits>
79 #include <ctime> 80 #include <ctime>
80 #include <exception> 81 #include <exception>
@@ -122,16 +123,30 @@ @@ -122,16 +123,30 @@
122 #pragma warning(disable:4820) 123 #pragma warning(disable:4820)
123 #pragma warning(disable:4996) 124 #pragma warning(disable:4996)
124 #define _CRT_SECURE_NO_DEPRECATE 1 125 #define _CRT_SECURE_NO_DEPRECATE 1
  126 +#define _CRT_SECURE_NO_WARNINGS 1
125 #define _CRT_NONSTDC_NO_DEPRECATE 1 127 #define _CRT_NONSTDC_NO_DEPRECATE 1
126 -#define cimg_snprintf cimg::c99_snprintf  
127 -#define cimg_vsnprintf cimg::c99_vsnprintf  
128 #endif 128 #endif
129 129
130 -#ifndef cimg_snprintf 130 +// Define correct string functions for each compiler and OS.
  131 +#if cimg_OS==2 && defined(_MSC_VER)
  132 +#define cimg_sscanf std::sscanf
  133 +#define cimg_sprintf std::sprintf
  134 +#define cimg_snprintf cimg::_snprintf
  135 +#define cimg_vsnprintf cimg::_vsnprintf
  136 +#else
131 #include <stdio.h> 137 #include <stdio.h>
  138 +#if defined(__MACOSX__) || defined(__APPLE__)
  139 +#define cimg_sscanf cimg::_sscanf
  140 +#define cimg_sprintf cimg::_sprintf
  141 +#define cimg_snprintf cimg::_snprintf
  142 +#define cimg_vsnprintf cimg::_vsnprintf
  143 +#else
  144 +#define cimg_sscanf std::sscanf
  145 +#define cimg_sprintf std::sprintf
132 #define cimg_snprintf snprintf 146 #define cimg_snprintf snprintf
133 #define cimg_vsnprintf vsnprintf 147 #define cimg_vsnprintf vsnprintf
134 #endif 148 #endif
  149 +#endif
135 150
136 // Include OS-specific headers. 151 // Include OS-specific headers.
137 #if cimg_OS==1 152 #if cimg_OS==1
@@ -145,6 +160,9 @@ @@ -145,6 +160,9 @@
145 #ifndef NOMINMAX 160 #ifndef NOMINMAX
146 #define NOMINMAX 161 #define NOMINMAX
147 #endif 162 #endif
  163 +#ifndef WIN32_LEAN_AND_MEAN
  164 +#define WIN32_LEAN_AND_MEAN
  165 +#endif
148 #include <windows.h> 166 #include <windows.h>
149 #ifndef _WIN32_IE 167 #ifndef _WIN32_IE
150 #define _WIN32_IE 0x0400 168 #define _WIN32_IE 0x0400
@@ -154,15 +172,28 @@ @@ -154,15 +172,28 @@
154 #include <io.h> 172 #include <io.h>
155 #endif 173 #endif
156 174
157 -// Look for C++11 features 175 +// Look for C++11 features.
158 #if !defined(cimg_use_cpp11) && __cplusplus>201100 176 #if !defined(cimg_use_cpp11) && __cplusplus>201100
159 -#define cimg_use_cpp11 177 +#define cimg_use_cpp11 1
160 #endif 178 #endif
161 -#ifdef cimg_use_cpp11 179 +#if defined(cimg_use_cpp11) && cimg_use_cpp11!=0
162 #include <initializer_list> 180 #include <initializer_list>
163 #include <utility> 181 #include <utility>
164 #endif 182 #endif
165 183
  184 +// Configure the 'abort' signal handler (does nothing by default).
  185 +// A typical signal handler can be defined in your own source like this:
  186 +// Without OpenMP support: #define cimg_test_abort() if (is_abort) throw CImgAbortException("")
  187 +//
  188 +// or
  189 +//
  190 +// With OpenMP support: #define cimg_test_abort() if (!omp_get_thread_num() && is_abort) throw CImgAbortException("")
  191 +//
  192 +// where 'is_abort' is a boolean variable.
  193 +#ifndef cimg_test_abort
  194 +#define cimg_test_abort()
  195 +#endif
  196 +
166 // Configure filename separator. 197 // Configure filename separator.
167 // 198 //
168 // Filename separator is set by default to '/', except for Windows where it is '\'. 199 // Filename separator is set by default to '/', except for Windows where it is '\'.
@@ -186,7 +217,11 @@ @@ -186,7 +217,11 @@
186 // 217 //
187 // Define 'cimg_use_vt100' to allow output of color messages on VT100-compatible terminals. 218 // Define 'cimg_use_vt100' to allow output of color messages on VT100-compatible terminals.
188 #ifndef cimg_verbosity 219 #ifndef cimg_verbosity
  220 +#if cimg_OS==2
189 #define cimg_verbosity 2 221 #define cimg_verbosity 2
  222 +#else
  223 +#define cimg_verbosity 1
  224 +#endif
190 #elif !(cimg_verbosity==0 || cimg_verbosity==1 || cimg_verbosity==2 || cimg_verbosity==3 || cimg_verbosity==4) 225 #elif !(cimg_verbosity==0 || cimg_verbosity==1 || cimg_verbosity==2 || cimg_verbosity==3 || cimg_verbosity==4)
191 #error CImg Library: Configuration variable 'cimg_verbosity' is badly defined. 226 #error CImg Library: Configuration variable 'cimg_verbosity' is badly defined.
192 #error (should be { 0=quiet | 1=console | 2=dialog | 3=console+warnings | 4=dialog+warnings }). 227 #error (should be { 0=quiet | 1=console | 2=dialog | 3=console+warnings | 4=dialog+warnings }).
@@ -201,11 +236,7 @@ @@ -201,11 +236,7 @@
201 #if cimg_OS==0 236 #if cimg_OS==0
202 #define cimg_display 0 237 #define cimg_display 0
203 #elif cimg_OS==1 238 #elif cimg_OS==1
204 -#if defined(__MACOSX__) || defined(__APPLE__)  
205 -#define cimg_display 1  
206 -#else  
207 #define cimg_display 1 239 #define cimg_display 1
208 -#endif  
209 #elif cimg_OS==2 240 #elif cimg_OS==2
210 #define cimg_display 2 241 #define cimg_display 2
211 #endif 242 #endif
@@ -471,26 +502,6 @@ extern &quot;C&quot; { @@ -471,26 +502,6 @@ extern &quot;C&quot; {
471 #define cimg_usage(usage) cimg_library_suffixed::cimg::option((char*)0,argc,argv,(char*)0,usage,false) 502 #define cimg_usage(usage) cimg_library_suffixed::cimg::option((char*)0,argc,argv,(char*)0,usage,false)
472 #define cimg_help(str) cimg_library_suffixed::cimg::option((char*)0,argc,argv,str,(char*)0) 503 #define cimg_help(str) cimg_library_suffixed::cimg::option((char*)0,argc,argv,str,(char*)0)
473 #define cimg_option(name,defaut,usage) cimg_library_suffixed::cimg::option(name,argc,argv,defaut,usage) 504 #define cimg_option(name,defaut,usage) cimg_library_suffixed::cimg::option(name,argc,argv,defaut,usage)
474 -#define cimg_argument(pos) \  
475 - cimg_library_suffixed::cimg::argument(pos,argc,argv)  
476 -#define cimg_argument1(pos,s0) \  
477 - cimg_library_suffixed::cimg::argument(pos,argc,argv,1,s0)  
478 -#define cimg_argument2(pos,s0,s1) \  
479 - cimg_library_suffixed::cimg::argument(pos,argc,argv,2,s0,s1)  
480 -#define cimg_argument3(pos,s0,s1,s2) \  
481 - cimg_library_suffixed::cimg::argument(pos,argc,argv,3,s0,s1,s2)  
482 -#define cimg_argument4(pos,s0,s1,s2,s3) \  
483 - cimg_library_suffixed::cimg::argument(pos,argc,argv,4,s0,s1,s2,s3)  
484 -#define cimg_argument5(pos,s0,s1,s2,s3,s4) \  
485 - cimg_library_suffixed::cimg::argument(pos,argc,argv,5,s0,s1,s2,s3,s4)  
486 -#define cimg_argument6(pos,s0,s1,s2,s3,s4,s5) \  
487 - cimg_library_suffixed::cimg::argument(pos,argc,argv,6,s0,s1,s2,s3,s4,s5)  
488 -#define cimg_argument7(pos,s0,s1,s2,s3,s4,s5,s6) \  
489 - cimg_library_suffixed::cimg::argument(pos,argc,argv,7,s0,s1,s2,s3,s4,s5,s6)  
490 -#define cimg_argument8(pos,s0,s1,s2,s3,s4,s5,s6,s7) \  
491 - cimg_library_suffixed::cimg::argument(pos,argc,argv,8,s0,s1,s2,s3,s4,s5,s6,s7)  
492 -#define cimg_argument9(pos,s0,s1,s2,s3,s4,s5,s6,s7,s8) \  
493 - cimg_library_suffixed::cimg::argument(pos,argc,argv,9,s0,s1,s2,s3,s4,s5,s6,s7,s8)  
494 505
495 // Macros to define and manipulate local neighborhoods. 506 // Macros to define and manipulate local neighborhoods.
496 #define CImg_2x2(I,T) T I[4]; \ 507 #define CImg_2x2(I,T) T I[4]; \
@@ -2069,26 +2080,26 @@ namespace cimg_library_suffixed { @@ -2069,26 +2080,26 @@ namespace cimg_library_suffixed {
2069 2080
2070 // Declare cimg:: namespace. 2081 // Declare cimg:: namespace.
2071 // This is an uncomplete namespace definition here. It only contains some 2082 // This is an uncomplete namespace definition here. It only contains some
2072 - // necessary stuffs to ensure a correct declaration order of the classes and functions 2083 + // necessary stuff to ensure a correct declaration order of the classes and functions
2073 // defined afterwards. 2084 // defined afterwards.
2074 namespace cimg { 2085 namespace cimg {
2075 2086
2076 // Define ascii sequences for colored terminal output. 2087 // Define ascii sequences for colored terminal output.
2077 #ifdef cimg_use_vt100 2088 #ifdef cimg_use_vt100
2078 - const char t_normal[] = { 0x1b, '[', '0', ';', '0', ';', '0', 'm', 0 };  
2079 - const char t_black[] = { 0x1b, '[', '0', ';', '3', '0', ';', '5', '9', 'm', 0 };  
2080 - const char t_red[] = { 0x1b, '[', '0', ';', '3', '1', ';', '5', '9', 'm', 0 };  
2081 - const char t_green[] = { 0x1b, '[', '0', ';', '3', '2', ';', '5', '9', 'm', 0 };  
2082 - const char t_yellow[] = { 0x1b, '[', '0', ';', '3', '3', ';', '5', '9', 'm', 0 };  
2083 - const char t_blue[] = { 0x1b, '[', '0', ';', '3', '4', ';', '5', '9', 'm', 0 };  
2084 - const char t_magenta[] = { 0x1b, '[', '0', ';', '3', '5', ';', '5', '9', 'm', 0 };  
2085 - const char t_cyan[] = { 0x1b, '[', '0', ';', '3', '6', ';', '5', '9', 'm', 0 };  
2086 - const char t_white[] = { 0x1b, '[', '0', ';', '3', '7', ';', '5', '9', 'm', 0 };  
2087 - const char t_bold[] = { 0x1b, '[', '1', 'm', 0 };  
2088 - const char t_underscore[] = { 0x1b, '[', '4', 'm', 0 }; 2089 + static const char t_normal[] = { 0x1b, '[', '0', ';', '0', ';', '0', 'm', 0 };
  2090 + static const char t_black[] = { 0x1b, '[', '0', ';', '3', '0', ';', '5', '9', 'm', 0 };
  2091 + static const char t_red[] = { 0x1b, '[', '0', ';', '3', '1', ';', '5', '9', 'm', 0 };
  2092 + static const char t_green[] = { 0x1b, '[', '0', ';', '3', '2', ';', '5', '9', 'm', 0 };
  2093 + static const char t_yellow[] = { 0x1b, '[', '0', ';', '3', '3', ';', '5', '9', 'm', 0 };
  2094 + static const char t_blue[] = { 0x1b, '[', '0', ';', '3', '4', ';', '5', '9', 'm', 0 };
  2095 + static const char t_magenta[] = { 0x1b, '[', '0', ';', '3', '5', ';', '5', '9', 'm', 0 };
  2096 + static const char t_cyan[] = { 0x1b, '[', '0', ';', '3', '6', ';', '5', '9', 'm', 0 };
  2097 + static const char t_white[] = { 0x1b, '[', '0', ';', '3', '7', ';', '5', '9', 'm', 0 };
  2098 + static const char t_bold[] = { 0x1b, '[', '1', 'm', 0 };
  2099 + static const char t_underscore[] = { 0x1b, '[', '4', 'm', 0 };
2089 #else 2100 #else
2090 - const char t_normal[] = { 0 };  
2091 - const char *const t_black = cimg::t_normal, 2101 + static const char t_normal[] = { 0 };
  2102 + static const char *const t_black = cimg::t_normal,
2092 *const t_red = cimg::t_normal, 2103 *const t_red = cimg::t_normal,
2093 *const t_green = cimg::t_normal, 2104 *const t_green = cimg::t_normal,
2094 *const t_yellow = cimg::t_normal, 2105 *const t_yellow = cimg::t_normal,
@@ -2114,30 +2125,68 @@ namespace cimg_library_suffixed { @@ -2114,30 +2125,68 @@ namespace cimg_library_suffixed {
2114 2125
2115 inline unsigned int& _exception_mode(const unsigned int value, const bool is_set) { 2126 inline unsigned int& _exception_mode(const unsigned int value, const bool is_set) {
2116 static unsigned int mode = cimg_verbosity; 2127 static unsigned int mode = cimg_verbosity;
2117 - cimg::mutex(0);  
2118 - if (is_set) mode = value;  
2119 - cimg::mutex(0,0); 2128 + if (is_set) { cimg::mutex(0); mode = value<4?value:4; cimg::mutex(0,0); }
2120 return mode; 2129 return mode;
2121 } 2130 }
2122 2131
2123 // Mandatory because Microsoft's _snprintf() and _vsnprintf() do not add the '\0' character 2132 // Mandatory because Microsoft's _snprintf() and _vsnprintf() do not add the '\0' character
2124 // at the end of the string. 2133 // at the end of the string.
2125 #if cimg_OS==2 && defined(_MSC_VER) 2134 #if cimg_OS==2 && defined(_MSC_VER)
2126 - inline int c99_vsnprintf(char* str, size_t size, const char* format, va_list ap) {  
2127 - int count = -1; 2135 + inline int _snprintf(char *const s, const size_t size, const char *const format, ...) {
  2136 + va_list ap;
  2137 + va_start(ap,format);
  2138 + const int result = _vsnprintf(s,size,format,ap);
  2139 + va_end(ap);
  2140 + return result;
  2141 + }
  2142 +
  2143 + inline int _vsnprintf(char *const s, const size_t size, const char *const format, va_list ap) {
  2144 + int result = -1;
2128 cimg::mutex(6); 2145 cimg::mutex(6);
2129 - if (size) count = _vsnprintf_s(str,size,_TRUNCATE,format,ap);  
2130 - if (count==-1) count = _vscprintf(format,ap); 2146 + if (size) result = _vsnprintf_s(s,size,_TRUNCATE,format,ap);
  2147 + if (result==-1) result = _vscprintf(format,ap);
2131 cimg::mutex(6,0); 2148 cimg::mutex(6,0);
2132 - return count; 2149 + return result;
2133 } 2150 }
2134 - inline int c99_snprintf(char* str, size_t size, const char* format, ...) {  
2135 - int count;  
2136 - va_list ap;  
2137 - va_start(ap, format);  
2138 - count = c99_vsnprintf(str,size,format,ap);  
2139 - va_end(ap);  
2140 - return count; 2151 +
  2152 + // Mutex-protected version of sscanf, sprintf and snprintf.
  2153 + // Used only MacOSX, as it seems those functions are not re-entrant on MacOSX.
  2154 +#elif defined(__MACOSX__) || defined(__APPLE__)
  2155 + inline int _sscanf(const char *const s, const char *const format, ...) {
  2156 + cimg::mutex(6);
  2157 + va_list args;
  2158 + va_start(args,format);
  2159 + const int result = std::vsscanf(s,format,args);
  2160 + va_end(args);
  2161 + cimg::mutex(6,0);
  2162 + return result;
  2163 + }
  2164 +
  2165 + inline int _sprintf(char *const s, const char *const format, ...) {
  2166 + cimg::mutex(6);
  2167 + va_list args;
  2168 + va_start(args,format);
  2169 + const int result = std::vsprintf(s,format,args);
  2170 + va_end(args);
  2171 + cimg::mutex(6,0);
  2172 + return result;
  2173 + }
  2174 +
  2175 + inline int _snprintf(char *const s, const size_t n, const char *const format, ...) {
  2176 + cimg::mutex(6);
  2177 + va_list args;
  2178 + va_start(args,format);
  2179 + const int result = std::vsnprintf(s,n,format,args);
  2180 + va_end(args);
  2181 + cimg::mutex(6,0);
  2182 + return result;
  2183 + }
  2184 +
  2185 + inline int _vsnprintf(char *const s, const size_t size, const char* format, va_list ap) {
  2186 + cimg::mutex(6);
  2187 + const int result = std::vsnprintf(s,size,format,ap);
  2188 + cimg::mutex(6,0);
  2189 + return result;
2141 } 2190 }
2142 #endif 2191 #endif
2143 2192
@@ -2163,6 +2212,31 @@ namespace cimg_library_suffixed { @@ -2163,6 +2212,31 @@ namespace cimg_library_suffixed {
2163 return _exception_mode(0,false); 2212 return _exception_mode(0,false);
2164 } 2213 }
2165 2214
  2215 + //! Set current \CImg openmp mode.
  2216 + /**
  2217 + The way openmp-based methods are handled by \CImg can be changed dynamically, using this function.
  2218 + \param mode Desired openmp mode. Possible values are:
  2219 + - \c 0: Never parallelize (quiet mode).
  2220 + - \c 1: Always parallelize.
  2221 + - \c 2: Adaptive parallelization mode (default behavior).
  2222 + **/
  2223 + inline unsigned int& _openmp_mode(const unsigned int value, const bool is_set) {
  2224 + static unsigned int mode = 2;
  2225 + if (is_set) { cimg::mutex(0); mode = value<2?value:2; cimg::mutex(0,0); }
  2226 + return mode;
  2227 + }
  2228 +
  2229 + inline unsigned int& openmp_mode(const unsigned int mode) {
  2230 + return _openmp_mode(mode,true);
  2231 + }
  2232 +
  2233 + //! Return current \CImg openmp mode.
  2234 + inline unsigned int& openmp_mode() {
  2235 + return _openmp_mode(0,false);
  2236 + }
  2237 +
  2238 +#define cimg_openmp_if(cond) if (cimg::openmp_mode()==1 || (cimg::openmp_mode()>1 && (cond)))
  2239 +
2166 // Display a simple dialog box, and wait for the user's response. 2240 // Display a simple dialog box, and wait for the user's response.
2167 inline int dialog(const char *const title, const char *const msg, const char *const button1_label="OK", 2241 inline int dialog(const char *const title, const char *const msg, const char *const button1_label="OK",
2168 const char *const button2_label=0, const char *const button3_label=0, 2242 const char *const button2_label=0, const char *const button3_label=0,
@@ -2172,6 +2246,7 @@ namespace cimg_library_suffixed { @@ -2172,6 +2246,7 @@ namespace cimg_library_suffixed {
2172 // Evaluate math expression. 2246 // Evaluate math expression.
2173 inline double eval(const char *const expression, 2247 inline double eval(const char *const expression,
2174 const double x=0, const double y=0, const double z=0, const double c=0); 2248 const double x=0, const double y=0, const double z=0, const double c=0);
  2249 +
2175 } 2250 }
2176 2251
2177 /*--------------------------------------- 2252 /*---------------------------------------
@@ -2183,9 +2258,12 @@ namespace cimg_library_suffixed { @@ -2183,9 +2258,12 @@ namespace cimg_library_suffixed {
2183 /** 2258 /**
2184 \par Overview 2259 \par Overview
2185 2260
2186 - CImgException is the base class of all exceptions thrown by \CImg. 2261 + CImgException is the base class of all exceptions thrown by \CImg (except \b CImgAbortException).
2187 CImgException is never thrown itself. Derived classes that specify the type of errord are thrown instead. 2262 CImgException is never thrown itself. Derived classes that specify the type of errord are thrown instead.
2188 - These derived classes can be: 2263 + These classes can be:
  2264 +
  2265 + - \b CImgAbortException: Thrown when a computationally-intensive function is aborted by an external signal.
  2266 + This is the only \c non-derived exception class.
2189 2267
2190 - \b CImgArgumentException: Thrown when one argument of a called \CImg function is invalid. 2268 - \b CImgArgumentException: Thrown when one argument of a called \CImg function is invalid.
2191 This is probably one of the most thrown exception by \CImg. 2269 This is probably one of the most thrown exception by \CImg.
@@ -2243,28 +2321,65 @@ namespace cimg_library_suffixed { @@ -2243,28 +2321,65 @@ namespace cimg_library_suffixed {
2243 **/ 2321 **/
2244 struct CImgException : public std::exception { 2322 struct CImgException : public std::exception {
2245 #define _cimg_exception_err(etype,disp_flag) \ 2323 #define _cimg_exception_err(etype,disp_flag) \
2246 - std::va_list ap; va_start(ap,format); cimg_vsnprintf(_message,16384,format,ap); va_end(ap); \  
2247 - if (cimg::exception_mode()) { \  
2248 - std::fprintf(cimg::output(),"\n%s[CImg] *** %s ***%s %s\n",cimg::t_red,etype,cimg::t_normal,_message); \  
2249 - if (cimg_display && disp_flag && !(cimg::exception_mode()%2)) try { cimg::dialog(etype,_message,"Abort"); } \  
2250 - catch (CImgException&) {} \  
2251 - if (cimg::exception_mode()>=3) cimg_library_suffixed::cimg::info(); \  
2252 - } 2324 + std::va_list ap, ap2; \
  2325 + va_start(ap,format); va_start(ap2,format); \
  2326 + int size = cimg_vsnprintf(0,0,format,ap2); \
  2327 + if (size++>=0) { \
  2328 + delete[] _message; \
  2329 + _message = new char[size]; \
  2330 + cimg_vsnprintf(_message,size,format,ap); \
  2331 + if (cimg::exception_mode()) { \
  2332 + std::fprintf(cimg::output(),"\n%s[CImg] *** %s ***%s %s\n",cimg::t_red,etype,cimg::t_normal,_message); \
  2333 + if (cimg_display && disp_flag && !(cimg::exception_mode()%2)) try { cimg::dialog(etype,_message,"Abort"); } \
  2334 + catch (CImgException&) {} \
  2335 + if (cimg::exception_mode()>=3) cimg_library_suffixed::cimg::info(); \
  2336 + } \
  2337 + } \
  2338 + va_end(ap); va_end(ap2); \
2253 2339
2254 char *_message; 2340 char *_message;
2255 - CImgException() { _message = new char[16384]; *_message = 0; }  
2256 - CImgException(const char *const format, ...) {  
2257 - _message = new char[16384]; *_message = 0; _cimg_exception_err("CImgException",true); 2341 + CImgException() { _message = new char[1]; *_message = 0; }
  2342 + CImgException(const char *const format, ...):_message(0) { _cimg_exception_err("CImgException",true); }
  2343 + CImgException(const CImgException& e) {
  2344 + const int size = std::strlen(e._message);
  2345 + _message = new char[size + 1];
  2346 + std::strncpy(_message,e._message,size);
  2347 + _message[size] = 0;
2258 } 2348 }
2259 ~CImgException() throw() { delete[] _message; } 2349 ~CImgException() throw() { delete[] _message; }
  2350 + CImgException& operator=(const CImgException& e) {
  2351 + const int size = std::strlen(e._message);
  2352 + _message = new char[size + 1];
  2353 + std::strncpy(_message,e._message,size);
  2354 + _message[size] = 0;
  2355 + return *this;
  2356 + }
2260 //! Return a C-string containing the error message associated to the thrown exception. 2357 //! Return a C-string containing the error message associated to the thrown exception.
2261 const char *what() const throw() { return _message; } 2358 const char *what() const throw() { return _message; }
2262 }; 2359 };
2263 2360
2264 - // The CImgInstanceException class is used to throw an exception related  
2265 - // to an invalid instance encountered in a library function call.  
2266 - struct CImgInstanceException : public CImgException {  
2267 - CImgInstanceException(const char *const format, ...) { _cimg_exception_err("CImgInstanceException",true); } 2361 + // The CImgAbortException class is used to throw an exception when
  2362 + // a computationally-intensive function has been aborted by an external signal.
  2363 + struct CImgAbortException : public std::exception {
  2364 + char *_message;
  2365 + CImgAbortException() { _message = new char[1]; *_message = 0; }
  2366 + CImgAbortException(const char *const format, ...):_message(0) { _cimg_exception_err("CImgAbortException",true); }
  2367 + CImgAbortException(const CImgAbortException& e) {
  2368 + const int size = std::strlen(e._message);
  2369 + _message = new char[size + 1];
  2370 + std::strncpy(_message,e._message,size);
  2371 + _message[size] = 0;
  2372 + }
  2373 + ~CImgAbortException() throw() { delete[] _message; }
  2374 + CImgAbortException& operator=(const CImgAbortException& e) {
  2375 + const int size = std::strlen(e._message);
  2376 + _message = new char[size + 1];
  2377 + std::strncpy(_message,e._message,size);
  2378 + _message[size] = 0;
  2379 + return *this;
  2380 + }
  2381 + //! Return a C-string containing the error message associated to the thrown exception.
  2382 + const char *what() const throw() { return _message; }
2268 }; 2383 };
2269 2384
2270 // The CImgArgumentException class is used to throw an exception related 2385 // The CImgArgumentException class is used to throw an exception related
@@ -2273,18 +2388,24 @@ namespace cimg_library_suffixed { @@ -2273,18 +2388,24 @@ namespace cimg_library_suffixed {
2273 CImgArgumentException(const char *const format, ...) { _cimg_exception_err("CImgArgumentException",true); } 2388 CImgArgumentException(const char *const format, ...) { _cimg_exception_err("CImgArgumentException",true); }
2274 }; 2389 };
2275 2390
2276 - // The CImgIOException class is used to throw an exception related  
2277 - // to input/output file problems encountered in a library function call.  
2278 - struct CImgIOException : public CImgException {  
2279 - CImgIOException(const char *const format, ...) { _cimg_exception_err("CImgIOException",true); }  
2280 - };  
2281 -  
2282 // The CImgDisplayException class is used to throw an exception related 2391 // The CImgDisplayException class is used to throw an exception related
2283 // to display problems encountered in a library function call. 2392 // to display problems encountered in a library function call.
2284 struct CImgDisplayException : public CImgException { 2393 struct CImgDisplayException : public CImgException {
2285 CImgDisplayException(const char *const format, ...) { _cimg_exception_err("CImgDisplayException",false); } 2394 CImgDisplayException(const char *const format, ...) { _cimg_exception_err("CImgDisplayException",false); }
2286 }; 2395 };
2287 2396
  2397 + // The CImgInstanceException class is used to throw an exception related
  2398 + // to an invalid instance encountered in a library function call.
  2399 + struct CImgInstanceException : public CImgException {
  2400 + CImgInstanceException(const char *const format, ...) { _cimg_exception_err("CImgInstanceException",true); }
  2401 + };
  2402 +
  2403 + // The CImgIOException class is used to throw an exception related
  2404 + // to input/output file problems encountered in a library function call.
  2405 + struct CImgIOException : public CImgException {
  2406 + CImgIOException(const char *const format, ...) { _cimg_exception_err("CImgIOException",true); }
  2407 + };
  2408 +
2288 // The CImgWarningException class is used to throw an exception for warnings 2409 // The CImgWarningException class is used to throw an exception for warnings
2289 // encountered in a library function call. 2410 // encountered in a library function call.
2290 struct CImgWarningException : public CImgException { 2411 struct CImgWarningException : public CImgException {
@@ -2497,10 +2618,22 @@ namespace cimg_library_suffixed { @@ -2497,10 +2618,22 @@ namespace cimg_library_suffixed {
2497 return !(val==val); 2618 return !(val==val);
2498 #endif 2619 #endif
2499 } 2620 }
2500 - static double min() { return -1.7E308; }  
2501 - static double max() { return 1.7E308; }  
2502 - static double inf() { return max()*max(); }  
2503 - static double nan() { const double val_nan = -std::sqrt(-1.0); return val_nan; } 2621 + static double min() { return -DBL_MAX; }
  2622 + static double max() { return DBL_MAX; }
  2623 + static double inf() {
  2624 +#ifdef INFINITY
  2625 + return (double)INFINITY;
  2626 +#else
  2627 + return max()*max();
  2628 +#endif
  2629 + }
  2630 + static double nan() {
  2631 +#ifdef NAN
  2632 + return (double)NAN;
  2633 +#else
  2634 + const double val_nan = -std::sqrt(-1.0); return val_nan;
  2635 +#endif
  2636 + }
2504 static double cut(const double val) { return val<min()?min():val>max()?max():val; } 2637 static double cut(const double val) { return val<min()?min():val>max()?max():val; }
2505 static const char* format() { return "%.16g"; } 2638 static const char* format() { return "%.16g"; }
2506 static double format(const double val) { return val; } 2639 static double format(const double val) { return val; }
@@ -2523,8 +2656,8 @@ namespace cimg_library_suffixed { @@ -2523,8 +2656,8 @@ namespace cimg_library_suffixed {
2523 return !(val==val); 2656 return !(val==val);
2524 #endif 2657 #endif
2525 } 2658 }
2526 - static float min() { return -3.4E38f; }  
2527 - static float max() { return 3.4E38f; } 2659 + static float min() { return -FLT_MAX; }
  2660 + static float max() { return FLT_MAX; }
2528 static float inf() { return (float)cimg::type<double>::inf(); } 2661 static float inf() { return (float)cimg::type<double>::inf(); }
2529 static float nan() { return (float)cimg::type<double>::nan(); } 2662 static float nan() { return (float)cimg::type<double>::nan(); }
2530 static float cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(float)val; } 2663 static float cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(float)val; }
@@ -2532,6 +2665,32 @@ namespace cimg_library_suffixed { @@ -2532,6 +2665,32 @@ namespace cimg_library_suffixed {
2532 static double format(const float val) { return (double)val; } 2665 static double format(const float val) { return (double)val; }
2533 }; 2666 };
2534 2667
  2668 + template<> struct type<long double> {
  2669 + static const char* string() { static const char *const s = "long double"; return s; }
  2670 + static bool is_float() { return true; }
  2671 + static bool is_inf(const long double val) {
  2672 +#ifdef isinf
  2673 + return (bool)isinf(val);
  2674 +#else
  2675 + return !is_nan(val) && (val<cimg::type<long double>::min() || val>cimg::type<long double>::max());
  2676 +#endif
  2677 + }
  2678 + static bool is_nan(const long double val) {
  2679 +#ifdef isnan
  2680 + return (bool)isnan(val);
  2681 +#else
  2682 + return !(val==val);
  2683 +#endif
  2684 + }
  2685 + static long double min() { return -LDBL_MAX; }
  2686 + static long double max() { return LDBL_MAX; }
  2687 + static long double inf() { return max()*max(); }
  2688 + static long double nan() { const long double val_nan = -std::sqrt(-1.0L); return val_nan; }
  2689 + static long double cut(const long double val) { return val<min()?min():val>max()?max():val; }
  2690 + static const char* format() { return "%.16g"; }
  2691 + static double format(const long double val) { return (double)val; }
  2692 + };
  2693 +
2535 template<typename T, typename t> struct superset { typedef T type; }; 2694 template<typename T, typename t> struct superset { typedef T type; };
2536 template<> struct superset<bool,unsigned char> { typedef unsigned char type; }; 2695 template<> struct superset<bool,unsigned char> { typedef unsigned char type; };
2537 template<> struct superset<bool,char> { typedef char type; }; 2696 template<> struct superset<bool,char> { typedef char type; };
@@ -3015,7 +3174,7 @@ namespace cimg_library_suffixed { @@ -3015,7 +3174,7 @@ namespace cimg_library_suffixed {
3015 const double PI = 3.14159265358979323846; //!< Value of the mathematical constant PI 3174 const double PI = 3.14159265358979323846; //!< Value of the mathematical constant PI
3016 3175
3017 // Define a 12x13 font (small size). 3176 // Define a 12x13 font (small size).
3018 - const char *const data_font12x13 = 3177 + static const char *const data_font12x13 =
3019 " .wjwlwmyuw>wjwkwbwjwkwRxuwmwjwkwmyuwJwjwlx`w Fw mwlwlwuwnwuynwuwmyTwlwkwuwmwuwnwlwkwuwmwuw_wuxl" 3178 " .wjwlwmyuw>wjwkwbwjwkwRxuwmwjwkwmyuwJwjwlx`w Fw mwlwlwuwnwuynwuwmyTwlwkwuwmwuwnwlwkwuwmwuw_wuxl"
3020 "wlwkwuwnwuynwuwTwlwlwtwnwtwnw my Qw +wlw b{ \\w Wx`xTw_w[wbxawSwkw nynwky<x1w `y ,w Xwuw CxlwiwlwmyuwbwuwUwiwlwbwiwrwqw^wuwmxuwnwiwlwmy" 3179 "wlwkwuwnwuynwuwTwlwlwtwnwtwnw my Qw +wlw b{ \\w Wx`xTw_w[wbxawSwkw nynwky<x1w `y ,w Xwuw CxlwiwlwmyuwbwuwUwiwlwbwiwrwqw^wuwmxuwnwiwlwmy"
3021 "uwJwiwlw^wnwEymymymymy1w^wkxnxtxnw<| gybwkwuwjwtwowmxswnxnwkxlxkw:wlymxlymykwn{myo{nymy2ykwqwqwm{myozn{o{mzpwrwpwkwkwswowkwqwqxswnyozlyozmzp}pwrwqwqwq" 3180 "uwJwiwlw^wnwEymymymymy1w^wkxnxtxnw<| gybwkwuwjwtwowmxswnxnwkxlxkw:wlymxlymykwn{myo{nymy2ykwqwqwm{myozn{o{mzpwrwpwkwkwswowkwqwqxswnyozlyozmzp}pwrwqwqwq"
@@ -3055,7 +3214,7 @@ namespace cimg_library_suffixed { @@ -3055,7 +3214,7 @@ namespace cimg_library_suffixed {
3055 "wlxm"; 3214 "wlxm";
3056 3215
3057 // Define a 20x23 font (normal size). 3216 // Define a 20x23 font (normal size).
3058 - const char *const data_font20x23 = 3217 + static const char *const data_font20x23 =
3059 " 9q\\q^r_rnp`qnq`plp7q\\q^q_qmqbq\\q^q_qmqHqmp_q\\q^r_rnp`qnq7q\\q^q_qmq_q \"r " 3218 " 9q\\q^r_rnp`qnq`plp7q\\q^q_qmqbq\\q^q_qmqHqmp_q\\q^r_rnp`qnq7q\\q^q_qmq_q \"r "
3060 " Mq^q^qnq`pnr`qnq`plp6q^q^pmp`qmqaq^q^pmp`qmqIpmq]q^q^qnq`pnr`qnq6q^q^pmp`qmq`q \"plp 'q 5qmq Vq " 3219 " Mq^q^qnq`pnr`qnq`plp6q^q^pmp`qmqaq^q^pmp`qmqIpmq]q^q^qnq`pnr`qnq6q^q^pmp`qmq`q \"plp 'q 5qmq Vq "
3061 " Xq [plp 3qYq_p^rnpLplp8qYq_qNqYq_q4rmpaqYq_q_rmp%qYq^pGq Irc|!pKp]raqjq`p HtNq_qmq\\plqbp_shpdscq[q^q[p [q]s_r`uau]rbv`tcxbua" 3220 " Xq [plp 3qYq_p^rnpLplp8qYq_qNqYq_q4rmpaqYq_q_rmp%qYq^pGq Irc|!pKp]raqjq`p HtNq_qmq\\plqbp_shpdscq[q^q[p [q]s_r`uau]rbv`tcxbua"
@@ -3123,7 +3282,7 @@ namespace cimg_library_suffixed { @@ -3123,7 +3282,7 @@ namespace cimg_library_suffixed {
3123 "r^q *q kr i"; 3282 "r^q *q kr i";
3124 3283
3125 // Define a 47x53 font (extra-large size). 3284 // Define a 47x53 font (extra-large size).
3126 - const char *const data_font47x53 = 3285 + static const char *const data_font47x53 =
3127 " " 3286 " "
3128 " 9])]2_2]T\\8^U^3] E])]2`4^U^>])]2_4^U^ 6^T\\5])]1_2]T\\8^U^ K])]2`4^V^3] " 3287 " 9])]2_2]T\\8^U^3] E])]2`4^U^>])]2_4^U^ 6^T\\5])]1_2]T\\8^U^ K])]2`4^V^3] "
3129 " U]*\\2a4`V\\8^U^5a F]*\\1\\X\\4^U^=]*\\" 3288 " U]*\\2a4`V\\8^U^5a F]*\\1\\X\\4^U^=]*\\"
@@ -3316,7 +3475,7 @@ namespace cimg_library_suffixed { @@ -3316,7 +3475,7 @@ namespace cimg_library_suffixed {
3316 " F]']2] +]']2^ D]']3_ E]']1] \"]']2^ 8] H"; 3475 " F]']2] +]']2^ D]']3_ E]']1] \"]']2^ 8] H";
3317 3476
3318 // Define a 90x103 font (huge size). 3477 // Define a 90x103 font (huge size).
3319 - const char *const _data_font90x103[] = { // Defined as an array to avoid MS compiler limit about constant string (65Kb). 3478 + static const char *const _data_font90x103[] = { // Defined as an array to avoid MS compiler limit about constant string (65Kb).
3320 // Start of first string. 3479 // Start of first string.
3321 " " 3480 " "
3322 " " 3481 " "
@@ -3856,7 +4015,7 @@ namespace cimg_library_suffixed { @@ -3856,7 +4015,7 @@ namespace cimg_library_suffixed {
3856 " D" }; 4015 " D" };
3857 4016
3858 // Define a 40x38 'danger' color logo (used by cimg::dialog()). 4017 // Define a 40x38 'danger' color logo (used by cimg::dialog()).
3859 - const unsigned char logo40x38[4576] = { 4018 + static const unsigned char logo40x38[4576] = {
3860 177,200,200,200,3,123,123,0,36,200,200,200,1,123,123,0,2,255,255,0,1,189,189,189,1,0,0,0,34,200,200,200, 4019 177,200,200,200,3,123,123,0,36,200,200,200,1,123,123,0,2,255,255,0,1,189,189,189,1,0,0,0,34,200,200,200,
3861 1,123,123,0,4,255,255,0,1,189,189,189,1,0,0,0,1,123,123,123,32,200,200,200,1,123,123,0,5,255,255,0,1,0,0, 4020 1,123,123,0,4,255,255,0,1,189,189,189,1,0,0,0,1,123,123,123,32,200,200,200,1,123,123,0,5,255,255,0,1,0,0,
3862 0,2,123,123,123,30,200,200,200,1,123,123,0,6,255,255,0,1,189,189,189,1,0,0,0,2,123,123,123,29,200,200,200, 4021 0,2,123,123,123,30,200,200,200,1,123,123,0,6,255,255,0,1,189,189,189,1,0,0,0,2,123,123,123,29,200,200,200,
@@ -3882,23 +4041,6 @@ namespace cimg_library_suffixed { @@ -3882,23 +4041,6 @@ namespace cimg_library_suffixed {
3882 0,4,123,123,123,10,200,200,200,1,123,123,0,24,0,0,0,5,123,123,123,12,200,200,200,27,123,123,123,14,200,200,200,25, 4041 0,4,123,123,123,10,200,200,200,1,123,123,0,24,0,0,0,5,123,123,123,12,200,200,200,27,123,123,123,14,200,200,200,25,
3883 123,123,123,86,200,200,200,91,49,124,118,124,71,32,124,95,49,56,114,52,82,121,0 }; 4042 123,123,123,86,200,200,200,91,49,124,118,124,71,32,124,95,49,56,114,52,82,121,0 };
3884 4043
3885 - // Mutex-protected version of sscanf.  
3886 - // Used only MacOSX, as it seems std::sscanf() is not re-entrant on MacOSX.  
3887 -#if (__MACOSX__) || defined(__APPLE__)  
3888 -#define cimg_sscanf cimg::_sscanf  
3889 - inline int _sscanf(const char *s, const char *format, ...) {  
3890 - cimg::mutex(13);  
3891 - va_list args;  
3892 - va_start(args, format);  
3893 - const int result = std::vsscanf(s,format,args);  
3894 - va_end(args);  
3895 - cimg::mutex(13,0);  
3896 - return result;  
3897 - }  
3898 -#else  
3899 -#define cimg_sscanf std::sscanf  
3900 -#endif  
3901 -  
3902 //! Get/set default output stream for the \CImg library messages. 4044 //! Get/set default output stream for the \CImg library messages.
3903 /** 4045 /**
3904 \param file Desired output stream. Set to \c 0 to get the currently used output stream only. 4046 \param file Desired output stream. Set to \c 0 to get the currently used output stream only.
@@ -3980,7 +4122,7 @@ namespace cimg_library_suffixed { @@ -3980,7 +4122,7 @@ namespace cimg_library_suffixed {
3980 return -1; 4122 return -1;
3981 #else 4123 #else
3982 #if cimg_OS==1 4124 #if cimg_OS==1
3983 - const unsigned int l = std::strlen(command); 4125 + const unsigned int l = (unsigned int)std::strlen(command);
3984 if (l) { 4126 if (l) {
3985 char *const ncommand = new char[l + 16]; 4127 char *const ncommand = new char[l + 16];
3986 std::strncpy(ncommand,command,l); 4128 std::strncpy(ncommand,command,l);
@@ -4243,8 +4385,9 @@ namespace cimg_library_suffixed { @@ -4243,8 +4385,9 @@ namespace cimg_library_suffixed {
4243 _rand(seed,true); 4385 _rand(seed,true);
4244 } 4386 }
4245 4387
4246 - inline double rand() {  
4247 - return cimg::_rand()/16777215.; 4388 + inline double rand(const double val_min, const double val_max) {
  4389 + const double val = cimg::_rand()/16777215.;
  4390 + return val_min + (val_max - val_min)*val;
4248 } 4391 }
4249 4392
4250 #else 4393 #else
@@ -4265,19 +4408,20 @@ namespace cimg_library_suffixed { @@ -4265,19 +4408,20 @@ namespace cimg_library_suffixed {
4265 std::srand(seed); 4408 std::srand(seed);
4266 } 4409 }
4267 4410
4268 - //! Return a random variable between [0,1] with respect to an uniform distribution. 4411 + //! Return a random variable uniformely distributed between [val_min,val_max].
4269 /** 4412 /**
4270 **/ 4413 **/
4271 - inline double rand() {  
4272 - return (double)std::rand()/RAND_MAX; 4414 + inline double rand(const double val_min, const double val_max) {
  4415 + const double val = (double)std::rand()/RAND_MAX;
  4416 + return val_min + (val_max - val_min)*val;
4273 } 4417 }
4274 #endif 4418 #endif
4275 4419
4276 - //! Return a random variable between [-1,1] with respect to an uniform distribution. 4420 + //! Return a random variable uniformely distributed between [0,val_max].
4277 /** 4421 /**
4278 - **/  
4279 - inline double crand() {  
4280 - return 1 - 2*cimg::rand(); 4422 + **/
  4423 + inline double rand(const double val_max=1) {
  4424 + return cimg::rand(0,val_max);
4281 } 4425 }
4282 4426
4283 //! Return a random variable following a gaussian distribution and a standard deviation of 1. 4427 //! Return a random variable following a gaussian distribution and a standard deviation of 1.
@@ -4286,8 +4430,8 @@ namespace cimg_library_suffixed { @@ -4286,8 +4430,8 @@ namespace cimg_library_suffixed {
4286 inline double grand() { 4430 inline double grand() {
4287 double x1, w; 4431 double x1, w;
4288 do { 4432 do {
4289 - const double x2 = 2*cimg::rand() - 1.0;  
4290 - x1 = 2*cimg::rand() - 1.0; 4433 + const double x2 = cimg::rand(-1,1);
  4434 + x1 = cimg::rand(-1,1);
4291 w = x1*x1 + x2*x2; 4435 w = x1*x1 + x2*x2;
4292 } while (w<=0 || w>=1.0); 4436 } while (w<=0 || w>=1.0);
4293 return x1*std::sqrt((-2*std::log(w))/w); 4437 return x1*std::sqrt((-2*std::log(w))/w);
@@ -4319,6 +4463,10 @@ namespace cimg_library_suffixed { @@ -4319,6 +4463,10 @@ namespace cimg_library_suffixed {
4319 return (double)rol((long)a,n); 4463 return (double)rol((long)a,n);
4320 } 4464 }
4321 4465
  4466 + inline double rol(const long double a, const unsigned int n=1) {
  4467 + return (double)rol((long)a,n);
  4468 + }
  4469 +
4322 //! Bitwise-rotate value on the right. 4470 //! Bitwise-rotate value on the right.
4323 template<typename T> 4471 template<typename T>
4324 inline T ror(const T& a, const unsigned int n=1) { 4472 inline T ror(const T& a, const unsigned int n=1) {
@@ -4333,6 +4481,10 @@ namespace cimg_library_suffixed { @@ -4333,6 +4481,10 @@ namespace cimg_library_suffixed {
4333 return (double)ror((long)a,n); 4481 return (double)ror((long)a,n);
4334 } 4482 }
4335 4483
  4484 + inline double ror(const long double a, const unsigned int n=1) {
  4485 + return (double)ror((long)a,n);
  4486 + }
  4487 +
4336 //! Return absolute value of a value. 4488 //! Return absolute value of a value.
4337 template<typename T> 4489 template<typename T>
4338 inline T abs(const T& a) { 4490 inline T abs(const T& a) {
@@ -4515,11 +4667,12 @@ namespace cimg_library_suffixed { @@ -4515,11 +4667,12 @@ namespace cimg_library_suffixed {
4515 else { const double tmp = absa/absb; return absb==0?0:absb*std::sqrt(1.0 + tmp*tmp); } 4667 else { const double tmp = absa/absb; return absb==0?0:absb*std::sqrt(1.0 + tmp*tmp); }
4516 } 4668 }
4517 4669
4518 - inline bool _is_self_expr(const char *expression) {  
4519 - if (!expression || *expression=='>' || *expression=='<') return false;  
4520 - for (const char *s = expression; *s; ++s)  
4521 - if ((*s=='i' || *s=='j') && (s[1]=='(' || s[1]=='[')) return true;  
4522 - return false; 4670 + //! Return sqrt(x^2 + y^2).
  4671 + inline double hypot(const double x, const double y) {
  4672 + double nx = cimg::abs(x), ny = cimg::abs(y), t;
  4673 + if (nx<ny) { t = nx; nx = ny; } else t = ny;
  4674 + if (nx>0) { t/=nx; return nx*std::sqrt(1+t*t); }
  4675 + return 0;
4523 } 4676 }
4524 4677
4525 //! Convert ascii character to lower case. 4678 //! Convert ascii character to lower case.
@@ -4575,6 +4728,51 @@ namespace cimg_library_suffixed { @@ -4575,6 +4728,51 @@ namespace cimg_library_suffixed {
4575 return cimg::strncasecmp(str1,str2,1 + (l1<l2?l1:l2)); 4728 return cimg::strncasecmp(str1,str2,1 + (l1<l2?l1:l2));
4576 } 4729 }
4577 4730
  4731 + //! Ellipsize a string.
  4732 + /**
  4733 + \param str C-string.
  4734 + \param l Max number of characters.
  4735 + \param is_ending Tell if the dots are placed at the end or at the center of the ellipsized string.
  4736 + **/
  4737 + inline char *strellipsize(char *const str, const unsigned int l=64,
  4738 + const bool is_ending=true) {
  4739 + if (!str) return str;
  4740 + const unsigned int nl = l<5?5:l, ls = (unsigned int)std::strlen(str);
  4741 + if (ls<=nl) return str;
  4742 + if (is_ending) std::strcpy(str + nl - 5,"(...)");
  4743 + else {
  4744 + const unsigned int ll = (nl - 5)/2 + 1 - (nl%2), lr = nl - ll - 5;
  4745 + std::strcpy(str + ll,"(...)");
  4746 + std::memmove(str + ll + 5,str + ls - lr,lr);
  4747 + }
  4748 + str[nl] = 0;
  4749 + return str;
  4750 + }
  4751 +
  4752 + //! Ellipsize a string.
  4753 + /**
  4754 + \param str C-string.
  4755 + \param res output C-string.
  4756 + \param l Max number of characters.
  4757 + \param is_ending Tell if the dots are placed at the end or at the center of the ellipsized string.
  4758 + **/
  4759 + inline char *strellipsize(const char *const str, char *const res, const unsigned int l=64,
  4760 + const bool is_ending=true) {
  4761 + const unsigned int nl = l<5?5:l, ls = (unsigned int)std::strlen(str);
  4762 + if (ls<=nl) { std::strcpy(res,str); return res; }
  4763 + if (is_ending) {
  4764 + std::strncpy(res,str,nl - 5);
  4765 + std::strcpy(res + nl -5,"(...)");
  4766 + } else {
  4767 + const unsigned int ll = (nl - 5)/2 + 1 - (nl%2), lr = nl - ll - 5;
  4768 + std::strncpy(res,str,ll);
  4769 + std::strcpy(res + ll,"(...)");
  4770 + std::strncpy(res + ll + 5,str + ls - lr,lr);
  4771 + }
  4772 + res[nl] = 0;
  4773 + return res;
  4774 + }
  4775 +
4578 //! Remove delimiters on the start and/or end of a C-string. 4776 //! Remove delimiters on the start and/or end of a C-string.
4579 /** 4777 /**
4580 \param[in,out] str C-string to work with (modified at output). 4778 \param[in,out] str C-string to work with (modified at output).
@@ -4638,7 +4836,7 @@ namespace cimg_library_suffixed { @@ -4638,7 +4836,7 @@ namespace cimg_library_suffixed {
4638 *nd = (char)val; break; 4836 *nd = (char)val; break;
4639 case 'x' : 4837 case 'x' :
4640 cimg_sscanf(++ns,"%x",&val); 4838 cimg_sscanf(++ns,"%x",&val);
4641 - while ((*ns>='0' && *ns<='7') || (*ns>='a' && *ns<='f') || (*ns>='A' && *ns<='F')) ++ns; 4839 + while ((*ns>='0' && *ns<='9') || (*ns>='a' && *ns<='f') || (*ns>='A' && *ns<='F')) ++ns;
4642 *nd = (char)val; break; 4840 *nd = (char)val; break;
4643 default : *nd = *(ns++); 4841 default : *nd = *(ns++);
4644 } else *nd = *(ns++); 4842 } else *nd = *(ns++);
@@ -4650,20 +4848,20 @@ namespace cimg_library_suffixed { @@ -4650,20 +4848,20 @@ namespace cimg_library_suffixed {
4650 // Return string that identifies the running OS. 4848 // Return string that identifies the running OS.
4651 inline const char *stros() { 4849 inline const char *stros() {
4652 #if defined(linux) || defined(__linux) || defined(__linux__) 4850 #if defined(linux) || defined(__linux) || defined(__linux__)
4653 - const char *const str = "Linux"; 4851 + static const char *const str = "Linux";
4654 #elif defined(sun) || defined(__sun) 4852 #elif defined(sun) || defined(__sun)
4655 - const char *const str = "Sun OS"; 4853 + static const char *const str = "Sun OS";
4656 #elif defined(BSD) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined (__DragonFly__) 4854 #elif defined(BSD) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined (__DragonFly__)
4657 - const char *const str = "BSD"; 4855 + static const char *const str = "BSD";
4658 #elif defined(sgi) || defined(__sgi) 4856 #elif defined(sgi) || defined(__sgi)
4659 - const char *const str = "Irix"; 4857 + static const char *const str = "Irix";
4660 #elif defined(__MACOSX__) || defined(__APPLE__) 4858 #elif defined(__MACOSX__) || defined(__APPLE__)
4661 - const char *const str = "Mac OS"; 4859 + static const char *const str = "Mac OS";
4662 #elif defined(unix) || defined(__unix) || defined(__unix__) 4860 #elif defined(unix) || defined(__unix) || defined(__unix__)
4663 - const char *const str = "Generic Unix"; 4861 + static const char *const str = "Generic Unix";
4664 #elif defined(_MSC_VER) || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || \ 4862 #elif defined(_MSC_VER) || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || \
4665 defined(WIN64) || defined(_WIN64) || defined(__WIN64__) 4863 defined(WIN64) || defined(_WIN64) || defined(__WIN64__)
4666 - const char *const str = "Windows"; 4864 + static const char *const str = "Windows";
4667 #else 4865 #else
4668 const char 4866 const char
4669 *const _str1 = std::getenv("OSTYPE"), 4867 *const _str1 = std::getenv("OSTYPE"),
@@ -4683,11 +4881,12 @@ namespace cimg_library_suffixed { @@ -4683,11 +4881,12 @@ namespace cimg_library_suffixed {
4683 // Return a random filename. 4881 // Return a random filename.
4684 inline const char* filenamerand() { 4882 inline const char* filenamerand() {
4685 cimg::mutex(6); 4883 cimg::mutex(6);
4686 - static char randomid[9] = { 0 }; 4884 + static char randomid[9];
4687 cimg::srand(); 4885 cimg::srand();
4688 for (unsigned int k = 0; k<8; ++k) { 4886 for (unsigned int k = 0; k<8; ++k) {
4689 - const int v = (int)std::rand()%3;  
4690 - randomid[k] = (char)(v==0?('0' + (std::rand()%10)):(v==1?('a' + (std::rand()%26)):('A' + (std::rand()%26)))); 4887 + const int v = (int)cimg::rand(65535)%3;
  4888 + randomid[k] = (char)(v==0?('0' + ((int)cimg::rand(65535)%10)):
  4889 + (v==1?('a' + ((int)cimg::rand(65535)%26)):('A' + ((int)cimg::rand(65535)%26))));
4691 } 4890 }
4692 cimg::mutex(6,0); 4891 cimg::mutex(6,0);
4693 return randomid; 4892 return randomid;
@@ -4815,7 +5014,7 @@ namespace cimg_library_suffixed { @@ -4815,7 +5014,7 @@ namespace cimg_library_suffixed {
4815 Can be { 0=year | 1=month | 2=day | 3=day of week | 4=hour | 5=minute | 6=second } 5014 Can be { 0=year | 1=month | 2=day | 3=day of week | 4=hour | 5=minute | 6=second }
4816 **/ 5015 **/
4817 inline int date(const unsigned int attr) { 5016 inline int date(const unsigned int attr) {
4818 - int res = -1; 5017 + int res;
4819 cimg::mutex(6); 5018 cimg::mutex(6);
4820 #if cimg_OS==2 5019 #if cimg_OS==2
4821 SYSTEMTIME st; 5020 SYSTEMTIME st;
@@ -4892,7 +5091,7 @@ namespace cimg_library_suffixed { @@ -4892,7 +5091,7 @@ namespace cimg_library_suffixed {
4892 const char *const ext = cimg::split_filename(filename,body); 5091 const char *const ext = cimg::split_filename(filename,body);
4893 if (*ext) cimg_snprintf(format,1024,"%%s_%%.%ud.%%s",digits); 5092 if (*ext) cimg_snprintf(format,1024,"%%s_%%.%ud.%%s",digits);
4894 else cimg_snprintf(format,1024,"%%s_%%.%ud",digits); 5093 else cimg_snprintf(format,1024,"%%s_%%.%ud",digits);
4895 - std::sprintf(str,format,body,number,ext); 5094 + cimg_sprintf(str,format,body,number,ext);
4896 delete[] format; delete[] body; 5095 delete[] format; delete[] body;
4897 return str; 5096 return str;
4898 } 5097 }
@@ -4970,7 +5169,8 @@ namespace cimg_library_suffixed { @@ -4970,7 +5169,8 @@ namespace cimg_library_suffixed {
4970 5169
4971 // Load file from network as a local temporary file. 5170 // Load file from network as a local temporary file.
4972 inline char *load_network(const char *const url, char *const filename_local, 5171 inline char *load_network(const char *const url, char *const filename_local,
4973 - const unsigned int timeout=0, const bool try_fallback=false); 5172 + const unsigned int timeout=0, const bool try_fallback=false,
  5173 + const char *const referer=0);
4974 5174
4975 //! Return options specified on the command line. 5175 //! Return options specified on the command line.
4976 inline const char* option(const char *const name, const int argc, const char *const *const argv, 5176 inline const char* option(const char *const name, const int argc, const char *const *const argv,
@@ -5033,8 +5233,8 @@ namespace cimg_library_suffixed { @@ -5033,8 +5233,8 @@ namespace cimg_library_suffixed {
5033 const char defaut, const char *const usage=0) { 5233 const char defaut, const char *const usage=0) {
5034 const char *const s = cimg::option(name,argc,argv,(char*)0); 5234 const char *const s = cimg::option(name,argc,argv,(char*)0);
5035 const char res = s?*s:defaut; 5235 const char res = s?*s:defaut;
5036 - char tmp[8] = { 0 };  
5037 - *tmp = res; 5236 + char tmp[8];
  5237 + *tmp = res; tmp[1] = 0;
5038 cimg::option(name,0,0,tmp,usage); 5238 cimg::option(name,0,0,tmp,usage);
5039 return res; 5239 return res;
5040 } 5240 }
@@ -5061,25 +5261,6 @@ namespace cimg_library_suffixed { @@ -5061,25 +5261,6 @@ namespace cimg_library_suffixed {
5061 return res; 5261 return res;
5062 } 5262 }
5063 5263
5064 - inline const char* argument(const unsigned int nb, const int argc, const char *const *const argv,  
5065 - const unsigned int nb_singles=0, ...) {  
5066 - for (int k = 1, pos = 0; k<argc;) {  
5067 - const char *const item = argv[k];  
5068 - bool option = (*item=='-'), single_option = false;  
5069 - if (option) {  
5070 - va_list ap;  
5071 - va_start(ap,nb_singles);  
5072 - for (unsigned int i = 0; i<nb_singles; ++i) if (!cimg::strcasecmp(item,va_arg(ap,char*))) {  
5073 - single_option = true; break;  
5074 - }  
5075 - va_end(ap);  
5076 - }  
5077 - if (option) { ++k; if (!single_option) ++k; }  
5078 - else { if (pos++==(int)nb) return item; else ++k; }  
5079 - }  
5080 - return 0;  
5081 - }