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 - }  
5082 -  
5083 //! Print information about \CImg environement variables. 5264 //! Print information about \CImg environement variables.
5084 /** 5265 /**
5085 \note Output is done on the default output stream. 5266 \note Output is done on the default output stream.
@@ -5372,6 +5553,7 @@ namespace cimg_library_suffixed { @@ -5372,6 +5553,7 @@ namespace cimg_library_suffixed {
5372 _cimg_create_ext_operators(long) 5553 _cimg_create_ext_operators(long)
5373 _cimg_create_ext_operators(float) 5554 _cimg_create_ext_operators(float)
5374 _cimg_create_ext_operators(double) 5555 _cimg_create_ext_operators(double)
  5556 + _cimg_create_ext_operators(long double)
5375 5557
5376 template<typename T> 5558 template<typename T>
5377 inline CImg<_cimg_Tfloat> operator+(const char *const expression, const CImg<T>& img) { 5559 inline CImg<_cimg_Tfloat> operator+(const char *const expression, const CImg<T>& img) {
@@ -5380,7 +5562,7 @@ namespace cimg_library_suffixed { @@ -5380,7 +5562,7 @@ namespace cimg_library_suffixed {
5380 5562
5381 template<typename T> 5563 template<typename T>
5382 inline CImg<_cimg_Tfloat> operator-(const char *const expression, const CImg<T>& img) { 5564 inline CImg<_cimg_Tfloat> operator-(const char *const expression, const CImg<T>& img) {
5383 - return CImg<_cimg_Tfloat>(img._width,img._height,img._depth,img._spectrum,expression,true)-=img; 5565 + return CImg<_cimg_Tfloat>(img,false).fill(expression,true)-=img;
5384 } 5566 }
5385 5567
5386 template<typename T> 5568 template<typename T>
@@ -5410,12 +5592,12 @@ namespace cimg_library_suffixed { @@ -5410,12 +5592,12 @@ namespace cimg_library_suffixed {
5410 5592
5411 template<typename T> 5593 template<typename T>
5412 inline bool operator==(const char *const expression, const CImg<T>& img) { 5594 inline bool operator==(const char *const expression, const CImg<T>& img) {
5413 - return img == expression; 5595 + return img==expression;
5414 } 5596 }
5415 5597
5416 template<typename T> 5598 template<typename T>
5417 inline bool operator!=(const char *const expression, const CImg<T>& img) { 5599 inline bool operator!=(const char *const expression, const CImg<T>& img) {
5418 - return img != expression; 5600 + return img!=expression;
5419 } 5601 }
5420 5602
5421 template<typename T> 5603 template<typename T>
@@ -5528,7 +5710,7 @@ namespace cimg_library_suffixed { @@ -5528,7 +5710,7 @@ namespace cimg_library_suffixed {
5528 # Define the CImgDisplay structure 5710 # Define the CImgDisplay structure
5529 # 5711 #
5530 ----------------------------------*/ 5712 ----------------------------------*/
5531 - //! Allow to create windows, display images on them and manage user events (keyboard, mouse and windows events). 5713 + //! Allow the creation of windows, display images on them and manage user events (keyboard, mouse and windows events).
5532 /** 5714 /**
5533 CImgDisplay methods rely on a low-level graphic library to perform: it can be either \b X-Window 5715 CImgDisplay methods rely on a low-level graphic library to perform: it can be either \b X-Window
5534 (X11, for Unix-based systems) or \b GDI32 (for Windows-based systems). 5716 (X11, for Unix-based systems) or \b GDI32 (for Windows-based systems).
@@ -5802,6 +5984,12 @@ namespace cimg_library_suffixed { @@ -5802,6 +5984,12 @@ namespace cimg_library_suffixed {
5802 return _empty.assign(); 5984 return _empty.assign();
5803 } 5985 }
5804 5986
  5987 + //! Return a reference to an empty display \const.
  5988 + static const CImgDisplay& const_empty() {
  5989 + static const CImgDisplay _empty;
  5990 + return _empty;
  5991 + }
  5992 +
5805 #define cimg_fitscreen(dx,dy,dz) CImgDisplay::_fitscreen(dx,dy,dz,128,-85,false), \ 5993 #define cimg_fitscreen(dx,dy,dz) CImgDisplay::_fitscreen(dx,dy,dz,128,-85,false), \
5806 CImgDisplay::_fitscreen(dx,dy,dz,128,-85,true) 5994 CImgDisplay::_fitscreen(dx,dy,dz,128,-85,true)
5807 static unsigned int _fitscreen(const unsigned int dx, const unsigned int dy, const unsigned int dz, 5995 static unsigned int _fitscreen(const unsigned int dx, const unsigned int dy, const unsigned int dz,
@@ -6191,7 +6379,7 @@ namespace cimg_library_suffixed { @@ -6191,7 +6379,7 @@ namespace cimg_library_suffixed {
6191 in fullscreen mode. 6379 in fullscreen mode.
6192 **/ 6380 **/
6193 const char *title() const { 6381 const char *title() const {
6194 - return _title; 6382 + return _title?_title:"";
6195 } 6383 }
6196 6384
6197 //! Return width of the associated window. 6385 //! Return width of the associated window.
@@ -7136,7 +7324,7 @@ namespace cimg_library_suffixed { @@ -7136,7 +7324,7 @@ namespace cimg_library_suffixed {
7136 XEvent event; 7324 XEvent event;
7137 pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,0); 7325 pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,0);
7138 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,0); 7326 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,0);
7139 - if (!arg) for (;;) { 7327 + if (!arg) for ( ; ; ) {
7140 cimg_lock_display(); 7328 cimg_lock_display();
7141 bool event_flag = XCheckTypedEvent(dpy,ClientMessage,&event); 7329 bool event_flag = XCheckTypedEvent(dpy,ClientMessage,&event);
7142 if (!event_flag) event_flag = XCheckMaskEvent(dpy, 7330 if (!event_flag) event_flag = XCheckMaskEvent(dpy,
@@ -7397,7 +7585,7 @@ namespace cimg_library_suffixed { @@ -7397,7 +7585,7 @@ namespace cimg_library_suffixed {
7397 7585
7398 // Allocate space for window title 7586 // Allocate space for window title
7399 const char *const nptitle = ptitle?ptitle:""; 7587 const char *const nptitle = ptitle?ptitle:"";
7400 - const unsigned int s = std::strlen(nptitle) + 1; 7588 + const unsigned int s = (unsigned int)std::strlen(nptitle) + 1;
7401 char *const tmp_title = s?new char[s]:0; 7589 char *const tmp_title = s?new char[s]:0;
7402 if (s) std::memcpy(tmp_title,nptitle,s*sizeof(char)); 7590 if (s) std::memcpy(tmp_title,nptitle,s*sizeof(char));
7403 7591
@@ -7535,7 +7723,7 @@ namespace cimg_library_suffixed { @@ -7535,7 +7723,7 @@ namespace cimg_library_suffixed {
7535 // Remove display window from event thread list. 7723 // Remove display window from event thread list.
7536 unsigned int i; 7724 unsigned int i;
7537 for (i = 0; i<cimg::X11_attr().nb_wins && cimg::X11_attr().wins[i]!=this; ++i) {} 7725 for (i = 0; i<cimg::X11_attr().nb_wins && cimg::X11_attr().wins[i]!=this; ++i) {}
7538 - for (; i<cimg::X11_attr().nb_wins - 1; ++i) cimg::X11_attr().wins[i] = cimg::X11_attr().wins[i + 1]; 7726 + for ( ; i<cimg::X11_attr().nb_wins - 1; ++i) cimg::X11_attr().wins[i] = cimg::X11_attr().wins[i + 1];
7539 --cimg::X11_attr().nb_wins; 7727 --cimg::X11_attr().nb_wins;
7540 7728
7541 // Destroy window, image, colormap and title. 7729 // Destroy window, image, colormap and title.
@@ -7630,24 +7818,27 @@ namespace cimg_library_suffixed { @@ -7630,24 +7818,27 @@ namespace cimg_library_suffixed {
7630 tmpdimy = (nheight>0)?nheight:(-nheight*height()/100), 7818 tmpdimy = (nheight>0)?nheight:(-nheight*height()/100),
7631 dimx = tmpdimx?tmpdimx:1, 7819 dimx = tmpdimx?tmpdimx:1,
7632 dimy = tmpdimy?tmpdimy:1; 7820 dimy = tmpdimy?tmpdimy:1;
7633 - cimg_lock_display();  
7634 - if (_window_width!=dimx || _window_height!=dimy) {  
7635 - XWindowAttributes attr;  
7636 - for (unsigned int i = 0; i<10; ++i) {  
7637 - XResizeWindow(dpy,_window,dimx,dimy);  
7638 - XGetWindowAttributes(dpy,_window,&attr);  
7639 - if (attr.width==(int)dimx && attr.height==(int)dimy) break;  
7640 - cimg::wait(5); 7821 + if (_width!=dimx || _height!=dimy || _window_width!=dimx || _window_height!=dimy) {
  7822 + show();
  7823 + cimg_lock_display();
  7824 + if (_window_width!=dimx || _window_height!=dimy) {
  7825 + XWindowAttributes attr;
  7826 + for (unsigned int i = 0; i<10; ++i) {
  7827 + XResizeWindow(dpy,_window,dimx,dimy);
  7828 + XGetWindowAttributes(dpy,_window,&attr);
  7829 + if (attr.width==(int)dimx && attr.height==(int)dimy) break;
  7830 + cimg::wait(5);
  7831 + }
7641 } 7832 }
  7833 + if (_width!=dimx || _height!=dimy) switch (cimg::X11_attr().nb_bits) {
  7834 + case 8 : { unsigned char pixel_type = 0; _resize(pixel_type,dimx,dimy,force_redraw); } break;
  7835 + case 16 : { unsigned short pixel_type = 0; _resize(pixel_type,dimx,dimy,force_redraw); } break;
  7836 + default : { unsigned int pixel_type = 0; _resize(pixel_type,dimx,dimy,force_redraw); }
  7837 + }
  7838 + _window_width = _width = dimx; _window_height = _height = dimy;
  7839 + cimg_unlock_display();
7642 } 7840 }
7643 - if (_width!=dimx || _height!=dimy) switch (cimg::X11_attr().nb_bits) {  
7644 - case 8 : { unsigned char pixel_type = 0; _resize(pixel_type,dimx,dimy,force_redraw); } break;  
7645 - case 16 : { unsigned short pixel_type = 0; _resize(pixel_type,dimx,dimy,force_redraw); } break;  
7646 - default : { unsigned int pixel_type = 0; _resize(pixel_type,dimx,dimy,force_redraw); }  
7647 - }  
7648 - _window_width = _width = dimx; _window_height = _height = dimy;  
7649 _is_resized = false; 7841 _is_resized = false;
7650 - cimg_unlock_display();  
7651 if (_is_fullscreen) move((screen_width() - _width)/2,(screen_height() - _height)/2); 7842 if (_is_fullscreen) move((screen_width() - _width)/2,(screen_height() - _height)/2);
7652 if (force_redraw) return paint(); 7843 if (force_redraw) return paint();
7653 return *this; 7844 return *this;
@@ -7692,13 +7883,15 @@ namespace cimg_library_suffixed { @@ -7692,13 +7883,15 @@ namespace cimg_library_suffixed {
7692 7883
7693 CImgDisplay& move(const int posx, const int posy) { 7884 CImgDisplay& move(const int posx, const int posy) {
7694 if (is_empty()) return *this; 7885 if (is_empty()) return *this;
7695 - show();  
7696 - Display *const dpy = cimg::X11_attr().display;  
7697 - cimg_lock_display();  
7698 - XMoveWindow(dpy,_window,posx,posy);  
7699 - _window_x = posx; _window_y = posy; 7886 + if (_window_x!=posx || _window_y!=posy) {
  7887 + show();
  7888 + Display *const dpy = cimg::X11_attr().display;
  7889 + cimg_lock_display();
  7890 + XMoveWindow(dpy,_window,posx,posy);
  7891 + _window_x = posx; _window_y = posy;
  7892 + cimg_unlock_display();
  7893 + }
7700 _is_moved = false; 7894 _is_moved = false;
7701 - cimg_unlock_display();  
7702 return paint(); 7895 return paint();
7703 } 7896 }
7704 7897
@@ -7715,7 +7908,7 @@ namespace cimg_library_suffixed { @@ -7715,7 +7908,7 @@ namespace cimg_library_suffixed {
7715 if (is_empty()) return *this; 7908 if (is_empty()) return *this;
7716 Display *const dpy = cimg::X11_attr().display; 7909 Display *const dpy = cimg::X11_attr().display;
7717 cimg_lock_display(); 7910 cimg_lock_display();
7718 - const char pix_data[8] = { 0 }; 7911 + static const char pix_data[8] = { 0 };
7719 XColor col; 7912 XColor col;
7720 col.red = col.green = col.blue = 0; 7913 col.red = col.green = col.blue = 0;
7721 Pixmap pix = XCreateBitmapFromData(dpy,_window,pix_data,8,8); 7914 Pixmap pix = XCreateBitmapFromData(dpy,_window,pix_data,8,8);
@@ -7747,7 +7940,7 @@ namespace cimg_library_suffixed { @@ -7747,7 +7940,7 @@ namespace cimg_library_suffixed {
7747 va_end(ap); 7940 va_end(ap);
7748 if (!std::strcmp(_title,tmp)) { delete[] tmp; return *this; } 7941 if (!std::strcmp(_title,tmp)) { delete[] tmp; return *this; }
7749 delete[] _title; 7942 delete[] _title;
7750 - const unsigned int s = std::strlen(tmp) + 1; 7943 + const unsigned int s = (unsigned int)std::strlen(tmp) + 1;
7751 _title = new char[s]; 7944 _title = new char[s];
7752 std::memcpy(_title,tmp,s*sizeof(char)); 7945 std::memcpy(_title,tmp,s*sizeof(char));
7753 Display *const dpy = cimg::X11_attr().display; 7946 Display *const dpy = cimg::X11_attr().display;
@@ -8269,7 +8462,9 @@ namespace cimg_library_suffixed { @@ -8269,7 +8462,9 @@ namespace cimg_library_suffixed {
8269 } break; 8462 } break;
8270 case WM_PAINT : 8463 case WM_PAINT :
8271 disp->paint(); 8464 disp->paint();
  8465 + cimg::mutex(15);
8272 if (disp->_is_cursor_visible) while (ShowCursor(TRUE)<0); else while (ShowCursor(FALSE)>=0); 8466 if (disp->_is_cursor_visible) while (ShowCursor(TRUE)<0); else while (ShowCursor(FALSE)>=0);
  8467 + cimg::mutex(15,0);
8273 break; 8468 break;
8274 case WM_ERASEBKGND : 8469 case WM_ERASEBKGND :
8275 // return 0; 8470 // return 0;
@@ -8299,12 +8494,16 @@ namespace cimg_library_suffixed { @@ -8299,12 +8494,16 @@ namespace cimg_library_suffixed {
8299 disp->_mouse_x = disp->_mouse_y = -1; 8494 disp->_mouse_x = disp->_mouse_y = -1;
8300 disp->_is_event = true; 8495 disp->_is_event = true;
8301 SetEvent(cimg::Win32_attr().wait_event); 8496 SetEvent(cimg::Win32_attr().wait_event);
  8497 + cimg::mutex(15);
8302 if (disp->_is_cursor_visible) while (ShowCursor(TRUE)<0); else while (ShowCursor(FALSE)>=0); 8498 if (disp->_is_cursor_visible) while (ShowCursor(TRUE)<0); else while (ShowCursor(FALSE)>=0);
  8499 + cimg::mutex(15,0);
8303 } break; 8500 } break;
8304 case WM_MOUSELEAVE : { 8501 case WM_MOUSELEAVE : {
8305 disp->_mouse_x = disp->_mouse_y = -1; 8502 disp->_mouse_x = disp->_mouse_y = -1;
8306 disp->_is_mouse_tracked = false; 8503 disp->_is_mouse_tracked = false;
  8504 + cimg::mutex(15);
8307 while (ShowCursor(TRUE)<0); 8505 while (ShowCursor(TRUE)<0);
  8506 + cimg::mutex(15,0);
8308 } break; 8507 } break;
8309 case WM_LBUTTONDOWN : 8508 case WM_LBUTTONDOWN :
8310 disp->set_button(1); 8509 disp->set_button(1);
@@ -8563,24 +8762,27 @@ namespace cimg_library_suffixed { @@ -8563,24 +8762,27 @@ namespace cimg_library_suffixed {
8563 tmpdimy = (nheight>0)?nheight:(-nheight*_height/100), 8762 tmpdimy = (nheight>0)?nheight:(-nheight*_height/100),
8564 dimx = tmpdimx?tmpdimx:1, 8763 dimx = tmpdimx?tmpdimx:1,
8565 dimy = tmpdimy?tmpdimy:1; 8764 dimy = tmpdimy?tmpdimy:1;
8566 - if (_window_width!=dimx || _window_height!=dimy) {  
8567 - RECT rect; rect.left = rect.top = 0; rect.right = (LONG)dimx - 1; rect.bottom = (LONG)dimy - 1;  
8568 - AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false);  
8569 - const int cwidth = rect.right - rect.left + 1, cheight = rect.bottom - rect.top + 1;  
8570 - SetWindowPos(_window,0,0,0,cwidth,cheight,SWP_NOMOVE | SWP_NOZORDER | SWP_NOCOPYBITS);  
8571 - }  
8572 - if (_width!=dimx || _height!=dimy) {  
8573 - unsigned int *const ndata = new unsigned int[dimx*dimy];  
8574 - if (force_redraw) _render_resize(_data,_width,_height,ndata,dimx,dimy);  
8575 - else std::memset(ndata,0x80,sizeof(unsigned int)*dimx*dimy);  
8576 - delete[] _data;  
8577 - _data = ndata;  
8578 - _bmi.bmiHeader.biWidth = (LONG)dimx;  
8579 - _bmi.bmiHeader.biHeight = -(int)dimy;  
8580 - _width = dimx;  
8581 - _height = dimy; 8765 + if (_width!=dimx || _height!=dimy || _window_width!=dimx || _window_height!=dimy) {
  8766 + if (_window_width!=dimx || _window_height!=dimy) {
  8767 + RECT rect; rect.left = rect.top = 0; rect.right = (LONG)dimx - 1; rect.bottom = (LONG)dimy - 1;
  8768 + AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false);
  8769 + const int cwidth = rect.right - rect.left + 1, cheight = rect.bottom - rect.top + 1;
  8770 + SetWindowPos(_window,0,0,0,cwidth,cheight,SWP_NOMOVE | SWP_NOZORDER | SWP_NOCOPYBITS);
  8771 + }
  8772 + if (_width!=dimx || _height!=dimy) {
  8773 + unsigned int *const ndata = new unsigned int[dimx*dimy];
  8774 + if (force_redraw) _render_resize(_data,_width,_height,ndata,dimx,dimy);
  8775 + else std::memset(ndata,0x80,sizeof(unsigned int)*dimx*dimy);
  8776 + delete[] _data;
  8777 + _data = ndata;
  8778 + _bmi.bmiHeader.biWidth = (LONG)dimx;
  8779 + _bmi.bmiHeader.biHeight = -(int)dimy;
  8780 + _width = dimx;
  8781 + _height = dimy;
  8782 + }
  8783 + _window_width = dimx; _window_height = dimy;
  8784 + show();
8582 } 8785 }
8583 - _window_width = dimx; _window_height = dimy;  
8584 _is_resized = false; 8786 _is_resized = false;
8585 if (_is_fullscreen) move((screen_width() - width())/2,(screen_height() - height())/2); 8787 if (_is_fullscreen) move((screen_width() - width())/2,(screen_height() - height())/2);
8586 if (force_redraw) return paint(); 8788 if (force_redraw) return paint();
@@ -8623,19 +8825,22 @@ namespace cimg_library_suffixed { @@ -8623,19 +8825,22 @@ namespace cimg_library_suffixed {
8623 8825
8624 CImgDisplay& move(const int posx, const int posy) { 8826 CImgDisplay& move(const int posx, const int posy) {
8625 if (is_empty()) return *this; 8827 if (is_empty()) return *this;
8626 - if (!_is_fullscreen) {  
8627 - RECT rect;  
8628 - rect.left = rect.top = 0; rect.right = (LONG)_window_width - 1; rect.bottom = (LONG)_window_height - 1;  
8629 - AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false);  
8630 - const int  
8631 - border1 = (int)((rect.right - rect.left + 1 -_width)/2),  
8632 - border2 = (int)(rect.bottom - rect.top + 1 - _height - border1);  
8633 - SetWindowPos(_window,0,posx - border1,posy - border2,0,0,SWP_NOSIZE | SWP_NOZORDER);  
8634 - } else SetWindowPos(_window,0,posx,posy,0,0,SWP_NOSIZE | SWP_NOZORDER);  
8635 - _window_x = posx;  
8636 - _window_y = posy; 8828 + if (_window_x!=posx || _window_y!=posy) {
  8829 + if (!_is_fullscreen) {
  8830 + RECT rect;
  8831 + rect.left = rect.top = 0; rect.right = (LONG)_window_width - 1; rect.bottom = (LONG)_window_height - 1;
  8832 + AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false);
  8833 + const int
  8834 + border1 = (int)((rect.right - rect.left + 1 -_width)/2),
  8835 + border2 = (int)(rect.bottom - rect.top + 1 - _height - border1);
  8836 + SetWindowPos(_window,0,posx - border1,posy - border2,0,0,SWP_NOSIZE | SWP_NOZORDER);
  8837 + } else SetWindowPos(_window,0,posx,posy,0,0,SWP_NOSIZE | SWP_NOZORDER);
  8838 + _window_x = posx;
  8839 + _window_y = posy;
  8840 + show();
  8841 + }
8637 _is_moved = false; 8842 _is_moved = false;
8638 - return show(); 8843 + return *this;
8639 } 8844 }
8640 8845
8641 CImgDisplay& show_mouse() { 8846 CImgDisplay& show_mouse() {
@@ -8651,7 +8856,7 @@ namespace cimg_library_suffixed { @@ -8651,7 +8856,7 @@ namespace cimg_library_suffixed {
8651 } 8856 }
8652 8857
8653 CImgDisplay& set_mouse(const int posx, const int posy) { 8858 CImgDisplay& set_mouse(const int posx, const int posy) {
8654 - if (_is_closed || posx<0 || posy<0) return *this; 8859 + if (is_empty() || _is_closed || posx<0 || posy<0) return *this;
8655 _update_window_pos(); 8860 _update_window_pos();
8656 const int res = (int)SetCursorPos(_window_x + posx,_window_y + posy); 8861 const int res = (int)SetCursorPos(_window_x + posx,_window_y + posy);
8657 if (res) { _mouse_x = posx; _mouse_y = posy; } 8862 if (res) { _mouse_x = posx; _mouse_y = posy; }
@@ -8891,10 +9096,8 @@ namespace cimg_library_suffixed { @@ -8891,10 +9096,8 @@ namespace cimg_library_suffixed {
8891 - Construct images from C-style arrays: 9096 - Construct images from C-style arrays:
8892 - <tt>CImg<int> img(data_buffer,256,256);</tt> constructs a 256x256 greyscale image from a \c int* buffer 9097 - <tt>CImg<int> img(data_buffer,256,256);</tt> constructs a 256x256 greyscale image from a \c int* buffer
8893 \c data_buffer (of size 256x256=65536). 9098 \c data_buffer (of size 256x256=65536).
8894 - - <tt>CImg<unsigned char> img(data_buffer,256,256,1,3,false);</tt> constructs a 256x256 color image 9099 + - <tt>CImg<unsigned char> img(data_buffer,256,256,1,3);</tt> constructs a 256x256 color image
8895 from a \c unsigned \c char* buffer \c data_buffer (where R,G,B channels follow each others). 9100 from a \c unsigned \c char* buffer \c data_buffer (where R,G,B channels follow each others).
8896 - - <tt>CImg<unsigned char> img(data_buffer,256,256,1,3,true);</tt> constructs a 256x256 color image  
8897 - from a \c unsigned \c char* buffer \c data_buffer (where R,G,B channels are multiplexed).  
8898 9101
8899 The complete list of constructors can be found <a href="#constructors">here</a>. 9102 The complete list of constructors can be found <a href="#constructors">here</a>.
8900 9103
@@ -8903,7 +9106,7 @@ namespace cimg_library_suffixed { @@ -8903,7 +9106,7 @@ namespace cimg_library_suffixed {
8903 The \c CImg<T> class contains a lot of functions that operates on images. 9106 The \c CImg<T> class contains a lot of functions that operates on images.
8904 Some of the most useful are: 9107 Some of the most useful are:
8905 9108
8906 - - operator()(): allows to access or write pixel values. 9109 + - operator()(): Read or write pixel values.
8907 - display(): displays the image in a new window. 9110 - display(): displays the image in a new window.
8908 **/ 9111 **/
8909 template<typename T> 9112 template<typename T>
@@ -8977,6 +9180,13 @@ namespace cimg_library_suffixed { @@ -8977,6 +9180,13 @@ namespace cimg_library_suffixed {
8977 typedef typename cimg::last<T,long>::type longT; 9180 typedef typename cimg::last<T,long>::type longT;
8978 typedef typename cimg::last<T,float>::type floatT; 9181 typedef typename cimg::last<T,float>::type floatT;
8979 typedef typename cimg::last<T,double>::type doubleT; 9182 typedef typename cimg::last<T,double>::type doubleT;
  9183 +#if cimg_OS==2
  9184 + typedef typename cimg::last<T,UINT_PTR>::type uptrT; // Unsigned integer type that can store a pointer.
  9185 + typedef typename cimg::last<T,INT_PTR>::type ptrT; // Signed integer type that can store a pointer.
  9186 +#else
  9187 + typedef typename cimg::last<T,unsigned long>::type uptrT;
  9188 + typedef typename cimg::last<T,long>::type ptrT;
  9189 +#endif
8980 9190
8981 //@} 9191 //@}
8982 //--------------------------- 9192 //---------------------------
@@ -9165,7 +9375,7 @@ namespace cimg_library_suffixed { @@ -9165,7 +9375,7 @@ namespace cimg_library_suffixed {
9165 *(ptrd++) = (T)a0; \ 9375 *(ptrd++) = (T)a0; \
9166 if (_siz--) { \ 9376 if (_siz--) { \
9167 *(ptrd++) = (T)a1; \ 9377 *(ptrd++) = (T)a1; \
9168 - for (; _siz; --_siz) *(ptrd++) = (T)va_arg(ap,t); \ 9378 + for ( ; _siz; --_siz) *(ptrd++) = (T)va_arg(ap,t); \
9169 } \ 9379 } \
9170 va_end(ap); \ 9380 va_end(ap); \
9171 } \ 9381 } \
@@ -9174,7 +9384,7 @@ namespace cimg_library_suffixed { @@ -9174,7 +9384,7 @@ namespace cimg_library_suffixed {
9174 _CImg_stdarg(*this,value0,value1,(unsigned long)size_x*size_y*size_z*size_c,int); 9384 _CImg_stdarg(*this,value0,value1,(unsigned long)size_x*size_y*size_z*size_c,int);
9175 } 9385 }
9176 9386
9177 -#ifdef cimg_use_cpp11 9387 +#if defined(cimg_use_cpp11) && cimg_use_cpp11!=0
9178 //! Construct image with specified size and initialize pixel values from an initializer list of integers. 9388 //! Construct image with specified size and initialize pixel values from an initializer list of integers.
9179 /** 9389 /**
9180 Construct a new image instance of size \c size_x x \c size_y x \c size_z x \c size_c, 9390 Construct a new image instance of size \c size_x x \c size_y x \c size_z x \c size_c,
@@ -9423,7 +9633,8 @@ namespace cimg_library_suffixed { @@ -9423,7 +9633,8 @@ namespace cimg_library_suffixed {
9423 cimg::strbuffersize(sizeof(T)*size_x*size_y*size_z*size_c), 9633 cimg::strbuffersize(sizeof(T)*size_x*size_y*size_z*size_c),
9424 size_x,size_y,size_z,size_c); 9634 size_x,size_y,size_z,size_c);
9425 } 9635 }
9426 - std::memcpy(_data,values,siz*sizeof(T)); } 9636 + std::memcpy(_data,values,siz*sizeof(T));
  9637 + }
9427 } else { _width = _height = _depth = _spectrum = 0; _is_shared = false; _data = 0; } 9638 } else { _width = _height = _depth = _spectrum = 0; _is_shared = false; _data = 0; }
9428 } 9639 }
9429 9640
@@ -9629,7 +9840,7 @@ namespace cimg_library_suffixed { @@ -9629,7 +9840,7 @@ namespace cimg_library_suffixed {
9629 9840
9630 // Constructor and assignment operator for rvalue references (c++11). 9841 // Constructor and assignment operator for rvalue references (c++11).
9631 // This avoids an additional image copy for methods returning new images. Can save RAM for big images ! 9842 // This avoids an additional image copy for methods returning new images. Can save RAM for big images !
9632 -#ifdef cimg_use_cpp11 9843 +#if defined(cimg_use_cpp11) && cimg_use_cpp11!=0
9633 CImg(CImg<T>&& img):_width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) { 9844 CImg(CImg<T>&& img):_width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) {
9634 swap(img); 9845 swap(img);
9635 } 9846 }
@@ -9954,10 +10165,7 @@ namespace cimg_library_suffixed { @@ -9954,10 +10165,7 @@ namespace cimg_library_suffixed {
9954 \endcode 10165 \endcode
9955 **/ 10166 **/
9956 CImg<T>& swap(CImg<T>& img) { 10167 CImg<T>& swap(CImg<T>& img) {
9957 - cimg::swap(_width,img._width);  
9958 - cimg::swap(_height,img._height);  
9959 - cimg::swap(_depth,img._depth);  
9960 - cimg::swap(_spectrum,img._spectrum); 10168 + cimg::swap(_width,img._width,_height,img._height,_depth,img._depth,_spectrum,img._spectrum);
9961 cimg::swap(_data,img._data); 10169 cimg::swap(_data,img._data);
9962 cimg::swap(_is_shared,img._is_shared); 10170 cimg::swap(_is_shared,img._is_shared);
9963 return img; 10171 return img;
@@ -9977,6 +10185,12 @@ namespace cimg_library_suffixed { @@ -9977,6 +10185,12 @@ namespace cimg_library_suffixed {
9977 return _empty.assign(); 10185 return _empty.assign();
9978 } 10186 }
9979 10187
  10188 + //! Return a reference to an empty image \const.
  10189 + static const CImg<T>& const_empty() {
  10190 + static const CImg<T> _empty;
  10191 + return _empty;
  10192 + }
  10193 +
9980 //@} 10194 //@}
9981 //------------------------------------------ 10195 //------------------------------------------
9982 // 10196 //
@@ -10023,9 +10237,9 @@ namespace cimg_library_suffixed { @@ -10023,9 +10237,9 @@ namespace cimg_library_suffixed {
10023 const unsigned long off = (unsigned long)offset(x,y,z,c); 10237 const unsigned long off = (unsigned long)offset(x,y,z,c);
10024 if (!_data || off>=size()) { 10238 if (!_data || off>=size()) {
10025 cimg::warn(_cimg_instance 10239 cimg::warn(_cimg_instance
10026 - "operator(): Invalid pixel request, at coordinates (%u,%u,%u,%u) [offset=%u].", 10240 + "operator(): Invalid pixel request, at coordinates (%d,%d,%d,%d) [offset=%u].",
10027 cimg_instance, 10241 cimg_instance,
10028 - x,y,z,c,off); 10242 + (int)x,(int)y,(int)z,(int)c,off);
10029 return *_data; 10243 return *_data;
10030 } 10244 }
10031 else return _data[off]; 10245 else return _data[off];
@@ -10191,7 +10405,7 @@ namespace cimg_library_suffixed { @@ -10191,7 +10405,7 @@ namespace cimg_library_suffixed {
10191 const unsigned int omode = cimg::exception_mode(); 10405 const unsigned int omode = cimg::exception_mode();
10192 cimg::exception_mode(0); 10406 cimg::exception_mode(0);
10193 try { 10407 try {
10194 - fill(expression,true); 10408 + _fill(expression,true,true,0,0,"operator=",0);
10195 } catch (CImgException&) { 10409 } catch (CImgException&) {
10196 cimg::exception_mode(omode); 10410 cimg::exception_mode(omode);
10197 load(expression); 10411 load(expression);
@@ -10254,7 +10468,7 @@ namespace cimg_library_suffixed { @@ -10254,7 +10468,7 @@ namespace cimg_library_suffixed {
10254 CImg<T>& operator+=(const t value) { 10468 CImg<T>& operator+=(const t value) {
10255 if (is_empty()) return *this; 10469 if (is_empty()) return *this;
10256 #ifdef cimg_use_openmp 10470 #ifdef cimg_use_openmp
10257 -#pragma omp parallel for if (size()>=524288) 10471 +#pragma omp parallel for cimg_openmp_if(size()>=524288)
10258 #endif 10472 #endif
10259 cimg_rof(*this,ptrd,T) *ptrd = (T)(*ptrd + value); 10473 cimg_rof(*this,ptrd,T) *ptrd = (T)(*ptrd + value);
10260 return *this; 10474 return *this;
@@ -10269,37 +10483,7 @@ namespace cimg_library_suffixed { @@ -10269,37 +10483,7 @@ namespace cimg_library_suffixed {
10269 instead of assigning them. 10483 instead of assigning them.
10270 **/ 10484 **/
10271 CImg<T>& operator+=(const char *const expression) { 10485 CImg<T>& operator+=(const char *const expression) {
10272 - if (is_empty()) return *this;  
10273 - const unsigned int omode = cimg::exception_mode();  
10274 - cimg::exception_mode(0);  
10275 - try {  
10276 - const CImg<T> _base = cimg::_is_self_expr(expression)?+*this:CImg<T>(), &base = _base?_base:*this;  
10277 - _cimg_math_parser mp(base,expression + (*expression=='>' || *expression=='<'?1:0),"operator+=");  
10278 - T *ptrd = *expression=='<'?end() - 1:_data;  
10279 - if (*expression=='<') cimg_rofXYZC(*this,x,y,z,c) { *ptrd = (T)(*ptrd + mp(x,y,z,c)); --ptrd; }  
10280 - else if (*expression=='>') cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)(*ptrd + mp(x,y,z,c)); ++ptrd; }  
10281 - else {  
10282 -#ifdef cimg_use_openmp  
10283 - if (_width>=512 && _height*_depth*_spectrum>=2 && std::strlen(expression)>=6)  
10284 -#pragma omp parallel  
10285 - {  
10286 - _cimg_math_parser _mp = omp_get_thread_num()?mp:_cimg_math_parser(), &lmp = omp_get_thread_num()?_mp:mp;  
10287 -#pragma omp for collapse(3)  
10288 - cimg_forYZC(*this,y,z,c) {  
10289 - T *ptrd = data(0,y,z,c);  
10290 - cimg_forX(*this,x) { *ptrd = (T)(*ptrd + lmp(x,y,z,c)); ++ptrd; }  
10291 - }  
10292 - }  
10293 - else  
10294 -#endif  
10295 - cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)(*ptrd + mp(x,y,z,c)); ++ptrd; }  
10296 - }  
10297 - } catch (CImgException&) {  
10298 - cimg::exception_mode(omode);  
10299 - *this+=CImg<T>(_width,_height,_depth,_spectrum,expression,true);  
10300 - }  
10301 - cimg::exception_mode(omode);  
10302 - return *this; 10486 + return *this+=(+*this)._fill(expression,true,true,0,0,"operator+=",this);
10303 } 10487 }
10304 10488
10305 //! In-place addition operator. 10489 //! In-place addition operator.
@@ -10345,7 +10529,7 @@ namespace cimg_library_suffixed { @@ -10345,7 +10529,7 @@ namespace cimg_library_suffixed {
10345 CImg<T>& operator++() { 10529 CImg<T>& operator++() {
10346 if (is_empty()) return *this; 10530 if (is_empty()) return *this;
10347 #ifdef cimg_use_openmp 10531 #ifdef cimg_use_openmp
10348 -#pragma omp parallel for if (size()>=524288) 10532 +#pragma omp parallel for cimg_openmp_if(size()>=524288)
10349 #endif 10533 #endif
10350 cimg_rof(*this,ptrd,T) ++*ptrd; 10534 cimg_rof(*this,ptrd,T) ++*ptrd;
10351 return *this; 10535 return *this;
@@ -10414,7 +10598,7 @@ namespace cimg_library_suffixed { @@ -10414,7 +10598,7 @@ namespace cimg_library_suffixed {
10414 CImg<T>& operator-=(const t value) { 10598 CImg<T>& operator-=(const t value) {
10415 if (is_empty()) return *this; 10599 if (is_empty()) return *this;
10416 #ifdef cimg_use_openmp 10600 #ifdef cimg_use_openmp
10417 -#pragma omp parallel for if (size()>=524288) 10601 +#pragma omp parallel for cimg_openmp_if(size()>=524288)
10418 #endif 10602 #endif
10419 cimg_rof(*this,ptrd,T) *ptrd = (T)(*ptrd - value); 10603 cimg_rof(*this,ptrd,T) *ptrd = (T)(*ptrd - value);
10420 return *this; 10604 return *this;
@@ -10425,37 +10609,7 @@ namespace cimg_library_suffixed { @@ -10425,37 +10609,7 @@ namespace cimg_library_suffixed {
10425 Similar to operator+=(const char*), except that it performs a substraction instead of an addition. 10609 Similar to operator+=(const char*), except that it performs a substraction instead of an addition.
10426 **/ 10610 **/
10427 CImg<T>& operator-=(const char *const expression) { 10611 CImg<T>& operator-=(const char *const expression) {
10428 - if (is_empty()) return *this;  
10429 - const unsigned int omode = cimg::exception_mode();  
10430 - cimg::exception_mode(0);  
10431 - try {  
10432 - const CImg<T> _base = cimg::_is_self_expr(expression)?+*this:CImg<T>(), &base = _base?_base:*this;  
10433 - _cimg_math_parser mp(base,expression + (*expression=='>' || *expression=='<'?1:0),"operator-=");  
10434 - T *ptrd = *expression=='<'?end() - 1:_data;  
10435 - if (*expression=='<') cimg_rofXYZC(*this,x,y,z,c) { *ptrd = (T)(*ptrd - mp(x,y,z,c)); --ptrd; }  
10436 - else if (*expression=='>') cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)(*ptrd - mp(x,y,z,c)); ++ptrd; }  
10437 - else {  
10438 -#ifdef cimg_use_openmp  
10439 - if (_width>=512 && _height*_depth*_spectrum>=2 && std::strlen(expression)>=6)  
10440 -#pragma omp parallel  
10441 - {  
10442 - _cimg_math_parser _mp = omp_get_thread_num()?mp:_cimg_math_parser(), &lmp = omp_get_thread_num()?_mp:mp;  
10443 -#pragma omp for collapse(3)  
10444 - cimg_forYZC(*this,y,z,c) {  
10445 - T *ptrd = data(0,y,z,c);  
10446 - cimg_forX(*this,x) { *ptrd = (T)(*ptrd - lmp(x,y,z,c)); ++ptrd; }  
10447 - }  
10448 - }  
10449 - else  
10450 -#endif  
10451 - cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)(*ptrd - mp(x,y,z,c)); ++ptrd; }  
10452 - }  
10453 - } catch (CImgException&) {  
10454 - cimg::exception_mode(omode);  
10455 - *this-=CImg<T>(_width,_height,_depth,_spectrum,expression,true);  
10456 - }  
10457 - cimg::exception_mode(omode);  
10458 - return *this; 10612 + return *this-=(+*this)._fill(expression,true,true,0,0,"operator-=",this);
10459 } 10613 }
10460 10614
10461 //! In-place substraction operator. 10615 //! In-place substraction operator.
@@ -10483,7 +10637,7 @@ namespace cimg_library_suffixed { @@ -10483,7 +10637,7 @@ namespace cimg_library_suffixed {
10483 CImg<T>& operator--() { 10637 CImg<T>& operator--() {
10484 if (is_empty()) return *this; 10638 if (is_empty()) return *this;
10485 #ifdef cimg_use_openmp 10639 #ifdef cimg_use_openmp
10486 -#pragma omp parallel for if (size()>=524288) 10640 +#pragma omp parallel for cimg_openmp_if(size()>=524288)
10487 #endif 10641 #endif
10488 cimg_rof(*this,ptrd,T) *ptrd = *ptrd - (T)1; 10642 cimg_rof(*this,ptrd,T) *ptrd = *ptrd - (T)1;
10489 return *this; 10643 return *this;
@@ -10554,7 +10708,7 @@ namespace cimg_library_suffixed { @@ -10554,7 +10708,7 @@ namespace cimg_library_suffixed {
10554 CImg<T>& operator*=(const t value) { 10708 CImg<T>& operator*=(const t value) {
10555 if (is_empty()) return *this; 10709 if (is_empty()) return *this;
10556 #ifdef cimg_use_openmp 10710 #ifdef cimg_use_openmp
10557 -#pragma omp parallel for if (size()>=262144) 10711 +#pragma omp parallel for cimg_openmp_if(size()>=262144)
10558 #endif 10712 #endif
10559 cimg_rof(*this,ptrd,T) *ptrd = (T)(*ptrd * value); 10713 cimg_rof(*this,ptrd,T) *ptrd = (T)(*ptrd * value);
10560 return *this; 10714 return *this;
@@ -10565,37 +10719,7 @@ namespace cimg_library_suffixed { @@ -10565,37 +10719,7 @@ namespace cimg_library_suffixed {
10565 Similar to operator+=(const char*), except that it performs a multiplication instead of an addition. 10719 Similar to operator+=(const char*), except that it performs a multiplication instead of an addition.
10566 **/ 10720 **/
10567 CImg<T>& operator*=(const char *const expression) { 10721 CImg<T>& operator*=(const char *const expression) {
10568 - if (is_empty()) return *this;  
10569 - const unsigned int omode = cimg::exception_mode();  
10570 - cimg::exception_mode(0);  
10571 - try {  
10572 - const CImg<T> _base = cimg::_is_self_expr(expression)?+*this:CImg<T>(), &base = _base?_base:*this;  
10573 - _cimg_math_parser mp(base,expression + (*expression=='>' || *expression=='<'?1:0),"operator*=");  
10574 - T *ptrd = *expression=='<'?end() - 1:_data;  
10575 - if (*expression=='<') cimg_rofXYZC(*this,x,y,z,c) { *ptrd = (T)(*ptrd * mp(x,y,z,c)); --ptrd; }  
10576 - else if (*expression=='>') cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)(*ptrd * mp(x,y,z,c)); ++ptrd; }  
10577 - else {  
10578 -#ifdef cimg_use_openmp  
10579 - if (_width>=512 && _height*_depth*_spectrum>=2 && std::strlen(expression)>=6)  
10580 -#pragma omp parallel  
10581 - {  
10582 - _cimg_math_parser _mp = omp_get_thread_num()?mp:_cimg_math_parser(), &lmp = omp_get_thread_num()?_mp:mp;  
10583 -#pragma omp for collapse(3)  
10584 - cimg_forYZC(*this,y,z,c) {  
10585 - T *ptrd = data(0,y,z,c);  
10586 - cimg_forX(*this,x) { *ptrd = (T)(*ptrd * lmp(x,y,z,c)); ++ptrd; }  
10587 - }  
10588 - }  
10589 - else  
10590 -#endif  
10591 - cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)(*ptrd * mp(x,y,z,c)); ++ptrd; }  
10592 - }  
10593 - } catch (CImgException&) {  
10594 - cimg::exception_mode(omode);  
10595 - mul(CImg<T>(_width,_height,_depth,_spectrum,expression,true));  
10596 - }  
10597 - cimg::exception_mode(omode);  
10598 - return *this; 10722 + return mul((+*this)._fill(expression,true,true,0,0,"operator*=",this));
10599 } 10723 }
10600 10724
10601 //! In-place multiplication operator. 10725 //! In-place multiplication operator.
@@ -10654,7 +10778,7 @@ namespace cimg_library_suffixed { @@ -10654,7 +10778,7 @@ namespace cimg_library_suffixed {
10654 img._width,img._height,img._depth,img._spectrum,img._data); 10778 img._width,img._height,img._depth,img._spectrum,img._data);
10655 CImg<_cimg_Tt> res(img._width,_height); 10779 CImg<_cimg_Tt> res(img._width,_height);
10656 #ifdef cimg_use_openmp 10780 #ifdef cimg_use_openmp
10657 -#pragma omp parallel for if (size()>1024 && img.size()>1024) collapse(2) 10781 +#pragma omp parallel for collapse(2) cimg_openmp_if(size()>1024 && img.size()>1024)
10658 cimg_forXY(res,i,j) { 10782 cimg_forXY(res,i,j) {
10659 _cimg_Ttdouble value = 0; cimg_forX(*this,k) value+=(*this)(k,j)*img(i,k); res(i,j) = (_cimg_Tt)value; 10783 _cimg_Ttdouble value = 0; cimg_forX(*this,k) value+=(*this)(k,j)*img(i,k); res(i,j) = (_cimg_Tt)value;
10660 } 10784 }
@@ -10675,7 +10799,7 @@ namespace cimg_library_suffixed { @@ -10675,7 +10799,7 @@ namespace cimg_library_suffixed {
10675 CImg<T>& operator/=(const t value) { 10799 CImg<T>& operator/=(const t value) {
10676 if (is_empty()) return *this; 10800 if (is_empty()) return *this;
10677 #ifdef cimg_use_openmp 10801 #ifdef cimg_use_openmp
10678 -#pragma omp parallel for if (size()>=32768) 10802 +#pragma omp parallel for cimg_openmp_if(size()>=32768)
10679 #endif 10803 #endif
10680 cimg_rof(*this,ptrd,T) *ptrd = (T)(*ptrd / value); 10804 cimg_rof(*this,ptrd,T) *ptrd = (T)(*ptrd / value);
10681 return *this; 10805 return *this;
@@ -10686,37 +10810,7 @@ namespace cimg_library_suffixed { @@ -10686,37 +10810,7 @@ namespace cimg_library_suffixed {
10686 Similar to operator+=(const char*), except that it performs a division instead of an addition. 10810 Similar to operator+=(const char*), except that it performs a division instead of an addition.
10687 **/ 10811 **/
10688 CImg<T>& operator/=(const char *const expression) { 10812 CImg<T>& operator/=(const char *const expression) {
10689 - if (is_empty()) return *this;  
10690 - const unsigned int omode = cimg::exception_mode();  
10691 - cimg::exception_mode(0);  
10692 - try {  
10693 - const CImg<T> _base = cimg::_is_self_expr(expression)?+*this:CImg<T>(), &base = _base?_base:*this;  
10694 - _cimg_math_parser mp(base,expression + (*expression=='>' || *expression=='<'?1:0),"operator/=");  
10695 - T *ptrd = *expression=='<'?end() - 1:_data;  
10696 - if (*expression=='<') cimg_rofXYZC(*this,x,y,z,c) { *ptrd = (T)(*ptrd / mp(x,y,z,c)); --ptrd; }  
10697 - else if (*expression=='>') cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)(*ptrd / mp(x,y,z,c)); ++ptrd; }  
10698 - else {  
10699 -#ifdef cimg_use_openmp  
10700 - if (_width>=512 && _height*_depth*_spectrum>=2 && std::strlen(expression)>=6)  
10701 -#pragma omp parallel  
10702 - {  
10703 - _cimg_math_parser _mp = omp_get_thread_num()?mp:_cimg_math_parser(), &lmp = omp_get_thread_num()?_mp:mp;  
10704 -#pragma omp for collapse(3)  
10705 - cimg_forYZC(*this,y,z,c) {  
10706 - T *ptrd = data(0,y,z,c);  
10707 - cimg_forX(*this,x) { *ptrd = (T)(*ptrd / lmp(x,y,z,c)); ++ptrd; }  
10708 - }  
10709 - }  
10710 - else  
10711 -#endif  
10712 - cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)(*ptrd / mp(x,y,z,c)); ++ptrd; }  
10713 - }  
10714 - } catch (CImgException&) {  
10715 - cimg::exception_mode(omode);  
10716 - div(CImg<T>(_width,_height,_depth,_spectrum,expression,true));  
10717 - }  
10718 - cimg::exception_mode(omode);  
10719 - return *this; 10813 + return div((+*this)._fill(expression,true,true,0,0,"operator/=",this));
10720 } 10814 }
10721 10815
10722 //! In-place division operator. 10816 //! In-place division operator.
@@ -10772,7 +10866,7 @@ namespace cimg_library_suffixed { @@ -10772,7 +10866,7 @@ namespace cimg_library_suffixed {
10772 CImg<T>& operator%=(const t value) { 10866 CImg<T>& operator%=(const t value) {
10773 if (is_empty()) return *this; 10867 if (is_empty()) return *this;
10774 #ifdef cimg_use_openmp 10868 #ifdef cimg_use_openmp
10775 -#pragma omp parallel for if (size()>=16384) 10869 +#pragma omp parallel for cimg_openmp_if(size()>=16384)
10776 #endif 10870 #endif
10777 cimg_rof(*this,ptrd,T) *ptrd = (T)cimg::mod(*ptrd,(T)value); 10871 cimg_rof(*this,ptrd,T) *ptrd = (T)cimg::mod(*ptrd,(T)value);
10778 return *this; 10872 return *this;
@@ -10783,37 +10877,7 @@ namespace cimg_library_suffixed { @@ -10783,37 +10877,7 @@ namespace cimg_library_suffixed {
10783 Similar to operator+=(const char*), except that it performs a modulo operation instead of an addition. 10877 Similar to operator+=(const char*), except that it performs a modulo operation instead of an addition.
10784 **/ 10878 **/
10785 CImg<T>& operator%=(const char *const expression) { 10879 CImg<T>& operator%=(const char *const expression) {
10786 - if (is_empty()) return *this;  
10787 - const unsigned int omode = cimg::exception_mode();  
10788 - cimg::exception_mode(0);  
10789 - try {  
10790 - const CImg<T> _base = cimg::_is_self_expr(expression)?+*this:CImg<T>(), &base = _base?_base:*this;  
10791 - _cimg_math_parser mp(base,expression + (*expression=='>' || *expression=='<'?1:0),"operator%=");  
10792 - T *ptrd = *expression=='<'?end() - 1:_data;  
10793 - if (*expression=='<') cimg_rofXYZC(*this,x,y,z,c) { *ptrd = (T)cimg::mod(*ptrd,(T)mp(x,y,z,c)); --ptrd; }  
10794 - else if (*expression=='>') cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)cimg::mod(*ptrd,(T)mp(x,y,z,c)); ++ptrd; }  
10795 - else {  
10796 -#ifdef cimg_use_openmp  
10797 - if (_width>=512 && _height*_depth*_spectrum>=2 && std::strlen(expression)>=6)  
10798 -#pragma omp parallel  
10799 - {  
10800 - _cimg_math_parser _mp = omp_get_thread_num()?mp:_cimg_math_parser(), &lmp = omp_get_thread_num()?_mp:mp;  
10801 -#pragma omp for collapse(3)  
10802 - cimg_forYZC(*this,y,z,c) {  
10803 - T *ptrd = data(0,y,z,c);  
10804 - cimg_forX(*this,x) { *ptrd = (T)cimg::mod(*ptrd,(T)lmp(x,y,z,c)); ++ptrd; }  
10805 - }  
10806 - }  
10807 - else  
10808 -#endif  
10809 - cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)cimg::mod(*ptrd,(T)mp(x,y,z,c)); ++ptrd; }  
10810 - }  
10811 - } catch (CImgException&) {  
10812 - cimg::exception_mode(omode);  
10813 - *this%=CImg<T>(_width,_height,_depth,_spectrum,expression,true);  
10814 - }  
10815 - cimg::exception_mode(omode);  
10816 - return *this; 10880 + return *this%=(+*this)._fill(expression,true,true,0,0,"operator%=",this);
10817 } 10881 }
10818 10882
10819 //! In-place modulo operator. 10883 //! In-place modulo operator.
@@ -10871,7 +10935,7 @@ namespace cimg_library_suffixed { @@ -10871,7 +10935,7 @@ namespace cimg_library_suffixed {
10871 CImg<T>& operator&=(const t value) { 10935 CImg<T>& operator&=(const t value) {
10872 if (is_empty()) return *this; 10936 if (is_empty()) return *this;
10873 #ifdef cimg_use_openmp 10937 #ifdef cimg_use_openmp
10874 -#pragma omp parallel for if (size()>=32768) 10938 +#pragma omp parallel for cimg_openmp_if(size()>=32768)
10875 #endif 10939 #endif
10876 cimg_rof(*this,ptrd,T) *ptrd = (T)((unsigned long)*ptrd & (unsigned long)value); 10940 cimg_rof(*this,ptrd,T) *ptrd = (T)((unsigned long)*ptrd & (unsigned long)value);
10877 return *this; 10941 return *this;
@@ -10882,39 +10946,7 @@ namespace cimg_library_suffixed { @@ -10882,39 +10946,7 @@ namespace cimg_library_suffixed {
10882 Similar to operator+=(const char*), except that it performs a bitwise AND operation instead of an addition. 10946 Similar to operator+=(const char*), except that it performs a bitwise AND operation instead of an addition.
10883 **/ 10947 **/
10884 CImg<T>& operator&=(const char *const expression) { 10948 CImg<T>& operator&=(const char *const expression) {
10885 - if (is_empty()) return *this;  
10886 - const unsigned int omode = cimg::exception_mode();  
10887 - cimg::exception_mode(0);  
10888 - try {  
10889 - const CImg<T> _base = cimg::_is_self_expr(expression)?+*this:CImg<T>(), &base = _base?_base:*this;  
10890 - _cimg_math_parser mp(base,expression + (*expression=='>' || *expression=='<'?1:0),"operator&=");  
10891 - T *ptrd = *expression=='<'?end() - 1:_data;  
10892 - if (*expression=='<')  
10893 - cimg_rofXYZC(*this,x,y,z,c) { *ptrd = (T)((unsigned long)*ptrd & (unsigned long)mp(x,y,z,c)); --ptrd; }  
10894 - else if (*expression=='>')  
10895 - cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)((unsigned long)*ptrd & (unsigned long)mp(x,y,z,c)); ++ptrd; }  
10896 - else {  
10897 -#ifdef cimg_use_openmp  
10898 - if (_width>=512 && _height*_depth*_spectrum>=2 && std::strlen(expression)>=6)  
10899 -#pragma omp parallel  
10900 - {  
10901 - _cimg_math_parser _mp = omp_get_thread_num()?mp:_cimg_math_parser(), &lmp = omp_get_thread_num()?_mp:mp;  
10902 -#pragma omp for collapse(3)  
10903 - cimg_forYZC(*this,y,z,c) {  
10904 - T *ptrd = data(0,y,z,c);  
10905 - cimg_forX(*this,x) { *ptrd = (T)((unsigned long)*ptrd & (unsigned long)lmp(x,y,z,c)); ++ptrd; }  
10906 - }  
10907 - }  
10908 - else  
10909 -#endif  
10910 - cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)((unsigned long)*ptrd & (unsigned long)mp(x,y,z,c)); ++ptrd; }  
10911 - }  
10912 - } catch (CImgException&) {  
10913 - cimg::exception_mode(omode);  
10914 - *this&=CImg<T>(_width,_height,_depth,_spectrum,expression,true);  
10915 - }  
10916 - cimg::exception_mode(omode);  
10917 - return *this; 10949 + return *this&=(+*this)._fill(expression,true,true,0,0,"operator&=",this);
10918 } 10950 }
10919 10951
10920 //! In-place bitwise AND operator. 10952 //! In-place bitwise AND operator.
@@ -10972,7 +11004,7 @@ namespace cimg_library_suffixed { @@ -10972,7 +11004,7 @@ namespace cimg_library_suffixed {
10972 CImg<T>& operator|=(const t value) { 11004 CImg<T>& operator|=(const t value) {
10973 if (is_empty()) return *this; 11005 if (is_empty()) return *this;
10974 #ifdef cimg_use_openmp 11006 #ifdef cimg_use_openmp
10975 -#pragma omp parallel for if (size()>=32768) 11007 +#pragma omp parallel for cimg_openmp_if(size()>=32768)
10976 #endif 11008 #endif
10977 cimg_rof(*this,ptrd,T) *ptrd = (T)((unsigned long)*ptrd | (unsigned long)value); 11009 cimg_rof(*this,ptrd,T) *ptrd = (T)((unsigned long)*ptrd | (unsigned long)value);
10978 return *this; 11010 return *this;
@@ -10983,39 +11015,7 @@ namespace cimg_library_suffixed { @@ -10983,39 +11015,7 @@ namespace cimg_library_suffixed {
10983 Similar to operator+=(const char*), except that it performs a bitwise OR operation instead of an addition. 11015 Similar to operator+=(const char*), except that it performs a bitwise OR operation instead of an addition.
10984 **/ 11016 **/
10985 CImg<T>& operator|=(const char *const expression) { 11017 CImg<T>& operator|=(const char *const expression) {
10986 - if (is_empty()) return *this;  
10987 - const unsigned int omode = cimg::exception_mode();  
10988 - cimg::exception_mode(0);  
10989 - try {  
10990 - const CImg<T> _base = cimg::_is_self_expr(expression)?+*this:CImg<T>(), &base = _base?_base:*this;  
10991 - _cimg_math_parser mp(base,expression + (*expression=='>' || *expression=='<'?1:0),"operator|=");  
10992 - T *ptrd = *expression=='<'?end() - 1:_data;  
10993 - if (*expression=='<')  
10994 - cimg_rofXYZC(*this,x,y,z,c) { *ptrd = (T)((unsigned long)*ptrd | (unsigned long)mp(x,y,z,c)); --ptrd; }  
10995 - else if (*expression=='>')  
10996 - cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)((unsigned long)*ptrd | (unsigned long)mp(x,y,z,c)); ++ptrd; }  
10997 - else {  
10998 -#ifdef cimg_use_openmp  
10999 - if (_width>=512 && _height*_depth*_spectrum>=2 && std::strlen(expression)>=6)  
11000 -#pragma omp parallel  
11001 - {  
11002 - _cimg_math_parser _mp = omp_get_thread_num()?mp:_cimg_math_parser(), &lmp = omp_get_thread_num()?_mp:mp;  
11003 -#pragma omp for collapse(3)  
11004 - cimg_forYZC(*this,y,z,c) {  
11005 - T *ptrd = data(0,y,z,c);  
11006 - cimg_forX(*this,x) { *ptrd = (T)((unsigned long)*ptrd | (unsigned long)lmp(x,y,z,c)); ++ptrd; }  
11007 - }  
11008 - }  
11009 - else  
11010 -#endif  
11011 - cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)((unsigned long)*ptrd | (unsigned long)mp(x,y,z,c)); ++ptrd; }  
11012 - }  
11013 - } catch (CImgException&) {  
11014 - cimg::exception_mode(omode);  
11015 - *this|=CImg<T>(_width,_height,_depth,_spectrum,expression,true);  
11016 - }  
11017 - cimg::exception_mode(omode);  
11018 - return *this; 11018 + return *this|=(+*this)._fill(expression,true,true,0,0,"operator|=",this);
11019 } 11019 }
11020 11020
11021 //! In-place bitwise OR operator. 11021 //! In-place bitwise OR operator.
@@ -11075,7 +11075,7 @@ namespace cimg_library_suffixed { @@ -11075,7 +11075,7 @@ namespace cimg_library_suffixed {
11075 CImg<T>& operator^=(const t value) { 11075 CImg<T>& operator^=(const t value) {
11076 if (is_empty()) return *this; 11076 if (is_empty()) return *this;
11077 #ifdef cimg_use_openmp 11077 #ifdef cimg_use_openmp
11078 -#pragma omp parallel for if (size()>=32768) 11078 +#pragma omp parallel for cimg_openmp_if(size()>=32768)
11079 #endif 11079 #endif
11080 cimg_rof(*this,ptrd,T) *ptrd = (T)((unsigned long)*ptrd ^ (unsigned long)value); 11080 cimg_rof(*this,ptrd,T) *ptrd = (T)((unsigned long)*ptrd ^ (unsigned long)value);
11081 return *this; 11081 return *this;
@@ -11088,39 +11088,7 @@ namespace cimg_library_suffixed { @@ -11088,39 +11088,7 @@ namespace cimg_library_suffixed {
11088 - It does \e not compute the \e power of pixel values. For this purpose, use pow(const char*) instead. 11088 - It does \e not compute the \e power of pixel values. For this purpose, use pow(const char*) instead.
11089 **/ 11089 **/
11090 CImg<T>& operator^=(const char *const expression) { 11090 CImg<T>& operator^=(const char *const expression) {
11091 - if (is_empty()) return *this;  
11092 - const unsigned int omode = cimg::exception_mode();  
11093 - cimg::exception_mode(0);  
11094 - try {  
11095 - const CImg<T> _base = cimg::_is_self_expr(expression)?+*this:CImg<T>(), &base = _base?_base:*this;  
11096 - _cimg_math_parser mp(base,expression + (*expression=='>' || *expression=='<'?1:0),"operator^=");  
11097 - T *ptrd = *expression=='<'?end() - 1:_data;  
11098 - if (*expression=='<')  
11099 - cimg_rofXYZC(*this,x,y,z,c) { *ptrd = (T)((unsigned long)*ptrd ^ (unsigned long)mp(x,y,z,c)); --ptrd; }  
11100 - else if (*expression=='>')  
11101 - cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)((unsigned long)*ptrd ^ (unsigned long)mp(x,y,z,c)); ++ptrd; }  
11102 - else {  
11103 -#ifdef cimg_use_openmp  
11104 - if (_width>=512 && _height*_depth*_spectrum>=2 && std::strlen(expression)>=6)  
11105 -#pragma omp parallel  
11106 - {  
11107 - _cimg_math_parser _mp = omp_get_thread_num()?mp:_cimg_math_parser(), &lmp = omp_get_thread_num()?_mp:mp;  
11108 -#pragma omp for collapse(3)  
11109 - cimg_forYZC(*this,y,z,c) {  
11110 - T *ptrd = data(0,y,z,c);  
11111 - cimg_forX(*this,x) { *ptrd = (T)((unsigned long)*ptrd ^ (unsigned long)lmp(x,y,z,c)); ++ptrd; }  
11112 - }  
11113 - }  
11114 - else  
11115 -#endif  
11116 - cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)((unsigned long)*ptrd ^ (unsigned long)mp(x,y,z,c)); ++ptrd; }  
11117 - }  
11118 - } catch (CImgException&) {  
11119 - cimg::exception_mode(omode);  
11120 - *this^=CImg<T>(_width,_height,_depth,_spectrum,expression,true);  
11121 - }  
11122 - cimg::exception_mode(omode);  
11123 - return *this; 11091 + return *this^=(+*this)._fill(expression,true,true,0,0,"operator^=",this);
11124 } 11092 }
11125 11093
11126 //! In-place bitwise XOR operator. 11094 //! In-place bitwise XOR operator.
@@ -11180,7 +11148,7 @@ namespace cimg_library_suffixed { @@ -11180,7 +11148,7 @@ namespace cimg_library_suffixed {
11180 CImg<T>& operator<<=(const t value) { 11148 CImg<T>& operator<<=(const t value) {
11181 if (is_empty()) return *this; 11149 if (is_empty()) return *this;
11182 #ifdef cimg_use_openmp 11150 #ifdef cimg_use_openmp
11183 -#pragma omp parallel for if (size()>=65536) 11151 +#pragma omp parallel for cimg_openmp_if(size()>=65536)
11184 #endif 11152 #endif
11185 cimg_rof(*this,ptrd,T) *ptrd = (T)(((long)*ptrd) << (int)value); 11153 cimg_rof(*this,ptrd,T) *ptrd = (T)(((long)*ptrd) << (int)value);
11186 return *this; 11154 return *this;
@@ -11191,37 +11159,7 @@ namespace cimg_library_suffixed { @@ -11191,37 +11159,7 @@ namespace cimg_library_suffixed {
11191 Similar to operator+=(const char*), except that it performs a bitwise left shift instead of an addition. 11159 Similar to operator+=(const char*), except that it performs a bitwise left shift instead of an addition.
11192 **/ 11160 **/
11193 CImg<T>& operator<<=(const char *const expression) { 11161 CImg<T>& operator<<=(const char *const expression) {
11194 - if (is_empty()) return *this;  
11195 - const unsigned int omode = cimg::exception_mode();  
11196 - cimg::exception_mode(0);  
11197 - try {  
11198 - const CImg<T> _base = cimg::_is_self_expr(expression)?+*this:CImg<T>(), &base = _base?_base:*this;  
11199 - _cimg_math_parser mp(base,expression + (*expression=='>' || *expression=='<'?1:0),"operator<<=");  
11200 - T *ptrd = *expression=='<'?end() - 1:_data;  
11201 - if (*expression=='<') cimg_rofXYZC(*this,x,y,z,c) { *ptrd = (T)((long)*ptrd << (int)mp(x,y,z,c)); --ptrd; }  
11202 - else if (*expression=='>') cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)((long)*ptrd << (int)mp(x,y,z,c)); ++ptrd; }  
11203 - else {  
11204 -#ifdef cimg_use_openmp  
11205 - if (_width>=512 && _height*_depth*_spectrum>=2 && std::strlen(expression)>=6)  
11206 -#pragma omp parallel  
11207 - {  
11208 - _cimg_math_parser _mp = omp_get_thread_num()?mp:_cimg_math_parser(), &lmp = omp_get_thread_num()?_mp:mp;  
11209 -#pragma omp for collapse(3)  
11210 - cimg_forYZC(*this,y,z,c) {  
11211 - T *ptrd = data(0,y,z,c);  
11212 - cimg_forX(*this,x) { *ptrd = (T)((long)*ptrd << (int)lmp(x,y,z,c)); ++ptrd; }  
11213 - }  
11214 - }  
11215 - else  
11216 -#endif  
11217 - cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)((long)*ptrd << (int)mp(x,y,z,c)); ++ptrd; }  
11218 - }  
11219 - } catch (CImgException&) {  
11220 - cimg::exception_mode(omode);  
11221 - *this<<=CImg<T>(_width,_height,_depth,_spectrum,expression,true);  
11222 - }  
11223 - cimg::exception_mode(omode);  
11224 - return *this; 11162 + return *this<<=(+*this)._fill(expression,true,true,0,0,"operator<<=",this);
11225 } 11163 }
11226 11164
11227 //! In-place bitwise left shift operator. 11165 //! In-place bitwise left shift operator.
@@ -11280,7 +11218,7 @@ namespace cimg_library_suffixed { @@ -11280,7 +11218,7 @@ namespace cimg_library_suffixed {
11280 CImg<T>& operator>>=(const t value) { 11218 CImg<T>& operator>>=(const t value) {
11281 if (is_empty()) return *this; 11219 if (is_empty()) return *this;
11282 #ifdef cimg_use_openmp 11220 #ifdef cimg_use_openmp
11283 -#pragma omp parallel for if (size()>=65536) 11221 +#pragma omp parallel for cimg_openmp_if(size()>=65536)
11284 #endif 11222 #endif
11285 cimg_rof(*this,ptrd,T) *ptrd = (T)(((long)*ptrd) >> (int)value); 11223 cimg_rof(*this,ptrd,T) *ptrd = (T)(((long)*ptrd) >> (int)value);
11286 return *this; 11224 return *this;
@@ -11291,37 +11229,7 @@ namespace cimg_library_suffixed { @@ -11291,37 +11229,7 @@ namespace cimg_library_suffixed {
11291 Similar to operator+=(const char*), except that it performs a bitwise right shift instead of an addition. 11229 Similar to operator+=(const char*), except that it performs a bitwise right shift instead of an addition.
11292 **/ 11230 **/
11293 CImg<T>& operator>>=(const char *const expression) { 11231 CImg<T>& operator>>=(const char *const expression) {
11294 - if (is_empty()) return *this;  
11295 - const unsigned int omode = cimg::exception_mode();  
11296 - cimg::exception_mode(0);  
11297 - try {  
11298 - const CImg<T> _base = cimg::_is_self_expr(expression)?+*this:CImg<T>(), &base = _base?_base:*this;  
11299 - _cimg_math_parser mp(base,expression + (*expression=='>' || *expression=='<'?1:0),"operator<<=");  
11300 - T *ptrd = *expression=='<'?end() - 1:_data;  
11301 - if (*expression=='<') cimg_rofXYZC(*this,x,y,z,c) { *ptrd = (T)((long)*ptrd >> (int)mp(x,y,z,c)); --ptrd; }  
11302 - else if (*expression=='>') cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)((long)*ptrd >> (int)mp(x,y,z,c)); ++ptrd; }  
11303 - else {  
11304 -#ifdef cimg_use_openmp  
11305 - if (_width>=512 && _height*_depth*_spectrum>=2 && std::strlen(expression)>=6)  
11306 -#pragma omp parallel  
11307 - {  
11308 - _cimg_math_parser _mp = omp_get_thread_num()?mp:_cimg_math_parser(), &lmp = omp_get_thread_num()?_mp:mp;  
11309 -#pragma omp for collapse(3)  
11310 - cimg_forYZC(*this,y,z,c) {  
11311 - T *ptrd = data(0,y,z,c);  
11312 - cimg_forX(*this,x) { *ptrd = (T)((long)*ptrd >> (int)lmp(x,y,z,c)); ++ptrd; }  
11313 - }  
11314 - }  
11315 - else  
11316 -#endif  
11317 - cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)((long)*ptrd >> (int)mp(x,y,z,c)); ++ptrd; }  
11318 - }  
11319 - } catch (CImgException&) {  
11320 - cimg::exception_mode(omode);  
11321 - *this>>=CImg<T>(_width,_height,_depth,_spectrum,expression,true);  
11322 - }  
11323 - cimg::exception_mode(omode);  
11324 - return *this; 11232 + return *this>>=(+*this)._fill(expression,true,true,0,0,"operator>>=",this);
11325 } 11233 }
11326 11234
11327 //! In-place bitwise right shift operator. 11235 //! In-place bitwise right shift operator.
@@ -11403,25 +11311,7 @@ namespace cimg_library_suffixed { @@ -11403,25 +11311,7 @@ namespace cimg_library_suffixed {
11403 \param expression Value string describing the way pixel values are compared. 11311 \param expression Value string describing the way pixel values are compared.
11404 **/ 11312 **/
11405 bool operator==(const char *const expression) const { 11313 bool operator==(const char *const expression) const {
11406 - if (is_empty()) return !*expression;  
11407 - const unsigned int omode = cimg::exception_mode();  
11408 - cimg::exception_mode(0);  
11409 - bool is_equal = true;  
11410 - try {  
11411 - const CImg<T> _base = cimg::_is_self_expr(expression)?+*this:CImg<T>(), &base = _base?_base:*this;  
11412 - _cimg_math_parser mp(base,expression + (*expression=='>' || *expression=='<'?1:0),"operator<<=");  
11413 - const T *ptrs = *expression=='<'?end() - 1:_data;  
11414 - if (*expression=='<')  
11415 - cimg_rofXYZC(*this,x,y,z,c) { if (!is_equal) break; is_equal = ((double)*(ptrs--)==mp(x,y,z,c)); }  
11416 - else if (*expression=='>')  
11417 - cimg_forXYZC(*this,x,y,z,c) { if (!is_equal) break; is_equal = ((double)*(ptrs++)==mp(x,y,z,c)); }  
11418 - else cimg_forXYZC(*this,x,y,z,c) { if (!is_equal) break; is_equal = ((double)*(ptrs++)==mp(x,y,z,c)); }  
11419 - } catch (CImgException&) {  
11420 - cimg::exception_mode(omode);  
11421 - is_equal = (*this==CImg<T>(_width,_height,_depth,_spectrum,expression,true));  
11422 - }  
11423 - cimg::exception_mode(omode);  
11424 - return is_equal; 11314 + return *this==(+*this)._fill(expression,true,true,0,0,"operator==",this);
11425 } 11315 }
11426 11316
11427 //! Test if two images have the same size and values. 11317 //! Test if two images have the same size and values.
@@ -12946,6 +12836,8 @@ namespace cimg_library_suffixed { @@ -12946,6 +12836,8 @@ namespace cimg_library_suffixed {
12946 of the image instance (written in base 10), separated by specified \c separator character. 12836 of the image instance (written in base 10), separated by specified \c separator character.
12947 \param separator A \c char character which specifies the separator between values in the returned C-string. 12837 \param separator A \c char character which specifies the separator between values in the returned C-string.
12948 \param max_size Maximum size of the returned image. 12838 \param max_size Maximum size of the returned image.
  12839 + \param format For float-values, tell the printf format used to generate the ascii representation of the numbers.
  12840 + (or \c 0 for default representation).
12949 \note 12841 \note
12950 - The returned image is never empty. 12842 - The returned image is never empty.
12951 - For an empty image instance, the returned string is <tt>""</tt>. 12843 - For an empty image instance, the returned string is <tt>""</tt>.
@@ -12953,15 +12845,18 @@ namespace cimg_library_suffixed { @@ -12953,15 +12845,18 @@ namespace cimg_library_suffixed {
12953 - Otherwise, if the maximum number of string characters is exceeded, the value string is cut off 12845 - Otherwise, if the maximum number of string characters is exceeded, the value string is cut off
12954 and terminated by character \c '\0'. In that case, the returned image size is <tt>max_size + 1</tt>. 12846 and terminated by character \c '\0'. In that case, the returned image size is <tt>max_size + 1</tt>.
12955 **/ 12847 **/
12956 - CImg<charT> value_string(const char separator=',', const unsigned int max_size=0) const { 12848 + CImg<charT> value_string(const char separator=',', const unsigned int max_size=0,
  12849 + const char *const format=0) const {
12957 if (is_empty()) return CImg<charT>::string(""); 12850 if (is_empty()) return CImg<charT>::string("");
12958 CImgList<charT> items; 12851 CImgList<charT> items;
12959 CImg<charT> s_item(256); *s_item = 0; 12852 CImg<charT> s_item(256); *s_item = 0;
12960 const T *ptrs = _data; 12853 const T *ptrs = _data;
12961 unsigned int string_size = 0; 12854 unsigned int string_size = 0;
  12855 + const char *const _format = format?format:cimg::type<T>::format();
  12856 +
12962 for (unsigned long off = 0, siz = (unsigned int)size(); off<siz && string_size<=max_size; ++off) { 12857 for (unsigned long off = 0, siz = (unsigned int)size(); off<siz && string_size<=max_size; ++off) {
12963 - const unsigned int printed_size = 1U + cimg_snprintf(s_item,s_item._width,  
12964 - cimg::type<T>::format(),cimg::type<T>::format(*(ptrs++))); 12858 + const unsigned int printed_size = 1U + cimg_snprintf(s_item,s_item._width,_format,
  12859 + cimg::type<T>::format(*(ptrs++)));
12965 CImg<charT> item(s_item._data,printed_size); 12860 CImg<charT> item(s_item._data,printed_size);
12966 item[printed_size - 1] = separator; 12861 item[printed_size - 1] = separator;
12967 item.move_to(items); 12862 item.move_to(items);
@@ -13011,9 +12906,9 @@ namespace cimg_library_suffixed { @@ -13011,9 +12906,9 @@ namespace cimg_library_suffixed {
13011 return false; 12906 return false;
13012 } 12907 }
13013 12908
13014 - //! Test if image instance contains a 'nan' value. 12909 + //! Test if image instance contains a NaN value.
13015 /** 12910 /**
13016 - Return \c true, if image instance contains a 'nan' value, and \c false otherwise. 12911 + Return \c true, if image instance contains a NaN value, and \c false otherwise.
13017 **/ 12912 **/
13018 bool is_nan() const { 12913 bool is_nan() const {
13019 if (cimg::type<T>::is_float()) cimg_for(*this,p,T) if (cimg::type<T>::is_nan((float)*p)) return true; 12914 if (cimg::type<T>::is_float()) cimg_for(*this,p,T) if (cimg::type<T>::is_nan((float)*p)) return true;
@@ -13430,7 +13325,7 @@ namespace cimg_library_suffixed { @@ -13430,7 +13325,7 @@ namespace cimg_library_suffixed {
13430 // Check consistency for the particular case of an empty 3d object. 13325 // Check consistency for the particular case of an empty 3d object.
13431 if (is_empty()) { 13326 if (is_empty()) {
13432 if (primitives || colors || opacities) { 13327 if (primitives || colors || opacities) {
13433 - if (error_message) std::sprintf(error_message, 13328 + if (error_message) cimg_sprintf(error_message,
13434 "3d object (%u,%u) defines no vertices but %u primitives, " 13329 "3d object (%u,%u) defines no vertices but %u primitives, "
13435 "%u colors and %lu opacities", 13330 "%u colors and %lu opacities",
13436 _width,primitives._width,primitives._width, 13331 _width,primitives._width,primitives._width,
@@ -13442,19 +13337,19 @@ namespace cimg_library_suffixed { @@ -13442,19 +13337,19 @@ namespace cimg_library_suffixed {
13442 13337
13443 // Check consistency of vertices. 13338 // Check consistency of vertices.
13444 if (_height!=3 || _depth>1 || _spectrum>1) { // Check vertices dimensions. 13339 if (_height!=3 || _depth>1 || _spectrum>1) { // Check vertices dimensions.
13445 - if (error_message) std::sprintf(error_message, 13340 + if (error_message) cimg_sprintf(error_message,
13446 "3d object (%u,%u) has invalid vertex dimensions (%u,%u,%u,%u)", 13341 "3d object (%u,%u) has invalid vertex dimensions (%u,%u,%u,%u)",
13447 _width,primitives._width,_width,_height,_depth,_spectrum); 13342 _width,primitives._width,_width,_height,_depth,_spectrum);
13448 return false; 13343 return false;
13449 } 13344 }
13450 if (colors._width>primitives._width + 1) { 13345 if (colors._width>primitives._width + 1) {
13451 - if (error_message) std::sprintf(error_message, 13346 + if (error_message) cimg_sprintf(error_message,
13452 "3d object (%u,%u) defines %u colors", 13347 "3d object (%u,%u) defines %u colors",
13453 _width,primitives._width,colors._width); 13348 _width,primitives._width,colors._width);
13454 return false; 13349 return false;
13455 } 13350 }
13456 if (opacities.size()>primitives._width) { 13351 if (opacities.size()>primitives._width) {
13457 - if (error_message) std::sprintf(error_message, 13352 + if (error_message) cimg_sprintf(error_message,
13458 "3d object (%u,%u) defines %lu opacities", 13353 "3d object (%u,%u) defines %lu opacities",
13459 _width,primitives._width,(unsigned long)opacities.size()); 13354 _width,primitives._width,(unsigned long)opacities.size());
13460 return false; 13355 return false;
@@ -13469,7 +13364,7 @@ namespace cimg_library_suffixed { @@ -13469,7 +13364,7 @@ namespace cimg_library_suffixed {
13469 case 1 : { // Point. 13364 case 1 : { // Point.
13470 const unsigned int i0 = (unsigned int)primitive(0); 13365 const unsigned int i0 = (unsigned int)primitive(0);
13471 if (i0>=_width) { 13366 if (i0>=_width) {
13472 - if (error_message) std::sprintf(error_message, 13367 + if (error_message) cimg_sprintf(error_message,
13473 "3d object (%u,%u) refers to invalid vertex indice %u in " 13368 "3d object (%u,%u) refers to invalid vertex indice %u in "
13474 "point primitive [%u]", 13369 "point primitive [%u]",
13475 _width,primitives._width,i0,l); 13370 _width,primitives._width,i0,l);
@@ -13481,7 +13376,7 @@ namespace cimg_library_suffixed { @@ -13481,7 +13376,7 @@ namespace cimg_library_suffixed {
13481 i0 = (unsigned int)primitive(0), 13376 i0 = (unsigned int)primitive(0),
13482 i1 = (unsigned int)primitive(1); 13377 i1 = (unsigned int)primitive(1);
13483 if (i0>=_width || i1>=_width) { 13378 if (i0>=_width || i1>=_width) {
13484 - if (error_message) std::sprintf(error_message, 13379 + if (error_message) cimg_sprintf(error_message,
13485 "3d object (%u,%u) refers to invalid vertex indices (%u,%u) in " 13380 "3d object (%u,%u) refers to invalid vertex indices (%u,%u) in "
13486 "sphere primitive [%u]", 13381 "sphere primitive [%u]",
13487 _width,primitives._width,i0,i1,l); 13382 _width,primitives._width,i0,i1,l);
@@ -13494,7 +13389,7 @@ namespace cimg_library_suffixed { @@ -13494,7 +13389,7 @@ namespace cimg_library_suffixed {
13494 i0 = (unsigned int)primitive(0), 13389 i0 = (unsigned int)primitive(0),
13495 i1 = (unsigned int)primitive(1); 13390 i1 = (unsigned int)primitive(1);
13496 if (i0>=_width || i1>=_width) { 13391 if (i0>=_width || i1>=_width) {
13497 - if (error_message) std::sprintf(error_message, 13392 + if (error_message) cimg_sprintf(error_message,
13498 "3d object (%u,%u) refers to invalid vertex indices (%u,%u) in " 13393 "3d object (%u,%u) refers to invalid vertex indices (%u,%u) in "
13499 "segment primitive [%u]", 13394 "segment primitive [%u]",
13500 _width,primitives._width,i0,i1,l); 13395 _width,primitives._width,i0,i1,l);
@@ -13508,7 +13403,7 @@ namespace cimg_library_suffixed { @@ -13508,7 +13403,7 @@ namespace cimg_library_suffixed {
13508 i1 = (unsigned int)primitive(1), 13403 i1 = (unsigned int)primitive(1),
13509 i2 = (unsigned int)primitive(2); 13404 i2 = (unsigned int)primitive(2);
13510 if (i0>=_width || i1>=_width || i2>=_width) { 13405 if (i0>=_width || i1>=_width || i2>=_width) {
13511 - if (error_message) std::sprintf(error_message, 13406 + if (error_message) cimg_sprintf(error_message,
13512 "3d object (%u,%u) refers to invalid vertex indices (%u,%u,%u) in " 13407 "3d object (%u,%u) refers to invalid vertex indices (%u,%u,%u) in "
13513 "triangle primitive [%u]", 13408 "triangle primitive [%u]",
13514 _width,primitives._width,i0,i1,i2,l); 13409 _width,primitives._width,i0,i1,i2,l);
@@ -13523,7 +13418,7 @@ namespace cimg_library_suffixed { @@ -13523,7 +13418,7 @@ namespace cimg_library_suffixed {
13523 i2 = (unsigned int)primitive(2), 13418 i2 = (unsigned int)primitive(2),
13524 i3 = (unsigned int)primitive(3); 13419 i3 = (unsigned int)primitive(3);
13525 if (i0>=_width || i1>=_width || i2>=_width || i3>=_width) { 13420 if (i0>=_width || i1>=_width || i2>=_width || i3>=_width) {
13526 - if (error_message) std::sprintf(error_message, 13421 + if (error_message) cimg_sprintf(error_message,
13527 "3d object (%u,%u) refers to invalid vertex indices (%u,%u,%u,%u) in " 13422 "3d object (%u,%u) refers to invalid vertex indices (%u,%u,%u,%u) in "
13528 "quadrangle primitive [%u]", 13423 "quadrangle primitive [%u]",
13529 _width,primitives._width,i0,i1,i2,i3,l); 13424 _width,primitives._width,i0,i1,i2,i3,l);
@@ -13531,7 +13426,7 @@ namespace cimg_library_suffixed { @@ -13531,7 +13426,7 @@ namespace cimg_library_suffixed {
13531 } 13426 }
13532 } break; 13427 } break;
13533 default : 13428 default :
13534 - if (error_message) std::sprintf(error_message, 13429 + if (error_message) cimg_sprintf(error_message,
13535 "3d object (%u,%u) defines an invalid primitive [%u] of size %u", 13430 "3d object (%u,%u) defines an invalid primitive [%u] of size %u",
13536 _width,primitives._width,l,(unsigned int)psiz); 13431 _width,primitives._width,l,(unsigned int)psiz);
13537 return false; 13432 return false;
@@ -13542,7 +13437,7 @@ namespace cimg_library_suffixed { @@ -13542,7 +13437,7 @@ namespace cimg_library_suffixed {
13542 cimglist_for(colors,c) { 13437 cimglist_for(colors,c) {
13543 const CImg<tc>& color = colors[c]; 13438 const CImg<tc>& color = colors[c];
13544 if (!color) { 13439 if (!color) {
13545 - if (error_message) std::sprintf(error_message, 13440 + if (error_message) cimg_sprintf(error_message,
13546 "3d object (%u,%u) defines no color for primitive [%u]", 13441 "3d object (%u,%u) defines no color for primitive [%u]",
13547 _width,primitives._width,c); 13442 _width,primitives._width,c);
13548 return false; 13443 return false;
@@ -13553,7 +13448,7 @@ namespace cimg_library_suffixed { @@ -13553,7 +13448,7 @@ namespace cimg_library_suffixed {
13553 if (colors._width>primitives._width) { 13448 if (colors._width>primitives._width) {
13554 const CImg<tc> &light = colors.back(); 13449 const CImg<tc> &light = colors.back();
13555 if (!light || light._depth>1) { 13450 if (!light || light._depth>1) {
13556 - if (error_message) std::sprintf(error_message, 13451 + if (error_message) cimg_sprintf(error_message,
13557 "3d object (%u,%u) defines an invalid light texture (%u,%u,%u,%u)", 13452 "3d object (%u,%u) defines an invalid light texture (%u,%u,%u,%u)",
13558 _width,primitives._width,light._width, 13453 _width,primitives._width,light._width,
13559 light._height,light._depth,light._spectrum); 13454 light._height,light._depth,light._spectrum);
@@ -13579,7 +13474,7 @@ namespace cimg_library_suffixed { @@ -13579,7 +13474,7 @@ namespace cimg_library_suffixed {
13579 13474
13580 // Check instance dimension and header. 13475 // Check instance dimension and header.
13581 if (_width!=1 || _height<8 || _depth!=1 || _spectrum!=1) { 13476 if (_width!=1 || _height<8 || _depth!=1 || _spectrum!=1) {
13582 - if (error_message) std::sprintf(error_message, 13477 + if (error_message) cimg_sprintf(error_message,
13583 "CImg3d has invalid dimensions (%u,%u,%u,%u)", 13478 "CImg3d has invalid dimensions (%u,%u,%u,%u)",
13584 _width,_height,_depth,_spectrum); 13479 _width,_height,_depth,_spectrum);
13585 return false; 13480 return false;
@@ -13587,7 +13482,7 @@ namespace cimg_library_suffixed { @@ -13587,7 +13482,7 @@ namespace cimg_library_suffixed {
13587 const T *ptrs = _data, *const ptre = end(); 13482 const T *ptrs = _data, *const ptre = end();
13588 if (!_is_CImg3d(*(ptrs++),'C') || !_is_CImg3d(*(ptrs++),'I') || !_is_CImg3d(*(ptrs++),'m') || 13483 if (!_is_CImg3d(*(ptrs++),'C') || !_is_CImg3d(*(ptrs++),'I') || !_is_CImg3d(*(ptrs++),'m') ||
13589 !_is_CImg3d(*(ptrs++),'g') || !_is_CImg3d(*(ptrs++),'3') || !_is_CImg3d(*(ptrs++),'d')) { 13484 !_is_CImg3d(*(ptrs++),'g') || !_is_CImg3d(*(ptrs++),'3') || !_is_CImg3d(*(ptrs++),'d')) {
13590 - if (error_message) std::sprintf(error_message, 13485 + if (error_message) cimg_sprintf(error_message,
13591 "CImg3d header not found"); 13486 "CImg3d header not found");
13592 return false; 13487 return false;
13593 } 13488 }
@@ -13599,7 +13494,7 @@ namespace cimg_library_suffixed { @@ -13599,7 +13494,7 @@ namespace cimg_library_suffixed {
13599 if (!full_check) { 13494 if (!full_check) {
13600 const unsigned long minimal_size = 8UL + 3*nb_points + 6*nb_primitives; 13495 const unsigned long minimal_size = 8UL + 3*nb_points + 6*nb_primitives;
13601 if (_data + minimal_size>ptre) { 13496 if (_data + minimal_size>ptre) {
13602 - if (error_message) std::sprintf(error_message, 13497 + if (error_message) cimg_sprintf(error_message,
13603 "CImg3d (%u,%u) has only %lu values, while at least %lu values were expected", 13498 "CImg3d (%u,%u) has only %lu values, while at least %lu values were expected",
13604 nb_points,nb_primitives,size(),minimal_size); 13499 nb_points,nb_primitives,size(),minimal_size);
13605 return false; 13500 return false;
@@ -13609,13 +13504,13 @@ namespace cimg_library_suffixed { @@ -13609,13 +13504,13 @@ namespace cimg_library_suffixed {
13609 // Check consistency of vertex data. 13504 // Check consistency of vertex data.
13610 if (!nb_points) { 13505 if (!nb_points) {
13611 if (nb_primitives) { 13506 if (nb_primitives) {
13612 - if (error_message) std::sprintf(error_message, 13507 + if (error_message) cimg_sprintf(error_message,
13613 "CImg3d (%u,%u) defines no vertices but %u primitives", 13508 "CImg3d (%u,%u) defines no vertices but %u primitives",
13614 nb_points,nb_primitives,nb_primitives); 13509 nb_points,nb_primitives,nb_primitives);
13615 return false; 13510 return false;
13616 } 13511 }
13617 if (ptrs!=ptre) { 13512 if (ptrs!=ptre) {
13618 - if (error_message) std::sprintf(error_message, 13513 + if (error_message) cimg_sprintf(error_message,
13619 "CImg3d (%u,%u) is an empty object but contains %u value%s " 13514 "CImg3d (%u,%u) is an empty object but contains %u value%s "
13620 "more than expected", 13515 "more than expected",
13621 nb_points,nb_primitives,(unsigned int)(ptre - ptrs),(ptre - ptrs)>1?"s":""); 13516 nb_points,nb_primitives,(unsigned int)(ptre - ptrs),(ptre - ptrs)>1?"s":"");
@@ -13624,7 +13519,7 @@ namespace cimg_library_suffixed { @@ -13624,7 +13519,7 @@ namespace cimg_library_suffixed {
13624 return true; 13519 return true;
13625 } 13520 }
13626 if (ptrs + 3*nb_points>ptre) { 13521 if (ptrs + 3*nb_points>ptre) {
13627 - if (error_message) std::sprintf(error_message, 13522 + if (error_message) cimg_sprintf(error_message,
13628 "CImg3d (%u,%u) defines only %u vertices data", 13523 "CImg3d (%u,%u) defines only %u vertices data",
13629 nb_points,nb_primitives,(unsigned int)(ptre - ptrs)/3); 13524 nb_points,nb_primitives,(unsigned int)(ptre - ptrs)/3);
13630 return false; 13525 return false;
@@ -13633,7 +13528,7 @@ namespace cimg_library_suffixed { @@ -13633,7 +13528,7 @@ namespace cimg_library_suffixed {
13633 13528
13634 // Check consistency of primitive data. 13529 // Check consistency of primitive data.
13635 if (ptrs==ptre) { 13530 if (ptrs==ptre) {
13636 - if (error_message) std::sprintf(error_message, 13531 + if (error_message) cimg_sprintf(error_message,
13637 "CImg3d (%u,%u) defines %u vertices but no primitive", 13532 "CImg3d (%u,%u) defines %u vertices but no primitive",
13638 nb_points,nb_primitives,nb_points); 13533 nb_points,nb_primitives,nb_points);
13639 return false; 13534 return false;
@@ -13647,7 +13542,7 @@ namespace cimg_library_suffixed { @@ -13647,7 +13542,7 @@ namespace cimg_library_suffixed {
13647 case 1 : { // Point. 13542 case 1 : { // Point.
13648 const unsigned int i0 = cimg::float2uint((float)*(ptrs++)); 13543 const unsigned int i0 = cimg::float2uint((float)*(ptrs++));
13649 if (i0>=nb_points) { 13544 if (i0>=nb_points) {
13650 - if (error_message) std::sprintf(error_message, 13545 + if (error_message) cimg_sprintf(error_message,
13651 "CImg3d (%u,%u) refers to invalid vertex indice %u in point primitive [%u]", 13546 "CImg3d (%u,%u) refers to invalid vertex indice %u in point primitive [%u]",
13652 nb_points,nb_primitives,i0,p); 13547 nb_points,nb_primitives,i0,p);
13653 return false; 13548 return false;
@@ -13659,7 +13554,7 @@ namespace cimg_library_suffixed { @@ -13659,7 +13554,7 @@ namespace cimg_library_suffixed {
13659 i1 = cimg::float2uint((float)*(ptrs++)); 13554 i1 = cimg::float2uint((float)*(ptrs++));
13660 ptrs+=3; 13555 ptrs+=3;
13661 if (i0>=nb_points || i1>=nb_points) { 13556 if (i0>=nb_points || i1>=nb_points) {
13662 - if (error_message) std::sprintf(error_message, 13557 + if (error_message) cimg_sprintf(error_message,
13663 "CImg3d (%u,%u) refers to invalid vertex indices (%u,%u) in " 13558 "CImg3d (%u,%u) refers to invalid vertex indices (%u,%u) in "
13664 "sphere primitive [%u]", 13559 "sphere primitive [%u]",
13665 nb_points,nb_primitives,i0,i1,p); 13560 nb_points,nb_primitives,i0,i1,p);
@@ -13672,7 +13567,7 @@ namespace cimg_library_suffixed { @@ -13672,7 +13567,7 @@ namespace cimg_library_suffixed {
13672 i1 = cimg::float2uint((float)*(ptrs++)); 13567 i1 = cimg::float2uint((float)*(ptrs++));
13673 if (nb_inds==6) ptrs+=4; 13568 if (nb_inds==6) ptrs+=4;
13674 if (i0>=nb_points || i1>=nb_points) { 13569 if (i0>=nb_points || i1>=nb_points) {
13675 - if (error_message) std::sprintf(error_message, 13570 + if (error_message) cimg_sprintf(error_message,
13676 "CImg3d (%u,%u) refers to invalid vertex indices (%u,%u) in " 13571 "CImg3d (%u,%u) refers to invalid vertex indices (%u,%u) in "
13677 "segment primitive [%u]", 13572 "segment primitive [%u]",
13678 nb_points,nb_primitives,i0,i1,p); 13573 nb_points,nb_primitives,i0,i1,p);
@@ -13686,7 +13581,7 @@ namespace cimg_library_suffixed { @@ -13686,7 +13581,7 @@ namespace cimg_library_suffixed {
13686 i2 = cimg::float2uint((float)*(ptrs++)); 13581 i2 = cimg::float2uint((float)*(ptrs++));
13687 if (nb_inds==9) ptrs+=6; 13582 if (nb_inds==9) ptrs+=6;
13688 if (i0>=nb_points || i1>=nb_points || i2>=nb_points) { 13583 if (i0>=nb_points || i1>=nb_points || i2>=nb_points) {
13689 - if (error_message) std::sprintf(error_message, 13584 + if (error_message) cimg_sprintf(error_message,
13690 "CImg3d (%u,%u) refers to invalid vertex indices (%u,%u,%u) in " 13585 "CImg3d (%u,%u) refers to invalid vertex indices (%u,%u,%u) in "
13691 "triangle primitive [%u]", 13586 "triangle primitive [%u]",
13692 nb_points,nb_primitives,i0,i1,i2,p); 13587 nb_points,nb_primitives,i0,i1,i2,p);
@@ -13701,7 +13596,7 @@ namespace cimg_library_suffixed { @@ -13701,7 +13596,7 @@ namespace cimg_library_suffixed {
13701 i3 = cimg::float2uint((float)*(ptrs++)); 13596 i3 = cimg::float2uint((float)*(ptrs++));
13702 if (nb_inds==12) ptrs+=8; 13597 if (nb_inds==12) ptrs+=8;
13703 if (i0>=nb_points || i1>=nb_points || i2>=nb_points || i3>=nb_points) { 13598 if (i0>=nb_points || i1>=nb_points || i2>=nb_points || i3>=nb_points) {
13704 - if (error_message) std::sprintf(error_message, 13599 + if (error_message) cimg_sprintf(error_message,
13705 "CImg3d (%u,%u) refers to invalid vertex indices (%u,%u,%u,%u) in " 13600 "CImg3d (%u,%u) refers to invalid vertex indices (%u,%u,%u,%u) in "
13706 "quadrangle primitive [%u]", 13601 "quadrangle primitive [%u]",
13707 nb_points,nb_primitives,i0,i1,i2,i3,p); 13602 nb_points,nb_primitives,i0,i1,i2,i3,p);
@@ -13709,13 +13604,13 @@ namespace cimg_library_suffixed { @@ -13709,13 +13604,13 @@ namespace cimg_library_suffixed {
13709 } 13604 }
13710 } break; 13605 } break;
13711 default : 13606 default :
13712 - if (error_message) std::sprintf(error_message, 13607 + if (error_message) cimg_sprintf(error_message,
13713 "CImg3d (%u,%u) defines an invalid primitive [%u] of size %u", 13608 "CImg3d (%u,%u) defines an invalid primitive [%u] of size %u",
13714 nb_points,nb_primitives,p,nb_inds); 13609 nb_points,nb_primitives,p,nb_inds);
13715 return false; 13610 return false;
13716 } 13611 }
13717 if (ptrs>ptre) { 13612 if (ptrs>ptre) {
13718 - if (error_message) std::sprintf(error_message, 13613 + if (error_message) cimg_sprintf(error_message,
13719 "CImg3d (%u,%u) has incomplete primitive data for primitive [%u], " 13614 "CImg3d (%u,%u) has incomplete primitive data for primitive [%u], "
13720 "%u values missing", 13615 "%u values missing",
13721 nb_points,nb_primitives,p,(unsigned int)(ptrs - ptre)); 13616 nb_points,nb_primitives,p,(unsigned int)(ptrs - ptre));
@@ -13725,7 +13620,7 @@ namespace cimg_library_suffixed { @@ -13725,7 +13620,7 @@ namespace cimg_library_suffixed {
13725 13620
13726 // Check consistency of color data. 13621 // Check consistency of color data.
13727 if (ptrs==ptre) { 13622 if (ptrs==ptre) {
13728 - if (error_message) std::sprintf(error_message, 13623 + if (error_message) cimg_sprintf(error_message,
13729 "CImg3d (%u,%u) defines no color/texture data", 13624 "CImg3d (%u,%u) defines no color/texture data",
13730 nb_points,nb_primitives); 13625 nb_points,nb_primitives);
13731 return false; 13626 return false;
@@ -13739,7 +13634,7 @@ namespace cimg_library_suffixed { @@ -13739,7 +13634,7 @@ namespace cimg_library_suffixed {
13739 s = (unsigned int)*(ptrs - 1); 13634 s = (unsigned int)*(ptrs - 1);
13740 if (!h && !s) { 13635 if (!h && !s) {
13741 if (w>=c) { 13636 if (w>=c) {
13742 - if (error_message) std::sprintf(error_message, 13637 + if (error_message) cimg_sprintf(error_message,
13743 "CImg3d (%u,%u) refers to invalid shared sprite/texture indice %u " 13638 "CImg3d (%u,%u) refers to invalid shared sprite/texture indice %u "
13744 "for primitive [%u]", 13639 "for primitive [%u]",
13745 nb_points,nb_primitives,w,c); 13640 nb_points,nb_primitives,w,c);
@@ -13748,7 +13643,7 @@ namespace cimg_library_suffixed { @@ -13748,7 +13643,7 @@ namespace cimg_library_suffixed {
13748 } else ptrs+=w*h*s; 13643 } else ptrs+=w*h*s;
13749 } 13644 }
13750 if (ptrs>ptre) { 13645 if (ptrs>ptre) {
13751 - if (error_message) std::sprintf(error_message, 13646 + if (error_message) cimg_sprintf(error_message,
13752 "CImg3d (%u,%u) has incomplete color/texture data for primitive [%u], " 13647 "CImg3d (%u,%u) has incomplete color/texture data for primitive [%u], "
13753 "%u values missing", 13648 "%u values missing",
13754 nb_points,nb_primitives,c,(unsigned int)(ptrs - ptre)); 13649 nb_points,nb_primitives,c,(unsigned int)(ptrs - ptre));
@@ -13758,7 +13653,7 @@ namespace cimg_library_suffixed { @@ -13758,7 +13653,7 @@ namespace cimg_library_suffixed {
13758 13653
13759 // Check consistency of opacity data. 13654 // Check consistency of opacity data.
13760 if (ptrs==ptre) { 13655 if (ptrs==ptre) {
13761 - if (error_message) std::sprintf(error_message, 13656 + if (error_message) cimg_sprintf(error_message,
13762 "CImg3d (%u,%u) defines no opacity data", 13657 "CImg3d (%u,%u) defines no opacity data",
13763 nb_points,nb_primitives); 13658 nb_points,nb_primitives);
13764 return false; 13659 return false;
@@ -13771,7 +13666,7 @@ namespace cimg_library_suffixed { @@ -13771,7 +13666,7 @@ namespace cimg_library_suffixed {
13771 s = (unsigned int)*(ptrs - 1); 13666 s = (unsigned int)*(ptrs - 1);
13772 if (!h && !s) { 13667 if (!h && !s) {
13773 if (w>=o) { 13668 if (w>=o) {
13774 - if (error_message) std::sprintf(error_message, 13669 + if (error_message) cimg_sprintf(error_message,
13775 "CImg3d (%u,%u) refers to invalid shared opacity indice %u " 13670 "CImg3d (%u,%u) refers to invalid shared opacity indice %u "
13776 "for primitive [%u]", 13671 "for primitive [%u]",
13777 nb_points,nb_primitives,w,o); 13672 nb_points,nb_primitives,w,o);
@@ -13780,7 +13675,7 @@ namespace cimg_library_suffixed { @@ -13780,7 +13675,7 @@ namespace cimg_library_suffixed {
13780 } else ptrs+=w*h*s; 13675 } else ptrs+=w*h*s;
13781 } 13676 }
13782 if (ptrs>ptre) { 13677 if (ptrs>ptre) {
13783 - if (error_message) std::sprintf(error_message, 13678 + if (error_message) cimg_sprintf(error_message,
13784 "CImg3d (%u,%u) has incomplete opacity data for primitive [%u]", 13679 "CImg3d (%u,%u) has incomplete opacity data for primitive [%u]",
13785 nb_points,nb_primitives,o); 13680 nb_points,nb_primitives,o);
13786 return false; 13681 return false;
@@ -13789,7 +13684,7 @@ namespace cimg_library_suffixed { @@ -13789,7 +13684,7 @@ namespace cimg_library_suffixed {
13789 13684
13790 // Check end of data. 13685 // Check end of data.
13791 if (ptrs<ptre) { 13686 if (ptrs<ptre) {
13792 - if (error_message) std::sprintf(error_message, 13687 + if (error_message) cimg_sprintf(error_message,
13793 "CImg3d (%u,%u) contains %u value%s more than expected", 13688 "CImg3d (%u,%u) contains %u value%s more than expected",
13794 nb_points,nb_primitives,(unsigned int)(ptre - ptrs),(ptre - ptrs)>1?"s":""); 13689 nb_points,nb_primitives,(unsigned int)(ptre - ptrs),(ptre - ptrs)>1?"s":"");
13795 return false; 13690 return false;
@@ -13808,1106 +13703,5206 @@ namespace cimg_library_suffixed { @@ -13808,1106 +13703,5206 @@ namespace cimg_library_suffixed {
13808 //@{ 13703 //@{
13809 //------------------------------------- 13704 //-------------------------------------
13810 13705
13811 - // Define the math formula parser/compiler and evaluator. 13706 + // Define the math formula parser/compiler and expression evaluator.
13812 struct _cimg_math_parser { 13707 struct _cimg_math_parser {
13813 - CImgList<longT> code;  
13814 - CImg<longT> opcode;  
13815 - const CImg<longT>* p_code;  
13816 - CImgList<charT> labelM;  
13817 - CImg<uintT> level, labelMpos, reserved_label;  
13818 CImg<doubleT> mem; 13708 CImg<doubleT> mem;
13819 - CImg<charT> expr;  
13820 - const CImg<T>& reference;  
13821 - CImg<Tdouble> reference_stats;  
13822 - double median_value;  
13823 - bool is_median_value;  
13824 - unsigned int mempos, result; 13709 + CImg<intT> memtype;
  13710 + CImgList<uptrT> _code, &code;
  13711 + CImg<uptrT> opcode;
  13712 + const CImg<uptrT> *p_code_begin, *p_code_end, *p_code;
  13713 +
  13714 + CImg<charT> expr, pexpr;
  13715 + const CImg<T>& imgin;
  13716 + const CImgList<T>& listin;
  13717 + CImg<T> &imgout;
  13718 + CImgList<T>& listout;
  13719 +
  13720 + CImg<doubleT> _img_stats, &img_stats;
  13721 + CImgList<doubleT> _list_stats, &list_stats, _list_median, &list_median;
  13722 + CImg<uintT> mem_img_stats;
  13723 +
  13724 + CImg<uintT> level, variable_pos, reserved_label;
  13725 + CImgList<charT> variable_def, function_def, function_body;
  13726 + char *user_function;
  13727 +
  13728 + unsigned int mempos, mem_img_median, debug_indent, init_size, result_dim;
  13729 + double *result;
13825 const char *const calling_function; 13730 const char *const calling_function;
13826 typedef double (*mp_func)(_cimg_math_parser&); 13731 typedef double (*mp_func)(_cimg_math_parser&);
13827 13732
  13733 +#define _cimg_mp_is_constant(arg) (memtype[arg]==1) // Is constant?
  13734 +#define _cimg_mp_is_scalar(arg) (memtype[arg]<2) // Is scalar?
  13735 +#define _cimg_mp_is_temp(arg) (!memtype[arg]) // Is temporary scalar?
  13736 +#define _cimg_mp_is_variable(arg) (memtype[arg]==-1) // Is scalar variable?
  13737 +#define _cimg_mp_is_vector(arg) (memtype[arg]>1) // Is vector?
  13738 +#define _cimg_mp_vector_size(arg) (_cimg_mp_is_scalar(arg)?0U:(unsigned int)memtype[arg] - 1) // Vector size
  13739 +#define _cimg_mp_calling_function calling_function_s()._data
  13740 +#define _cimg_mp_check_type(arg,n_arg,s_op,mode,N) check_type(arg,n_arg,s_op,mode,N,ss,se,saved_char)
  13741 +#define _cimg_mp_check_constant(arg,n_arg,s_op,is_strict) check_constant(arg,n_arg,s_op,is_strict,ss,se,saved_char)
  13742 +#define _cimg_mp_check_matrix_square(arg,n_arg,s_op) check_matrix_square(arg,n_arg,s_op,ss,se,saved_char)
  13743 +#define _cimg_mp_check_vector0(dim,s_op) check_vector0(dim,s_op,ss,se,saved_char)
  13744 +#define _cimg_mp_defunc(mp) (*(mp_func)(*(mp).opcode))(mp)
13828 #define _cimg_mp_return(x) { *se = saved_char; return x; } 13745 #define _cimg_mp_return(x) { *se = saved_char; return x; }
13829 -#define _cimg_mp_opcode0(op) _cimg_mp_return(opcode0(op));  
13830 -#define _cimg_mp_opcode1(op,i1) _cimg_mp_return(opcode1(op,i1));  
13831 -#define _cimg_mp_opcode2(op,i1,i2) { const unsigned int _i1 = i1, _i2 = i2; _cimg_mp_return(opcode2(op,_i1,_i2)); }  
13832 -#define _cimg_mp_opcode3(op,i1,i2,i3) \  
13833 - { const unsigned int _i1 = i1, _i2 = i2, _i3 = i3; _cimg_mp_return(opcode3(op,_i1,_i2,_i3)); }  
13834 -#define _cimg_mp_opcode6(op,i1,i2,i3,i4,i5,i6) \  
13835 - { const unsigned int _i1 = i1, _i2 = i2, _i3 = i3, _i4 = i4, _i5 = i5, _i6 = i6; \  
13836 - _cimg_mp_return(opcode6(op,_i1,_i2,_i3,_i4,_i5,_i6)); }  
13837 -  
13838 -#if defined(_WIN64)  
13839 - // On Win64 and gcc 4.7, sizeof(long)!=sizeof(pointer), so a workaround is needed..  
13840 -#define _cimg_mp_enfunc(op) (long)((char*)(op) - (char*)mp_u)  
13841 -#define _cimg_mp_defunc(mp) (*(mp_func)((char*)mp_u + (mp).opcode[0]))(mp)  
13842 -#else  
13843 -#define _cimg_mp_enfunc(op) (long)(op)  
13844 -#define _cimg_mp_defunc(mp) (*(mp_func)((mp).opcode[0]))(mp)  
13845 -#endif 13746 +#define _cimg_mp_constant(val) _cimg_mp_return(constant(val))
  13747 +#define _cimg_mp_scalar0(op) _cimg_mp_return(scalar0(op))
  13748 +#define _cimg_mp_scalar1(op,i1) _cimg_mp_return(scalar1(op,i1))
  13749 +#define _cimg_mp_scalar2(op,i1,i2) _cimg_mp_return(scalar2(op,i1,i2))
  13750 +#define _cimg_mp_scalar3(op,i1,i2,i3) _cimg_mp_return(scalar3(op,i1,i2,i3))
  13751 +#define _cimg_mp_scalar6(op,i1,i2,i3,i4,i5,i6) _cimg_mp_return(scalar6(op,i1,i2,i3,i4,i5,i6))
  13752 +#define _cimg_mp_scalar7(op,i1,i2,i3,i4,i5,i6,i7) _cimg_mp_return(scalar7(op,i1,i2,i3,i4,i5,i6,i7))
  13753 +#define _cimg_mp_vector1_v(op,i1) _cimg_mp_return(vector1_v(op,i1))
  13754 +#define _cimg_mp_vector2_sv(op,i1,i2) _cimg_mp_return(vector2_sv(op,i1,i2))
  13755 +#define _cimg_mp_vector2_vs(op,i1,i2) _cimg_mp_return(vector2_vs(op,i1,i2))
  13756 +#define _cimg_mp_vector2_vv(op,i1,i2) _cimg_mp_return(vector2_vv(op,i1,i2))
  13757 +#define _cimg_mp_vector3_vss(op,i1,i2,i3) _cimg_mp_return(vector3_vss(op,i1,i2,i3))
13846 13758
13847 // Constructors. 13759 // Constructors.
13848 - _cimg_math_parser():reference(CImg<T>::empty()),median_value(0),is_median_value(false),calling_function(0) {}  
13849 -  
13850 - _cimg_math_parser(const CImg<T>& img, const char *const expression, const char *const funcname=0):  
13851 - reference(img),median_value(0),is_median_value(false),calling_function(funcname?funcname:"cimg_math_parser") { 13760 + _cimg_math_parser(const char *const expression, const char *const funcname=0,
  13761 + const CImg<T>& img_input=CImg<T>::const_empty(), CImg<T> *const img_output=0,
  13762 + const CImgList<T> *const list_input=0, CImgList<T> *const list_output=0):
  13763 + code(_code),imgin(img_input),listin(list_input?*list_input:CImgList<T>::const_empty()),
  13764 + imgout(img_output?*img_output:CImg<T>::empty()),listout(list_output?*list_output:CImgList<T>::empty()),
  13765 + img_stats(_img_stats),list_stats(_list_stats),list_median(_list_median),user_function(0),
  13766 + mem_img_median(~0U),debug_indent(0),init_size(0),result_dim(0),
  13767 + calling_function(funcname?funcname:"cimg_math_parser") {
13852 if (!expression || !*expression) 13768 if (!expression || !*expression)
13853 throw CImgArgumentException("[_cimg_math_parser] " 13769 throw CImgArgumentException("[_cimg_math_parser] "
13854 - "CImg<%s>::%s(): Empty specified expression.",  
13855 - pixel_type(),calling_function);  
13856 - CImg<charT>::string(expression).move_to(expr); 13770 + "CImg<%s>::%s: Empty expression.",
  13771 + pixel_type(),_cimg_mp_calling_function);
  13772 + const char *_expression = expression;
  13773 + while (*_expression && *_expression<=' ') ++_expression;
  13774 + CImg<charT>::string(_expression).move_to(expr);
  13775 +
  13776 + // Ease the retrieval of previous non-space characters afterwards.
  13777 + pexpr.assign(expr._width);
  13778 + const char *ps;
  13779 + char c, *pe = pexpr._data;
  13780 + for (ps = expr._data, c = ' '; *ps; ++ps) {
  13781 + if (*ps!=' ') c = *ps;
  13782 + *(pe++) = c;
  13783 + }
  13784 + *pe = 0;
  13785 +
  13786 + // Count parentheses/brackets level of expression.
13857 level.assign(expr._width - 1); 13787 level.assign(expr._width - 1);
13858 - int lv = 0; // Count parentheses/brackets level of expression. 13788 + int lv = 0;
13859 unsigned int *pd = level._data; 13789 unsigned int *pd = level._data;
13860 - for (const char *ps = expr._data; *ps && lv>=0; ++ps) 13790 + for (ps = expr._data; *ps && lv>=0; ++ps)
13861 *(pd++) = (unsigned int)(*ps=='('||*ps=='['?lv++:*ps==')'||*ps==']'?--lv:lv); 13791 *(pd++) = (unsigned int)(*ps=='('||*ps=='['?lv++:*ps==')'||*ps==']'?--lv:lv);
13862 if (lv!=0) { 13792 if (lv!=0) {
  13793 + cimg::strellipsize(expr,64);
13863 throw CImgArgumentException("[_cimg_math_parser] " 13794 throw CImgArgumentException("[_cimg_math_parser] "
13864 - "CImg<%s>::%s(): Unbalanced parentheses/brackets in specified expression '%s'.",  
13865 - pixel_type(),calling_function, 13795 + "CImg<%s>::%s: Unbalanced parentheses/brackets, in expression '%s'.",
  13796 + pixel_type(),_cimg_mp_calling_function,
13866 expr._data); 13797 expr._data);
13867 } 13798 }
13868 13799
13869 // Init constant values. 13800 // Init constant values.
13870 - mem.assign(512);  
13871 - mem[0] = 0.0;  
13872 - mem[1] = 1.0;  
13873 - mem[2] = 2.0;  
13874 - mem[3] = 3.0;  
13875 - mem[4] = 4.0;  
13876 - mem[5] = 5.0;  
13877 - mem[6] = (double)reference._width;  
13878 - mem[7] = (double)reference._height;  
13879 - mem[8] = (double)reference._depth;  
13880 - mem[9] = (double)reference._spectrum;  
13881 - mem[10] = (double)reference._is_shared;  
13882 - mem[11] = (double)reference._width*reference._height;  
13883 - mem[12] = (double)reference._width*reference._height*reference._depth;  
13884 - mem[13] = (double)reference._width*reference._height*reference._depth*reference._spectrum;  
13885 - mem[14] = cimg::PI;  
13886 - mem[15] = std::exp(1.0); // Then [16] = x, [17] = y, [18] = z and [19] = c.  
13887 - mempos = 20;  
13888 - labelMpos.assign(8); 13801 + mem.assign(96);
  13802 + memtype.assign(96);
  13803 + double *p_mem = mem._data;
  13804 + for (unsigned int i = 0; i<=10; ++i) *(p_mem++) = (double)i; // mem[0-10]
  13805 + for (unsigned int i = 1; i<=5; ++i) *(p_mem++) = -(double)i; // mem[11-15]
  13806 + *(p_mem++) = 0.5; // mem[16]
  13807 + *(p_mem++) = 0; // mem[17] = thread_id
  13808 + *(p_mem++) = (double)imgin._width; // mem[18]
  13809 + *(p_mem++) = (double)imgin._height; // mem[19]
  13810 + *(p_mem++) = (double)imgin._depth; // mem[20]
  13811 + *(p_mem++) = (double)imgin._spectrum; // mem[21]
  13812 + *(p_mem++) = (double)imgin._is_shared; // mem[22]
  13813 + *(p_mem++) = (double)imgin._width*imgin._height; // mem[23]
  13814 + *(p_mem++) = (double)imgin._width*imgin._height*imgin._depth; // mem[24]
  13815 + *(p_mem++) = (double)imgin._width*imgin._height*imgin._depth*imgin._spectrum; // mem[25]
  13816 + *(p_mem++) = cimg::PI; // mem[26]
  13817 + *(p_mem++) = std::exp(1.0); // mem[27]
  13818 + *(p_mem++) = cimg::type<double>::nan(); // mem[28]
  13819 +
  13820 + // Then, [29] = x, [30] = y, [31] = z and [32] = c.
  13821 +#define _cimg_mp_x 29
  13822 +#define _cimg_mp_y 30
  13823 +#define _cimg_mp_z 31
  13824 +#define _cimg_mp_c 32
  13825 +
  13826 + // Set value property :
  13827 + // { -1 = variable | 0 = regular value | 1 = compile time constant | N>1 = constant ptr to vector[N-1] }.
  13828 + std::memset(memtype._data,0,sizeof(int)*memtype._width);
  13829 + int *p_memtype = memtype._data; for (unsigned int i = 0; i<_cimg_mp_x; ++i) *(p_memtype++) = 1;
  13830 + memtype[17] = 0;
  13831 +
  13832 + mempos = _cimg_mp_c + 1;
  13833 + variable_pos.assign(8);
13889 reserved_label.assign(128,1,1,1,~0U); 13834 reserved_label.assign(128,1,1,1,~0U);
13890 - reserved_label['w'] = 6;  
13891 - reserved_label['h'] = 7;  
13892 - reserved_label['d'] = 8;  
13893 - reserved_label['s'] = 9;  
13894 - reserved_label['r'] = 10;  
13895 - reserved_label[0] = 11; // wh  
13896 - reserved_label[1] = 12; // whd  
13897 - reserved_label[2] = 13; // whds  
13898 - reserved_label[3] = 14; // pi  
13899 - reserved_label['e'] = 15;  
13900 - reserved_label['x'] = 16;  
13901 - reserved_label['y'] = 17;  
13902 - reserved_label['z'] = 18;  
13903 - reserved_label['c'] = 19;  
13904 - result = compile(expr._data,expr._data + expr._width - 1); // Compile formula into a serie of opcodes.  
13905 - }  
13906 -  
13907 - // Insert code instructions.  
13908 - unsigned int opcode0(const mp_func op) {  
13909 - if (mempos>=mem._width) mem.resize(-200,1,1,1,0);  
13910 - const unsigned int pos = mempos++;  
13911 - CImg<longT>::vector(_cimg_mp_enfunc(op),pos).move_to(code);  
13912 - return pos;  
13913 - }  
13914 -  
13915 - unsigned int opcode1(const mp_func op, const unsigned int arg1) {  
13916 - if (mempos>=mem._width) mem.resize(-200,1,1,1,0);  
13917 - const unsigned int pos = mempos++;  
13918 - CImg<longT>::vector(_cimg_mp_enfunc(op),pos,arg1).move_to(code);  
13919 - return pos;  
13920 - }  
13921 -  
13922 - unsigned int opcode2(const mp_func op, const unsigned int arg1, const unsigned int arg2) {  
13923 - if (mempos>=mem._width) mem.resize(-200,1,1,1,0);  
13924 - const unsigned int pos = mempos++;  
13925 - CImg<longT>::vector(_cimg_mp_enfunc(op),pos,arg1,arg2).move_to(code);  
13926 - return pos; 13835 + reserved_label['t'] = 17;
  13836 + reserved_label['w'] = 18;
  13837 + reserved_label['h'] = 19;
  13838 + reserved_label['d'] = 20;
  13839 + reserved_label['s'] = 21;
  13840 + reserved_label['r'] = 22;
  13841 + reserved_label[0] = 23; // wh
  13842 + reserved_label[1] = 24; // whd
  13843 + reserved_label[2] = 25; // whds
  13844 + reserved_label[3] = 26; // pi
  13845 + reserved_label['e'] = 27;
  13846 + reserved_label[29] = 0; // interpolation
  13847 + reserved_label[30] = 0; // boundary
  13848 + reserved_label['x'] = _cimg_mp_x;
  13849 + reserved_label['y'] = _cimg_mp_y;
  13850 + reserved_label['z'] = _cimg_mp_z;
  13851 + reserved_label['c'] = _cimg_mp_c;
  13852 + // reserved_label[4-28] store also two-char variables:
  13853 + // [4] = im, [5] = iM, [6] = ia, [7] = iv, [8] = is, [9] = ip, [10] = ic,
  13854 + // [11] = xm, [12] = ym, [13] = zm, [14] = cm, [15] = xM, [16] = yM, [17] = zM, [18]=cM, [19]=i0...[28]=i9,
  13855 +
  13856 + // Compile expression into a serie of opcodes.
  13857 + const unsigned int ind_result = compile(expr._data,expr._data + expr._width - 1,0,0);
  13858 + p_code_end = code.end();
  13859 +
  13860 + // Free resources used for parsing and prepare for evaluation.
  13861 + if (_cimg_mp_is_vector(ind_result)) result_dim = _cimg_mp_vector_size(ind_result);
  13862 + mem.resize(mempos,1,1,1,-1);
  13863 + result = mem._data + ind_result;
  13864 + memtype.assign();
  13865 + level.assign();
  13866 + variable_pos.assign();
  13867 + reserved_label.assign();
  13868 + expr.assign();
  13869 + pexpr.assign();
  13870 + opcode._width = opcode._depth = opcode._spectrum = 1;
  13871 + opcode._is_shared = true;
  13872 +
  13873 + // Execute init() function if any specified.
  13874 + p_code_begin = code._data + init_size;
  13875 + if (init_size) {
  13876 + mem[_cimg_mp_x] = mem[_cimg_mp_y] = mem[_cimg_mp_z] = mem[_cimg_mp_c] = 0;
  13877 + for (p_code = code._data; p_code<p_code_begin; ++p_code) {
  13878 + const CImg<uptrT> &op = *p_code;
  13879 + opcode._data = op._data; opcode._height = op._height;
  13880 + const uptrT target = opcode[1];
  13881 + mem[target] = _cimg_mp_defunc(*this);
  13882 + }
  13883 + }
  13884 + }
  13885 +
  13886 + _cimg_math_parser():
  13887 + code(_code),p_code_begin(0),p_code_end(0),
  13888 + imgin(CImg<T>::const_empty()),listin(CImgList<T>::const_empty()),
  13889 + imgout(CImg<T>::empty()),listout(CImgList<T>::empty()),
  13890 + img_stats(_img_stats),list_stats(_list_stats),list_median(_list_median),debug_indent(0),
  13891 + result_dim(0),calling_function(0) {
  13892 + mem.assign(1 + _cimg_mp_c,1,1,1,0); // Allow to skip 'is_empty?' test in operator()()
  13893 + result = mem._data;
  13894 + }
  13895 +
  13896 + _cimg_math_parser(const _cimg_math_parser& mp):
  13897 + mem(mp.mem),code(mp.code),p_code_begin(mp.p_code_begin),p_code_end(mp.p_code_end),
  13898 + imgin(mp.imgin),listin(mp.listin),imgout(mp.imgout),listout(mp.listout),img_stats(mp.img_stats),
  13899 + list_stats(mp.list_stats),list_median(mp.list_median),debug_indent(0),
  13900 + result_dim(mp.result_dim), result(mem._data + (mp.result - mp.mem._data)),calling_function(0) {
  13901 +#ifdef cimg_use_openmp
  13902 + mem[17] = omp_get_thread_num();
  13903 +#endif
  13904 + opcode._width = opcode._depth = opcode._spectrum = 1;
  13905 + opcode._is_shared = true;
  13906 + }
  13907 +
  13908 + // Return 'true' is the specified mathematical expression requires the input image to be copied.
  13909 + // Set 'is_parallelizable' to 'false' if expression should be evaluated with a single thread.
  13910 + static bool needs_input_copy(const char *expression, bool &is_parallelizable) {
  13911 + if (!expression || *expression=='>' || *expression=='<') return is_parallelizable = false;
  13912 + for (const char *s = expression; *s; ++s)
  13913 + if ((*s=='i' || *s=='j' || *s=='I' || *s=='J') && (s[1]=='(' || s[1]=='[')) {
  13914 + if (s[2]=='#') is_parallelizable = false;
  13915 + else {
  13916 + const char opening = s[1], ending = opening=='('?')':']';
  13917 + const char *ns;
  13918 + int level = 0;
  13919 + for (ns = s + 2; *ns; ++ns) { // Find ending ')' or ']'.
  13920 + if (*ns==ending && !level) break;
  13921 + if (*ns==opening) ++level; else if (*ns==ending) --level;
  13922 + }
  13923 + if (*ns && (ns[1]!='=' || ns[2]=='=')) return true;
  13924 + }
  13925 + } else if (((*s=='R' || *s=='G' || *s=='B' || *s=='A' || *s=='I' || *s=='J') && s[1]!='#') ||
  13926 + (*s=='i' && s[1]>='0' && s[1]<='7' && s[2]!='#')) return true;
  13927 + return false;
13927 } 13928 }
13928 13929
13929 - unsigned int opcode3(const mp_func op,  
13930 - const unsigned int arg1, const unsigned int arg2, const unsigned int arg3) {  
13931 - if (mempos>=mem._width) mem.resize(-200,1,1,1,0);  
13932 - const unsigned int pos = mempos++;  
13933 - CImg<longT>::vector(_cimg_mp_enfunc(op),pos,arg1,arg2,arg3).move_to(code);  
13934 - return pos;  
13935 - } 13930 + // Compilation procedure.
  13931 + unsigned int compile(char *ss, char *se, const unsigned int depth, unsigned int *p_ref) {
  13932 + if (depth>256) {
  13933 + cimg::strellipsize(expr,64);
  13934 + throw CImgArgumentException("[_cimg_math_parser] "
  13935 + "CImg<%s>::%s: Call stack overflow (infinite recursion?), "
  13936 + "in expression '%s%s%s'.",
  13937 + pixel_type(),_cimg_mp_calling_function,
  13938 + (ss - 4)>expr._data?"...":"",
  13939 + (ss - 4)>expr._data?ss - 4:expr._data,
  13940 + se<&expr.back()?"...":"");
  13941 + }
13936 13942
13937 - unsigned int opcode6(const mp_func op,  
13938 - const unsigned int arg1, const unsigned int arg2, const unsigned int arg3,  
13939 - const unsigned int arg4, const unsigned int arg5, const unsigned int arg6) {  
13940 - if (mempos>=mem._width) mem.resize(-200,1,1,1,0);  
13941 - const unsigned int pos = mempos++;  
13942 - CImg<longT>::vector(_cimg_mp_enfunc(op),pos,arg1,arg2,arg3,arg4,arg5,arg6).move_to(code);  
13943 - return pos;  
13944 - } 13943 + const char *const ss0 = ss;
  13944 + char c1, c2, c3, c4;
13945 13945
13946 - // Compilation procedure.  
13947 - unsigned int compile(char *ss, char *se) {  
13948 - while (*ss==' ') ++ss;  
13949 - while (se>ss && *(se-1)==' ') --se; 13946 + if (ss<se) {
  13947 + while (*ss && (*ss<=' ' || *ss==';')) ++ss;
  13948 + while (se>ss && (c1=*(se - 1))>0 && (c1<=' ' || c1==';')) --se;
  13949 + }
  13950 + if (se>ss && *(se - 1)==';') --se;
  13951 + while (*ss=='(' && *(se - 1)==')' && std::strchr(ss,')')==se - 1) { // Detect simple content around parentheses.
  13952 + ++ss; --se;
  13953 + }
13950 if (se<=ss || !*ss) { 13954 if (se<=ss || !*ss) {
  13955 + cimg::strellipsize(expr,64);
13951 throw CImgArgumentException("[_cimg_math_parser] " 13956 throw CImgArgumentException("[_cimg_math_parser] "
13952 - "CImg<%s>::%s(): Missing item in specified expression '%s'.",  
13953 - pixel_type(),calling_function, 13957 + "CImg<%s>::%s: Missing item, in expression '%s'.",
  13958 + pixel_type(),_cimg_mp_calling_function,
13954 expr._data); 13959 expr._data);
13955 } 13960 }
  13961 + const unsigned int depth1 = depth + 1;
  13962 + unsigned int pos, p1, p2, p3, arg1, arg2, arg3, arg4, arg5, arg6;
13956 char 13963 char
13957 - *const se1 = se - 1, *const se2 = se - 2, *const se3 = se - 3, *const se4 = se - 4, 13964 + *const se1 = se - 1, *const se2 = se - 2, *const se3 = se - 3,
13958 *const ss1 = ss + 1, *const ss2 = ss + 2, *const ss3 = ss + 3, *const ss4 = ss + 4, 13965 *const ss1 = ss + 1, *const ss2 = ss + 2, *const ss3 = ss + 3, *const ss4 = ss + 4,
13959 - *const ss5 = ss + 5, *const ss6 = ss + 6, *const ss7 = ss + 7; 13966 + *const ss5 = ss + 5, *const ss6 = ss + 6, *const ss7 = ss + 7, *const ss8 = ss + 8,
  13967 + *s, *ps, *ns, *s0, *s1, *s2, *s3, sep = 0, end = 0;
  13968 + double val, val1, val2;
  13969 + const char *s_op;
  13970 + mp_func op;
  13971 +
  13972 + // 'p_ref' is a 'unsigned int[7]' used to return a reference to an image or vector value
  13973 + // linked to the returned memory slot (reference that cannot be determined at compile time).
  13974 + // p_ref[0] can be { 0 = scalar (unlinked) | 1 = vector value | 2 = image value (offset) |
  13975 + // 3 = image value (coordinates) | 4 = image value as a vector (offsets) |
  13976 + // 5 = image value as a vector (coordinates) }.
  13977 + // Depending on p_ref[0], the remaining p_ref[k] have the following meaning:
  13978 + // When p_ref[0]==0, p_ref is actually unlinked.
  13979 + // When p_ref[0]==1, p_ref = [ 1, vector_ind, offset ].
  13980 + // When p_ref[0]==2, p_ref = [ 2, image_ind (or ~0U), is_relative, offset ].
  13981 + // When p_ref[0]==3, p_ref = [ 3, image_ind (or ~0U), is_relative, x, y, z, c ].
  13982 + // When p_ref[0]==4, p_ref = [ 4, image_ind (or ~0U), is_relative, offset ].
  13983 + // When p_ref[0]==5, p_ref = [ 5, image_ind (or ~0U), is_relative, x, y, z ].
  13984 + if (p_ref) { *p_ref = 0; p_ref[1] = p_ref[2] = p_ref[3] = p_ref[4] = p_ref[5] = p_ref[6] = ~0U; }
  13985 +
13960 const char saved_char = *se; *se = 0; 13986 const char saved_char = *se; *se = 0;
13961 const unsigned int clevel = level[ss - expr._data], clevel1 = clevel + 1; 13987 const unsigned int clevel = level[ss - expr._data], clevel1 = clevel + 1;
13962 - if (*se1==';') return compile(ss,se1); 13988 + bool is_sth, is_relative;
  13989 + CImg<uintT> ref;
  13990 + CImgList<uptrT> _opcode;
  13991 + CImg<charT> variable_name;
13963 13992
13964 - // Look for a single value, variable or variable assignment.  
13965 - char end = 0, sep = 0; double val = 0;  
13966 - int nb = cimg_sscanf(ss,"%lf%c%c",&val,&sep,&end); 13993 + // Look for a single value or a pre-defined variable.
  13994 + int nb = cimg_sscanf(ss,"%lf%c%c",&val,&(sep=0),&(end=0));
13967 13995
13968 #if cimg_OS==2 13996 #if cimg_OS==2
13969 // Check for +/-NaN and +/-inf as Microsoft's sscanf() version is not able 13997 // Check for +/-NaN and +/-inf as Microsoft's sscanf() version is not able
13970 // to read those particular values. 13998 // to read those particular values.
13971 if (!nb && (*ss=='+' || *ss=='-' || *ss=='i' || *ss=='I' || *ss=='n' || *ss=='N')) { 13999 if (!nb && (*ss=='+' || *ss=='-' || *ss=='i' || *ss=='I' || *ss=='n' || *ss=='N')) {
13972 - bool is_positive = true;  
13973 - const char *_ss = ss;  
13974 - if (*_ss=='+') ++_ss; else if (*_ss=='-') { ++_ss; is_positive = false; }  
13975 - if (!cimg::strcasecmp(_ss,"inf")) { val = cimg::type<double>::inf(); nb = 1; }  
13976 - else if (!cimg::strcasecmp(_ss,"nan")) { val = cimg::type<double>::nan(); nb = 1; }  
13977 - if (nb==1 && !is_positive) val = -val;  
13978 - }  
13979 -#endif  
13980 -  
13981 - if (nb==1) {  
13982 - if (val==0 || val==1 || val==2 || val==3 || val==4 || val==5)  
13983 - _cimg_mp_return((unsigned int)val);  
13984 - if (mempos>=mem._width) mem.resize(-200,1,1,1,0);  
13985 - const unsigned int pos = mempos++;  
13986 - mem[pos] = val;  
13987 - _cimg_mp_return(pos);  
13988 - }  
13989 - if (nb==2 && sep=='%') {  
13990 - if (val==0 || val==100 || val==200 || val==300 || val==400 || val==500)  
13991 - _cimg_mp_return((unsigned int)val/100);  
13992 - if (mempos>=mem._width) mem.resize(-200,1,1,1,0);  
13993 - const unsigned int pos = mempos++;  
13994 - mem[pos] = val/100;  
13995 - _cimg_mp_return(pos);  
13996 - }  
13997 - if (ss1==se) switch (*ss) { // One-char variable.  
13998 - case 'w' : case 'h' : case 'd' : case 's' : case 'r' :  
13999 - case 'x' : case 'y' : case 'z' : case 'c' : case 'e' : _cimg_mp_return(reserved_label[*ss]);  
14000 - case 'u' : if (reserved_label['u']!=~0U) _cimg_mp_return(reserved_label['u']); _cimg_mp_opcode2(mp_u,0,1);  
14001 - case 'g' : if (reserved_label['g']!=~0U) _cimg_mp_return(reserved_label['g']); _cimg_mp_opcode0(mp_g);  
14002 - case 'i' : if (reserved_label['i']!=~0U) _cimg_mp_return(reserved_label['i']); _cimg_mp_opcode0(mp_i);  
14003 - case '?' : _cimg_mp_opcode2(mp_u,0,1);  
14004 - }  
14005 - else if (ss2==se) { // Two-chars variable. 14000 + is_sth = true;
  14001 + s = ss;
  14002 + if (*s=='+') ++s; else if (*s=='-') { ++s; is_sth = false; }
  14003 + if (!cimg::strcasecmp(s,"inf")) { val = cimg::type<double>::inf(); nb = 1; }
  14004 + else if (!cimg::strcasecmp(s,"nan")) { val = cimg::type<double>::nan(); nb = 1; }
  14005 + if (nb==1 && !is_sth) val = -val;
  14006 + }
  14007 +#endif
  14008 + if (nb==1) _cimg_mp_constant(val);
  14009 + if (nb==2 && sep=='%') _cimg_mp_constant(val/100);
  14010 +
  14011 + if (ss1==se) switch (*ss) { // One-char variable
  14012 + case 't' : case 'w' : case 'h' : case 'd' : case 's' : case 'r' :
  14013 + case 'x' : case 'y' : case 'z' : case 'c' : case 'e' :
  14014 + _cimg_mp_return(reserved_label[*ss]);
  14015 + case 'u' :
  14016 + if (reserved_label['u']!=~0U) _cimg_mp_return(reserved_label['u']);
  14017 + _cimg_mp_scalar2(mp_u,0,1);
  14018 + case 'g' :
  14019 + if (reserved_label['g']!=~0U) _cimg_mp_return(reserved_label['g']);
  14020 + _cimg_mp_scalar0(mp_g);
  14021 + case 'i' :
  14022 + if (reserved_label['i']!=~0U) _cimg_mp_return(reserved_label['i']);
  14023 + _cimg_mp_scalar0(mp_i);
  14024 + case 'I' :
  14025 + if (reserved_label['I']!=~0U) _cimg_mp_return(reserved_label['I']);
  14026 + _cimg_mp_check_vector0(imgin._spectrum,"variable 'I'");
  14027 + pos = vector(imgin._spectrum);
  14028 + CImg<uptrT>::vector((uptrT)mp_Joff,pos,0,0).move_to(code);
  14029 + _cimg_mp_return(pos);
  14030 + case 'R' :
  14031 + if (reserved_label['R']!=~0U) _cimg_mp_return(reserved_label['R']);
  14032 + _cimg_mp_scalar6(mp_ixyzc,_cimg_mp_x,_cimg_mp_y,_cimg_mp_z,0,0,0);
  14033 + case 'G' :
  14034 + if (reserved_label['G']!=~0U) _cimg_mp_return(reserved_label['G']);
  14035 + _cimg_mp_scalar6(mp_ixyzc,_cimg_mp_x,_cimg_mp_y,_cimg_mp_z,1,0,0);
  14036 + case 'B' :
  14037 + if (reserved_label['B']!=~0U) _cimg_mp_return(reserved_label['B']);
  14038 + _cimg_mp_scalar6(mp_ixyzc,_cimg_mp_x,_cimg_mp_y,_cimg_mp_z,2,0,0);
  14039 + case 'A' :
  14040 + if (reserved_label['A']!=~0U) _cimg_mp_return(reserved_label['A']);
  14041 + _cimg_mp_scalar6(mp_ixyzc,_cimg_mp_x,_cimg_mp_y,_cimg_mp_z,3,0,0);
  14042 + }
  14043 + else if (ss2==se) { // Two-chars variable
  14044 + arg1 = arg2 = ~0U;
14006 if (*ss=='w' && *ss1=='h') _cimg_mp_return(reserved_label[0]); // wh 14045 if (*ss=='w' && *ss1=='h') _cimg_mp_return(reserved_label[0]); // wh
14007 if (*ss=='p' && *ss1=='i') _cimg_mp_return(reserved_label[3]); // pi 14046 if (*ss=='p' && *ss1=='i') _cimg_mp_return(reserved_label[3]); // pi
14008 - if (*ss=='i') { // im  
14009 - if (*ss1=='m') {  
14010 - if (!reference_stats) reference.get_stats().move_to(reference_stats);  
14011 - if (reserved_label[4]!=~0U) _cimg_mp_return(reserved_label[4]); _cimg_mp_opcode0(mp_im); 14047 + if (*ss=='i') {
  14048 + if (*ss1>='0' && *ss1<='9') { // i0...i9
  14049 + pos = 19 + *ss1 - '0';
  14050 + if (reserved_label[pos]!=~0U) _cimg_mp_return(reserved_label[pos]);
  14051 + _cimg_mp_scalar6(mp_ixyzc,_cimg_mp_x,_cimg_mp_y,_cimg_mp_z,pos - 19,0,0);
  14052 + }
  14053 + switch (*ss1) {
  14054 + case 'm' : arg1 = 4; arg2 = 0; break; // im
  14055 + case 'M' : arg1 = 5; arg2 = 1; break; // iM
  14056 + case 'a' : arg1 = 6; arg2 = 2; break; // ia
  14057 + case 'v' : arg1 = 7; arg2 = 3; break; // iv
  14058 + case 's' : arg1 = 8; arg2 = 12; break; // is
  14059 + case 'p' : arg1 = 9; arg2 = 13; break; // is
  14060 + case 'c' : // ic
  14061 + if (reserved_label[10]!=~0U) _cimg_mp_return(reserved_label[10]);
  14062 + if (mem_img_median==~0U) mem_img_median = imgin?constant(imgin.median()):0;
  14063 + _cimg_mp_return(mem_img_median);
  14064 + break;
14012 } 14065 }
14013 - if (*ss1=='M') { // iM  
14014 - if (!reference_stats) reference.get_stats().move_to(reference_stats);  
14015 - if (reserved_label[5]!=~0U) _cimg_mp_return(reserved_label[5]); _cimg_mp_opcode0(mp_iM); 14066 + }
  14067 + else if (*ss1=='m') switch (*ss) {
  14068 + case 'x' : arg1 = 11; arg2 = 4; break; // xm
  14069 + case 'y' : arg1 = 12; arg2 = 5; break; // ym
  14070 + case 'z' : arg1 = 13; arg2 = 6; break; // zm
  14071 + case 'c' : arg1 = 14; arg2 = 7; break; // cm
  14072 + }
  14073 + else if (*ss1=='M') switch (*ss) {
  14074 + case 'x' : arg1 = 15; arg2 = 8; break; // xM
  14075 + case 'y' : arg1 = 16; arg2 = 9; break; // yM
  14076 + case 'z' : arg1 = 17; arg2 = 10; break; // zM
  14077 + case 'c' : arg1 = 18; arg2 = 11; break; // cM
14016 } 14078 }
14017 - if (*ss1=='a') { // ia  
14018 - if (!reference_stats) reference.get_stats().move_to(reference_stats);  
14019 - if (reserved_label[6]!=~0U) _cimg_mp_return(reserved_label[6]); _cimg_mp_opcode0(mp_ia); 14079 + if (arg1!=~0U) {
  14080 + if (reserved_label[arg1]!=~0U) _cimg_mp_return(reserved_label[arg1]);
  14081 + if (!img_stats) {
  14082 + img_stats.assign(1,14,1,1,0).fill(imgin.get_stats(),false);
  14083 + mem_img_stats.assign(1,14,1,1,~0U);
  14084 + }
  14085 + if (mem_img_stats[arg2]==~0U) mem_img_stats[arg2] = constant(img_stats[arg2]);
  14086 + _cimg_mp_return(mem_img_stats[arg2]);
  14087 + }
  14088 + } else if (ss3==se) { // Three-chars variable
  14089 + if (*ss=='w' && *ss1=='h' && *ss2=='d') _cimg_mp_return(reserved_label[1]); // whd
  14090 + } else if (ss4==se) { // Four-chars variable
  14091 + if (*ss=='w' && *ss1=='h' && *ss2=='d' && *ss3=='s') _cimg_mp_return(reserved_label[2]); // whds
  14092 + }
  14093 +
  14094 + pos = ~0U;
  14095 + for (s0 = ss, s = ss1; s<se1; ++s)
  14096 + if (*s==';' && level[s - expr._data]==clevel) { // Separator ';'
  14097 + pos = compile(s0,s,depth,0);
  14098 + s0 = s + 1;
  14099 + }
  14100 + if (pos!=~0U) _cimg_mp_return(compile(s0,se,depth,p_ref));
  14101 +
  14102 + // Declare / assign variable, vector value or image value.
  14103 + for (s = ss1, ps = ss, ns = ss2; s<se1; ++s, ++ps, ++ns)
  14104 + if (*s=='=' && *ns!='=' && *ps!='=' && *ps!='>' && *ps!='<' && *ps!='!' &&
  14105 + *ps!='+' && *ps!='-' && *ps!='*' && *ps!='/' && *ps!='%' &&
  14106 + *ps!='>' && *ps!='<' && *ps!='&' && *ps!='|' && *ps!='^' &&
  14107 + level[s - expr._data]==clevel) {
  14108 + variable_name.assign(ss,(unsigned int)(s + 1 - ss)).back() = 0;
  14109 + cimg::strpare(variable_name);
  14110 + const unsigned int l_variable_name = (unsigned int)std::strlen(variable_name);
  14111 + char *const ve1 = ss + l_variable_name - 1;
  14112 + s_op = "Operator '='";
  14113 +
  14114 + // Assign image value (direct).
  14115 + if (l_variable_name>2 && (*ss=='i' || *ss=='j' || *ss=='I' || *ss=='J') && (*ss1=='(' || *ss1=='[') &&
  14116 + (reserved_label[*ss]==~0U || *ss1=='(' || !_cimg_mp_is_vector(reserved_label[*ss]))) {
  14117 + is_relative = *ss=='j' || *ss=='J';
  14118 +
  14119 + if (*ss1=='[' && *ve1==']') { // i/j/I/J[_#ind,offset] = value
  14120 + if (*ss2=='#') { // Index specified
  14121 + s0 = ss3; while (s0<ve1 && (*s0!=',' || level[s0 - expr._data]!=clevel1)) ++s0;
  14122 + p1 = compile(ss3,s0++,depth1,0);
  14123 + } else { p1 = ~0U; s0 = ss2; }
  14124 + arg1 = compile(s0,ve1,depth1,0); // Offset
  14125 + arg2 = compile(s + 1,se,depth1,0); // Value to assign
  14126 + if (_cimg_mp_is_vector(arg2)) {
  14127 + p2 = ~0U; // 'p2' must the dimension of the vector-valued operand if any
  14128 + if (p1==~0U) p2 = imgin._spectrum;
  14129 + else if (_cimg_mp_is_constant(p1)) {
  14130 + p3 = (unsigned int)cimg::mod((int)mem[p1],listin.width());
  14131 + p2 = listin[p3]._spectrum;
  14132 + }
  14133 + _cimg_mp_check_vector0(p2,s_op);
  14134 + } else p2 = 0;
  14135 + _cimg_mp_check_type(arg2,2,s_op,*ss>='i'?1:3,p2);
  14136 +
  14137 + if (p_ref) {
  14138 + *p_ref = _cimg_mp_is_vector(arg2)?4:2;
  14139 + p_ref[1] = p1;
  14140 + p_ref[2] = (unsigned int)is_relative;
  14141 + p_ref[3] = arg1;
  14142 + if (_cimg_mp_is_vector(arg2))
  14143 + set_variable_vector(arg2); // Prevent from being used in further optimization
  14144 + else if (_cimg_mp_is_temp(arg2)) memtype[arg2] = -1;
  14145 + if (p1!=~0U && _cimg_mp_is_temp(p1)) memtype[p1] = -1;
  14146 + if (_cimg_mp_is_temp(arg1)) memtype[arg1] = -1;
  14147 + }
  14148 + if (p1!=~0U) {
  14149 + if (!listout) _cimg_mp_return(arg2);
  14150 + if (*ss>='i')
  14151 + CImg<uptrT>::vector((uptrT)(is_relative?mp_list_set_joff:mp_list_set_ioff),
  14152 + arg2,p1,arg1).move_to(code);
  14153 + else if (_cimg_mp_is_scalar(arg2))
  14154 + CImg<uptrT>::vector((uptrT)(is_relative?mp_list_set_Joff_s:mp_list_set_Ioff_s),
  14155 + arg2,p1,arg1).move_to(code);
  14156 + else
  14157 + CImg<uptrT>::vector((uptrT)(is_relative?mp_list_set_Joff_v:mp_list_set_Ioff_v),
  14158 + arg2,p1,arg1).move_to(code);
  14159 + } else {
  14160 + if (!imgout) _cimg_mp_return(arg2);
  14161 + if (*ss>='i')
  14162 + CImg<uptrT>::vector((uptrT)(is_relative?mp_set_joff:mp_set_ioff),
  14163 + arg2,arg1).move_to(code);
  14164 + if (_cimg_mp_is_scalar(arg2))
  14165 + CImg<uptrT>::vector((uptrT)(is_relative?mp_set_Joff_s:mp_set_Ioff_s),
  14166 + arg2,arg1).move_to(code);
  14167 + else
  14168 + CImg<uptrT>::vector((uptrT)(is_relative?mp_set_Joff_v:mp_set_Ioff_v),
  14169 + arg2,arg1).move_to(code);
  14170 + }
  14171 + _cimg_mp_return(arg2);
  14172 + }
  14173 +
  14174 + if (*ss1=='(' && *ve1==')') { // i/j/I/J(_#ind,_x,_y,_z,_c) = value
  14175 + if (*ss2=='#') { // Index specified
  14176 + s0 = ss3; while (s0<ve1 && (*s0!=',' || level[s0 - expr._data]!=clevel1)) ++s0;
  14177 + p1 = compile(ss3,s0++,depth1,0);
  14178 + } else { p1 = ~0U; s0 = ss2; }
  14179 + arg1 = is_relative?0U:(unsigned int)_cimg_mp_x;
  14180 + arg2 = is_relative?0U:(unsigned int)_cimg_mp_y;
  14181 + arg3 = is_relative?0U:(unsigned int)_cimg_mp_z;
  14182 + arg4 = is_relative?0U:(unsigned int)_cimg_mp_c;
  14183 + arg5 = compile(s + 1,se,depth1,0); // Value to assign
  14184 + if (s0<ve1) { // X or [ X,_Y,_Z,_C ]
  14185 + s1 = s0; while (s1<ve1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
  14186 + arg1 = compile(s0,s1,depth1,0);
  14187 + if (_cimg_mp_is_vector(arg1)) { // Coordinates specified as a vector [X,Y,Z,C]
  14188 + p2 = _cimg_mp_vector_size(arg1); // Vector size
  14189 + arg1 = arg1 + 1;
  14190 + if (p2>1) {
  14191 + arg2 = arg1 + 1;
  14192 + if (p2>2) {
  14193 + arg3 = arg2 + 1;
  14194 + if (p2>3) arg4 = arg3 + 1;
  14195 + }
  14196 + }
  14197 + } else if (s1<ve1) { // Y
  14198 + s2 = ++s1; while (s2<ve1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;
  14199 + arg2 = compile(s1,s2,depth1,0);
  14200 + if (s2<ve1) { // Z
  14201 + s3 = ++s2; while (s3<ve1 && (*s3!=',' || level[s3 - expr._data]!=clevel1)) ++s3;
  14202 + arg3 = compile(s2,s3,depth1,0);
  14203 + if (s3<ve1) arg4 = compile(++s3,ve1,depth1,0); // C
  14204 + }
  14205 + }
  14206 + }
  14207 +
  14208 + if (_cimg_mp_is_vector(arg5)) {
  14209 + p2 = ~0U; // 'p2' must the dimension of the vector-valued operand if any
  14210 + if (p1==~0U) p2 = imgin._spectrum;
  14211 + else if (_cimg_mp_is_constant(p1)) {
  14212 + p3 = (unsigned int)cimg::mod((int)mem[p1],listin.width());
  14213 + p2 = listin[p3]._spectrum;
  14214 + }
  14215 + _cimg_mp_check_vector0(p2,s_op);
  14216 + } else p2 = 0;
  14217 + _cimg_mp_check_type(arg5,2,s_op,*ss>='i'?1:3,p2);
  14218 +
  14219 + if (p_ref) {
  14220 + *p_ref = _cimg_mp_is_vector(arg5)?5:3;
  14221 + p_ref[1] = p1;
  14222 + p_ref[2] = (unsigned int)is_relative;
  14223 + p_ref[3] = arg1;
  14224 + p_ref[4] = arg2;
  14225 + p_ref[5] = arg3;
  14226 + p_ref[6] = arg4;
  14227 + if (_cimg_mp_is_vector(arg5))
  14228 + set_variable_vector(arg5); // Prevent from being used in further optimization
  14229 + else if (_cimg_mp_is_temp(arg5)) memtype[arg5] = -1;
  14230 + if (p1!=~0U && _cimg_mp_is_temp(p1)) memtype[p1] = -1;
  14231 + if (_cimg_mp_is_temp(arg1)) memtype[arg1] = -1;
  14232 + if (_cimg_mp_is_temp(arg2)) memtype[arg2] = -1;
  14233 + if (_cimg_mp_is_temp(arg3)) memtype[arg3] = -1;
  14234 + if (_cimg_mp_is_temp(arg4)) memtype[arg4] = -1;
  14235 + }
  14236 + if (p1!=~0U) {
  14237 + if (!listout) _cimg_mp_return(arg5);
  14238 + if (*ss>='i')
  14239 + CImg<uptrT>::vector((uptrT)(is_relative?mp_list_set_jxyzc:mp_list_set_ixyzc),
  14240 + arg5,p1,arg1,arg2,arg3,arg4).move_to(code);
  14241 + else if (_cimg_mp_is_scalar(arg5))
  14242 + CImg<uptrT>::vector((uptrT)(is_relative?mp_list_set_Jxyz_s:mp_list_set_Ixyz_s),
  14243 + arg5,p1,arg1,arg2,arg3).move_to(code);
  14244 + else
  14245 + CImg<uptrT>::vector((uptrT)(is_relative?mp_list_set_Jxyz_v:mp_list_set_Ixyz_v),
  14246 + arg5,p1,arg1,arg2,arg3).move_to(code);
  14247 + } else {
  14248 + if (!imgout) _cimg_mp_return(arg5);
  14249 + if (*ss>='i')
  14250 + CImg<uptrT>::vector((uptrT)(is_relative?mp_set_jxyzc:mp_set_ixyzc),
  14251 + arg5,arg1,arg2,arg3,arg4).move_to(code);
  14252 + else if (_cimg_mp_is_scalar(arg5))
  14253 + CImg<uptrT>::vector((uptrT)(is_relative?mp_set_Jxyz_s:mp_set_Ixyz_s),
  14254 + arg5,arg1,arg2,arg3).move_to(code);
  14255 + else
  14256 + CImg<uptrT>::vector((uptrT)(is_relative?mp_set_Jxyz_v:mp_set_Ixyz_v),
  14257 + arg5,arg1,arg2,arg3).move_to(code);
  14258 + }
  14259 + _cimg_mp_return(arg5);
  14260 + }
14020 } 14261 }
14021 - if (*ss1=='v') { // iv  
14022 - if (!reference_stats) reference.get_stats().move_to(reference_stats);  
14023 - if (reserved_label[7]!=~0U) _cimg_mp_return(reserved_label[7]); _cimg_mp_opcode0(mp_iv); 14262 +
  14263 + // Assign vector value (direct).
  14264 + if (l_variable_name>3 && *ve1==']' && *ss!='[') {
  14265 + s0 = ve1; while (s0>ss && *s0!='[') --s0;
  14266 + is_sth = true; // is_valid_variable_name?
  14267 + if (*ss>='0' && *ss<='9') is_sth = false;
  14268 + else for (ns = ss; ns<s0; ++ns)
  14269 + if (!is_varchar(*ns)) { is_sth = false; break; }
  14270 + if (is_sth && s0>ss) {
  14271 + variable_name[s0 - ss] = 0; // Remove brackets in variable name
  14272 + arg1 = ~0U; // Vector slot
  14273 + arg2 = compile(++s0,ve1,depth1,0); // Index
  14274 + arg3 = compile(s + 1,se,depth1,0); // Value to assign
  14275 + _cimg_mp_check_type(arg3,2,s_op,1,0);
  14276 +
  14277 + if (variable_name[1]) { // Multi-char variable
  14278 + cimglist_for(variable_def,i) if (!std::strcmp(variable_name,variable_def[i])) {
  14279 + arg1 = variable_pos[i]; break;
  14280 + }
  14281 + } else arg1 = reserved_label[*variable_name]; // Single-char variable
  14282 + if (arg1==~0U) compile(ss,s0 - 1,depth1,0); // Variable does not exist -> error
  14283 + else { // Variable already exists
  14284 + if (_cimg_mp_is_scalar(arg1)) compile(ss,s,depth1,0); // Variable is not a vector -> error
  14285 + if (_cimg_mp_is_constant(arg2)) { // Constant index -> return corresponding variable slot directly
  14286 + nb = (int)mem[arg2];
  14287 + if (nb>=0 && nb<(int)_cimg_mp_vector_size(arg1)) {
  14288 + arg1+=nb + 1;
  14289 + CImg<uptrT>::vector((uptrT)mp_copy,arg1,arg3).move_to(code);
  14290 + _cimg_mp_return(arg1);
  14291 + }
  14292 + compile(ss,s,depth1,0); // Out-of-bounds reference -> error
  14293 + }
  14294 +
  14295 + // Case of non-constant index -> return assigned value + linked reference
  14296 + if (p_ref) {
  14297 + *p_ref = 1;
  14298 + p_ref[1] = arg1;
  14299 + p_ref[2] = arg2;
  14300 + if (_cimg_mp_is_temp(arg3)) memtype[arg3] = -1; // Prevent from being used in further optimization
  14301 + if (_cimg_mp_is_temp(arg2)) memtype[arg2] = -1;
  14302 + }
  14303 + CImg<uptrT>::vector((uptrT)mp_vector_set_off,arg3,arg1,(uptrT)_cimg_mp_vector_size(arg1),arg2,arg3).
  14304 + move_to(code);
  14305 + _cimg_mp_return(arg3);
  14306 + }
  14307 + }
14024 } 14308 }
14025 - if (*ss1=='s') { // is  
14026 - if (!reference_stats) reference.get_stats().move_to(reference_stats);  
14027 - if (reserved_label[8]!=~0U) _cimg_mp_return(reserved_label[8]); _cimg_mp_opcode0(mp_is); 14309 +
  14310 + // Assign user-defined function.
  14311 + if (l_variable_name>3 && *ve1==')' && *ss!='(') {
  14312 + s0 = ve1; while (s0>ss && *s0!='(') --s0;
  14313 + is_sth = std::strncmp(variable_name,"debug(",6) &&
  14314 + std::strncmp(variable_name,"print(",6); // is_valid_function_name?
  14315 + if (*ss>='0' && *ss<='9') is_sth = false;
  14316 + else for (ns = ss; ns<s0; ++ns)
  14317 + if (!is_varchar(*ns)) { is_sth = false; break; }
  14318 +
  14319 + if (is_sth && s0>ss) { // Looks like a valid function declaration
  14320 + s0 = variable_name._data + (s0 - ss);
  14321 + *s0 = 0;
  14322 + s1 = variable_name._data + l_variable_name - 1; // Pointer to closing parenthesis
  14323 + CImg<charT>(variable_name._data,s0 - variable_name._data + 1).move_to(function_def,0);
  14324 + ++s; while (*s && *s<=' ') ++s;
  14325 + CImg<charT>(s,se - s + 1).move_to(function_body,0);
  14326 +
  14327 + p1 = 1; // Indice of current parsed argument
  14328 + for (s = s0 + 1; s<=s1; ++p1, s = ns + 1) { // Parse function arguments
  14329 + if (p1>24) {
  14330 + *se = saved_char; cimg::strellipsize(variable_name,64); cimg::strellipsize(expr,64);
  14331 + throw CImgArgumentException("[_cimg_math_parser] "
  14332 + "CImg<%s>::%s: %s: Too much specified arguments (>24) when defining "
  14333 + "function '%s()', in expression '%s%s%s'.",
  14334 + pixel_type(),_cimg_mp_calling_function,s_op,
  14335 + variable_name._data,
  14336 + (ss - 4)>expr._data?"...":"",
  14337 + (ss - 4)>expr._data?ss - 4:expr._data,
  14338 + se<&expr.back()?"...":"");
  14339 + }
  14340 + while (*s && *s<=' ') ++s;
  14341 + if (*s==')' && p1==1) break; // Function has no arguments
  14342 +
  14343 + s2 = s; // Start of the argument name
  14344 + is_sth = true; // is_valid_argument_name?
  14345 + if (*s>='0' && *s<='9') is_sth = false;
  14346 + else for (ns = s; ns<s1 && *ns!=',' && *ns>' '; ++ns)
  14347 + if (!is_varchar(*ns)) { is_sth = false; break; }
  14348 + s3 = ns; // End of the argument name
  14349 + while (*ns && *ns<=' ') ++ns;
  14350 + if (!is_sth || s2==s3 || (*ns!=',' && ns!=s1)) {
  14351 + *se = saved_char; cimg::strellipsize(variable_name,64); cimg::strellipsize(expr,64);
  14352 + throw CImgArgumentException("[_cimg_math_parser] "
  14353 + "CImg<%s>::%s: %s: %s name specified for argument %u when defining "
  14354 + "function '%s()', in expression '%s%s%s'.",
  14355 + pixel_type(),_cimg_mp_calling_function,s_op,
  14356 + is_sth?"Empty":"Invalid",p1,
  14357 + variable_name._data,
  14358 + (ss - 4)>expr._data?"...":"",
  14359 + (ss - 4)>expr._data?ss - 4:expr._data,
  14360 + se<&expr.back()?"...":"");
  14361 + }
  14362 + if (ns==s1 || *ns==',') { // New argument found
  14363 + *s3 = 0;
  14364 + p2 = s3 - s2; // Argument length
  14365 + p3 = function_body[0]._width - p2 + 1; // Related to copy length
  14366 + for (ps = std::strstr(function_body[0],s2); ps; ps = std::strstr(ps,s2)) { // Replace by arg number
  14367 + if (!((ps>function_body[0]._data && is_varchar(*(ps - 1))) ||
  14368 + (ps + p2<function_body[0].end() && is_varchar(*(ps + p2))))) {
  14369 + *(ps++) = (char)p1;
  14370 + if (p2>1) {
  14371 + std::memmove(ps,ps + p2 - 1,function_body[0]._data + p3 - ps);
  14372 + function_body[0]._width-=p2 - 1;
  14373 + }
  14374 + } else ++ps;
  14375 + }
  14376 + }
  14377 + }
  14378 + // Store number of arguments
  14379 + function_def[0].resize(function_def[0]._width + 1,1,1,1,0).back() = (char)(p1 - 1);
  14380 + _cimg_mp_return(28);
  14381 + }
14028 } 14382 }
14029 - if (*ss1=='p') { // ip  
14030 - if (!reference_stats) reference.get_stats().move_to(reference_stats);  
14031 - if (reserved_label[9]!=~0U) _cimg_mp_return(reserved_label[9]); _cimg_mp_opcode0(mp_ip); 14383 +
  14384 + // Check if the variable name could be valid. If not, this is probably an lvalue assignment.
  14385 + is_sth = true; // is_valid_variable_name?
  14386 + if (*variable_name>='0' && *variable_name<='9') is_sth = false;
  14387 + else for (ns = variable_name._data; *ns; ++ns)
  14388 + if (!is_varchar(*ns)) { is_sth = false; break; }
  14389 +
  14390 + // Assign variable (direct).
  14391 + if (is_sth) {
  14392 + if (variable_name[1] && !variable_name[2]) { // Two-chars variable
  14393 + c1 = variable_name[0];
  14394 + c2 = variable_name[1];
  14395 + if (c1=='w' && c2=='h') variable_name.fill((char)0,(char)0); // wh
  14396 + else if (c1=='p' && c2=='i') variable_name.fill(3,0); // pi
  14397 + else if (c1=='i') {
  14398 + if (c2>='0' && c2<='9') variable_name.fill(19 + c2 - '0',0); // i0...i9
  14399 + else if (c2=='m') variable_name.fill(4,0); // im
  14400 + else if (c2=='M') variable_name.fill(5,0); // iM
  14401 + else if (c2=='a') variable_name.fill(6,0); // ia
  14402 + else if (c2=='v') variable_name.fill(7,0); // iv
  14403 + else if (c2=='s') variable_name.fill(8,0); // is
  14404 + else if (c2=='p') variable_name.fill(9,0); // ip
  14405 + else if (c2=='c') variable_name.fill(10,0); // ic
  14406 + } else if (c2=='m') {
  14407 + if (c1=='x') variable_name.fill(11,0); // xm
  14408 + else if (c1=='y') variable_name.fill(12,0); // ym
  14409 + else if (c1=='z') variable_name.fill(13,0); // zm
  14410 + else if (c1=='c') variable_name.fill(14,0); // cm
  14411 + } else if (c2=='M') {
  14412 + if (c1=='x') variable_name.fill(15,0); // xM
  14413 + else if (c1=='y') variable_name.fill(16,0); // yM
  14414 + else if (c1=='z') variable_name.fill(17,0); // zM
  14415 + else if (c1=='c') variable_name.fill(18,0); // cM
  14416 + }
  14417 + } else if (variable_name[1] && variable_name[2] && !variable_name[3]) { // Three-chars variable
  14418 + c1 = variable_name[0];
  14419 + c2 = variable_name[1];
  14420 + c3 = variable_name[2];
  14421 + if (c1=='w' && c2=='h' && c3=='d') variable_name.fill(1,0); // whd
  14422 + } else if (variable_name[1] && variable_name[2] && variable_name[3] &&
  14423 + !variable_name[4]) { // Four-chars variable
  14424 + c1 = variable_name[0];
  14425 + c2 = variable_name[1];
  14426 + c3 = variable_name[2];
  14427 + c4 = variable_name[3];
  14428 + if (c1=='w' && c2=='h' && c3=='d' && c4=='s') variable_name.fill(2,0); // whds
  14429 + } else if (!std::strcmp(variable_name,"interpolation")) variable_name.fill(29,0);
  14430 + else if (!std::strcmp(variable_name,"boundary")) variable_name.fill(30,0);
  14431 +
  14432 + arg1 = ~0U;
  14433 + arg2 = compile(s + 1,se,depth1,0);
  14434 + if (!variable_name[1]) // One-char variable, or variable in reserved_labels
  14435 + arg1 = reserved_label[*variable_name];
  14436 + else // Multi-char variable name : check for existing variable with same name
  14437 + cimglist_for(variable_def,i)
  14438 + if (!std::strcmp(variable_name,variable_def[i])) { arg1 = variable_pos[i]; break; }
  14439 +
  14440 + if (arg1==~0U || arg1<=_cimg_mp_c) { // Create new variable
  14441 + if (_cimg_mp_is_vector(arg2)) { // Vector variable
  14442 + arg1 = vector_copy(arg2);
  14443 + set_variable_vector(arg1);
  14444 + } else { // Scalar variable
  14445 + arg1 = scalar1(mp_copy,arg2);
  14446 + memtype[arg1] = -1;
  14447 + }
  14448 +
  14449 + if (!variable_name[1]) reserved_label[*variable_name] = arg1;
  14450 + else {
  14451 + if (variable_def._width>=variable_pos._width) variable_pos.resize(-200,1,1,1,0);
  14452 + variable_pos[variable_def._width] = arg1;
  14453 + variable_name.move_to(variable_def);
  14454 + }
  14455 +
  14456 + } else { // Variable already exists -> assign a new value
  14457 + _cimg_mp_check_type(arg2,2,s_op,_cimg_mp_is_vector(arg1)?3:1,0);
  14458 + if (_cimg_mp_is_vector(arg1)) { // Vector
  14459 + if (_cimg_mp_is_vector(arg2)) // From vector
  14460 + CImg<uptrT>::vector((uptrT)mp_vector_copy,arg1,arg2,(uptrT)_cimg_mp_vector_size(arg1)).
  14461 + move_to(code);
  14462 + else // From scalar
  14463 + CImg<uptrT>::vector((uptrT)mp_vector_init,arg1,(uptrT)_cimg_mp_vector_size(arg1),arg2).
  14464 + move_to(code);
  14465 + } else // Scalar
  14466 + CImg<uptrT>::vector((uptrT)mp_copy,arg1,arg2).move_to(code);
  14467 + }
  14468 + _cimg_mp_return(arg1);
  14469 + }
  14470 +
  14471 + // Assign lvalue (variable name was not valid).
  14472 + is_sth = (bool)std::strchr(variable_name,'?'); // Contains_ternary_operator?
  14473 + if (is_sth) break; // Do nothing and make ternary operator prioritary over assignment
  14474 +
  14475 + if (l_variable_name>2 && (std::strchr(variable_name,'(') || std::strchr(variable_name,'['))) {
  14476 + ref.assign(7);
  14477 + arg1 = compile(ss,s,depth1,ref); // Lvalue slot
  14478 + arg2 = compile(s + 1,se,depth1,0); // Value to assign
  14479 +
  14480 + if (*ref==1) { // Vector value (scalar): V[k] = scalar
  14481 + _cimg_mp_check_type(arg2,2,s_op,1,0);
  14482 + arg3 = ref[1]; // Vector slot
  14483 + arg4 = ref[2]; // Index
  14484 + if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int));
  14485 + CImg<uptrT>::vector((uptrT)mp_vector_set_off,arg2,arg3,(uptrT)_cimg_mp_vector_size(arg3),arg4,arg2).
  14486 + move_to(code);
  14487 + _cimg_mp_return(arg2);
  14488 + }
  14489 +
  14490 + if (*ref==2) { // Image value (scalar): i/j[_#ind,off] = scalar
  14491 + _cimg_mp_check_type(arg2,2,s_op,1,0);
  14492 + p1 = ref[1]; // Index
  14493 + is_relative = (bool)ref[2];
  14494 + arg3 = ref[3]; // Offset
  14495 + if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int));
  14496 + if (p1!=~0U) {
  14497 + if (!listout) _cimg_mp_return(arg2);
  14498 + CImg<uptrT>::vector((uptrT)(is_relative?mp_list_set_joff:mp_list_set_ioff),
  14499 + arg2,p1,arg3).move_to(code);
  14500 + } else {
  14501 + if (!imgout) _cimg_mp_return(arg2);
  14502 + CImg<uptrT>::vector((uptrT)(is_relative?mp_set_joff:mp_set_ioff),
  14503 + arg2,arg3).move_to(code);
  14504 + }
  14505 + _cimg_mp_return(arg2);
  14506 + }
  14507 +
  14508 + if (*ref==3) { // Image value (scalar): i/j(_#ind,_x,_y,_z,_c) = scalar
  14509 + _cimg_mp_check_type(arg2,2,s_op,1,0);
  14510 + p1 = ref[1]; // Index
  14511 + is_relative = (bool)ref[2];
  14512 + arg3 = ref[3]; // X
  14513 + arg4 = ref[4]; // Y
  14514 + arg5 = ref[5]; // Z
  14515 + arg6 = ref[6]; // C
  14516 + if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int));
  14517 + if (p1!=~0U) {
  14518 + if (!listout) _cimg_mp_return(arg2);
  14519 + CImg<uptrT>::vector((uptrT)(is_relative?mp_list_set_jxyzc:mp_list_set_ixyzc),
  14520 + arg2,p1,arg3,arg4,arg5,arg6).move_to(code);
  14521 + } else {
  14522 + if (!imgout) _cimg_mp_return(arg2);
  14523 + CImg<uptrT>::vector((uptrT)(is_relative?mp_set_jxyzc:mp_set_ixyzc),
  14524 + arg2,arg3,arg4,arg5,arg6).move_to(code);
  14525 + }
  14526 + _cimg_mp_return(arg2);
  14527 + }
  14528 +
  14529 + if (*ref==4) { // Image value (vector): I/J[_#ind,off] = value
  14530 + _cimg_mp_check_type(arg2,2,s_op,3,_cimg_mp_vector_size(arg1));
  14531 + p1 = ref[1]; // Index
  14532 + is_relative = (bool)ref[2];
  14533 + arg3 = ref[3]; // Offset
  14534 + if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int));
  14535 + if (p1!=~0U) {
  14536 + if (!listout) _cimg_mp_return(arg2);
  14537 + if (_cimg_mp_is_scalar(arg2))
  14538 + CImg<uptrT>::vector((uptrT)(is_relative?mp_list_set_Joff_s:mp_list_set_Ioff_s),
  14539 + arg2,p1,arg3).move_to(code);
  14540 + else
  14541 + CImg<uptrT>::vector((uptrT)(is_relative?mp_list_set_Joff_v:mp_list_set_Ioff_v),
  14542 + arg2,p1,arg3).move_to(code);
  14543 + } else {
  14544 + if (!imgout) _cimg_mp_return(arg2);
  14545 + if (_cimg_mp_is_scalar(arg2))
  14546 + CImg<uptrT>::vector((uptrT)(is_relative?mp_set_Joff_s:mp_set_Ioff_s),
  14547 + arg2,arg3).move_to(code);
  14548 + else
  14549 + CImg<uptrT>::vector((uptrT)(is_relative?mp_set_Joff_v:mp_set_Ioff_v),
  14550 + arg2,arg3).move_to(code);
  14551 + }
  14552 + _cimg_mp_return(arg2);
  14553 + }
  14554 +
  14555 + if (*ref==5) { // Image value (vector): I/J(_#ind,_x,_y,_z,_c) = value
  14556 + _cimg_mp_check_type(arg2,2,s_op,3,_cimg_mp_vector_size(arg1));
  14557 + p1 = ref[1]; // Index
  14558 + is_relative = (bool)ref[2];
  14559 + arg3 = ref[3]; // X
  14560 + arg4 = ref[4]; // Y
  14561 + arg5 = ref[5]; // Z
  14562 + if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int));
  14563 + if (p1!=~0U) {
  14564 + if (!listout) _cimg_mp_return(arg2);
  14565 + if (_cimg_mp_is_scalar(arg2))
  14566 + CImg<uptrT>::vector((uptrT)(is_relative?mp_list_set_Jxyz_s:mp_list_set_Ixyz_s),
  14567 + arg2,p1,arg3,arg4,arg5).move_to(code);
  14568 + else
  14569 + CImg<uptrT>::vector((uptrT)(is_relative?mp_list_set_Jxyz_v:mp_list_set_Ixyz_v),
  14570 + arg2,p1,arg3,arg4,arg5).move_to(code);
  14571 + } else {
  14572 + if (!imgout) _cimg_mp_return(arg2);
  14573 + if (_cimg_mp_is_scalar(arg2))
  14574 + CImg<uptrT>::vector((uptrT)(is_relative?mp_set_Jxyz_s:mp_set_Ixyz_s),
  14575 + arg2,arg3,arg4,arg5).move_to(code);
  14576 + else
  14577 + CImg<uptrT>::vector((uptrT)(is_relative?mp_set_Jxyz_v:mp_set_Ixyz_v),
  14578 + arg2,arg3,arg4,arg5).move_to(code);
  14579 + }
  14580 + _cimg_mp_return(arg2);
  14581 + }
  14582 +
  14583 + if (_cimg_mp_is_vector(arg1)) { // Vector variable: V = value
  14584 + _cimg_mp_check_type(arg2,2,s_op,1,0);
  14585 + if (_cimg_mp_is_vector(arg2)) // From vector
  14586 + CImg<uptrT>::vector((uptrT)mp_vector_copy,arg1,arg2,(uptrT)_cimg_mp_vector_size(arg1)).
  14587 + move_to(code);
  14588 + else // From scalar
  14589 + CImg<uptrT>::vector((uptrT)mp_vector_init,arg1,(uptrT)_cimg_mp_vector_size(arg1),arg2).
  14590 + move_to(code);
  14591 + _cimg_mp_return(arg1);
  14592 + }
  14593 +
  14594 + if (_cimg_mp_is_variable(arg1)) { // Scalar variable: s = scalar
  14595 + _cimg_mp_check_type(arg2,2,s_op,1,0);
  14596 + CImg<uptrT>::vector((uptrT)mp_copy,arg1,arg2).move_to(code);
  14597 + _cimg_mp_return(arg1);
  14598 +
  14599 + }
14032 } 14600 }
14033 - if (*ss1=='c') { // ic  
14034 - if (!is_median_value && reference) { median_value = reference.median(); is_median_value = true; }  
14035 - if (reserved_label[10]!=~0U) _cimg_mp_return(reserved_label[10]); _cimg_mp_opcode0(mp_ic); 14601 +
  14602 + // No assignment expressions match -> error
  14603 + *se = saved_char; cimg::strellipsize(variable_name,64); cimg::strellipsize(expr,64);
  14604 + throw CImgArgumentException("[_cimg_math_parser] "
  14605 + "CImg<%s>::%s: %s: Invalid left-hand operand '%s', "
  14606 + "in expression '%s%s%s'.",
  14607 + pixel_type(),_cimg_mp_calling_function,s_op,
  14608 + variable_name._data,
  14609 + (ss - 4)>expr._data?"...":"",
  14610 + (ss - 4)>expr._data?ss - 4:expr._data,
  14611 + se<&expr.back()?"...":"");
  14612 + }
  14613 +
  14614 + // Apply unary/binary/ternary operators. The operator precedences should be roughly the same as in C++.
  14615 + for (s = se2, ps = se3, ns = ps - 1; s>ss1; --s, --ps, --ns) // Here, ns = ps - 1
  14616 + if (*s=='=' && (*ps=='*' || *ps=='/' || *ps=='^') && *ns==*ps &&
  14617 + level[s - expr._data]==clevel) { // Self-operators for complex numbers only (**=,//=,^^=)
  14618 + s_op = *ps=='*'?"Operator '**='":*ps=='/'?"Operator '//='":"Operator '^^='";
  14619 +
  14620 + ref.assign(7);
  14621 + arg1 = compile(ss,ns,depth1,ref); // Vector slot
  14622 + arg2 = compile(s + 1,se,depth1,0); // Right operand
  14623 + if (*ps!='*') {
  14624 + _cimg_mp_check_type(arg1,2,s_op,2,2);
  14625 + _cimg_mp_check_type(arg2,2,s_op,2,2);
  14626 + }
  14627 + if (_cimg_mp_is_vector(arg2)) { // Complex **= complex or Matrix **= matrix
  14628 + if (*ps=='*') {
  14629 + if (_cimg_mp_vector_size(arg1)==2 && _cimg_mp_vector_size(arg2)==2)
  14630 + CImg<uptrT>::vector((uptrT)mp_complex_mul,arg1,arg1,arg2).move_to(code);
  14631 + else {
  14632 + _cimg_mp_check_matrix_square(arg2,2,s_op);
  14633 + p3 = _cimg_mp_vector_size(arg1);
  14634 + p2 = (unsigned int)std::sqrt((float)_cimg_mp_vector_size(arg2));
  14635 + p1 = p3/p2;
  14636 + if (p1*p2!=p3) {
  14637 + *se = saved_char; cimg::strellipsize(expr,64);
  14638 + throw CImgArgumentException("[_cimg_math_parser] "
  14639 + "CImg<%s>::%s: %s: Sizes of left-hand and right-hand operands "
  14640 + "('%s' and '%s') do not match, in expression '%s%s%s'.",
  14641 + pixel_type(),_cimg_mp_calling_function,s_op,
  14642 + s_type(arg1)._data,s_type(arg2)._data,
  14643 + (ss - 4)>expr._data?"...":"",
  14644 + (ss - 4)>expr._data?ss - 4:expr._data,
  14645 + se<&expr.back()?"...":"");
  14646 + }
  14647 + CImg<uptrT>::vector((uptrT)mp_matrix_mul,arg1,arg1,arg2,p1,p2,p2).move_to(code);
  14648 + }
  14649 + } else if (*ps=='/')
  14650 + CImg<uptrT>::vector((uptrT)mp_complex_div_vv,arg1,arg1,arg2).move_to(code);
  14651 + else
  14652 + CImg<uptrT>::vector((uptrT)mp_complex_pow_vv,arg1,arg1,arg2).move_to(code);
  14653 + } else { // Complex **= scalar
  14654 + if (*ps=='*')
  14655 + CImg<uptrT>::vector((uptrT)mp_self_map_vector_s,arg1,2,(uptrT)mp_self_mul,arg2).move_to(code);
  14656 + else if (*ps=='/')
  14657 + CImg<uptrT>::vector((uptrT)mp_self_map_vector_s,arg1,2,(uptrT)mp_self_div,arg2).move_to(code);
  14658 + else
  14659 + CImg<uptrT>::vector((uptrT)mp_complex_pow_vs,arg1,arg1,arg2).move_to(code);
  14660 + }
  14661 +
  14662 + // Write computed value back in image if necessary.
  14663 + if (*ref==4) { // Image value (vector): I/J[_#ind,off] **= value
  14664 + p1 = ref[1]; // Index
  14665 + is_relative = (bool)ref[2];
  14666 + arg3 = ref[3]; // Offset
  14667 + if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int));
  14668 + if (p1!=~0U) {
  14669 + if (!listout) _cimg_mp_return(arg1);
  14670 + CImg<uptrT>::vector((uptrT)(is_relative?mp_list_set_Joff_v:mp_list_set_Ioff_v),
  14671 + arg1,p1,arg3).move_to(code);
  14672 + } else {
  14673 + if (!imgout) _cimg_mp_return(arg1);
  14674 + CImg<uptrT>::vector((uptrT)(is_relative?mp_set_Joff_v:mp_set_Ioff_v),
  14675 + arg1,arg3).move_to(code);
  14676 + }
  14677 +
  14678 + } else if (*ref==5) { // Image value (vector): I/J(_#ind,_x,_y,_z,_c) **= value
  14679 + p1 = ref[1]; // Index
  14680 + is_relative = (bool)ref[2];
  14681 + arg3 = ref[3]; // X
  14682 + arg4 = ref[4]; // Y
  14683 + arg5 = ref[5]; // Z
  14684 + if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int));
  14685 + if (p1!=~0U) {
  14686 + if (!listout) _cimg_mp_return(arg1);
  14687 + CImg<uptrT>::vector((uptrT)(is_relative?mp_list_set_Jxyz_v:mp_list_set_Ixyz_v),
  14688 + arg1,p1,arg3,arg4,arg5).move_to(code);
  14689 + } else {
  14690 + if (!imgout) _cimg_mp_return(arg1);
  14691 + CImg<uptrT>::vector((uptrT)(is_relative?mp_set_Jxyz_v:mp_set_Ixyz_v),
  14692 + arg1,arg3,arg4,arg5).move_to(code);
  14693 + }
14036 } 14694 }
  14695 +
  14696 + _cimg_mp_return(arg1);
  14697 + }
  14698 +
  14699 + for (s = se2, ps = se3, ns = ps - 1; s>ss1; --s, --ps, --ns) // Here, ns = ps - 1
  14700 + if (*s=='=' && (*ps=='+' || *ps=='-' || *ps=='*' || *ps=='/' || *ps=='%' ||
  14701 + *ps=='&' || *ps=='^' || *ps=='|' ||
  14702 + (*ps=='>' && *ns=='>') || (*ps=='<' && *ns=='<')) &&
  14703 + level[s - expr._data]==clevel) { // Self-operators (+=,-=,*=,/=,%=,>>=,<<=,&=,^=,|=)
  14704 + switch (*ps) {
  14705 + case '+' : op = mp_self_add; s_op = "Operator '+='"; break;
  14706 + case '-' : op = mp_self_sub; s_op = "Operator '-='"; break;
  14707 + case '*' : op = mp_self_mul; s_op = "Operator '*='"; break;
  14708 + case '/' : op = mp_self_div; s_op = "Operator '/='"; break;
  14709 + case '%' : op = mp_self_modulo; s_op = "Operator '%='"; break;
  14710 + case '<' : op = mp_self_bitwise_left_shift; s_op = "Operator '<<='"; break;
  14711 + case '>' : op = mp_self_bitwise_right_shift; s_op = "Operator '>=='"; break;
  14712 + case '&' : op = mp_self_bitwise_and; s_op = "Operator '&='"; break;
  14713 + case '|' : op = mp_self_bitwise_or; s_op = "Operator '|='"; break;
  14714 + default : op = mp_self_pow; s_op = "Operator '^='"; break;
  14715 + }
  14716 + s1 = *ps=='>' || *ps=='<'?ns:ps;
  14717 +
  14718 + ref.assign(7);
  14719 + arg1 = compile(ss,s1,depth1,ref); // Variable slot
  14720 + arg2 = compile(s + 1,se,depth1,0); // Value to apply
  14721 +
  14722 + if (*ref>0 && !_cimg_mp_is_temp(arg1)) { // Apply operator on a copy if necessary.
  14723 + if (_cimg_mp_is_vector(arg1)) arg1 = vector_copy(arg1);
  14724 + else arg1 = scalar1(mp_copy,arg1);
  14725 + }
  14726 +
  14727 + if (*ref==1) { // Vector value (scalar): V[k] += scalar
  14728 + _cimg_mp_check_type(arg2,2,s_op,1,0);
  14729 + arg3 = ref[1]; // Vector slot
  14730 + arg4 = ref[2]; // Index
  14731 + if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int));
  14732 + CImg<uptrT>::vector((uptrT)op,arg1,arg2).move_to(code);
  14733 + CImg<uptrT>::vector((uptrT)mp_vector_set_off,arg1,arg3,(uptrT)_cimg_mp_vector_size(arg3),arg4,arg1).
  14734 + move_to(code);
  14735 + _cimg_mp_return(arg1);
  14736 + }
  14737 +
  14738 + if (*ref==2) { // Image value (scalar): i/j[_#ind,off] += scalar
  14739 + _cimg_mp_check_type(arg2,2,s_op,1,0);
  14740 + p1 = ref[1]; // Index
  14741 + is_relative = (bool)ref[2];
  14742 + arg3 = ref[3]; // Offset
  14743 + if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int));
  14744 + CImg<uptrT>::vector((uptrT)op,arg1,arg2).move_to(code);
  14745 + if (p1!=~0U) {
  14746 + if (!listout) _cimg_mp_return(arg1);
  14747 + CImg<uptrT>::vector((uptrT)(is_relative?mp_list_set_joff:mp_list_set_ioff),
  14748 + arg1,p1,arg3).move_to(code);
  14749 + } else {
  14750 + if (!imgout) _cimg_mp_return(arg1);
  14751 + CImg<uptrT>::vector((uptrT)(is_relative?mp_set_joff:mp_set_ioff),
  14752 + arg1,arg3).move_to(code);
  14753 + }
  14754 + _cimg_mp_return(arg1);
  14755 + }
  14756 +
  14757 + if (*ref==3) { // Image value (scalar): i/j(_#ind,_x,_y,_z,_c) += scalar
  14758 + _cimg_mp_check_type(arg2,2,s_op,1,0);
  14759 + p1 = ref[1]; // Index
  14760 + is_relative = (bool)ref[2];
  14761 + arg3 = ref[3]; // X
  14762 + arg4 = ref[4]; // Y
  14763 + arg5 = ref[5]; // Z
  14764 + arg6 = ref[6]; // C
  14765 + if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int));
  14766 + CImg<uptrT>::vector((uptrT)op,arg1,arg2).move_to(code);
  14767 + if (p1!=~0U) {
  14768 + if (!listout) _cimg_mp_return(arg1);
  14769 + CImg<uptrT>::vector((uptrT)(is_relative?mp_list_set_jxyzc:mp_list_set_ixyzc),
  14770 + arg1,p1,arg3,arg4,arg5,arg6).move_to(code);
  14771 + } else {
  14772 + if (!imgout) _cimg_mp_return(arg1);
  14773 + CImg<uptrT>::vector((uptrT)(is_relative?mp_set_jxyzc:mp_set_ixyzc),
  14774 + arg1,arg3,arg4,arg5,arg6).move_to(code);
  14775 + }
  14776 + _cimg_mp_return(arg1);
  14777 + }
  14778 +
  14779 + if (*ref==4) { // Image value (vector): I/J[_#ind,off] += value
  14780 + _cimg_mp_check_type(arg2,2,s_op,3,_cimg_mp_vector_size(arg1));
  14781 + p1 = ref[1]; // Index
  14782 + is_relative = (bool)ref[2];
  14783 + arg3 = ref[3]; // Offset
  14784 + if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int));
  14785 + if (_cimg_mp_is_scalar(arg2))
  14786 + CImg<uptrT>::vector((uptrT)mp_self_map_vector_s,arg1,(uptrT)_cimg_mp_vector_size(arg1),(uptrT)op,arg2).
  14787 + move_to(code);
  14788 + else
  14789 + CImg<uptrT>::vector((uptrT)mp_self_map_vector_v,arg1,(uptrT)_cimg_mp_vector_size(arg1),(uptrT)op,arg2).
  14790 + move_to(code);
  14791 + if (p1!=~0U) {
  14792 + if (!listout) _cimg_mp_return(arg1);
  14793 + CImg<uptrT>::vector((uptrT)(is_relative?mp_list_set_Joff_v:mp_list_set_Ioff_v),
  14794 + arg1,p1,arg3).move_to(code);
  14795 + } else {
  14796 + if (!imgout) _cimg_mp_return(arg1);
  14797 + CImg<uptrT>::vector((uptrT)(is_relative?mp_set_Joff_v:mp_set_Ioff_v),
  14798 + arg1,arg3).move_to(code);
  14799 + }
  14800 + _cimg_mp_return(arg1);
  14801 + }
  14802 +
  14803 + if (*ref==5) { // Image value (vector): I/J(_#ind,_x,_y,_z,_c) = value
  14804 + _cimg_mp_check_type(arg2,2,s_op,3,_cimg_mp_vector_size(arg1));
  14805 + p1 = ref[1]; // Index
  14806 + is_relative = (bool)ref[2];
  14807 + arg3 = ref[3]; // X
  14808 + arg4 = ref[4]; // Y
  14809 + arg5 = ref[5]; // Z
  14810 + if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int));
  14811 + if (_cimg_mp_is_scalar(arg2))
  14812 + CImg<uptrT>::vector((uptrT)mp_self_map_vector_s,arg1,(uptrT)_cimg_mp_vector_size(arg1),(uptrT)op,arg2).
  14813 + move_to(code);
  14814 + else
  14815 + CImg<uptrT>::vector((uptrT)mp_self_map_vector_v,arg1,(uptrT)_cimg_mp_vector_size(arg1),(uptrT)op,arg2).
  14816 + move_to(code);
  14817 + if (p1!=~0U) {
  14818 + if (!listout) _cimg_mp_return(arg1);
  14819 + CImg<uptrT>::vector((uptrT)(is_relative?mp_list_set_Jxyz_v:mp_list_set_Ixyz_v),
  14820 + arg1,p1,arg3,arg4,arg5).move_to(code);
  14821 + } else {
  14822 + if (!imgout) _cimg_mp_return(arg1);
  14823 + CImg<uptrT>::vector((uptrT)(is_relative?mp_set_Jxyz_v:mp_set_Ixyz_v),
  14824 + arg1,arg3,arg4,arg5).move_to(code);
  14825 + }
  14826 + _cimg_mp_return(arg1);
  14827 + }
  14828 +
  14829 + if (_cimg_mp_is_vector(arg1)) { // Vector variable: V += value
  14830 + _cimg_mp_check_type(arg2,2,s_op,3,_cimg_mp_vector_size(arg1));
  14831 + if (_cimg_mp_is_vector(arg2)) // Vector += vector
  14832 + CImg<uptrT>::vector((uptrT)mp_self_map_vector_v,arg1,(uptrT)_cimg_mp_vector_size(arg1),(uptrT)op,arg2).
  14833 + move_to(code);
  14834 + else // Vector += scalar
  14835 + CImg<uptrT>::vector((uptrT)mp_self_map_vector_s,arg1,(uptrT)_cimg_mp_vector_size(arg1),(uptrT)op,arg2).
  14836 + move_to(code);
  14837 + _cimg_mp_return(arg1);
  14838 + }
  14839 +
  14840 + if (_cimg_mp_is_variable(arg1)) { // Scalar variable: s += scalar
  14841 + _cimg_mp_check_type(arg2,2,s_op,1,0);
  14842 + CImg<uptrT>::vector((uptrT)op,arg1,arg2).move_to(code);
  14843 + _cimg_mp_return(arg1);
  14844 + }
  14845 +
  14846 + variable_name.assign(ss,(unsigned int)(s - ss)).back() = 0;
  14847 + *se = saved_char; cimg::strellipsize(expr,64);
  14848 + throw CImgArgumentException("[_cimg_math_parser] "
  14849 + "CImg<%s>::%s: %s: Invalid left-hand operand '%s', "
  14850 + "in expression '%s%s%s'.",
  14851 + pixel_type(),_cimg_mp_calling_function,s_op,
  14852 + variable_name._data,
  14853 + (ss - 4)>expr._data?"...":"",
  14854 + (ss - 4)>expr._data?ss - 4:expr._data,
  14855 + se<&expr.back()?"...":"");
  14856 + }
  14857 +
  14858 + for (s = ss1; s<se1; ++s)
  14859 + if (*s=='?' && level[s - expr._data]==clevel) { // Ternary operator 'cond?expr1:expr2'
  14860 + s_op = "Operator '?:'";
  14861 + s1 = s + 1; while (s1<se1 && (*s1!=':' || level[s1 - expr._data]!=clevel)) ++s1;
  14862 + arg1 = compile(ss,s,depth1,0);
  14863 + p2 = code._width;
  14864 + arg2 = compile(s + 1,*s1!=':'?se:s1,depth1,0);
  14865 + p3 = code._width;
  14866 + arg3 = *s1!=':'?0:compile(s1 + 1,se,depth1,0);
  14867 + _cimg_mp_check_type(arg1,1,s_op,1,0);
  14868 + _cimg_mp_check_type(arg3,3,s_op,_cimg_mp_is_vector(arg2)?2:1,_cimg_mp_vector_size(arg2));
  14869 + if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2) && _cimg_mp_is_constant(arg3))
  14870 + _cimg_mp_constant(mem[arg1]?mem[arg2]:mem[arg3]);
  14871 + arg4 = _cimg_mp_is_vector(arg2)?_cimg_mp_vector_size(arg2):0; // Output vector size (or 0 if scalar)
  14872 + if (arg4) pos = vector(arg4); else pos = scalar();
  14873 + CImg<uptrT>::vector((uptrT)mp_if,pos,arg1,arg2,arg3,
  14874 + p3 - p2,code._width - p3,arg4).move_to(code,p2);
  14875 + _cimg_mp_return(pos);
  14876 + }
  14877 +
  14878 + for (s = se3, ns = se2; s>ss; --s, --ns)
  14879 + if (*s=='|' && *ns=='|' && level[s - expr._data]==clevel) { // Logical or ('||')
  14880 + s_op = "Operator '||'";
  14881 + arg1 = compile(ss,s,depth1,0);
  14882 + p2 = code._width;
  14883 + arg2 = compile(s + 2,se,depth1,0);
  14884 + _cimg_mp_check_type(arg1,1,s_op,1,0);
  14885 + _cimg_mp_check_type(arg2,2,s_op,1,0);
  14886 + if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2))
  14887 + _cimg_mp_constant(mem[arg1] || mem[arg2]);
  14888 + pos = scalar();
  14889 + CImg<uptrT>::vector((uptrT)mp_logical_or,pos,arg1,arg2,code._width - p2).
  14890 + move_to(code,p2);
  14891 + _cimg_mp_return(pos);
  14892 + }
  14893 +
  14894 + for (s = se3, ns = se2; s>ss; --s, --ns)
  14895 + if (*s=='&' && *ns=='&' && level[s - expr._data]==clevel) { // Logical and ('&&')
  14896 + s_op = "Operator '&&'";
  14897 + arg1 = compile(ss,s,depth1,0);
  14898 + p2 = code._width;
  14899 + arg2 = compile(s + 2,se,depth1,0);
  14900 + _cimg_mp_check_type(arg1,1,s_op,1,0);
  14901 + _cimg_mp_check_type(arg2,2,s_op,1,0);
  14902 + if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2))
  14903 + _cimg_mp_constant(mem[arg1] && mem[arg2]);
  14904 + pos = scalar();
  14905 + CImg<uptrT>::vector((uptrT)mp_logical_and,pos,arg1,arg2,code._width - p2).
  14906 + move_to(code,p2);
  14907 + _cimg_mp_return(pos);
14037 } 14908 }
14038 - if (*ss1=='m') {  
14039 - if (*ss=='x') { // xm  
14040 - if (!reference_stats) reference.get_stats().move_to(reference_stats);  
14041 - if (reserved_label[11]!=~0U) _cimg_mp_return(reserved_label[11]); _cimg_mp_opcode0(mp_xm); 14909 +
  14910 + for (s = se2; s>ss; --s)
  14911 + if (*s=='|' && level[s - expr._data]==clevel) { // Bitwise or ('|')
  14912 + arg1 = compile(ss,s,depth1,0);
  14913 + arg2 = compile(s + 1,se,depth1,0);
  14914 + _cimg_mp_check_type(arg2,2,"operator '|'",3,_cimg_mp_vector_size(arg1));
  14915 + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_bitwise_or,arg1,arg2);
  14916 + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_bitwise_or,arg1,arg2);
  14917 + if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_bitwise_or,arg1,arg2);
  14918 + if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2))
  14919 + _cimg_mp_constant((unsigned long)mem[arg1] | (unsigned long)mem[arg2]);
  14920 + _cimg_mp_scalar2(mp_bitwise_or,arg1,arg2);
  14921 + }
  14922 +
  14923 + for (s = se2; s>ss; --s)
  14924 + if (*s=='&' && level[s - expr._data]==clevel) { // Bitwise and ('&')
  14925 + arg1 = compile(ss,s,depth1,0);
  14926 + arg2 = compile(s + 1,se,depth1,0);
  14927 + _cimg_mp_check_type(arg2,2,"operator '&'",3,_cimg_mp_vector_size(arg1));
  14928 + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_bitwise_and,arg1,arg2);
  14929 + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_bitwise_and,arg1,arg2);
  14930 + if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_bitwise_and,arg1,arg2);
  14931 + if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2))
  14932 + _cimg_mp_constant((unsigned long)mem[arg1] & (unsigned long)mem[arg2]);
  14933 + _cimg_mp_scalar2(mp_bitwise_and,arg1,arg2);
  14934 + }
  14935 +
  14936 + for (s = se3, ns = se2; s>ss; --s, --ns)
  14937 + if (*s=='!' && *ns=='=' && level[s - expr._data]==clevel) { // Not equal to ('!=')
  14938 + arg1 = compile(ss,s,depth1,0);
  14939 + arg2 = compile(s + 2,se,depth1,0);
  14940 + _cimg_mp_check_type(arg2,2,"operator '!='",3,_cimg_mp_vector_size(arg1));
  14941 + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_neq,arg1,arg2);
  14942 + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_neq,arg1,arg2);
  14943 + if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_neq,arg1,arg2);
  14944 + if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1]!=mem[arg2]);
  14945 + _cimg_mp_scalar2(mp_neq,arg1,arg2);
  14946 + }
  14947 +
  14948 + for (s = se3, ns = se2; s>ss; --s, --ns)
  14949 + if (*s=='=' && *ns=='=' && level[s - expr._data]==clevel) { // Equal to ('==')
  14950 + arg1 = compile(ss,s,depth1,0);
  14951 + arg2 = compile(s + 2,se,depth1,0);
  14952 + _cimg_mp_check_type(arg2,2,"operator '=='",3,_cimg_mp_vector_size(arg1));
  14953 + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_eq,arg1,arg2);
  14954 + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_eq,arg1,arg2);
  14955 + if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_eq,arg1,arg2);
  14956 + if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1]==mem[arg2]);
  14957 + _cimg_mp_scalar2(mp_eq,arg1,arg2);
  14958 + }
  14959 +
  14960 + for (s = se3, ns = se2; s>ss; --s, --ns)
  14961 + if (*s=='<' && *ns=='=' && level[s - expr._data]==clevel) { // Less or equal than ('<=')
  14962 + arg1 = compile(ss,s,depth1,0);
  14963 + arg2 = compile(s + 2,se,depth1,0);
  14964 + _cimg_mp_check_type(arg2,2,"operator '<='",3,_cimg_mp_vector_size(arg1));
  14965 + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_lte,arg1,arg2);
  14966 + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_lte,arg1,arg2);
  14967 + if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_lte,arg1,arg2);
  14968 + if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1]<=mem[arg2]);
  14969 + _cimg_mp_scalar2(mp_lte,arg1,arg2);
  14970 + }
  14971 +
  14972 + for (s = se3, ns = se2; s>ss; --s, --ns)
  14973 + if (*s=='>' && *ns=='=' && level[s - expr._data]==clevel) { // Greater or equal than ('>=')
  14974 + arg1 = compile(ss,s,depth1,0);
  14975 + arg2 = compile(s + 2,se,depth1,0);
  14976 + _cimg_mp_check_type(arg2,2,"operator '>='",3,_cimg_mp_vector_size(arg1));
  14977 + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_gte,arg1,arg2);
  14978 + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_gte,arg1,arg2);
  14979 + if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_gte,arg1,arg2);
  14980 + if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1]>=mem[arg2]);
  14981 + _cimg_mp_scalar2(mp_gte,arg1,arg2);
  14982 + }
  14983 +
  14984 + for (s = se2, ns = se1, ps = se3; s>ss; --s, --ns, --ps)
  14985 + if (*s=='<' && *ns!='<' && *ps!='<' && level[s - expr._data]==clevel) { // Less than ('<')
  14986 + arg1 = compile(ss,s,depth1,0);
  14987 + arg2 = compile(s + 1,se,depth1,0);
  14988 + _cimg_mp_check_type(arg2,2,"operator '<'",3,_cimg_mp_vector_size(arg1));
  14989 + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_lt,arg1,arg2);
  14990 + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_lt,arg1,arg2);
  14991 + if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_lt,arg1,arg2);
  14992 + if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1]<mem[arg2]);
  14993 + _cimg_mp_scalar2(mp_lt,arg1,arg2);
  14994 + }
  14995 +
  14996 + for (s = se2, ns = se1, ps = se3; s>ss; --s, --ns, --ps)
  14997 + if (*s=='>' && *ns!='>' && *ps!='>' && level[s - expr._data]==clevel) { // Greather than ('>')
  14998 + arg1 = compile(ss,s,depth1,0);
  14999 + arg2 = compile(s + 1,se,depth1,0);
  15000 + _cimg_mp_check_type(arg2,2,"operator '>'",3,_cimg_mp_vector_size(arg1));
  15001 + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_gt,arg1,arg2);
  15002 + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_gt,arg1,arg2);
  15003 + if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_gt,arg1,arg2);
  15004 + if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1]>mem[arg2]);
  15005 + _cimg_mp_scalar2(mp_gt,arg1,arg2);
  15006 + }
  15007 +
  15008 + for (s = se3, ns = se2; s>ss; --s, --ns)
  15009 + if (*s=='<' && *ns=='<' && level[s - expr._data]==clevel) { // Left bit shift ('<<')
  15010 + arg1 = compile(ss,s,depth1,0);
  15011 + arg2 = compile(s + 2,se,depth1,0);
  15012 + _cimg_mp_check_type(arg2,2,"operator '<<'",3,_cimg_mp_vector_size(arg1));
  15013 + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2))
  15014 + _cimg_mp_vector2_vv(mp_bitwise_left_shift,arg1,arg2);
  15015 + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2))
  15016 + _cimg_mp_vector2_vs(mp_bitwise_left_shift,arg1,arg2);
  15017 + if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2))
  15018 + _cimg_mp_vector2_sv(mp_bitwise_left_shift,arg1,arg2);
  15019 + if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2))
  15020 + _cimg_mp_constant((long)mem[arg1]<<(unsigned int)mem[arg2]);
  15021 + _cimg_mp_scalar2(mp_bitwise_left_shift,arg1,arg2);
  15022 + }
  15023 +
  15024 + for (s = se3, ns = se2; s>ss; --s, --ns)
  15025 + if (*s=='>' && *ns=='>' && level[s - expr._data]==clevel) { // Right bit shift ('>>')
  15026 + arg1 = compile(ss,s,depth1,0);
  15027 + arg2 = compile(s + 2,se,depth1,0);
  15028 + _cimg_mp_check_type(arg2,2,"operator '>>'",3,_cimg_mp_vector_size(arg1));
  15029 + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2))
  15030 + _cimg_mp_vector2_vv(mp_bitwise_right_shift,arg1,arg2);
  15031 + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2))
  15032 + _cimg_mp_vector2_vs(mp_bitwise_right_shift,arg1,arg2);
  15033 + if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2))
  15034 + _cimg_mp_vector2_sv(mp_bitwise_right_shift,arg1,arg2);
  15035 + if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2))
  15036 + _cimg_mp_constant((long)mem[arg1]>>(unsigned int)mem[arg2]);
  15037 + _cimg_mp_scalar2(mp_bitwise_right_shift,arg1,arg2);
  15038 + }
  15039 +
  15040 + for (ns = se1, s = se2, ps = pexpr._data + (se3 - expr._data); s>ss; --ns, --s, --ps)
  15041 + if (*s=='+' && (*ns!='+' || ns!=se1) && *ps!='-' && *ps!='+' && *ps!='*' && *ps!='/' && *ps!='%' &&
  15042 + *ps!='&' && *ps!='|' && *ps!='^' && *ps!='!' && *ps!='~' && *ps!='#' &&
  15043 + (*ps!='e' || !(ps - pexpr._data>ss - expr._data && (*(ps - 1)=='.' || (*(ps - 1)>='0' &&
  15044 + *(ps - 1)<='9')))) &&
  15045 + level[s - expr._data]==clevel) { // Addition ('+')
  15046 + arg1 = compile(ss,s,depth1,0);
  15047 + arg2 = compile(s + 1,se,depth1,0);
  15048 + _cimg_mp_check_type(arg2,2,"operator '+'",3,_cimg_mp_vector_size(arg1));
  15049 + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_add,arg1,arg2);
  15050 + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_add,arg1,arg2);
  15051 + if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_add,arg1,arg2);
  15052 + if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1] + mem[arg2]);
  15053 + if (arg2==1) _cimg_mp_scalar1(mp_increment,arg1);
  15054 + if (arg1==1) _cimg_mp_scalar1(mp_increment,arg2);
  15055 + _cimg_mp_scalar2(mp_add,arg1,arg2);
  15056 + }
  15057 +
  15058 + for (ns = se1, s = se2, ps = pexpr._data + (se3 - expr._data); s>ss; --ns, --s, --ps)
  15059 + if (*s=='-' && (*ns!='-' || ns!=se1) && *ps!='-' && *ps!='+' && *ps!='*' && *ps!='/' && *ps!='%' &&
  15060 + *ps!='&' && *ps!='|' && *ps!='^' && *ps!='!' && *ps!='~' && *ps!='#' &&
  15061 + (*ps!='e' || !(ps - pexpr._data>ss - expr._data && (*(ps - 1)=='.' || (*(ps - 1)>='0' &&
  15062 + *(ps - 1)<='9')))) &&
  15063 + level[s - expr._data]==clevel) { // Subtraction ('-')
  15064 + arg1 = compile(ss,s,depth1,0);
  15065 + arg2 = compile(s + 1,se,depth1,0);
  15066 + _cimg_mp_check_type(arg2,2,"operator '-'",3,_cimg_mp_vector_size(arg1));
  15067 + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_sub,arg1,arg2);
  15068 + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_sub,arg1,arg2);
  15069 + if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_sub,arg1,arg2);
  15070 + if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1] - mem[arg2]);
  15071 + if (arg2==1) _cimg_mp_scalar1(mp_decrement,arg1);
  15072 + _cimg_mp_scalar2(mp_sub,arg1,arg2);
  15073 + }
  15074 +
  15075 + for (s = se3, ns = se2; s>ss; --s, --ns)
  15076 + if (*s=='*' && *ns=='*' && level[s - expr._data]==clevel) { // Complex/matrix multiplication ('**')
  15077 + s_op = "Operator '**'";
  15078 + arg1 = compile(ss,s,depth1,0);
  15079 + arg2 = compile(s + 2,se,depth1,0);
  15080 + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) {
  15081 + if (_cimg_mp_vector_size(arg1)==2 && _cimg_mp_vector_size(arg2)==2) { // Complex multiplication
  15082 + pos = vector(2);
  15083 + CImg<uptrT>::vector((uptrT)mp_complex_mul,pos,arg1,arg2).move_to(code);
  15084 + _cimg_mp_return(pos);
  15085 + } else { // Matrix multiplication
  15086 + p1 = _cimg_mp_vector_size(arg1);
  15087 + p2 = _cimg_mp_vector_size(arg2);
  15088 + arg4 = p1/p2;
  15089 + if (arg4*p2!=p1) {
  15090 + *se = saved_char; cimg::strellipsize(expr,64);
  15091 + throw CImgArgumentException("[_cimg_math_parser] "
  15092 + "CImg<%s>::%s: %s: Sizes of left-hand and right-hand operands "
  15093 + "('%s' and '%s') do not match, in expression '%s%s%s'.",
  15094 + pixel_type(),_cimg_mp_calling_function,s_op,
  15095 + s_type(arg1)._data,s_type(arg2)._data,
  15096 + (ss - 4)>expr._data?"...":"",
  15097 + (ss - 4)>expr._data?ss - 4:expr._data,
  15098 + se<&expr.back()?"...":"");
  15099 + }
  15100 + pos = vector(arg4);
  15101 + CImg<uptrT>::vector((uptrT)mp_matrix_mul,pos,arg1,arg2,arg4,p2,1).move_to(code);
  15102 + _cimg_mp_return(pos);
  15103 + }
14042 } 15104 }
14043 - if (*ss=='y') { // ym  
14044 - if (!reference_stats) reference.get_stats().move_to(reference_stats);  
14045 - if (reserved_label[12]!=~0U) _cimg_mp_return(reserved_label[12]); _cimg_mp_opcode0(mp_ym); 15105 + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_mul,arg1,arg2);
  15106 + if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_mul,arg1,arg2);
  15107 + if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1]*mem[arg2]);
  15108 + _cimg_mp_scalar2(mp_mul,arg1,arg2);
  15109 + }
  15110 +
  15111 + for (s = se3, ns = se2; s>ss; --s, --ns)
  15112 + if (*s=='/' && *ns=='/' && level[s - expr._data]==clevel) { // Complex division ('//')
  15113 + s_op = "Operator '//'";
  15114 + arg1 = compile(ss,s,depth1,0);
  15115 + arg2 = compile(s + 2,se,depth1,0);
  15116 + _cimg_mp_check_type(arg1,1,s_op,3,2);
  15117 + _cimg_mp_check_type(arg2,2,s_op,3,2);
  15118 + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) {
  15119 + pos = vector(2);
  15120 + CImg<uptrT>::vector((uptrT)mp_complex_div_vv,pos,arg1,arg2).move_to(code);
  15121 + _cimg_mp_return(pos);
14046 } 15122 }
14047 - if (*ss=='z') { // zm  
14048 - if (!reference_stats) reference.get_stats().move_to(reference_stats);  
14049 - if (reserved_label[13]!=~0U) _cimg_mp_return(reserved_label[13]); _cimg_mp_opcode0(mp_zm); 15123 + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_div,arg1,arg2);
  15124 + if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) {
  15125 + pos = vector(2);
  15126 + CImg<uptrT>::vector((uptrT)mp_complex_div_sv,pos,arg1,arg2).move_to(code);
  15127 + _cimg_mp_return(pos);
14050 } 15128 }
14051 - if (*ss=='c') { // cm  
14052 - if (!reference_stats) reference.get_stats().move_to(reference_stats);  
14053 - if (reserved_label[14]!=~0U) _cimg_mp_return(reserved_label[14]); _cimg_mp_opcode0(mp_cm); 15129 + if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1]/mem[arg2]);
  15130 + _cimg_mp_scalar2(mp_div,arg1,arg2);
  15131 + }
  15132 +
  15133 + for (s = se2; s>ss; --s) if (*s=='*' && level[s - expr._data]==clevel) { // Multiplication ('*')
  15134 + arg1 = compile(ss,s,depth1,0);
  15135 + arg2 = compile(s + 1,se,depth1,0);
  15136 + _cimg_mp_check_type(arg2,2,"operator '*'",3,_cimg_mp_vector_size(arg1));
  15137 + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_mul,arg1,arg2);
  15138 + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_mul,arg1,arg2);
  15139 + if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_mul,arg1,arg2);
  15140 + if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1]*mem[arg2]);
  15141 + _cimg_mp_scalar2(mp_mul,arg1,arg2);
  15142 + }
  15143 +
  15144 +
  15145 + for (s = se2; s>ss; --s) if (*s=='/' && level[s - expr._data]==clevel) { // Division ('/')
  15146 + arg1 = compile(ss,s,depth1,0);
  15147 + arg2 = compile(s + 1,se,depth1,0);
  15148 + _cimg_mp_check_type(arg2,2,"operator '/'",3,_cimg_mp_vector_size(arg1));
  15149 + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_div,arg1,arg2);
  15150 + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_div,arg1,arg2);
  15151 + if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_div,arg1,arg2);
  15152 + if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) _cimg_mp_constant(mem[arg1]/mem[arg2]);
  15153 + _cimg_mp_scalar2(mp_div,arg1,arg2);
  15154 + }
  15155 +
  15156 + for (s = se2, ns = se1; s>ss; --s, --ns)
  15157 + if (*s=='%' && *ns!='^' && level[s - expr._data]==clevel) { // Modulo ('%')
  15158 + arg1 = compile(ss,s,depth1,0);
  15159 + arg2 = compile(s + 1,se,depth1,0);
  15160 + _cimg_mp_check_type(arg2,2,"operator '%'",3,_cimg_mp_vector_size(arg1));
  15161 + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_modulo,arg1,arg2);
  15162 + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_modulo,arg1,arg2);
  15163 + if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_modulo,arg1,arg2);
  15164 + if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2))
  15165 + _cimg_mp_constant(cimg::mod(mem[arg1],mem[arg2]));
  15166 + _cimg_mp_scalar2(mp_modulo,arg1,arg2);
  15167 + }
  15168 +
  15169 + if (se1>ss) {
  15170 + if (*ss=='+' && (*ss1!='+' || (ss2<se && *ss2>='0' && *ss2<='9'))) // Unary plus ('+')
  15171 + _cimg_mp_return(compile(ss1,se,depth1,0));
  15172 +
  15173 + if (*ss=='-' && (*ss1!='-' || (ss2<se && *ss2>='0' && *ss2<='9'))) { // Unary minus ('-')
  15174 + arg1 = compile(ss1,se,depth1,0);
  15175 + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_minus,arg1);
  15176 + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(-mem[arg1]);
  15177 + _cimg_mp_scalar1(mp_minus,arg1);
  15178 + }
  15179 +
  15180 + if (*ss=='!') { // Logical not ('!')
  15181 + arg1 = compile(ss1,se,depth1,0);
  15182 + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_logical_not,arg1);
  15183 + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(!mem[arg1]);
  15184 + _cimg_mp_scalar1(mp_logical_not,arg1);
  15185 + }
  15186 +
  15187 + if (*ss=='~') { // Bitwise not ('~')
  15188 + arg1 = compile(ss1,se,depth1,0);
  15189 + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_bitwise_not,arg1);
  15190 + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(~(unsigned long)mem[arg1]);
  15191 + _cimg_mp_scalar1(mp_bitwise_not,arg1);
  15192 + }
  15193 + }
  15194 +
  15195 + for (s = se3, ns = se2; s>ss; --s, --ns)
  15196 + if (*s=='^' && *ns=='^' && level[s - expr._data]==clevel) { // Complex power ('^^')
  15197 + s_op = "Operator '^^'";
  15198 + arg1 = compile(ss,s,depth1,0);
  15199 + arg2 = compile(s + 2,se,depth1,0);
  15200 + _cimg_mp_check_type(arg1,1,s_op,3,2);
  15201 + _cimg_mp_check_type(arg2,2,s_op,3,2);
  15202 + pos = (_cimg_mp_is_vector(arg1) || _cimg_mp_is_vector(arg2))?vector(2):0;
  15203 + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) {
  15204 + CImg<uptrT>::vector((uptrT)mp_complex_pow_vv,pos,arg1,arg2).move_to(code);
  15205 + _cimg_mp_return(pos);
14054 } 15206 }
14055 - }  
14056 - if (*ss1=='M') {  
14057 - if (*ss=='x') { // xM  
14058 - if (!reference_stats) reference.get_stats().move_to(reference_stats);  
14059 - if (reserved_label[15]!=~0U) _cimg_mp_return(reserved_label[15]); _cimg_mp_opcode0(mp_xM); 15207 + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) {
  15208 + CImg<uptrT>::vector((uptrT)mp_complex_pow_vs,pos,arg1,arg2).move_to(code);
  15209 + _cimg_mp_return(pos);
14060 } 15210 }
14061 - if (*ss=='y') { // yM  
14062 - if (!reference_stats) reference.get_stats().move_to(reference_stats);  
14063 - if (reserved_label[16]!=~0U) _cimg_mp_return(reserved_label[16]); _cimg_mp_opcode0(mp_yM); 15211 + if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) {
  15212 + CImg<uptrT>::vector((uptrT)mp_complex_pow_sv,pos,arg1,arg2).move_to(code);
  15213 + _cimg_mp_return(pos);
14064 } 15214 }
14065 - if (*ss=='z') { // zM  
14066 - if (!reference_stats) reference.get_stats().move_to(reference_stats);  
14067 - if (reserved_label[17]!=~0U) _cimg_mp_return(reserved_label[17]); _cimg_mp_opcode0(mp_zM); 15215 + if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2))
  15216 + _cimg_mp_constant(std::pow(mem[arg1],mem[arg2]));
  15217 + switch (arg2) {
  15218 + case 0 : _cimg_mp_return(1);
  15219 + case 1 : _cimg_mp_return(arg1);
  15220 + case 2 : _cimg_mp_scalar1(mp_sqr,arg1);
  15221 + case 3 : _cimg_mp_scalar1(mp_pow3,arg1);
  15222 + case 4 : _cimg_mp_scalar1(mp_pow4,arg1);
  15223 + default : _cimg_mp_scalar2(mp_pow,arg1,arg2);
14068 } 15224 }
14069 - if (*ss=='c') { // cM  
14070 - if (!reference_stats) reference.get_stats().move_to(reference_stats);  
14071 - if (reserved_label[18]!=~0U) _cimg_mp_return(reserved_label[18]); _cimg_mp_opcode0(mp_cM); 15225 + }
  15226 +
  15227 + for (s = se2; s>ss; --s)
  15228 + if (*s=='^' && level[s - expr._data]==clevel) { // Power ('^')
  15229 + arg1 = compile(ss,s,depth1,0);
  15230 + arg2 = compile(s + 1,se,depth1,0);
  15231 + _cimg_mp_check_type(arg2,2,"operator '^'",3,_cimg_mp_vector_size(arg1));
  15232 + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_pow,arg1,arg2);
  15233 + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_pow,arg1,arg2);
  15234 + if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_pow,arg1,arg2);
  15235 + if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2))
  15236 + _cimg_mp_constant(std::pow(mem[arg1],mem[arg2]));
  15237 + switch (arg2) {
  15238 + case 0 : _cimg_mp_return(1);
  15239 + case 1 : _cimg_mp_return(arg1);
  15240 + case 2 : _cimg_mp_scalar1(mp_sqr,arg1);
  15241 + case 3 : _cimg_mp_scalar1(mp_pow3,arg1);
  15242 + case 4 : _cimg_mp_scalar1(mp_pow4,arg1);
  15243 + default : _cimg_mp_scalar2(mp_pow,arg1,arg2);
14072 } 15244 }
14073 } 15245 }
14074 - } else if (ss3==se) { // Three-chars variable.  
14075 - if (*ss=='w' && *ss1=='h' && *ss2=='d') _cimg_mp_return(reserved_label[1]); // whd  
14076 - } else if (ss4==se) { // Four-chars variable.  
14077 - if (*ss=='w' && *ss1=='h' && *ss2=='d' && *ss3=='s') _cimg_mp_return(reserved_label[2]); // whds  
14078 - }  
14079 15246
14080 - // Look for variable declarations.  
14081 - for (char *s = se2; s>ss; --s)  
14082 - if (*s==';' && level[s - expr._data]==clevel) { compile(ss,s); _cimg_mp_return(compile(s + 1,se)); }  
14083 - for (char *s = ss1, *ps = ss, *ns = ss2; s<se1; ++s, ++ps, ++ns)  
14084 - if (*s=='=' && *ns!='=' && *ps!='=' && *ps!='>' && *ps!='<' && *ps!='!' && level[s - expr._data]==clevel) {  
14085 - CImg<charT> variable_name(ss,(unsigned int)(s - ss + 1));  
14086 - variable_name.back() = 0;  
14087 - cimg::strpare(variable_name);  
14088 - bool is_valid_name = true;  
14089 - if (*variable_name>='0' && *variable_name<='9') is_valid_name = false;  
14090 - else for (const char *ns = variable_name._data + 1; *ns; ++ns)  
14091 - if ((*ns<'a' || *ns>'z') && (*ns<'A' || *ns>'Z') && (*ns<'0' || *ns>'9') && *ns!='_') {  
14092 - is_valid_name = false; break;  
14093 - }  
14094 - if (!is_valid_name) {  
14095 - *se = saved_char;  
14096 - throw CImgArgumentException("[_cimg_math_parser] "  
14097 - "CImg<%s>::%s(): Invalid variable name '%s' in specified expression "  
14098 - "'%s%s%s'.",  
14099 - pixel_type(),calling_function,  
14100 - variable_name._data,  
14101 - (ss - 8)>expr._data?"...":"",  
14102 - (ss - 8)>expr._data?ss - 8:expr._data,  
14103 - se<&expr.back()?"...":""); 15247 + is_sth = ss1<se1 && (*ss=='+' || *ss=='-') && *ss1==*ss; // is pre-?
  15248 + if (is_sth || (se2>ss && (*se1=='+' || *se1=='-') && *se2==*se1)) { // Pre/post-decrement and increment
  15249 + if ((is_sth && *ss=='+') || (!is_sth && *se1=='+')) { op = mp_self_increment; s_op = "Operator '++'"; }
  15250 + else { op = mp_self_decrement; s_op = "Operator '--'"; }
  15251 +
  15252 + ref.assign(7);
  15253 + arg1 = is_sth?compile(ss2,se,depth1,ref):compile(ss,se2,depth1,ref); // Variable slot
  15254 +
  15255 + if (*ref>0 && !_cimg_mp_is_temp(arg1)) { // Apply operator on a copy if necessary.
  15256 + if (_cimg_mp_is_vector(arg1)) arg1 = vector_copy(arg1);
  15257 + else arg1 = scalar1(mp_copy,arg1);
  15258 + }
  15259 +
  15260 + if (is_sth) pos = arg1; // Determine return indice, depending on pre/post action
  15261 + else {
  15262 + if (_cimg_mp_is_vector(arg1)) pos = vector_copy(arg1);
  15263 + else pos = scalar1(mp_copy,arg1);
  15264 + }
  15265 +
  15266 + if (*ref==1) { // Vector value (scalar): V[k]++
  15267 + arg3 = ref[1]; // Vector slot
  15268 + arg4 = ref[2]; // Index
  15269 + if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int));
  15270 + CImg<uptrT>::vector((uptrT)op,arg1,1).move_to(code);
  15271 + CImg<uptrT>::vector((uptrT)mp_vector_set_off,arg1,arg3,(uptrT)_cimg_mp_vector_size(arg3),arg4,arg1).
  15272 + move_to(code);
  15273 + _cimg_mp_return(pos);
  15274 + }
  15275 +
  15276 + if (*ref==2) { // Image value (scalar): i/j[_#ind,off]++
  15277 + p1 = ref[1]; // Index
  15278 + is_relative = (bool)ref[2];
  15279 + arg3 = ref[3]; // Offset
  15280 + if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int));
  15281 + CImg<uptrT>::vector((uptrT)op,arg1).move_to(code);
  15282 + if (p1!=~0U) {
  15283 + if (!listout) _cimg_mp_return(pos);
  15284 + CImg<uptrT>::vector((uptrT)(is_relative?mp_list_set_joff:mp_list_set_ioff),
  15285 + arg1,p1,arg3).move_to(code);
  15286 + } else {
  15287 + if (!imgout) _cimg_mp_return(pos);
  15288 + CImg<uptrT>::vector((uptrT)(is_relative?mp_set_joff:mp_set_ioff),
  15289 + arg1,arg3).move_to(code);
14104 } 15290 }
14105 - const unsigned int pos = compile(s + 1,se);  
14106 -  
14107 - // Check for particular case of a reserved variable.  
14108 - if (variable_name[1] && !variable_name[2]) { // Two-chars variable.  
14109 - const char c1 = variable_name[0], c2 = variable_name[1];  
14110 - if (c1=='w' && c2=='h') variable_name.fill((char)0,(char)0); // wh  
14111 - else if (c1=='p' && c2=='i') variable_name.fill(3,0); // pi  
14112 - else if (c1=='i') {  
14113 - if (c2=='m') variable_name.fill(4,0); // im  
14114 - else if (c2=='M') variable_name.fill(5,0); // iM  
14115 - else if (c2=='a') variable_name.fill(6,0); // ia  
14116 - else if (c2=='v') variable_name.fill(7,0); // iv  
14117 - else if (c2=='s') variable_name.fill(8,0); // is  
14118 - else if (c2=='p') variable_name.fill(9,0); // ip  
14119 - else if (c2=='c') variable_name.fill(10,0); // ic  
14120 - } else if (c2=='m') {  
14121 - if (c1=='x') variable_name.fill(11,0); // xm  
14122 - else if (c1=='y') variable_name.fill(12,0); // ym  
14123 - else if (c1=='z') variable_name.fill(13,0); // zm  
14124 - else if (c1=='c') variable_name.fill(14,0); // cm  
14125 - } else if (c2=='M') {  
14126 - if (c1=='x') variable_name.fill(15,0); // xM  
14127 - else if (c1=='y') variable_name.fill(16,0); // yM  
14128 - else if (c1=='z') variable_name.fill(17,0); // zM  
14129 - else if (c1=='c') variable_name.fill(18,0); // cM  
14130 - }  
14131 - } else if (variable_name[1] && variable_name[2] && !variable_name[3]) { // Three-chars variable.  
14132 - const char c1 = variable_name[0], c2 = variable_name[1], c3 = variable_name[2];  
14133 - if (c1=='w' && c2=='h' && c3=='d') variable_name.fill(1,0,0); // whd  
14134 - } else if (variable_name[1] && variable_name[2] && variable_name[3] &&  
14135 - !variable_name[4]) { // Four-chars variable.  
14136 - const char c1 = variable_name[0], c2 = variable_name[1], c3 = variable_name[2],  
14137 - c4 = variable_name[3];  
14138 - if (c1=='w' && c2=='h' && c3=='d' && c4=='s') variable_name.fill(2,0,0,0); // whds 15291 + _cimg_mp_return(pos);
  15292 + }
  15293 +
  15294 + if (*ref==3) { // Image value (scalar): i/j(_#ind,_x,_y,_z,_c)++
  15295 + p1 = ref[1]; // Index
  15296 + is_relative = (bool)ref[2];
  15297 + arg3 = ref[3]; // X
  15298 + arg4 = ref[4]; // Y
  15299 + arg5 = ref[5]; // Z
  15300 + arg6 = ref[6]; // C
  15301 + if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int));
  15302 + CImg<uptrT>::vector((uptrT)op,arg1).move_to(code);
  15303 + if (p1!=~0U) {
  15304 + if (!listout) _cimg_mp_return(pos);
  15305 + CImg<uptrT>::vector((uptrT)(is_relative?mp_list_set_jxyzc:mp_list_set_ixyzc),
  15306 + arg1,p1,arg3,arg4,arg5,arg6).move_to(code);
  15307 + } else {
  15308 + if (!imgout) _cimg_mp_return(pos);
  15309 + CImg<uptrT>::vector((uptrT)(is_relative?mp_set_jxyzc:mp_set_ixyzc),
  15310 + arg1,arg3,arg4,arg5,arg6).move_to(code);
  15311 + }
  15312 + _cimg_mp_return(pos);
  15313 + }
  15314 +
  15315 + if (*ref==4) { // Image value (vector): I/J[_#ind,off]++
  15316 + p1 = ref[1]; // Index
  15317 + is_relative = (bool)ref[2];
  15318 + arg3 = ref[3]; // Offset
  15319 + if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int));
  15320 + CImg<uptrT>::vector((uptrT)mp_self_map_vector_s,arg1,(uptrT)_cimg_mp_vector_size(arg1),
  15321 + (uptrT)(op==mp_self_increment?mp_self_add:mp_self_sub),1).
  15322 + move_to(code);
  15323 + if (p1!=~0U) {
  15324 + if (!listout) _cimg_mp_return(pos);
  15325 + CImg<uptrT>::vector((uptrT)(is_relative?mp_list_set_Joff_v:mp_list_set_Ioff_v),
  15326 + arg1,p1,arg3).move_to(code);
  15327 + } else {
  15328 + if (!imgout) _cimg_mp_return(pos);
  15329 + CImg<uptrT>::vector((uptrT)(is_relative?mp_set_Joff_v:mp_set_Ioff_v),
  15330 + arg1,arg3).move_to(code);
14139 } 15331 }
  15332 + _cimg_mp_return(pos);
  15333 + }
14140 15334
14141 - // Set new variable value.  
14142 - if (!variable_name[1]) reserved_label[*variable_name] = pos;  
14143 - else {  
14144 - int label_pos = -1;  
14145 - cimglist_for(labelM,i) // Check for existing variable with same name.  
14146 - if (!std::strcmp(variable_name,labelM[i])) { label_pos = i; break; }  
14147 - if (label_pos<0) { // If new variable.  
14148 - if (labelM._width>=labelMpos._width) labelMpos.resize(-200,1,1,1,0);  
14149 - label_pos = labelM.width();  
14150 - variable_name.move_to(labelM);  
14151 - }  
14152 - labelMpos[label_pos] = pos; 15335 + if (*ref==5) { // Image value (vector): I/J(_#ind,_x,_y,_z,_c)++
  15336 + p1 = ref[1]; // Index
  15337 + is_relative = (bool)ref[2];
  15338 + arg3 = ref[3]; // X
  15339 + arg4 = ref[4]; // Y
  15340 + arg5 = ref[5]; // Z
  15341 + if (p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int));
  15342 + CImg<uptrT>::vector((uptrT)mp_self_map_vector_s,arg1,(uptrT)_cimg_mp_vector_size(arg1),
  15343 + (uptrT)(op==mp_self_increment?mp_self_add:mp_self_sub),1).
  15344 + move_to(code);
  15345 + if (p1!=~0U) {
  15346 + if (!listout) _cimg_mp_return(pos);
  15347 + CImg<uptrT>::vector((uptrT)(is_relative?mp_list_set_Jxyz_v:mp_list_set_Ixyz_v),
  15348 + arg1,p1,arg3,arg4,arg5).move_to(code);
  15349 + } else {
  15350 + if (!imgout) _cimg_mp_return(pos);
  15351 + CImg<uptrT>::vector((uptrT)(is_relative?mp_set_Jxyz_v:mp_set_Ixyz_v),
  15352 + arg1,arg3,arg4,arg5).move_to(code);
14153 } 15353 }
14154 _cimg_mp_return(pos); 15354 _cimg_mp_return(pos);
14155 } 15355 }
14156 15356
14157 - // Look for unary/binary operators. The operator precedences is defined as in C++.  
14158 - for (char *s = se3, *ns = se2; s>ss; --s, --ns) if (*s=='|' && *ns=='|' && level[s - expr._data]==clevel) {  
14159 - const unsigned int mem_A = compile(ss,s), bp1 = code._width, mem_B = compile(s + 2,se);  
14160 - if (mempos>=mem._width) mem.resize(-200,1,1,1,0);  
14161 - const unsigned int pos = mempos++;  
14162 - CImg<longT>::vector(_cimg_mp_enfunc(mp_logical_or),pos,mem_A,mem_B,code._width - bp1).move_to(code,bp1); 15357 + if (_cimg_mp_is_vector(arg1)) { // Vector variable: V++
  15358 + CImg<uptrT>::vector((uptrT)mp_self_map_vector_s,arg1,(uptrT)_cimg_mp_vector_size(arg1),
  15359 + (uptrT)(op==mp_self_increment?mp_self_add:mp_self_sub),1).
  15360 + move_to(code);
14163 _cimg_mp_return(pos); 15361 _cimg_mp_return(pos);
14164 } 15362 }
14165 - for (char *s = se3, *ns = se2; s>ss; --s, --ns) if (*s=='&' && *ns=='&' && level[s - expr._data]==clevel) {  
14166 - const unsigned int mem_A = compile(ss,s), bp1 = code._width, mem_B = compile(s + 2,se);  
14167 - if (mempos>=mem._width) mem.resize(-200,1,1,1,0);  
14168 - const unsigned int pos = mempos++;  
14169 - CImg<longT>::vector(_cimg_mp_enfunc(mp_logical_and),pos,mem_A,mem_B,code._width - bp1).move_to(code,bp1); 15363 +
  15364 + if (_cimg_mp_is_variable(arg1)) { // Scalar variable: s++
  15365 + CImg<uptrT>::vector((uptrT)op,arg1).move_to(code);
14170 _cimg_mp_return(pos); 15366 _cimg_mp_return(pos);
14171 } 15367 }
14172 - for (char *s = se2; s>ss; --s)  
14173 - if (*s=='|' && level[s - expr._data]==clevel)  
14174 - _cimg_mp_opcode2(mp_bitwise_or,compile(ss,s),compile(s + 1,se));  
14175 - for (char *s = se2; s>ss; --s)  
14176 - if (*s=='&' && level[s - expr._data]==clevel)  
14177 - _cimg_mp_opcode2(mp_bitwise_and,compile(ss,s),compile(s + 1,se));  
14178 - for (char *s = se3, *ns = se2; s>ss; --s, --ns)  
14179 - if (*s=='!' && *ns=='=' && level[s - expr._data]==clevel)  
14180 - _cimg_mp_opcode2(mp_noteq,compile(ss,s),compile(s + 2,se));  
14181 - for (char *s = se3, *ns = se2; s>ss; --s, --ns)  
14182 - if (*s=='=' && *ns=='=' && level[s - expr._data]==clevel)  
14183 - _cimg_mp_opcode2(mp_eqeq,compile(ss,s),compile(s + 2,se));  
14184 - for (char *s = se3, *ns = se2; s>ss; --s, --ns)  
14185 - if (*s=='<' && *ns=='=' && level[s - expr._data]==clevel)  
14186 - _cimg_mp_opcode2(mp_infeq,compile(ss,s),compile(s + 2,se));  
14187 - for (char *s = se3, *ns = se2; s>ss; --s, --ns)  
14188 - if (*s=='>' && *ns=='=' && level[s - expr._data]==clevel)  
14189 - _cimg_mp_opcode2(mp_supeq,compile(ss,s),compile(s + 2,se));  
14190 - for (char *s = se2, *ns = se1, *ps = se3; s>ss; --s, --ns, --ps)  
14191 - if (*s=='<' && *ns!='<' && *ps!='<' && level[s - expr._data]==clevel)  
14192 - _cimg_mp_opcode2(mp_inf,compile(ss,s),compile(s + 1,se));  
14193 - for (char *s = se2, *ns = se1, *ps = se3; s>ss; --s, --ns, --ps)  
14194 - if (*s=='>' && *ns!='>' && *ps!='>' && level[s - expr._data]==clevel)  
14195 - _cimg_mp_opcode2(mp_sup,compile(ss,s),compile(s + 1,se));  
14196 - for (char *s = se3, *ns = se2; s>ss; --s, --ns)  
14197 - if (*s=='<' && *ns=='<' && level[s - expr._data]==clevel)  
14198 - _cimg_mp_opcode2(mp_lsl,compile(ss,s),compile(s + 2,se));  
14199 - for (char *s = se3, *ns = se2; s>ss; --s, --ns)  
14200 - if (*s=='>' && *ns=='>' && level[s - expr._data]==clevel)  
14201 - _cimg_mp_opcode2(mp_lsr,compile(ss,s),compile(s + 2,se));  
14202 - for (char *s = se2, *ps = se3; s>ss; --s, --ps)  
14203 - if (*s=='+' && *ps!='-' && *ps!='+' && *ps!='*' && *ps!='/' && *ps!='%' &&  
14204 - *ps!='&' && *ps!='|' && *ps!='^' && *ps!='!' && *ps!='~' &&  
14205 - (*ps!='e' || !(ps>ss && (*(ps - 1)=='.' || (*(ps - 1)>='0' && *(ps - 1)<='9')))) &&  
14206 - level[s - expr._data]==clevel)  
14207 - _cimg_mp_opcode2(mp_add,compile(ss,s),compile(s + 1,se));  
14208 - for (char *s = se2, *ps = se3; s>ss; --s, --ps)  
14209 - if (*s=='-' && *ps!='-' && *ps!='+' && *ps!='*' && *ps!='/' && *ps!='%' &&  
14210 - *ps!='&' && *ps!='|' && *ps!='^' && *ps!='!' && *ps!='~' &&  
14211 - (*ps!='e' || !(ps>ss && (*(ps - 1)=='.' || (*(ps - 1)>='0' && *(ps - 1)<='9')))) &&  
14212 - level[s - expr._data]==clevel)  
14213 - _cimg_mp_opcode2(mp_sub,compile(ss,s),compile(s + 1,se));  
14214 - for (char *s = se2; s>ss; --s) if (*s=='*' && level[s - expr._data]==clevel) {  
14215 - const unsigned int mem_A = compile(ss,s), bp1 = code._width, mem_B = compile(s + 1,se);  
14216 - if (mempos>=mem._width) mem.resize(-200,1,1,1,0);  
14217 - const unsigned int pos = mempos++;  
14218 - CImg<longT>::vector(_cimg_mp_enfunc(mp_mul),pos,mem_A,mem_B,code._width - bp1).move_to(code,bp1); 15368 +
  15369 + if (is_sth) variable_name.assign(ss2,(unsigned int)(se - ss1));
  15370 + else variable_name.assign(ss,(unsigned int)(se1 - ss));
  15371 + variable_name.back() = 0;
  15372 + *se = saved_char; cimg::strellipsize(variable_name,64); cimg::strellipsize(expr,64);
  15373 + throw CImgArgumentException("[_cimg_math_parser] "
  15374 + "CImg<%s>::%s: %s: Invalid operand '%s', "
  15375 + "in expression '%s%s%s'.",
  15376 + pixel_type(),_cimg_mp_calling_function,s_op,
  15377 + variable_name._data,
  15378 + (ss - 4)>expr._data?"...":"",
  15379 + (ss - 4)>expr._data?ss - 4:expr._data,
  15380 + se<&expr.back()?"...":"");
  15381 + }
  15382 +
  15383 + // Array-like access to vectors and image values 'i/j[_#ind,offset,_boundary]' and 'vector[offset]'.
  15384 + if (*se1==']' && *ss!='[') {
  15385 + s_op = "Operator '[]'";
  15386 + is_relative = *ss=='j' || *ss=='J';
  15387 +
  15388 + if ((*ss=='I' || *ss=='J') && *ss1=='[' &&
  15389 + (reserved_label[*ss]==~0U || !_cimg_mp_is_vector(reserved_label[*ss]))) { // Image value as a vector
  15390 + if (*ss2=='#') { // Index specified
  15391 + s0 = ss3; while (s0<se1 && (*s0!=',' || level[s0 - expr._data]!=clevel1)) ++s0;
  15392 + p1 = compile(ss3,s0++,depth1,0);
  15393 + } else { p1 = ~0U; s0 = ss2; }
  15394 + s1 = s0; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
  15395 + arg1 = compile(s0,s1,depth1,0); // Offset
  15396 + arg2 = s1<se1?compile(s1 + 1,se1,depth1,0):~0U; // Boundary
  15397 + if (p_ref && arg2==~0U) {
  15398 + *p_ref = 4;
  15399 + p_ref[1] = p1;
  15400 + p_ref[2] = (unsigned int)is_relative;
  15401 + p_ref[3] = arg1;
  15402 + if (p1!=~0U && _cimg_mp_is_temp(p1)) memtype[p1] = -1; // Prevent from being used in further optimization
  15403 + if (_cimg_mp_is_temp(arg1)) memtype[arg1] = -1;
  15404 + }
  15405 + p2 = ~0U; // 'p2' must the dimension of the vector-valued operand if any
  15406 + if (p1==~0U) p2 = imgin._spectrum;
  15407 + else if (_cimg_mp_is_constant(p1)) {
  15408 + p3 = (unsigned int)cimg::mod((int)mem[p1],listin.width());
  15409 + p2 = listin[p3]._spectrum;
  15410 + }
  15411 + _cimg_mp_check_vector0(p2,s_op);
  15412 + pos = vector(p2);
  15413 + if (p1!=~0U) {
  15414 + CImg<uptrT>::vector((uptrT)(is_relative?mp_list_Joff:mp_list_Ioff),
  15415 + pos,p1,arg1,arg2==~0U?reserved_label[30]:arg2).move_to(code);
  15416 + } else {
  15417 + CImg<uptrT>::vector((uptrT)(is_relative?mp_Joff:mp_Ioff),
  15418 + pos,arg1,arg2==~0U?reserved_label[30]:arg2).move_to(code);
  15419 + }
14219 _cimg_mp_return(pos); 15420 _cimg_mp_return(pos);
14220 } 15421 }
14221 - for (char *s = se2; s>ss; --s)  
14222 - if (*s=='/' && level[s - expr._data]==clevel)  
14223 - _cimg_mp_opcode2(mp_div,compile(ss,s),compile(s + 1,se));  
14224 - for (char *s = se2, *ns = se1; s>ss; --s, --ns)  
14225 - if (*s=='%' && *ns!='^' && level[s - expr._data]==clevel)  
14226 - _cimg_mp_opcode2(mp_modulo,compile(ss,s),compile(s + 1,se));  
14227 - if (ss<se1) {  
14228 - if (*ss=='+') _cimg_mp_return(compile(ss1,se));  
14229 - if (*ss=='-') _cimg_mp_opcode1(mp_minus,compile(ss1,se));  
14230 - if (*ss=='!') _cimg_mp_opcode1(mp_logical_not,compile(ss1,se));  
14231 - if (*ss=='~') _cimg_mp_opcode1(mp_bitwise_not,compile(ss1,se));  
14232 - }  
14233 - for (char *s = se2; s>ss; --s)  
14234 - if (*s=='^' && level[s - expr._data]==clevel)  
14235 - _cimg_mp_opcode2(mp_pow,compile(ss,s),compile(s + 1,se));  
14236 15422
14237 - // Array-like access to image values 'i[]' and 'j[]'.  
14238 - if (*se1==']') {  
14239 - const bool is_relative = *ss=='j';  
14240 - if ((*ss=='i' || is_relative) && *ss1=='[') {  
14241 - if (*ss2==']') _cimg_mp_opcode0(mp_i);  
14242 - _cimg_mp_opcode1(is_relative?mp_joff:mp_ioff,compile(ss2,se1)); 15423 + if ((*ss=='i' || *ss=='j') && *ss1=='[' &&
  15424 + (reserved_label[*ss]==~0U || !_cimg_mp_is_vector(reserved_label[*ss]))) { // Image value as a scalar
  15425 + if (*ss2=='#') { // Index specified
  15426 + s0 = ss3; while (s0<se1 && (*s0!=',' || level[s0 - expr._data]!=clevel1)) ++s0;
  15427 + p1 = compile(ss3,s0++,depth1,0);
  15428 + } else { p1 = ~0U; s0 = ss2; }
  15429 + s1 = s0; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
  15430 + arg1 = compile(s0,s1,depth1,0); // Offset
  15431 + arg2 = s1<se1?compile(s1 + 1,se1,depth1,0):~0U; // Boundary
  15432 + if (p_ref && arg2==~0U) {
  15433 + *p_ref = 2;
  15434 + p_ref[1] = p1;
  15435 + p_ref[2] = (unsigned int)is_relative;
  15436 + p_ref[3] = arg1;
  15437 + if (p1!=~0U && _cimg_mp_is_temp(p1)) memtype[p1] = -1; // Prevent from being used in further optimization
  15438 + if (_cimg_mp_is_temp(arg1)) memtype[arg1] = -1;
  15439 + }
  15440 + if (p1!=~0U) {
  15441 + if (!listin) _cimg_mp_return(0);
  15442 + pos = scalar3(is_relative?mp_list_joff:mp_list_ioff,p1,arg1,arg2==~0U?reserved_label[30]:arg2);
  15443 + } else {
  15444 + if (!imgin) _cimg_mp_return(0);
  15445 + pos = scalar2(is_relative?mp_joff:mp_ioff,arg1,arg2==~0U?reserved_label[30]:arg2);
  15446 + }
  15447 + memtype[pos] = -1; // Create it as a variable to prevent from being used in further optimization
  15448 + _cimg_mp_return(pos);
  15449 + }
  15450 +
  15451 + s0 = se1; while (s0>ss && *s0!='[') --s0;
  15452 + if (s0>ss) { // Vector value
  15453 + arg1 = compile(ss,s0,depth1,0);
  15454 + s1 = s0 + 1; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
  15455 +
  15456 + if (s1<se1) { // Two arguments -> sub-vector extraction
  15457 + arg2 = compile(++s0,s1,depth1,0);
  15458 + arg3 = compile(++s1,se1,depth1,0);
  15459 + _cimg_mp_check_constant(arg2,1,s_op,false);
  15460 + _cimg_mp_check_constant(arg3,2,s_op,false);
  15461 + p1 = (unsigned int)mem[arg2];
  15462 + p2 = (unsigned int)mem[arg3];
  15463 + p3 = _cimg_mp_vector_size(arg1);
  15464 + if (p1>=p3 || p2>=p3) {
  15465 + variable_name.assign(ss,(unsigned int)(s0 - ss)).back() = 0;
  15466 + *se = saved_char; cimg::strellipsize(variable_name,64); cimg::strellipsize(expr,64);
  15467 + throw CImgArgumentException("[_cimg_math_parser] "
  15468 + "CImg<%s>::%s: %s: Out-of-bounds request for sub-vector '%s[%d,%d]' "
  15469 + "(vector '%s' has dimension %u), "
  15470 + "in expression '%s%s%s'.",
  15471 + pixel_type(),_cimg_mp_calling_function,s_op,
  15472 + variable_name._data,(int)mem[arg2],(int)mem[arg3],
  15473 + variable_name._data,p3,
  15474 + (ss - 4)>expr._data?"...":"",
  15475 + (ss - 4)>expr._data?ss - 4:expr._data,
  15476 + se<&expr.back()?"...":"");
  15477 + }
  15478 + if (p1>p2) cimg::swap(p1,p2);
  15479 + (p2-=p1)++;
  15480 + pos = vector(p2);
  15481 + CImg<uptrT>::vector((uptrT)mp_vector_crop,pos,arg1,p1,p2).move_to(code);
  15482 + _cimg_mp_return(pos);
  15483 + }
  15484 +
  15485 + // One argument -> vector value reference
  15486 + if (_cimg_mp_is_scalar(arg1)) {
  15487 + variable_name.assign(ss,(unsigned int)(s0 - ss)).back() = 0;
  15488 + *se = saved_char; cimg::strellipsize(variable_name,64); cimg::strellipsize(expr,64);
  15489 + throw CImgArgumentException("[_cimg_math_parser] "
  15490 + "CImg<%s>::%s: %s: Array brackets used on non-vector variable '%s', "
  15491 + "in expression '%s%s%s'.",
  15492 + pixel_type(),_cimg_mp_calling_function,s_op,
  15493 + variable_name._data,
  15494 + (ss - 4)>expr._data?"...":"",
  15495 + (ss - 4)>expr._data?ss - 4:expr._data,
  15496 + se<&expr.back()?"...":"");
  15497 + }
  15498 +
  15499 + arg2 = compile(++s0,se1,depth1,0);
  15500 + if (_cimg_mp_is_constant(arg2)) { // Constant index
  15501 + nb = (int)mem[arg2];
  15502 + if (nb>=0 && nb<(int)_cimg_mp_vector_size(arg1)) _cimg_mp_return(arg1 + 1 + nb);
  15503 + variable_name.assign(ss,(unsigned int)(s0 - ss)).back() = 0;
  15504 + *se = saved_char; cimg::strellipsize(variable_name,64); cimg::strellipsize(expr,64);
  15505 + throw CImgArgumentException("[_cimg_math_parser] "
  15506 + "CImg<%s>::%s: Out-of-bounds reference '%s[%d]' "
  15507 + "(vector '%s' has dimension %u), "
  15508 + "in expression '%s%s%s'.",
  15509 + pixel_type(),_cimg_mp_calling_function,
  15510 + variable_name._data,nb,
  15511 + variable_name._data,_cimg_mp_vector_size(arg1),
  15512 + (ss - 4)>expr._data?"...":"",
  15513 + (ss - 4)>expr._data?ss - 4:expr._data,
  15514 + se<&expr.back()?"...":"");
  15515 + }
  15516 + if (p_ref) {
  15517 + *p_ref = 1;
  15518 + p_ref[1] = arg1;
  15519 + p_ref[2] = arg2;
  15520 + if (_cimg_mp_is_temp(arg2)) memtype[arg2] = -1; // Prevent from being used in further optimization
  15521 + }
  15522 + _cimg_mp_scalar3(mp_vector_off,arg1,(uptrT)_cimg_mp_vector_size(arg1),arg2);
14243 } 15523 }
14244 } 15524 }
14245 15525
14246 - // Look for a function call or a parenthesis. 15526 + // Look for a function call, an access to image value, or a parenthesis.
14247 if (*se1==')') { 15527 if (*se1==')') {
14248 - if (*ss=='(') _cimg_mp_return(compile(ss1,se1));  
14249 -  
14250 - const bool is_relative = *ss=='j';  
14251 - if ((*ss=='i' || is_relative) && *ss1=='(') {  
14252 - if (*ss2==')') _cimg_mp_opcode0(mp_i);  
14253 - unsigned int  
14254 - indx = is_relative?0U:16U, indy = is_relative?0U:17U,  
14255 - indz = is_relative?0U:18U, indc = is_relative?0U:19U,  
14256 - borders = 0, interpolation = 0;  
14257 - if (ss2!=se1) {  
14258 - char *s1 = ss2; while (s1<se2 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;  
14259 - indx = compile(ss2,s1==se2?++s1:s1);  
14260 - if (s1<se1) {  
14261 - char *s2 = s1 + 1; while (s2<se2 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;  
14262 - indy = compile(s1 + 1,s2==se2?++s2:s2); 15528 + if (*ss=='(') _cimg_mp_return(compile(ss1,se1,depth1,p_ref)); // Simple parentheses
  15529 + is_relative = *ss=='j' || *ss=='J';
  15530 +
  15531 + // I/J(_#ind,_x,_y,_z,_c,_interpolation,_boundary)
  15532 + if ((*ss=='I' || *ss=='J') && *ss1=='(') { // Image value as scalar
  15533 + if (*ss2=='#') { // Index specified
  15534 + s0 = ss3; while (s0<se1 && (*s0!=',' || level[s0 - expr._data]!=clevel1)) ++s0;
  15535 + p1 = compile(ss3,s0++,depth1,0);
  15536 + } else { p1 = ~0U; s0 = ss2; }
  15537 + arg1 = is_relative?0U:(unsigned int)_cimg_mp_x;
  15538 + arg2 = is_relative?0U:(unsigned int)_cimg_mp_y;
  15539 + arg3 = is_relative?0U:(unsigned int)_cimg_mp_z;
  15540 + arg4 = arg5 = ~0U;
  15541 + if (s0<se1) {
  15542 + s1 = s0; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
  15543 + arg1 = compile(s0,s1,depth1,0);
  15544 + if (_cimg_mp_is_vector(arg1)) { // Coordinates specified as a vector [X,Y,Z]
  15545 + p2 = _cimg_mp_vector_size(arg1);
  15546 + arg1 = arg1 + 1;
  15547 + if (p2>1) {
  15548 + arg2 = arg1 + 1;
  15549 + if (p2>2) arg3 = arg2 + 1;
  15550 + }
  15551 + if (s1<se1) {
  15552 + s2 = ++s1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;
  15553 + arg4 = compile(s1,s2,depth1,0);
  15554 + if (s2<se1) arg5 = compile(++s2,se1,depth1,0);
  15555 + }
  15556 + } else if (s1<se1) {
  15557 + s2 = ++s1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;
  15558 + arg2 = compile(s1,s2,depth1,0);
14263 if (s2<se1) { 15559 if (s2<se1) {
14264 - char *s3 = s2 + 1; while (s3<se2 && (*s3!=',' || level[s3 - expr._data]!=clevel1)) ++s3;  
14265 - indz = compile(s2 + 1,s3==se2?++s3:s3); 15560 + s3 = ++s2; while (s3<se1 && (*s3!=',' || level[s3 - expr._data]!=clevel1)) ++s3;
  15561 + arg3 = compile(s2,s3,depth1,0);
14266 if (s3<se1) { 15562 if (s3<se1) {
14267 - char *s4 = s3 + 1; while (s4<se2 && (*s4!=',' || level[s4 - expr._data]!=clevel1)) ++s4;  
14268 - indc = compile(s3 + 1,s4==se2?++s4:s4);  
14269 - if (s4<se1) {  
14270 - char *s5 = s4 + 1; while (s5<se2 && (*s5!=',' || level[s5 - expr._data]!=clevel1)) ++s5;  
14271 - interpolation = compile(s4 + 1,s5==se2?++s5:s5);  
14272 - if (s5<se1) borders = compile(s5 + 1,se1);  
14273 - } 15563 + s2 = ++s3; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;
  15564 + arg4 = compile(s3,s2,depth1,0);
  15565 + if (s2<se1) arg5 = compile(++s2,se1,depth1,0);
14274 } 15566 }
14275 } 15567 }
14276 } 15568 }
14277 } 15569 }
14278 - _cimg_mp_opcode6(is_relative?mp_jxyzc:mp_ixyzc,indx,indy,indz,indc,interpolation,borders);  
14279 - }  
14280 - if (!std::strncmp(ss,"sin(",4)) _cimg_mp_opcode1(mp_sin,compile(ss4,se1));  
14281 - if (!std::strncmp(ss,"cos(",4)) _cimg_mp_opcode1(mp_cos,compile(ss4,se1));  
14282 - if (!std::strncmp(ss,"tan(",4)) _cimg_mp_opcode1(mp_tan,compile(ss4,se1));  
14283 - if (!std::strncmp(ss,"log(",4)) _cimg_mp_opcode1(mp_log,compile(ss4,se1));  
14284 - if (!std::strncmp(ss,"exp(",4)) _cimg_mp_opcode1(mp_exp,compile(ss4,se1));  
14285 - if (!std::strncmp(ss,"abs(",4)) _cimg_mp_opcode1(mp_abs,compile(ss4,se1));  
14286 - if (!std::strncmp(ss,"int(",4)) _cimg_mp_opcode1(mp_int,compile(ss4,se1));  
14287 - if (!std::strncmp(ss,"sqr(",4)) _cimg_mp_opcode1(mp_sqr,compile(ss4,se1));  
14288 - if (!std::strncmp(ss,"asin(",5)) _cimg_mp_opcode1(mp_asin,compile(ss5,se1));  
14289 - if (!std::strncmp(ss,"acos(",5)) _cimg_mp_opcode1(mp_acos,compile(ss5,se1));  
14290 - if (!std::strncmp(ss,"atan(",5)) _cimg_mp_opcode1(mp_atan,compile(ss5,se1));  
14291 - if (!std::strncmp(ss,"sinh(",5)) _cimg_mp_opcode1(mp_sinh,compile(ss5,se1));  
14292 - if (!std::strncmp(ss,"cosh(",5)) _cimg_mp_opcode1(mp_cosh,compile(ss5,se1));  
14293 - if (!std::strncmp(ss,"tanh(",5)) _cimg_mp_opcode1(mp_tanh,compile(ss5,se1));  
14294 - if (!std::strncmp(ss,"log2(",5)) _cimg_mp_opcode1(mp_log2,compile(ss5,se1));  
14295 - if (!std::strncmp(ss,"sqrt(",5)) _cimg_mp_opcode1(mp_sqrt,compile(ss5,se1));  
14296 - if (!std::strncmp(ss,"cbrt(",5)) _cimg_mp_opcode1(mp_cbrt,compile(ss5,se1));  
14297 - if (!std::strncmp(ss,"sign(",5)) _cimg_mp_opcode1(mp_sign,compile(ss5,se1));  
14298 - if (!std::strncmp(ss,"sinc(",5)) _cimg_mp_opcode1(mp_sinc,compile(ss5,se1));  
14299 - if (!std::strncmp(ss,"log10(",6)) _cimg_mp_opcode1(mp_log10,compile(ss6,se1));  
14300 -  
14301 - if ((*ss=='?' || *ss=='u') && *ss1=='(') {  
14302 - if (*ss2==')') _cimg_mp_opcode2(mp_u,0,1);  
14303 - char *s1 = ss2; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;  
14304 - if (s1<se1) _cimg_mp_opcode2(mp_u,compile(ss2,s1),compile(s1 + 1,se1));  
14305 - _cimg_mp_opcode2(mp_u,0,compile(ss2,s1));  
14306 - }  
14307 - if (*ss=='i' && *ss1=='f' && *ss2=='(') {  
14308 - char *s1 = ss3; while (s1<se4 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;  
14309 - char *s2 = s1 + 1; while (s2<se2 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;  
14310 - const unsigned int mem_cond = compile(ss3,s1), bp1 = code._width, mem_A = compile(s1 + 1,s2),  
14311 - bp2 = code._width, mem_B = compile(s2 + 1,se1);  
14312 - if (mempos>=mem._width) mem.resize(-200,1,1,1,0);  
14313 - const unsigned int pos = mempos++;  
14314 - CImg<longT>::vector(_cimg_mp_enfunc(mp_if),pos,mem_cond,mem_A,mem_B,bp2 - bp1,code._width - bp2).  
14315 - move_to(code,bp1); 15570 + if (p_ref && arg4==~0U && arg5==~0U) {
  15571 + *p_ref = 5;
  15572 + p_ref[1] = p1;
  15573 + p_ref[2] = (unsigned int)is_relative;
  15574 + p_ref[3] = arg1;
  15575 + p_ref[4] = arg2;
  15576 + p_ref[5] = arg3;
  15577 + if (p1!=~0U && _cimg_mp_is_temp(p1)) memtype[p1] = -1; // Prevent from being used in further optimization
  15578 + if (_cimg_mp_is_temp(arg1)) memtype[arg1] = -1;
  15579 + if (_cimg_mp_is_temp(arg2)) memtype[arg2] = -1;
  15580 + if (_cimg_mp_is_temp(arg3)) memtype[arg3] = -1;
  15581 + }
  15582 + p2 = ~0U; // 'p2' must the dimension of the vector-valued operand if any
  15583 + if (p1==~0U) p2 = imgin._spectrum;
  15584 + else if (_cimg_mp_is_constant(p1)) {
  15585 + p3 = (unsigned int)cimg::mod((int)mem[p1],listin.width());
  15586 + p2 = listin[p3]._spectrum;
  15587 + }
  15588 + _cimg_mp_check_vector0(p2,"operator '()'");
  15589 + pos = vector(p2);
  15590 + if (p1!=~0U)
  15591 + CImg<uptrT>::vector((uptrT)(is_relative?mp_list_Jxyz:mp_list_Ixyz),
  15592 + pos,p1,arg1,arg2,arg3,
  15593 + arg4==~0U?reserved_label[29]:arg4,
  15594 + arg5==~0U?reserved_label[30]:arg5).move_to(code);
  15595 + else
  15596 + CImg<uptrT>::vector((uptrT)(is_relative?mp_Jxyz:mp_Ixyz),
  15597 + pos,arg1,arg2,arg3,
  15598 + arg4==~0U?reserved_label[29]:arg4,
  15599 + arg5==~0U?reserved_label[30]:arg5).move_to(code);
14316 _cimg_mp_return(pos); 15600 _cimg_mp_return(pos);
14317 } 15601 }
14318 - if (!std::strncmp(ss,"min(",4) || !std::strncmp(ss,"max(",4) ||  
14319 - !std::strncmp(ss,"med(",4) || !std::strncmp(ss,"kth(",4) ||  
14320 - !std::strncmp(ss,"arg(",4)) {  
14321 - CImgList<longT> opcode;  
14322 - if (mempos>=mem.size()) mem.resize(-200,1,1,1,0);  
14323 - const unsigned int pos = mempos++;  
14324 - CImg<longT>::vector(_cimg_mp_enfunc(*ss=='a'?mp_arg:*ss=='k'?mp_kth:ss[1]=='i'?mp_min:  
14325 - ss[1]=='a'?mp_max:mp_med),pos).  
14326 - move_to(opcode);  
14327 - for (char *s = ss4; s<se; ++s) {  
14328 - char *ns = s; while (ns<se && (*ns!=',' || level[ns - expr._data]!=clevel1) &&  
14329 - (*ns!=')' || level[ns - expr._data]!=clevel)) ++ns;  
14330 - CImg<longT>::vector(compile(s,ns)).move_to(opcode);  
14331 - s = ns; 15602 +
  15603 + // i/j(_#ind,_x,_y,_z,_c,_interpolation,_boundary)
  15604 + if ((*ss=='i' || *ss=='j') && *ss1=='(') { // Image value as scalar
  15605 + if (*ss2=='#') { // Index specified
  15606 + s0 = ss3; while (s0<se1 && (*s0!=',' || level[s0 - expr._data]!=clevel1)) ++s0;
  15607 + p1 = compile(ss3,s0++,depth1,0);
  15608 + } else { p1 = ~0U; s0 = ss2; }
  15609 + arg1 = is_relative?0U:(unsigned int)_cimg_mp_x;
  15610 + arg2 = is_relative?0U:(unsigned int)_cimg_mp_y;
  15611 + arg3 = is_relative?0U:(unsigned int)_cimg_mp_z;
  15612 + arg4 = is_relative?0U:(unsigned int)_cimg_mp_c;
  15613 + arg5 = arg6 = ~0U;
  15614 + if (s0<se1) {
  15615 + s1 = s0; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
  15616 + arg1 = compile(s0,s1,depth1,0);
  15617 + if (_cimg_mp_is_vector(arg1)) { // Coordinates specified as a vector [X,Y,Z,C]
  15618 + p2 = _cimg_mp_vector_size(arg1);
  15619 + arg1 = arg1 + 1;
  15620 + if (p2>1) {
  15621 + arg2 = arg1 + 1;
  15622 + if (p2>2) {
  15623 + arg3 = arg2 + 1;
  15624 + if (p2>3) arg4 = arg3 + 1;
  15625 + }
  15626 + }
  15627 + if (s1<se1) {
  15628 + s2 = ++s1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;
  15629 + arg5 = compile(s1,s2,depth1,0);
  15630 + if (s2<se1) arg6 = compile(++s2,se1,depth1,0);
  15631 + }
  15632 + } else if (s1<se1) {
  15633 + s2 = ++s1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;
  15634 + arg2 = compile(s1,s2,depth1,0);
  15635 + if (s2<se1) {
  15636 + s3 = ++s2; while (s3<se1 && (*s3!=',' || level[s3 - expr._data]!=clevel1)) ++s3;
  15637 + arg3 = compile(s2,s3,depth1,0);
  15638 + if (s3<se1) {
  15639 + s2 = ++s3; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;
  15640 + arg4 = compile(s3,s2,depth1,0);
  15641 + if (s2<se1) {
  15642 + s3 = ++s2; while (s3<se1 && (*s3!=',' || level[s3 - expr._data]!=clevel1)) ++s3;
  15643 + arg5 = compile(s2,s3,depth1,0);
  15644 + if (s3<se1) arg6 = compile(++s3,se1,depth1,0);
  15645 + }
  15646 + }
  15647 + }
  15648 + }
14332 } 15649 }
14333 - (opcode>'y').move_to(code);  
14334 - _cimg_mp_return(pos);  
14335 - }  
14336 - if (!std::strncmp(ss,"rol(",4) || !std::strncmp(ss,"ror(",4)) {  
14337 - unsigned int value = 0, nb = 1;  
14338 - char *s1 = ss4; while (s1<se2 && (*s1!=',' || level[s1-expr._data]!=clevel1)) ++s1;  
14339 - value = compile(ss4,s1==se2?++s1:s1);  
14340 - if (s1<se1) {  
14341 - char *s2 = s1 + 1; while (s2<se2 && (*s2!=',' || level[s2-expr._data]!=clevel1)) ++s2;  
14342 - nb = compile(s1 + 1,se1);  
14343 - }  
14344 - _cimg_mp_opcode2(*ss2=='l'?mp_rol:mp_ror,value,nb);  
14345 - }  
14346 - if (!std::strncmp(ss,"narg(",5)) {  
14347 - if (*ss5==')') _cimg_mp_return(0);  
14348 - unsigned int nb_args = 0;  
14349 - for (char *s = ss5; s<se; ++s) {  
14350 - char *ns = s; while (ns<se && (*ns!=',' || level[ns - expr._data]!=clevel1) &&  
14351 - (*ns!=')' || level[ns - expr._data]!=clevel)) ++ns;  
14352 - ++nb_args; s = ns;  
14353 - }  
14354 - if (nb_args==0 || nb_args==1) _cimg_mp_return(nb_args);  
14355 - if (mempos>=mem.size()) mem.resize(-200,1,1,1,0);  
14356 - const unsigned int pos = mempos++;  
14357 - mem[pos] = nb_args;  
14358 - _cimg_mp_return(pos);  
14359 - }  
14360 - if (!std::strncmp(ss,"atan2(",6)) {  
14361 - char *s1 = ss6; while (s1<se2 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;  
14362 - _cimg_mp_opcode2(mp_atan2,compile(ss6,s1),compile(s1 + 1,se1));  
14363 - }  
14364 - if (!std::strncmp(ss,"hypot(",6)) {  
14365 - char *s1 = ss6; while (s1<se2 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;  
14366 - _cimg_mp_opcode2(mp_hypot,compile(ss6,s1),compile(s1 + 1,se1));  
14367 - }  
14368 - if (!std::strncmp(ss,"round(",6)) {  
14369 - unsigned int value = 0, round = 1, direction = 0;  
14370 - char *s1 = ss6; while (s1<se2 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;  
14371 - value = compile(ss6,s1==se2?++s1:s1);  
14372 - if (s1<se1) {  
14373 - char *s2 = s1 + 1; while (s2<se2 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;  
14374 - round = compile(s1 + 1,s2==se2?++s2:s2);  
14375 - if (s2<se1) direction = compile(s2 + 1,se1);  
14376 - }  
14377 - _cimg_mp_opcode3(mp_round,value,round,direction);  
14378 - }  
14379 - unsigned int norm_type = ~0U;  
14380 - if ((std::sscanf(ss,"norm%u%c",&norm_type,&sep)==2 && sep=='(') ||  
14381 - !std::strncmp(ss,"norminf(",8)) {  
14382 - CImgList<longT> opcode;  
14383 - if (mempos>=mem.size()) mem.resize(-200,1,1,1,0);  
14384 - const unsigned int pos = mempos++;  
14385 - CImg<longT>::vector(_cimg_mp_enfunc(mp_norm),pos,(longT)(norm_type==~0U?-1:(int)norm_type)).  
14386 - move_to(opcode);  
14387 - for (char *s = std::strchr(ss5,'(') + 1; s<se; ++s) {  
14388 - char *ns = s; while (ns<se && (*ns!=',' || level[ns - expr._data]!=clevel1) &&  
14389 - (*ns!=')' || level[ns - expr._data]!=clevel)) ++ns;  
14390 - CImg<longT>::vector(compile(s,ns)).move_to(opcode);  
14391 - s = ns; 15650 + if (p_ref && arg5==~0U && arg6==~0U) {
  15651 + *p_ref = 3;
  15652 + p_ref[1] = p1;
  15653 + p_ref[2] = (unsigned int)is_relative;
  15654 + p_ref[3] = arg1;
  15655 + p_ref[4] = arg2;
  15656 + p_ref[5] = arg3;
  15657 + p_ref[6] = arg4;
  15658 + if (p1!=~0U && _cimg_mp_is_temp(p1)) memtype[p1] = -1; // Prevent from being used in further optimization
  15659 + if (_cimg_mp_is_temp(arg1)) memtype[arg1] = -1;
  15660 + if (_cimg_mp_is_temp(arg2)) memtype[arg2] = -1;
  15661 + if (_cimg_mp_is_temp(arg3)) memtype[arg3] = -1;
  15662 + if (_cimg_mp_is_temp(arg4)) memtype[arg4] = -1;
  15663 + }
  15664 +
  15665 + if (p1!=~0U) {
  15666 + if (!listin) _cimg_mp_return(0);
  15667 + pos = scalar7(is_relative?mp_list_jxyzc:mp_list_ixyzc,
  15668 + p1,arg1,arg2,arg3,arg4,
  15669 + arg5==~0U?reserved_label[29]:arg5,
  15670 + arg6==~0U?reserved_label[30]:arg6);
  15671 + } else {
  15672 + if (!imgin) _cimg_mp_return(0);
  15673 + pos = scalar6(is_relative?mp_jxyzc:mp_ixyzc,
  15674 + arg1,arg2,arg3,arg4,
  15675 + arg5==~0U?reserved_label[29]:arg5,
  15676 + arg6==~0U?reserved_label[30]:arg6);
14392 } 15677 }
14393 - (opcode>'y').move_to(code); 15678 + memtype[pos] = -1; // Create it as a variable to prevent from being used in further optimization
14394 _cimg_mp_return(pos); 15679 _cimg_mp_return(pos);
14395 } 15680 }
14396 - if (!std::strncmp(ss,"date(",5)) {  
14397 - char *s1 = ss5; while (s1<se2 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;  
14398 - unsigned int attr;  
14399 - int d = -1;  
14400 - if (cimg_sscanf(ss5,"%u%c",&attr,&sep)==2 && sep==')') {  
14401 - *se1 = 0;  
14402 - d = cimg::date(attr);  
14403 - *se1 = ')'; 15681 +
  15682 + // Mathematical functions.
  15683 + switch (*ss) {
  15684 + case 'a' :
  15685 + if (!std::strncmp(ss,"abs(",4)) { // Absolute value
  15686 + arg1 = compile(ss4,se1,depth1,0);
  15687 + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_abs,arg1);
  15688 + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(cimg::abs(mem[arg1]));
  15689 + _cimg_mp_scalar1(mp_abs,arg1);
14404 } 15690 }
14405 - if (d==0 || d==1) _cimg_mp_return((unsigned int)d);  
14406 - if (mempos>=mem.size()) mem.resize(-200,1,1,1,0);  
14407 - const unsigned int pos = mempos++;  
14408 - mem[pos] = d;  
14409 - _cimg_mp_return(pos);  
14410 - }  
14411 - if (!std::strncmp(ss,"fdate(",6)) {  
14412 - char *s1 = ss6; while (s1<se2 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;  
14413 - unsigned int attr;  
14414 - int d = -1;  
14415 - if (cimg_sscanf(ss6,"%u%c",&attr,&(sep=0))==2 && sep) { 15691 +
  15692 + if (!std::strncmp(ss,"acos(",5)) { // Arccos
  15693 + arg1 = compile(ss5,se1,depth1,0);
  15694 + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_acos,arg1);
  15695 + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::acos(mem[arg1]));
  15696 + _cimg_mp_scalar1(mp_acos,arg1);
  15697 + }
  15698 +
  15699 + if (!std::strncmp(ss,"asin(",5)) { // Arcsin
  15700 + arg1 = compile(ss5,se1,depth1,0);
  15701 + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_asin,arg1);
  15702 + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::asin(mem[arg1]));
  15703 + _cimg_mp_scalar1(mp_asin,arg1);
  15704 + }
  15705 +
  15706 + if (!std::strncmp(ss,"atan(",5)) { // Arctan
  15707 + arg1 = compile(ss5,se1,depth1,0);
  15708 + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_atan,arg1);
  15709 + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::atan(mem[arg1]));
  15710 + _cimg_mp_scalar1(mp_atan,arg1);
  15711 + }
  15712 +
  15713 + if (!std::strncmp(ss,"atan2(",6)) { // Arctan2
  15714 + s1 = ss6; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
  15715 + arg1 = compile(ss6,s1,depth1,0);
  15716 + arg2 = compile(s1 + 1,se1,depth1,0);
  15717 + _cimg_mp_check_type(arg2,2,"Function 'atan2()'",3,_cimg_mp_vector_size(arg1));
  15718 + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_atan2,arg1,arg2);
  15719 + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_atan2,arg1,arg2);
  15720 + if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_atan2,arg1,arg2);
  15721 + if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2))
  15722 + _cimg_mp_constant(std::atan2(mem[arg1],mem[arg2]));
  15723 + _cimg_mp_scalar2(mp_atan2,arg1,arg2);
  15724 + }
  15725 + break;
  15726 +
  15727 + case 'c' :
  15728 + if (!std::strncmp(ss,"cabs(",5)) { // Complex absolute value
  15729 + arg1 = compile(ss5,se1,depth1,0);
  15730 + _cimg_mp_check_type(arg1,0,"Function 'cabs()'",2,2);
  15731 + _cimg_mp_scalar2(mp_hypot,arg1 + 1,arg1 + 2);
  15732 + }
  15733 +
  15734 + if (!std::strncmp(ss,"carg(",5)) { // Complex argument
  15735 + arg1 = compile(ss5,se1,depth1,0);
  15736 + _cimg_mp_check_type(arg1,0,"Function 'carg()'",2,2);
  15737 + _cimg_mp_scalar2(mp_atan2,arg1 + 2,arg1 + 1);
  15738 + }
  15739 +
  15740 + if (!std::strncmp(ss,"cbrt(",5)) { // Cubic root
  15741 + arg1 = compile(ss5,se1,depth1,0);
  15742 + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_cbrt,arg1);
  15743 + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::pow(mem[arg1],1.0/3));
  15744 + _cimg_mp_scalar1(mp_cbrt,arg1);
  15745 + }
  15746 +
  15747 + if (!std::strncmp(ss,"cconj(",6)) { // Complex conjugate
  15748 + arg1 = compile(ss6,se1,depth1,0);
  15749 + _cimg_mp_check_type(arg1,0,"Function 'cconj()'",2,2);
  15750 + pos = vector(2);
  15751 + CImg<uptrT>::vector((uptrT)mp_complex_conj,pos,arg1).move_to(code);
  15752 + _cimg_mp_return(pos);
  15753 + }
  15754 +
  15755 + if (!std::strncmp(ss,"cexp(",5)) { // Complex exponential
  15756 + arg1 = compile(ss5,se1,depth1,0);
  15757 + _cimg_mp_check_type(arg1,0,"Function 'cexp()'",2,2);
  15758 + pos = vector(2);
  15759 + CImg<uptrT>::vector((uptrT)mp_complex_exp,pos,arg1).move_to(code);
  15760 + _cimg_mp_return(pos);
  15761 + }
  15762 +
  15763 + if (!std::strncmp(ss,"clog(",5)) { // Complex logarithm
  15764 + arg1 = compile(ss5,se1,depth1,0);
  15765 + _cimg_mp_check_type(arg1,0,"Function 'clog()'",2,2);
  15766 + pos = vector(2);
  15767 + CImg<uptrT>::vector((uptrT)mp_complex_log,pos,arg1).move_to(code);
  15768 + _cimg_mp_return(pos);
  15769 + }
  15770 +
  15771 + if (!std::strncmp(ss,"cos(",4)) { // Cosine
  15772 + arg1 = compile(ss4,se1,depth1,0);
  15773 + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_cos,arg1);
  15774 + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::cos(mem[arg1]));
  15775 + _cimg_mp_scalar1(mp_cos,arg1);
  15776 + }
  15777 +
  15778 + if (!std::strncmp(ss,"cosh(",5)) { // Hyperbolic cosine
  15779 + arg1 = compile(ss5,se1,depth1,0);
  15780 + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_cosh,arg1);
  15781 + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::cosh(mem[arg1]));
  15782 + _cimg_mp_scalar1(mp_cosh,arg1);
  15783 + }
  15784 +
  15785 + if (!std::strncmp(ss,"cross(",6)) { // Cross product
  15786 + s_op = "Function 'cross()";
  15787 + s1 = ss6; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
  15788 + arg1 = compile(ss6,s1,depth1,0);
  15789 + arg2 = compile(s1 + 1,se1,depth1,0);
  15790 + _cimg_mp_check_type(arg1,1,s_op,2,3);
  15791 + _cimg_mp_check_type(arg2,2,s_op,2,3);
  15792 + pos = vector(3);
  15793 + CImg<uptrT>::vector((uptrT)mp_cross,pos,arg1,arg2).move_to(code);
  15794 + _cimg_mp_return(pos);
  15795 + }
  15796 +
  15797 + if (!std::strncmp(ss,"cut(",4)) { // Cut
  15798 + s1 = ss4; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
  15799 + arg1 = compile(ss4,s1==se2?++s1:s1,depth1,0);
  15800 + s2 = s1 + 1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;
  15801 + arg2 = compile(s1 + 1,s2==se2?++s2:s2,depth1,0);
  15802 + arg3 = compile(s2 + 1,se1,depth1,0);
  15803 + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector3_vss(mp_cut,arg1,arg2,arg3);
  15804 + if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2) && _cimg_mp_is_constant(arg3)) {
  15805 + val = mem[arg1];
  15806 + val1 = mem[arg2];
  15807 + val2 = mem[arg3];
  15808 + _cimg_mp_constant(val<val1?val1:val>val2?val2:val);
  15809 + }
  15810 + _cimg_mp_scalar3(mp_cut,arg1,arg2,arg3);
  15811 + }
  15812 + break;
  15813 +
  15814 + case 'd' :
  15815 + if (!std::strncmp(ss,"date(",5)) { // Date and file date
  15816 + s1 = ss5; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
  15817 + arg1 = 0;
  15818 + is_sth = s1!=se1; // is_fdate
  15819 + if (s1==se1 && ss5!=se1 && // Exactly one argument
  15820 + (cimg_sscanf(ss5,"%u%c",&arg1,&sep)!=2 || sep!=')')) is_sth = true;
  15821 + if (is_sth) {
  15822 + if (cimg_sscanf(ss5,"%u%c",&arg1,&sep)!=2 || sep!=',') { arg1 = 0; s1 = ss4; }
  15823 + *se1 = 0; val = (double)cimg::fdate(s1 + 1,arg1); *se1 = ')';
  15824 + } else val = (double)cimg::date(arg1);
  15825 + _cimg_mp_constant(val);
  15826 + }
  15827 +
  15828 + if (!std::strncmp(ss,"debug(",6)) { // Print debug info
  15829 + p1 = code._width;
  15830 + arg1 = compile(ss6,se1,depth1,p_ref);
14416 *se1 = 0; 15831 *se1 = 0;
14417 - d = cimg::fdate(s1+1,attr); 15832 + ((CImg<uptrT>::vector((uptrT)mp_debug,arg1,code._width - p1),
  15833 + CImg<uptrT>::string(ss6).unroll('y'))>'y').move_to(code,p1);
14418 *se1 = ')'; 15834 *se1 = ')';
  15835 + _cimg_mp_return(arg1);
  15836 + }
  15837 +
  15838 + if (!std::strncmp(ss,"dot(",4)) { // Dot product
  15839 + s_op = "Function 'dot()'";
  15840 + s1 = ss4; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
  15841 + arg1 = compile(ss4,s1,depth1,0);
  15842 + arg2 = compile(s1 + 1,se1,depth1,0);
  15843 + _cimg_mp_check_type(arg1,1,s_op,2,0);
  15844 + _cimg_mp_check_type(arg2,2,s_op,2,0);
  15845 + if (_cimg_mp_is_vector(arg1)) _cimg_mp_scalar3(mp_dot,arg1,arg2,_cimg_mp_vector_size(arg1));
  15846 + _cimg_mp_scalar2(mp_mul,arg1,arg2);
  15847 + }
  15848 +
  15849 + if (!std::strncmp(ss,"dowhile",7) && (*ss7=='(' || (*ss7 && *ss7<=' ' && *ss8=='('))) { // Do..while
  15850 + if (*ss7<=' ') cimg::swap(*ss7,*ss8); // Allow space before opening brace
  15851 + s1 = ss8; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
  15852 + p1 = code._width;
  15853 + arg1 = compile(ss8,s1,depth1,0);
  15854 + if (s1<se1) arg2 = compile(s1 + 1,se1,depth1,0);
  15855 + else arg2 = arg1;
  15856 + _cimg_mp_check_type(arg2,2,"Function 'dowhile()'",1,0);
  15857 + CImg<uptrT>::vector((uptrT)mp_dowhile,arg1,arg2,code._width - p1).move_to(code,p1);
  15858 + _cimg_mp_return(arg1);
14419 } 15859 }
14420 - if (d==0 || d==1) _cimg_mp_return((unsigned int)d);  
14421 - if (mempos>=mem.size()) mem.resize(-200,1,1,1,0);  
14422 - const unsigned int pos = mempos++;  
14423 - mem[pos] = d;  
14424 - _cimg_mp_return(pos);  
14425 - } 15860 + break;
14426 15861
14427 - // Sub-family of 'is_?()' functions.  
14428 - if (*ss=='i' && *ss1=='s') {  
14429 - if (!std::strncmp(ss,"isin(",5)) {  
14430 - CImgList<longT> opcode;  
14431 - if (mempos>=mem.size()) mem.resize(-200,1,1,1,0);  
14432 - const unsigned int pos = mempos++;  
14433 - CImg<longT>::vector(_cimg_mp_enfunc(mp_isin),pos).move_to(opcode);  
14434 - for (char *s = ss5; s<se; ++s) {  
14435 - char *ns = s; while (ns<se && (*ns!=',' || level[ns - expr._data]!=clevel1) &&  
14436 - (*ns!=')' || level[ns - expr._data]!=clevel)) ++ns;  
14437 - CImg<longT>::vector(compile(s,ns)).move_to(opcode);  
14438 - s = ns; 15862 + case 'e' :
  15863 + if (!std::strncmp(ss,"exp(",4)) { // Exponential
  15864 + arg1 = compile(ss4,se1,depth1,0);
  15865 + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_exp,arg1);
  15866 + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::exp(mem[arg1]));
  15867 + _cimg_mp_scalar1(mp_exp,arg1);
  15868 + }
  15869 + break;
  15870 +
  15871 + case 'f' :
  15872 + if (*ss1=='o' && *ss2=='r' && (*ss3=='(' || (*ss3 && *ss3<=' ' && *ss4=='('))) { // For loop
  15873 + if (*ss3<=' ') cimg::swap(*ss3,*ss4); // Allow space before opening brace
  15874 + s1 = ss4; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
  15875 + s2 = s1 + 1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;
  15876 + s3 = s2 + 1; while (s3<se1 && (*s3!=',' || level[s3 - expr._data]!=clevel1)) ++s3;
  15877 + compile(ss4,s1,depth1,0);
  15878 + p1 = code._width;
  15879 + arg1 = compile(s1 + 1,s2,depth1,0);
  15880 + p2 = code._width;
  15881 + if (s3<se1) { pos = compile(s3 + 1,se1,depth1,0); compile(s2 + 1,s3,depth1,0); } // Body + proc
  15882 + else pos = compile(s2 + 1,se1,depth1,0); // Proc only
  15883 + _cimg_mp_check_type(arg1,2,"Function 'for()'",1,0);
  15884 + arg2 = _cimg_mp_is_vector(pos)?_cimg_mp_vector_size(pos):0; // Output vector size (or 0 if scalar)
  15885 + CImg<uptrT>::vector((uptrT)mp_whiledo,pos,arg1,p2 - p1,code._width - p2,arg2).move_to(code,p1);
  15886 + _cimg_mp_return(pos);
  15887 + }
  15888 + break;
  15889 +
  15890 + case 'g' :
  15891 + if (!std::strncmp(ss,"gauss(",6)) { // Gaussian function
  15892 + s1 = ss6; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
  15893 + arg1 = compile(ss6,s1,depth1,0);
  15894 + arg2 = 1;
  15895 + if (s1<se1) {
  15896 + s2 = s1 + 1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;
  15897 + arg2 = compile(s1 + 1,s2==se2?++s2:s2,depth1,0);
  15898 + }
  15899 + _cimg_mp_check_type(arg2,2,"Function 'gauss()'",1,0);
  15900 + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector2_vs(mp_gauss,arg1,arg2);
  15901 + if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) {
  15902 + val1 = mem[arg1];
  15903 + val2 = mem[arg2];
  15904 + _cimg_mp_constant(std::exp(-val1*val1/(2*val2*val2))/std::sqrt(2*val2*val2*cimg::PI));
  15905 + }
  15906 + _cimg_mp_scalar2(mp_gauss,arg1,arg2);
  15907 + }
  15908 + break;
  15909 +
  15910 + case 'h' :
  15911 + if (!std::strncmp(ss,"hypot(",6)) { // Hypothenuse
  15912 + s_op = "Function 'hypot()'";
  15913 + s1 = ss6; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
  15914 + arg1 = compile(ss6,s1,depth1,0);
  15915 + arg2 = compile(s1 + 1,se1,depth1,0);
  15916 + _cimg_mp_check_type(arg1,1,s_op,1,0);
  15917 + _cimg_mp_check_type(arg2,2,s_op,1,0);
  15918 + if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2)) {
  15919 + val1 = cimg::abs(mem[arg1]);
  15920 + val2 = cimg::abs(mem[arg2]);
  15921 + if (val1<val2) { val = val1; val1 = val2; } else val = val2;
  15922 + if (val1>0) { val/=val1; _cimg_mp_constant(val1*std::sqrt(1+val*val)); }
  15923 + _cimg_mp_constant(0);
14439 } 15924 }
14440 - (opcode>'y').move_to(code); 15925 + _cimg_mp_scalar2(mp_hypot,arg1,arg2);
  15926 + }
  15927 + break;
  15928 +
  15929 + case 'i' :
  15930 + if (*ss1=='f' && (*ss2=='(' || (*ss2 && *ss2<=' ' && *ss3=='('))) { // If..then[..else.]
  15931 + s_op = "Function 'if()'";
  15932 + if (*ss2<=' ') cimg::swap(*ss2,*ss3); // Allow space before opening brace
  15933 + s1 = ss3; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
  15934 + s2 = s1 + 1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;
  15935 + arg1 = compile(ss3,s1,depth1,0);
  15936 + p2 = code._width;
  15937 + arg2 = compile(s1 + 1,s2,depth1,0);
  15938 + p3 = code._width;
  15939 + arg3 = s2>=se1?0:compile(s2 + 1,se1,depth1,0);
  15940 + _cimg_mp_check_type(arg1,1,s_op,1,0);
  15941 + _cimg_mp_check_type(arg3,3,s_op,3,_cimg_mp_vector_size(arg2));
  15942 + if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2) && _cimg_mp_is_constant(arg3))
  15943 + _cimg_mp_constant(mem[arg1]?mem[arg2]:mem[arg3]);
  15944 + arg4 = _cimg_mp_is_vector(arg2)?_cimg_mp_vector_size(arg2):0; // Output vector size (or 0 if scalar)
  15945 + if (arg4) pos = vector(arg4); else pos = scalar();
  15946 + CImg<uptrT>::vector((uptrT)mp_if,pos,arg1,arg2,arg3,
  15947 + p3 - p2,code._width - p3,arg4).move_to(code,p2);
14441 _cimg_mp_return(pos); 15948 _cimg_mp_return(pos);
14442 } 15949 }
14443 - if (!std::strncmp(ss,"isval(",6)) {  
14444 - double val = 0;  
14445 - if (cimg_sscanf(ss6,"%lf%c%c",&val,&sep,&end)==2 && sep==')') _cimg_mp_return(1);  
14446 - _cimg_mp_return(0); 15950 +
  15951 + if (!std::strncmp(ss,"init(",5)) { // Init
  15952 + if (ss0!=expr._data || code.width()) { // (only allowed as the first instruction)
  15953 + *se = saved_char; cimg::strellipsize(expr,64);
  15954 + throw CImgArgumentException("[_cimg_math_parser] "
  15955 + "CImg<%s>::%s: Function 'init()': Init invokation not done at the "
  15956 + "beginning of expression '%s%s%s'.",
  15957 + pixel_type(),_cimg_mp_calling_function,
  15958 + (ss - 4)>expr._data?"...":"",
  15959 + (ss - 4)>expr._data?ss - 4:expr._data,
  15960 + se<&expr.back()?"...":"");
  15961 + }
  15962 + arg1 = compile(ss5,se1,depth1,p_ref);
  15963 + init_size = code.width();
  15964 + _cimg_mp_return(arg1);
14447 } 15965 }
14448 - if (!std::strncmp(ss,"isdir(",6)) {  
14449 - *se1 = 0;  
14450 - const bool is_dir = cimg::is_directory(ss6);  
14451 - *se1 = ')';  
14452 - _cimg_mp_return(is_dir?1U:0U); 15966 +
  15967 + if (!std::strncmp(ss,"int(",4)) { // Integer cast
  15968 + arg1 = compile(ss4,se1,depth1,0);
  15969 + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_int,arg1);
  15970 + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant((long)mem[arg1]);
  15971 + _cimg_mp_scalar1(mp_int,arg1);
14453 } 15972 }
14454 - if (!std::strncmp(ss,"isfile(",7)) {  
14455 - *se1 = 0;  
14456 - const bool is_file = cimg::is_file(ss7);  
14457 - *se1 = ')';  
14458 - _cimg_mp_return(is_file?1U:0U); 15973 +
  15974 + if (*ss1=='s') { // Family of 'is_?()' functions
  15975 +
  15976 + if (!std::strncmp(ss,"isbool(",7)) { // Is boolean?
  15977 + if (ss7==se1) _cimg_mp_return(0);
  15978 + arg1 = compile(ss7,se1,depth1,0);
  15979 + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_isbool,arg1);
  15980 + if (_cimg_mp_is_constant(arg1)) _cimg_mp_return(mem[arg1]==0.0 || mem[arg1]==1.0);
  15981 + _cimg_mp_scalar1(mp_isbool,arg1);
  15982 + }
  15983 +
  15984 + if (!std::strncmp(ss,"isdir(",6)) { // Is directory?
  15985 + *se1 = 0;
  15986 + is_sth = cimg::is_directory(ss6);
  15987 + *se1 = ')';
  15988 + _cimg_mp_return(is_sth?1U:0U);
  15989 + }
  15990 +
  15991 + if (!std::strncmp(ss,"isfile(",7)) { // Is file?
  15992 + *se1 = 0;
  15993 + is_sth = cimg::is_file(ss7);
  15994 + *se1 = ')';
  15995 + _cimg_mp_return(is_sth?1U:0U);
  15996 + }
  15997 +
  15998 + if (!std::strncmp(ss,"isin(",5)) { // Is in sequence/vector?
  15999 + pos = scalar();
  16000 + CImg<uptrT>::vector((uptrT)mp_isin,pos).move_to(_opcode);
  16001 + for (s = ss5; s<se; ++s) {
  16002 + ns = s; while (ns<se && (*ns!=',' || level[ns - expr._data]!=clevel1) &&
  16003 + (*ns!=')' || level[ns - expr._data]!=clevel)) ++ns;
  16004 + arg1 = compile(s,ns,depth1,0);
  16005 + if (_cimg_mp_is_vector(arg1))
  16006 + CImg<uptrT>::sequence((uptrT)_cimg_mp_vector_size(arg1),arg1 + 1,
  16007 + arg1 + (uptrT)_cimg_mp_vector_size(arg1)).
  16008 + move_to(_opcode);
  16009 + else CImg<uptrT>::vector(arg1).move_to(_opcode);
  16010 + s = ns;
  16011 + }
  16012 + (_opcode>'y').move_to(code);
  16013 + _cimg_mp_return(pos);
  16014 + }
  16015 +
  16016 + if (!std::strncmp(ss,"isinf(",6)) { // Is infinite?
  16017 + if (ss6==se1) _cimg_mp_return(0);
  16018 + arg1 = compile(ss6,se1,depth1,0);
  16019 + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_isinf,arg1);
  16020 + if (_cimg_mp_is_constant(arg1)) _cimg_mp_return((unsigned int)cimg::type<double>::is_inf(mem[arg1]));
  16021 + _cimg_mp_scalar1(mp_isinf,arg1);
  16022 + }
  16023 +
  16024 + if (!std::strncmp(ss,"isint(",6)) { // Is integer?
  16025 + if (ss6==se1) _cimg_mp_return(0);
  16026 + arg1 = compile(ss6,se1,depth1,0);
  16027 + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_isint,arg1);
  16028 + if (_cimg_mp_is_constant(arg1)) _cimg_mp_return((unsigned int)cimg::mod(mem[arg1],1.0)==0);
  16029 + _cimg_mp_scalar1(mp_isint,arg1);
  16030 + }
  16031 +
  16032 + if (!std::strncmp(ss,"isnan(",6)) { // Is NaN?
  16033 + if (ss6==se1) _cimg_mp_return(0);
  16034 + arg1 = compile(ss6,se1,depth1,0);
  16035 + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_isnan,arg1);
  16036 + if (_cimg_mp_is_constant(arg1)) _cimg_mp_return((unsigned int)cimg::type<double>::is_nan(mem[arg1]));
  16037 + _cimg_mp_scalar1(mp_isnan,arg1);
  16038 + }
  16039 +
  16040 + if (!std::strncmp(ss,"isval(",6)) { // Is value?
  16041 + val = 0;
  16042 + if (cimg_sscanf(ss6,"%lf%c%c",&val,&sep,&end)==2 && sep==')') _cimg_mp_return(1);
  16043 + _cimg_mp_return(0);
  16044 + }
  16045 +
14459 } 16046 }
14460 - if (!std::strncmp(ss,"isnan(",6)) _cimg_mp_opcode1(mp_isnan,compile(ss6,se1));  
14461 - if (!std::strncmp(ss,"isinf(",6)) _cimg_mp_opcode1(mp_isinf,compile(ss6,se1));  
14462 - if (!std::strncmp(ss,"isint(",6)) _cimg_mp_opcode1(mp_isint,compile(ss6,se1));  
14463 - if (!std::strncmp(ss,"isbool(",7)) _cimg_mp_opcode1(mp_isbool,compile(ss7,se1));  
14464 - }  
14465 - } 16047 + break;
14466 16048
14467 - // No known item found, assuming this is an already initialized variable.  
14468 - CImg<charT> variable_name(ss,(unsigned int)(se - ss + 1));  
14469 - variable_name.back() = 0;  
14470 - if (variable_name[1]) { // Multi-char variable.  
14471 - cimglist_for(labelM,i) if (!std::strcmp(variable_name,labelM[i])) _cimg_mp_return(labelMpos[i]);  
14472 - } else if (reserved_label[*variable_name]!=~0U) // Single-char variable.  
14473 - _cimg_mp_return(reserved_label[*variable_name]);  
14474 - *se = saved_char;  
14475 - throw CImgArgumentException("[_cimg_math_parser] "  
14476 - "CImg<%s>::%s(): Invalid item '%s' in specified expression '%s%s%s'.\n",  
14477 - pixel_type(),calling_function,  
14478 - variable_name._data,  
14479 - (ss - 8)>expr._data?"...":"",  
14480 - (ss - 8)>expr._data?ss - 8:expr._data,  
14481 - se<&expr.back()?"...":"");  
14482 - } 16049 + case 'l' :
  16050 + if (!std::strncmp(ss,"log(",4)) { // Natural logarithm
  16051 + arg1 = compile(ss4,se1,depth1,0);
  16052 + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_log,arg1);
  16053 + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::log(mem[arg1]));
  16054 + _cimg_mp_scalar1(mp_log,arg1);
  16055 + }
14483 16056
14484 - // Evaluation functions, known by the parser.  
14485 - // Defining these functions 'static' ensures that sizeof(mp_func)==sizeof(ulong), so we can store pointers to them  
14486 - // directly in the opcode vectors.  
14487 - static double mp_u(_cimg_math_parser& mp) {  
14488 - return mp.mem[mp.opcode(2)] + cimg::rand()*(mp.mem[mp.opcode(3)] - mp.mem[mp.opcode(2)]);  
14489 - }  
14490 - static double mp_g(_cimg_math_parser& mp) {  
14491 - cimg::unused(mp);  
14492 - return cimg::grand();  
14493 - }  
14494 - static double mp_i(_cimg_math_parser& mp) {  
14495 - return (double)mp.reference.atXYZC((int)mp.mem[16],(int)mp.mem[17],(int)mp.mem[18],(int)mp.mem[19],0);  
14496 - }  
14497 - static double mp_logical_and(_cimg_math_parser& mp) {  
14498 - const bool is_A = (bool)mp.mem[mp.opcode(2)];  
14499 - const CImg<longT> *const pE = ++mp.p_code + mp.opcode(4);  
14500 - if (!is_A) { mp.p_code = pE - 1; return 0; }  
14501 - const unsigned int mem_B = (unsigned int)mp.opcode(3);  
14502 - for ( ; mp.p_code<pE; ++mp.p_code) {  
14503 - const CImg<longT> &op = *mp.p_code;  
14504 - mp.opcode._data = op._data; mp.opcode._height = op._height;  
14505 - const unsigned int target = (unsigned int)mp.opcode[1];  
14506 - mp.mem[target] = _cimg_mp_defunc(mp);  
14507 - }  
14508 - --mp.p_code;  
14509 - return (double)(bool)mp.mem[mem_B];  
14510 - }  
14511 - static double mp_logical_or(_cimg_math_parser& mp) {  
14512 - const bool is_A = (bool)mp.mem[mp.opcode(2)];  
14513 - const CImg<longT> *const pE = ++mp.p_code + mp.opcode(4);  
14514 - if (is_A) { mp.p_code = pE - 1; return 1; }  
14515 - const unsigned int mem_B = (unsigned int)mp.opcode(3);  
14516 - for ( ; mp.p_code<pE; ++mp.p_code) {  
14517 - const CImg<longT> &op = *mp.p_code;  
14518 - mp.opcode._data = op._data; mp.opcode._height = op._height;  
14519 - const unsigned int target = (unsigned int)mp.opcode[1];  
14520 - mp.mem[target] = _cimg_mp_defunc(mp);  
14521 - }  
14522 - --mp.p_code;  
14523 - return (double)(bool)mp.mem[mem_B];  
14524 - }  
14525 - static double mp_infeq(_cimg_math_parser& mp) {  
14526 - return (double)(mp.mem[mp.opcode(2)]<=mp.mem[mp.opcode(3)]);  
14527 - }  
14528 - static double mp_supeq(_cimg_math_parser& mp) {  
14529 - return (double)(mp.mem[mp.opcode(2)]>=mp.mem[mp.opcode(3)]);  
14530 - }  
14531 - static double mp_noteq(_cimg_math_parser& mp) {  
14532 - return (double)(mp.mem[mp.opcode(2)]!=mp.mem[mp.opcode(3)]);  
14533 - }  
14534 - static double mp_eqeq(_cimg_math_parser& mp) {  
14535 - return (double)(mp.mem[mp.opcode(2)]==mp.mem[mp.opcode(3)]);  
14536 - }  
14537 - static double mp_inf(_cimg_math_parser& mp) {  
14538 - return (double)(mp.mem[mp.opcode(2)]<mp.mem[mp.opcode(3)]);  
14539 - }  
14540 - static double mp_sup(_cimg_math_parser& mp) {  
14541 - return (double)(mp.mem[mp.opcode(2)]>mp.mem[mp.opcode(3)]);  
14542 - }  
14543 - static double mp_add(_cimg_math_parser& mp) {  
14544 - return mp.mem[mp.opcode(2)] + mp.mem[mp.opcode(3)];  
14545 - }  
14546 - static double mp_sub(_cimg_math_parser& mp) {  
14547 - return mp.mem[mp.opcode(2)] - mp.mem[mp.opcode(3)];  
14548 - }  
14549 - static double mp_mul(_cimg_math_parser& mp) {  
14550 - const double A = mp.mem[mp.opcode(2)];  
14551 - const CImg<longT> *const pE = ++mp.p_code + mp.opcode(4);  
14552 - if (!A) { mp.p_code = pE - 1; return 0; }  
14553 - const unsigned int mem_B = (unsigned int)mp.opcode(3);  
14554 - for ( ; mp.p_code<pE; ++mp.p_code) {  
14555 - const CImg<longT> &op = *mp.p_code;  
14556 - mp.opcode._data = op._data; mp.opcode._height = op._height;  
14557 - const unsigned int target = (unsigned int)mp.opcode[1];  
14558 - mp.mem[target] = _cimg_mp_defunc(mp); 16057 + if (!std::strncmp(ss,"log2(",5)) { // Base-2 logarithm
  16058 + arg1 = compile(ss5,se1,depth1,0);
  16059 + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_log2,arg1);
  16060 + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(cimg::log2(mem[arg1]));
  16061 + _cimg_mp_scalar1(mp_log2,arg1);
  16062 + }
  16063 +
  16064 + if (!std::strncmp(ss,"log10(",6)) { // Base-10 logarithm
  16065 + arg1 = compile(ss6,se1,depth1,0);
  16066 + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_log10,arg1);
  16067 + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::log10(mem[arg1]));
  16068 + _cimg_mp_scalar1(mp_log10,arg1);
  16069 + }
  16070 + break;
  16071 +
  16072 + case 'm' :
  16073 + if (!std::strncmp(ss,"mdet(",5)) { // Matrix determinant
  16074 + arg1 = compile(ss5,se1,depth1,0);
  16075 + _cimg_mp_check_matrix_square(arg1,1,"Function 'mdet()'");
  16076 + p1 = (unsigned int)std::sqrt((float)_cimg_mp_vector_size(arg1));
  16077 + _cimg_mp_scalar2(mp_matrix_det,arg1,p1);
  16078 + }
  16079 +
  16080 + if (!std::strncmp(ss,"mdiag(",5)) { // Diagonal matrix
  16081 + arg1 = compile(ss6,se1,depth1,0);
  16082 + _cimg_mp_check_type(arg1,1,"Function 'mdiag()'",2,0);
  16083 + p1 = _cimg_mp_vector_size(arg1);
  16084 + pos = vector(p1*p1);
  16085 + CImg<uptrT>::vector((uptrT)mp_matrix_diag,pos,arg1,p1).move_to(code);
  16086 + _cimg_mp_return(pos);
  16087 + }
  16088 +
  16089 + if (!std::strncmp(ss,"meig(",5)) { // Matrix eigenvalues/eigenvector
  16090 + arg1 = compile(ss5,se1,depth1,0);
  16091 + _cimg_mp_check_matrix_square(arg1,1,"Function 'meig()'");
  16092 + p1 = (unsigned int)std::sqrt((float)_cimg_mp_vector_size(arg1));
  16093 + pos = vector((p1 + 1)*p1);
  16094 + CImg<uptrT>::vector((uptrT)mp_matrix_eig,pos,arg1,p1).move_to(code);
  16095 + _cimg_mp_return(pos);
  16096 + }
  16097 +
  16098 + if (!std::strncmp(ss,"meye(",5)) { // Matrix eigenvalues/eigenvector
  16099 + arg1 = compile(ss5,se1,depth1,0);
  16100 + _cimg_mp_check_constant(arg1,1,"Function 'meye()'",true);
  16101 + p1 = (unsigned int)mem[arg1];
  16102 + pos = vector(p1*p1);
  16103 + CImg<uptrT>::vector((uptrT)mp_matrix_eye,pos,p1).move_to(code);
  16104 + _cimg_mp_return(pos);
  16105 + }
  16106 +
  16107 + if (!std::strncmp(ss,"minv(",5)) { // Matrix inversion
  16108 + arg1 = compile(ss5,se1,depth1,0);
  16109 + _cimg_mp_check_matrix_square(arg1,1,"Function 'minv()'");
  16110 + p1 = (unsigned int)std::sqrt((float)_cimg_mp_vector_size(arg1));
  16111 + pos = vector(p1*p1);
  16112 + CImg<uptrT>::vector((uptrT)mp_matrix_inv,pos,arg1,p1).move_to(code);
  16113 + _cimg_mp_return(pos);
  16114 + }
  16115 +
  16116 + if (!std::strncmp(ss,"mmul(",5)) { // Matrix multiplication
  16117 + s_op = "Function 'mmul()'";
  16118 + s1 = ss5; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
  16119 + arg1 = compile(ss5,s1==se2?++s1:s1,depth1,0);
  16120 + s2 = s1 + 1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;
  16121 + arg2 = compile(s1 + 1,s2==se2?++s2:s2,depth1,0);
  16122 + if (s2<se1) arg3 = compile(++s2,se1,depth1,0); else arg3 = 1;
  16123 + _cimg_mp_check_type(arg1,1,s_op,2,0);
  16124 + _cimg_mp_check_type(arg2,2,s_op,2,0);
  16125 + _cimg_mp_check_constant(arg3,3,s_op,true);
  16126 + p1 = _cimg_mp_vector_size(arg1);
  16127 + p2 = _cimg_mp_vector_size(arg2);
  16128 + p3 = (unsigned int)mem[arg3];
  16129 + arg5 = p2/p3;
  16130 + arg4 = p1/arg5;
  16131 + if (arg4*arg5!=p1 || arg5*p3!=p2) {
  16132 + *se = saved_char; cimg::strellipsize(expr,64);
  16133 + throw CImgArgumentException("[_cimg_math_parser] "
  16134 + "CImg<%s>::%s: %s: Sizes of first and second arguments ('%s' and '%s') "
  16135 + "do not match for third argument 'nb_colsB=%u', "
  16136 + "in expression '%s%s%s'.",
  16137 + pixel_type(),_cimg_mp_calling_function,s_op,
  16138 + s_type(arg1)._data,s_type(arg2)._data,p3,
  16139 + (ss - 4)>expr._data?"...":"",
  16140 + (ss - 4)>expr._data?ss - 4:expr._data,
  16141 + se<&expr.back()?"...":"");
  16142 + }
  16143 + pos = vector(arg4*p3);
  16144 + CImg<uptrT>::vector((uptrT)mp_matrix_mul,pos,arg1,arg2,arg4,arg5,p3).move_to(code);
  16145 + _cimg_mp_return(pos);
  16146 + }
  16147 +
  16148 + if (!std::strncmp(ss,"mrot(",5)) { // Rotation matrix
  16149 + s_op = "Function 'mrot()'";
  16150 + s1 = ss5; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
  16151 + arg1 = compile(ss5,s1==se2?++s1:s1,depth1,0);
  16152 + s2 = s1 + 1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;
  16153 + arg2 = compile(s1 + 1,s2==se2?++s2:s2,depth1,0);
  16154 + s3 = s2 + 1; while (s3<se1 && (*s3!=',' || level[s3 - expr._data]!=clevel1)) ++s3;
  16155 + arg3 = compile(s2 + 1,s3==se2?++s3:s3,depth1,0);
  16156 + arg4 = compile(++s3,se1,depth1,0);
  16157 + _cimg_mp_check_type(arg1,1,s_op,1,0);
  16158 + _cimg_mp_check_type(arg2,2,s_op,1,0);
  16159 + _cimg_mp_check_type(arg3,3,s_op,1,0);
  16160 + _cimg_mp_check_type(arg4,4,s_op,1,0);
  16161 + pos = vector(9);
  16162 + CImg<uptrT>::vector((uptrT)mp_matrix_rot,pos,arg1,arg2,arg3,arg4).move_to(code);
  16163 + _cimg_mp_return(pos);
  16164 + }
  16165 +
  16166 + if (!std::strncmp(ss,"msolve(",7)) { // Solve linear system
  16167 + s_op = "Function 'msolve()'";
  16168 + s1 = ss7; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
  16169 + arg1 = compile(ss7,s1==se2?++s1:s1,depth1,0);
  16170 + s2 = s1 + 1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;
  16171 + arg2 = compile(s1 + 1,s2==se2?++s2:s2,depth1,0);
  16172 + if (s2<se1) arg3 = compile(++s2,se1,depth1,0); else arg3 = 1;
  16173 + _cimg_mp_check_type(arg1,1,s_op,2,0);
  16174 + _cimg_mp_check_type(arg2,2,s_op,2,0);
  16175 + _cimg_mp_check_constant(arg3,3,s_op,true);
  16176 + p1 = _cimg_mp_vector_size(arg1);
  16177 + p2 = _cimg_mp_vector_size(arg2);
  16178 + p3 = (unsigned int)mem[arg3];
  16179 + arg5 = p2/p3;
  16180 + arg4 = p1/arg5;
  16181 + if (arg4*arg5!=p1 || arg4*p3!=p2) {
  16182 + *se = saved_char; cimg::strellipsize(expr,64);
  16183 + throw CImgArgumentException("[_cimg_math_parser] "
  16184 + "CImg<%s>::%s: %s: Sizes of first and second arguments ('%s' and '%s') "
  16185 + "do not match for third argument 'nb_colsB=%u', "
  16186 + "in expression '%s%s%s'.",
  16187 + pixel_type(),_cimg_mp_calling_function,s_op,
  16188 + s_type(arg1)._data,s_type(arg2)._data,p3,
  16189 + (ss - 4)>expr._data?"...":"",
  16190 + (ss - 4)>expr._data?ss - 4:expr._data,
  16191 + se<&expr.back()?"...":"");
  16192 + }
  16193 + pos = vector(arg5*p3);
  16194 + CImg<uptrT>::vector((uptrT)mp_matrix_solve,pos,arg1,arg2,arg4,arg5,p3).move_to(code);
  16195 + _cimg_mp_return(pos);
  16196 + }
  16197 +
  16198 + if (!std::strncmp(ss,"mtrace(",7)) { // Matrix trace
  16199 + arg1 = compile(ss7,se1,depth1,0);
  16200 + _cimg_mp_check_matrix_square(arg1,1,"Function 'mtrace()'");
  16201 + p1 = (unsigned int)std::sqrt((float)_cimg_mp_vector_size(arg1));
  16202 + _cimg_mp_scalar2(mp_matrix_trace,arg1,p1);
  16203 + }
  16204 +
  16205 + if (!std::strncmp(ss,"mtrans(",7)) { // Matrix transpose
  16206 + s_op = "Function 'mtrans()'";
  16207 + s1 = ss7; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
  16208 + arg1 = compile(ss7,s1==se2?++s1:s1,depth1,0);
  16209 + arg2 = compile(++s1,se1,depth1,0);
  16210 + _cimg_mp_check_type(arg1,1,s_op,2,0);
  16211 + _cimg_mp_check_constant(arg2,2,s_op,true);
  16212 + p1 = _cimg_mp_vector_size(arg1);
  16213 + p2 = (unsigned int)mem[arg2];
  16214 + p3 = p1/p2;
  16215 + if (p2*p3!=p1) {
  16216 + *se = saved_char; cimg::strellipsize(expr,64);
  16217 + throw CImgArgumentException("[_cimg_math_parser] "
  16218 + "CImg<%s>::%s: %s: Size of first argument ('%s') does not match"
  16219 + "for second specified argument 'nb_cols=%u', "
  16220 + "in expression '%s%s%s'.",
  16221 + pixel_type(),_cimg_mp_calling_function,s_op,
  16222 + s_type(arg1)._data,p2,
  16223 + (ss - 4)>expr._data?"...":"",
  16224 + (ss - 4)>expr._data?ss - 4:expr._data,
  16225 + se<&expr.back()?"...":"");
  16226 + }
  16227 + pos = vector(p3*p2);
  16228 + CImg<uptrT>::vector((uptrT)mp_matrix_trans,pos,arg1,p2,p3).move_to(code);
  16229 + _cimg_mp_return(pos);
  16230 + }
  16231 + break;
  16232 +
  16233 + case 'n' :
  16234 + if (!std::strncmp(ss,"narg(",5)) { // Number of arguments
  16235 + if (*ss5==')') _cimg_mp_return(0);
  16236 + arg1 = 0;
  16237 + for (s = ss5; s<se; ++s) {
  16238 + ns = s; while (ns<se && (*ns!=',' || level[ns - expr._data]!=clevel1) &&
  16239 + (*ns!=')' || level[ns - expr._data]!=clevel)) ++ns;
  16240 + ++arg1; s = ns;
  16241 + }
  16242 + _cimg_mp_constant(arg1);
  16243 + }
  16244 +
  16245 + if ((cimg_sscanf(ss,"norm%u%c",&(arg1=~0U),&sep)==2 && sep=='(') ||
  16246 + !std::strncmp(ss,"norminf(",8)) { // Lp norm
  16247 + pos = scalar();
  16248 + switch (arg1) {
  16249 + case 0 : CImg<uptrT>::vector((uptrT)mp_norm0,pos).move_to(_opcode); break;
  16250 + case 1 : CImg<uptrT>::vector((uptrT)mp_norm1,pos).move_to(_opcode); break;
  16251 + case 2 : CImg<uptrT>::vector((uptrT)mp_norm2,pos).move_to(_opcode); break;
  16252 + case ~0U : CImg<uptrT>::vector((uptrT)mp_norminf,pos).move_to(_opcode); break;
  16253 + default :
  16254 + CImg<uptrT>::vector((uptrT)mp_normp,pos,(uptrT)(arg1==~0U?-1:(int)arg1)).
  16255 + move_to(_opcode);
  16256 + }
  16257 + for (s = std::strchr(ss5,'(') + 1; s<se; ++s) {
  16258 + ns = s; while (ns<se && (*ns!=',' || level[ns - expr._data]!=clevel1) &&
  16259 + (*ns!=')' || level[ns - expr._data]!=clevel)) ++ns;
  16260 + arg2 = compile(s,ns,depth1,0);
  16261 + if (_cimg_mp_is_vector(arg2))
  16262 + CImg<uptrT>::sequence((uptrT)_cimg_mp_vector_size(arg2),arg2 + 1,
  16263 + arg2 + (uptrT)_cimg_mp_vector_size(arg2)).
  16264 + move_to(_opcode);
  16265 + else CImg<uptrT>::vector(arg2).move_to(_opcode);
  16266 + s = ns;
  16267 + }
  16268 + (_opcode>'y').move_to(code);
  16269 + _cimg_mp_return(pos);
  16270 + }
  16271 + break;
  16272 +
  16273 + case 'p' :
  16274 + if (!std::strncmp(ss,"print(",6)) { // Print expression
  16275 + pos = compile(ss6,se1,depth1,p_ref);
  16276 + *se1 = 0;
  16277 + if (_cimg_mp_is_vector(pos)) // Vector
  16278 + ((CImg<uptrT>::vector((uptrT)mp_vector_print,pos,(uptrT)_cimg_mp_vector_size(pos)),
  16279 + CImg<uptrT>::string(ss6).unroll('y'))>'y').move_to(code);
  16280 + else // Scalar
  16281 + ((CImg<uptrT>::vector((uptrT)mp_print,pos),
  16282 + CImg<uptrT>::string(ss6).unroll('y'))>'y').move_to(code);
  16283 + *se1 = ')';
  16284 + _cimg_mp_return(pos);
  16285 + }
  16286 + break;
  16287 +
  16288 + case 'r' :
  16289 + if (!std::strncmp(ss,"rol(",4) || !std::strncmp(ss,"ror(",4)) { // Bitwise rotation
  16290 + s1 = ss4; while (s1<se1 && (*s1!=',' || level[s1-expr._data]!=clevel1)) ++s1;
  16291 + arg1 = compile(ss4,s1==se2?++s1:s1,depth1,0);
  16292 + arg2 = 1;
  16293 + if (s1<se1) {
  16294 + s2 = s1 + 1; while (s2<se1 && (*s2!=',' || level[s2-expr._data]!=clevel1)) ++s2;
  16295 + arg2 = compile(s1 + 1,se1,depth1,0);
  16296 + }
  16297 + _cimg_mp_check_type(arg2,2,"Function 'rol()'",1,0);
  16298 + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector2_vs(*ss2=='l'?mp_rol:mp_ror,arg1,arg2);
  16299 + if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2))
  16300 + _cimg_mp_constant(*ss2=='l'?cimg::rol(mem[arg1],(unsigned int)mem[arg2]):
  16301 + cimg::ror(mem[arg1],(unsigned int)mem[arg2]));
  16302 + _cimg_mp_scalar2(*ss2=='l'?mp_rol:mp_ror,arg1,arg2);
  16303 + }
  16304 +
  16305 + if (!std::strncmp(ss,"round(",6)) { // Value rounding
  16306 + s_op = "Function 'round()'";
  16307 + s1 = ss6; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
  16308 + arg1 = compile(ss6,s1==se2?++s1:s1,depth1,0);
  16309 + arg2 = 1;
  16310 + arg3 = 0;
  16311 + if (s1<se1) {
  16312 + s2 = s1 + 1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;
  16313 + arg2 = compile(s1 + 1,s2==se2?++s2:s2,depth1,0);
  16314 + if (s2<se1) arg3 = compile(s2 + 1,se1,depth1,0);
  16315 + }
  16316 + _cimg_mp_check_type(arg2,2,s_op,1,0);
  16317 + _cimg_mp_check_type(arg3,3,s_op,1,0);
  16318 + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector3_vss(mp_round,arg1,arg2,arg3);
  16319 + if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2) && _cimg_mp_is_constant(arg3))
  16320 + _cimg_mp_constant(cimg::round(mem[arg1],mem[arg2],(int)mem[arg3]));
  16321 + _cimg_mp_scalar3(mp_round,arg1,arg2,arg3);
  16322 + }
  16323 + break;
  16324 +
  16325 + case 's' :
  16326 + if (!std::strncmp(ss,"sign(",5)) { // Sign
  16327 + arg1 = compile(ss5,se1,depth1,0);
  16328 + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_sign,arg1);
  16329 + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(cimg::sign(mem[arg1]));
  16330 + _cimg_mp_scalar1(mp_sign,arg1);
  16331 + }
  16332 +
  16333 + if (!std::strncmp(ss,"sin(",4)) { // Sine
  16334 + arg1 = compile(ss4,se1,depth1,0);
  16335 + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_sin,arg1);
  16336 + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::sin(mem[arg1]));
  16337 + _cimg_mp_scalar1(mp_sin,arg1);
  16338 + }
  16339 +
  16340 + if (!std::strncmp(ss,"sinc(",5)) { // Sine cardinal
  16341 + arg1 = compile(ss5,se1,depth1,0);
  16342 + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_sinc,arg1);
  16343 + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(cimg::sinc(mem[arg1]));
  16344 + _cimg_mp_scalar1(mp_sinc,arg1);
  16345 + }
  16346 +
  16347 + if (!std::strncmp(ss,"sinh(",5)) { // Hyperbolic sine
  16348 + arg1 = compile(ss5,se1,depth1,0);
  16349 + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_sinh,arg1);
  16350 + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::sinh(mem[arg1]));
  16351 + _cimg_mp_scalar1(mp_sinh,arg1);
  16352 + }
  16353 +
  16354 + if (!std::strncmp(ss,"size(",5)) { // Vector size.
  16355 + arg1 = compile(ss5,se1,depth1,0);
  16356 + _cimg_mp_constant(_cimg_mp_is_scalar(arg1)?0:_cimg_mp_vector_size(arg1));
  16357 + }
  16358 +
  16359 + if (!std::strncmp(ss,"sort(",5)) { // Sort vector
  16360 + s_op = "Function 'sort()'";
  16361 + s1 = ss6; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
  16362 + arg1 = compile(ss5,s1,depth1,0);
  16363 + if (s1<se1) arg2 = compile(++s1,se1,depth1,0); else arg2 = 1;
  16364 + _cimg_mp_check_type(arg1,1,s_op,2,0);
  16365 + _cimg_mp_check_type(arg2,2,s_op,1,0);
  16366 + p1 = _cimg_mp_vector_size(arg1);
  16367 + pos = vector(p1);
  16368 + CImg<uptrT>::vector((uptrT)mp_vector_sort,pos,arg1,p1,arg2).move_to(code);
  16369 + _cimg_mp_return(pos);
  16370 + }
  16371 +
  16372 + if (!std::strncmp(ss,"sqr(",4)) { // Square
  16373 + arg1 = compile(ss4,se1,depth1,0);
  16374 + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_sqr,arg1);
  16375 + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(cimg::sqr(mem[arg1]));
  16376 + _cimg_mp_scalar1(mp_sqr,arg1);
  16377 + }
  16378 +
  16379 + if (!std::strncmp(ss,"sqrt(",5)) { // Square root
  16380 + arg1 = compile(ss5,se1,depth1,0);
  16381 + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_sqrt,arg1);
  16382 + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::sqrt(mem[arg1]));
  16383 + _cimg_mp_scalar1(mp_sqrt,arg1);
  16384 + }
  16385 + break;
  16386 +
  16387 + case 't' :
  16388 + if (!std::strncmp(ss,"tan(",4)) { // Tangent
  16389 + arg1 = compile(ss4,se1,depth1,0);
  16390 + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_tan,arg1);
  16391 + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::tan(mem[arg1]));
  16392 + _cimg_mp_scalar1(mp_tan,arg1);
  16393 + }
  16394 +
  16395 + if (!std::strncmp(ss,"tanh(",5)) { // Hyperbolic tangent
  16396 + arg1 = compile(ss5,se1,depth1,0);
  16397 + if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_tanh,arg1);
  16398 + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(std::tanh(mem[arg1]));
  16399 + _cimg_mp_scalar1(mp_tanh,arg1);
  16400 + }
  16401 + break;
  16402 +
  16403 + case 'u' :
  16404 + if (*ss1=='(') { // Random value with uniform distribution
  16405 + if (*ss2==')') _cimg_mp_scalar2(mp_u,0,1);
  16406 + s1 = ss2; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
  16407 + arg1 = compile(ss2,s1,depth1,0);
  16408 + if (s1<se1) arg2 = compile(s1 + 1,se1,depth1,0); else { arg2 = arg1; arg1 = 0; }
  16409 + _cimg_mp_check_type(arg2,2,"Function 'u()'",3,_cimg_mp_vector_size(arg1));
  16410 + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_u,arg1,arg2);
  16411 + if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_u,arg1,arg2);
  16412 + if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_u,arg1,arg2);
  16413 + _cimg_mp_scalar2(mp_u,arg1,arg2);
  16414 + }
  16415 + break;
  16416 +
  16417 + case 'v' :
  16418 + if ((cimg_sscanf(ss,"vector%u%c",&(arg1=~0U),&sep)==2 && sep=='(' && arg1>0) ||
  16419 + !std::strncmp(ss,"vector(",7)) { // Vector
  16420 + arg2 = 0; // Number of specified values.
  16421 + s = std::strchr(ss6,'(') + 1;
  16422 + if (*s!=')' || arg1==~0U) for (; s<se; ++s) {
  16423 + ns = s; while (ns<se && (*ns!=',' || level[ns - expr._data]!=clevel1) &&
  16424 + (*ns!=')' || level[ns - expr._data]!=clevel)) ++ns;
  16425 + arg3 = compile(s,ns,depth1,0);
  16426 + if (_cimg_mp_is_vector(arg3)) {
  16427 + arg4 = _cimg_mp_vector_size(arg3);
  16428 + CImg<uptrT>::sequence(arg4,arg3 + 1,arg3 + arg4).move_to(_opcode);
  16429 + arg2+=arg4;
  16430 + } else { CImg<uptrT>::vector(arg3).move_to(_opcode); ++arg2; }
  16431 + s = ns;
  16432 + }
  16433 + if (arg1==~0U) arg1 = arg2;
  16434 + _cimg_mp_check_vector0(arg1,"Function 'vector()'");
  16435 + pos = vector(arg1);
  16436 + _opcode.insert(CImg<uptrT>::vector((uptrT)mp_vector_init,pos,arg1),0);
  16437 + (_opcode>'y').move_to(code);
  16438 + _cimg_mp_return(pos);
  16439 + }
  16440 + break;
  16441 +
  16442 + case 'w' :
  16443 + if (!std::strncmp(ss,"whiledo",7) && (*ss7=='(' || (*ss7 && *ss7<=' ' && *ss8=='('))) { // While...do
  16444 + if (*ss7<=' ') cimg::swap(*ss7,*ss8); // Allow space before opening brace
  16445 + s1 = ss8; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
  16446 + p1 = code._width;
  16447 + arg1 = compile(ss8,s1,depth1,0);
  16448 + p2 = code._width;
  16449 + pos = compile(s1 + 1,se1,depth1,0);
  16450 + _cimg_mp_check_type(arg1,1,"Function 'whiledo()'",1,0);
  16451 + arg2 = _cimg_mp_is_vector(pos)?_cimg_mp_vector_size(pos):0; // Output vector size (or 0 if scalar)
  16452 + CImg<uptrT>::vector((uptrT)mp_whiledo,pos,arg1,p2 - p1,code._width - p2,arg2).move_to(code,p1);
  16453 + _cimg_mp_return(pos);
  16454 + }
  16455 + break;
  16456 + }
  16457 +
  16458 + if (!std::strncmp(ss,"min(",4) || !std::strncmp(ss,"max(",4) ||
  16459 + !std::strncmp(ss,"med(",4) || !std::strncmp(ss,"kth(",4) ||
  16460 + !std::strncmp(ss,"arg(",4) ||
  16461 + !std::strncmp(ss,"argmin(",7) || !std::strncmp(ss,"argmax(",7)) { // Multi-argument functions
  16462 + pos = scalar();
  16463 + is_sth = *ss=='a' && ss[3]!='(';
  16464 + CImg<uptrT>::vector((uptrT)(*ss=='a'?(ss[3]=='('?mp_arg:ss[4]=='i'?mp_argmin:mp_argmax):
  16465 + *ss=='k'?mp_kth:ss[1]=='i'?mp_min:
  16466 + ss[1]=='a'?mp_max:mp_med),pos).
  16467 + move_to(_opcode);
  16468 + for (s = is_sth?ss7:ss4; s<se; ++s) {
  16469 + ns = s; while (ns<se && (*ns!=',' || level[ns - expr._data]!=clevel1) &&
  16470 + (*ns!=')' || level[ns - expr._data]!=clevel)) ++ns;
  16471 + arg2 = compile(s,ns,depth1,0);
  16472 + if (_cimg_mp_is_vector(arg2))
  16473 + CImg<uptrT>::sequence((uptrT)_cimg_mp_vector_size(arg2),arg2 + 1,
  16474 + arg2 + (uptrT)_cimg_mp_vector_size(arg2)).
  16475 + move_to(_opcode);
  16476 + else CImg<uptrT>::vector(arg2).move_to(_opcode);
  16477 + s = ns;
  16478 + }
  16479 + (_opcode>'y').move_to(code);
  16480 + _cimg_mp_return(pos);
  16481 + }
  16482 +
  16483 + // No corresponding built-in function -> Look for a user-defined function.
  16484 + s0 = strchr(ss,'(');
  16485 + if (s0) {
  16486 + variable_name.assign(ss,s0 - ss + 1).back() = 0;
  16487 + cimglist_for(function_def,l) if (!std::strcmp(function_def[l],variable_name)) {
  16488 + p2 = (unsigned int)function_def[l].back(); // Number of required arguments
  16489 + CImg<charT> _expr = function_body[l]; // Expression to be substituted
  16490 + p1 = 1; // Indice of current parsed argument
  16491 + for (s = s0 + 1; s<=se1; ++p1, s = ns + 1) { // Parse function arguments
  16492 + while (*s && *s<=' ') ++s;
  16493 + if (*s==')' && p1==1) break; // Function has no arguments
  16494 + if (p1>p2) { ++p1; break; }
  16495 + ns = s; while (ns<se && (*ns!=',' || level[ns - expr._data]!=clevel1) &&
  16496 + (*ns!=')' || level[ns - expr._data]!=clevel)) ++ns;
  16497 +
  16498 + variable_name.assign(s,ns - s + 1).back() = 0; // Argument to write
  16499 +
  16500 + cimg_forX(_expr,k) if (_expr[k]==(char)p1) { // Perform argument substitution
  16501 + _expr.resize(_expr._width + variable_name._width,1,1,1,0);
  16502 + _expr[k++] = '(';
  16503 + std::memmove(_expr._data + k + variable_name._width,_expr._data + k,
  16504 + _expr._width - variable_name._width - k);
  16505 + std::memcpy(_expr._data + k,variable_name,variable_name._width - 1);
  16506 + k+=variable_name._width - 1;
  16507 + _expr[k++] = ')';
  16508 + }
  16509 + *ns = 0;
  16510 + }
  16511 +
  16512 + if (p1!=p2+1) { // Number of specified argument do not fit
  16513 + *se = saved_char; cimg::strellipsize(variable_name,64); cimg::strellipsize(expr,64);
  16514 + throw CImgArgumentException("[_cimg_math_parser] "
  16515 + "CImg<%s>::%s: function '%s()': Number of specified arguments does not "
  16516 + "match function declaration (%u argument%s required), "
  16517 + "in expression '%s%s%s'.",
  16518 + pixel_type(),_cimg_mp_calling_function,variable_name._data,
  16519 + p2,p2!=1?"s":"",
  16520 + (ss - 4)>expr._data?"...":"",
  16521 + (ss - 4)>expr._data?ss - 4:expr._data,
  16522 + se<&expr.back()?"...":"");
  16523 + }
  16524 +
  16525 + // Recompute 'pexpr' and 'level' for evaluating substituted expression.
  16526 + CImg<charT> _pexpr(_expr._width);
  16527 + ns = _pexpr._data;
  16528 + for (ps = _expr._data, c1 = ' '; *ps; ++ps) {
  16529 + if (*ps!=' ') c1 = *ps;
  16530 + *(ns++) = c1;
  16531 + }
  16532 + *ns = 0;
  16533 +
  16534 + CImg<uintT> _level(_expr._width - 1);
  16535 + unsigned int *pd = _level._data;
  16536 + nb = 0;
  16537 + for (ps = _expr._data; *ps && nb>=0; ++ps)
  16538 + *(pd++) = (unsigned int)(*ps=='('||*ps=='['?nb++:*ps==')'||*ps==']'?--nb:nb);
  16539 +
  16540 + expr.swap(_expr); pexpr.swap(_pexpr); level.swap(_level);
  16541 + s0 = user_function;
  16542 + user_function = function_def[l];
  16543 + pos = compile(expr._data,expr._data + expr._width - 1,depth1,p_ref);
  16544 + user_function = s0;
  16545 + expr.swap(_expr); pexpr.swap(_pexpr); level.swap(_level);
  16546 + _cimg_mp_return(pos);
  16547 + }
  16548 + }
  16549 + } // if (se1==')')
  16550 +
  16551 + // Vector specification using initializer '[ ... ]'.
  16552 + if (*ss=='[' && *se1==']') {
  16553 + arg1 = 0; // Number of specified values.
  16554 + if (*ss1!=']') for (s = ss1; s<se; ++s) {
  16555 + ns = s; while (ns<se && (*ns!=',' || level[ns - expr._data]!=clevel1) &&
  16556 + (*ns!=']' || level[ns - expr._data]!=clevel)) ++ns;
  16557 + arg2 = compile(s,ns,depth1,0);
  16558 + if (_cimg_mp_is_vector(arg2)) {
  16559 + arg3 = _cimg_mp_vector_size(arg2);
  16560 + CImg<uptrT>::sequence(arg3,arg2 + 1,arg2 + arg3).move_to(_opcode);
  16561 + arg1+=arg3;
  16562 + } else { CImg<uptrT>::vector(arg2).move_to(_opcode); ++arg1; }
  16563 + s = ns;
  16564 + }
  16565 + _cimg_mp_check_vector0(arg1,"operator '[]'");
  16566 + pos = vector(arg1);
  16567 + _opcode.insert(CImg<uptrT>::vector((uptrT)mp_vector_init,pos,arg1),0);
  16568 + (_opcode>'y').move_to(code);
  16569 + _cimg_mp_return(pos);
14559 } 16570 }
14560 - --mp.p_code;  
14561 - return A*(double)mp.mem[mem_B]; 16571 +
  16572 + // Variables related to the input list of images.
  16573 + if (*ss1=='#' && ss2<se) {
  16574 + arg1 = compile(ss2,se,depth1,0);
  16575 + p1 = (unsigned int)(listin._width && _cimg_mp_is_constant(arg1)?cimg::mod((int)mem[arg1],listin.width()):0);
  16576 + switch (*ss) {
  16577 + case 'w' : // w#ind
  16578 + if (!listin) _cimg_mp_return(0);
  16579 + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(listin[p1]._width);
  16580 + _cimg_mp_scalar1(mp_list_width,arg1);
  16581 + case 'h' : // h#ind
  16582 + if (!listin) _cimg_mp_return(0);
  16583 + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(listin[p1]._height);
  16584 + _cimg_mp_scalar1(mp_list_height,arg1);
  16585 + case 'd' : // d#ind
  16586 + if (!listin) _cimg_mp_return(0);
  16587 + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(listin[p1]._depth);
  16588 + _cimg_mp_scalar1(mp_list_depth,arg1);
  16589 + case 'r' : // r#ind
  16590 + if (!listin) _cimg_mp_return(0);
  16591 + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(listin[p1]._is_shared);
  16592 + _cimg_mp_scalar1(mp_list_is_shared,arg1);
  16593 + case 's' : // s#ind
  16594 + if (!listin) _cimg_mp_return(0);
  16595 + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(listin[p1]._spectrum);
  16596 + _cimg_mp_scalar1(mp_list_spectrum,arg1);
  16597 + case 'i' : // i#ind
  16598 + if (!listin) _cimg_mp_return(0);
  16599 + _cimg_mp_scalar7(mp_list_ixyzc,arg1,_cimg_mp_x,_cimg_mp_y,_cimg_mp_z,_cimg_mp_c,
  16600 + reserved_label[29],reserved_label[30]);
  16601 + case 'R' : // R#ind
  16602 + if (!listin) _cimg_mp_return(0);
  16603 + _cimg_mp_scalar7(mp_list_ixyzc,arg1,_cimg_mp_x,_cimg_mp_y,_cimg_mp_z,0,
  16604 + reserved_label[29],reserved_label[30]);
  16605 + case 'G' : // G#ind
  16606 + if (!listin) _cimg_mp_return(0);
  16607 + _cimg_mp_scalar7(mp_list_ixyzc,arg1,_cimg_mp_x,_cimg_mp_y,_cimg_mp_z,1,
  16608 + reserved_label[29],reserved_label[30]);
  16609 + case 'B' : // B#ind
  16610 + if (!listin) _cimg_mp_return(0);
  16611 + _cimg_mp_scalar7(mp_list_ixyzc,arg1,_cimg_mp_x,_cimg_mp_y,_cimg_mp_z,2,
  16612 + reserved_label[29],reserved_label[30]);
  16613 + case 'A' : // A#ind
  16614 + if (!listin) _cimg_mp_return(0);
  16615 + _cimg_mp_scalar7(mp_list_ixyzc,arg1,_cimg_mp_x,_cimg_mp_y,_cimg_mp_z,3,
  16616 + reserved_label[29],reserved_label[30]);
  16617 + }
  16618 + }
  16619 +
  16620 + if (*ss1 && *ss2=='#' && ss3<se) {
  16621 + arg1 = compile(ss3,se,depth1,0);
  16622 + p1 = (unsigned int)(listin._width && _cimg_mp_is_constant(arg1)?cimg::mod((int)mem[arg1],listin.width()):0);
  16623 + if (*ss=='w' && *ss1=='h') { // wh#ind
  16624 + if (!listin) _cimg_mp_return(0);
  16625 + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(listin[p1]._width*listin[p1]._height);
  16626 + _cimg_mp_scalar1(mp_list_wh,arg1);
  16627 + }
  16628 + arg2 = ~0U;
  16629 +
  16630 + if (*ss=='i') {
  16631 + if (*ss1=='c') { // ic#ind
  16632 + if (!listin) _cimg_mp_return(0);
  16633 + if (_cimg_mp_is_constant(arg1)) {
  16634 + if (!list_median) list_median.assign(listin._width);
  16635 + if (!list_median[p1]) CImg<doubleT>::vector(listin[p1].median()).move_to(list_median[p1]);
  16636 + _cimg_mp_constant(*list_median[p1]);
  16637 + }
  16638 + _cimg_mp_scalar1(mp_list_median,arg1);
  16639 + }
  16640 + if (*ss1>='0' && *ss1<='9') { // i0#ind...i9#ind
  16641 + if (!listin) _cimg_mp_return(0);
  16642 + _cimg_mp_scalar7(mp_list_ixyzc,arg1,_cimg_mp_x,_cimg_mp_y,_cimg_mp_z,*ss1 - '0',
  16643 + reserved_label[29],reserved_label[30]);
  16644 + }
  16645 + switch (*ss1) {
  16646 + case 'm' : arg2 = 0; break; // im#ind
  16647 + case 'M' : arg2 = 1; break; // iM#ind
  16648 + case 'a' : arg2 = 2; break; // ia#ind
  16649 + case 'v' : arg2 = 3; break; // iv#ind
  16650 + case 's' : arg2 = 12; break; // is#ind
  16651 + case 'p' : arg2 = 13; break; // ip#ind
  16652 + }
  16653 + } else if (*ss1=='m') switch (*ss) {
  16654 + case 'x' : arg2 = 4; break; // xm#ind
  16655 + case 'y' : arg2 = 5; break; // ym#ind
  16656 + case 'z' : arg2 = 6; break; // zm#ind
  16657 + case 'c' : arg2 = 7; break; // cm#ind
  16658 + } else if (*ss1=='M') switch (*ss) {
  16659 + case 'x' : arg2 = 8; break; // xM#ind
  16660 + case 'y' : arg2 = 9; break; // yM#ind
  16661 + case 'z' : arg2 = 10; break; // zM#ind
  16662 + case 'c' : arg2 = 11; break; // cM#ind
  16663 + }
  16664 + if (arg2!=~0U) {
  16665 + if (!listin) _cimg_mp_return(0);
  16666 + if (_cimg_mp_is_constant(arg1)) {
  16667 + if (!list_stats) list_stats.assign(listin._width);
  16668 + if (!list_stats[p1]) list_stats[p1].assign(1,14,1,1,0).fill(listin[p1].get_stats(),false);
  16669 + _cimg_mp_constant(list_stats(p1,arg2));
  16670 + }
  16671 + _cimg_mp_scalar2(mp_list_stats,arg1,arg2);
  16672 + }
  16673 + }
  16674 +
  16675 + if (*ss=='w' && *ss1=='h' && *ss2=='d' && *ss3=='#' && ss4<se) { // whd#ind
  16676 + arg1 = compile(ss4,se,depth1,0);
  16677 + if (!listin) _cimg_mp_return(0);
  16678 + p1 = (unsigned int)(_cimg_mp_is_constant(arg1)?cimg::mod((int)mem[arg1],listin.width()):0);
  16679 + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(listin[p1]._width*listin[p1]._height*listin[p1]._depth);
  16680 + _cimg_mp_scalar1(mp_list_whd,arg1);
  16681 + }
  16682 + if (*ss=='w' && *ss1=='h' && *ss2=='d' && *ss3=='s' && *ss4=='#' && ss5<se) { // whds#ind
  16683 + arg1 = compile(ss5,se,depth1,0);
  16684 + if (!listin) _cimg_mp_return(0);
  16685 + p1 = (unsigned int)(_cimg_mp_is_constant(arg1)?cimg::mod((int)mem[arg1],listin.width()):0);
  16686 + if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(listin[p1]._width*listin[p1]._height*listin[p1]._depth*
  16687 + listin[p1]._spectrum);
  16688 + _cimg_mp_scalar1(mp_list_whds,arg1);
  16689 + }
  16690 +
  16691 + if (!std::strcmp(ss,"interpolation")) _cimg_mp_return(reserved_label[29]); // interpolation
  16692 + if (!std::strcmp(ss,"boundary")) _cimg_mp_return(reserved_label[30]); // boundary
  16693 +
  16694 + // No known item found, assuming this is an already initialized variable.
  16695 + variable_name.assign(ss,(unsigned int)(se + 1 - ss)).back() = 0;
  16696 + if (variable_name[1]) { // Multi-char variable
  16697 + cimglist_for(variable_def,i) if (!std::strcmp(variable_name,variable_def[i]))
  16698 + _cimg_mp_return(variable_pos[i]);
  16699 + } else if (reserved_label[*variable_name]!=~0U) // Single-char variable
  16700 + _cimg_mp_return(reserved_label[*variable_name]);
  16701 +
  16702 + // Reached an unknown item -> error.
  16703 + is_sth = true; // is_valid_variable_name
  16704 + if (*variable_name>='0' && *variable_name<='9') is_sth = false;
  16705 + else for (ns = variable_name._data + 1; *ns; ++ns)
  16706 + if (!is_varchar(*ns)) { is_sth = false; break; }
  16707 +
  16708 + *se = saved_char; cimg::strellipsize(variable_name,64); cimg::strellipsize(expr,64);
  16709 + if (is_sth)
  16710 + throw CImgArgumentException("[_cimg_math_parser] "
  16711 + "CImg<%s>::%s: Undefined variable '%s' in expression '%s%s%s'.",
  16712 + pixel_type(),_cimg_mp_calling_function,
  16713 + variable_name._data,
  16714 + (ss - 4)>expr._data?"...":"",
  16715 + (ss - 4)>expr._data?ss - 4:expr._data,
  16716 + se<&expr.back()?"...":"");
  16717 + s0 = std::strchr(ss,'(');
  16718 + if (s0 && *se1==')') s_op = "function call"; else s_op = "item";
  16719 + throw CImgArgumentException("[_cimg_math_parser] "
  16720 + "CImg<%s>::%s: Unrecognized %s '%s' in expression '%s%s%s'.",
  16721 + pixel_type(),_cimg_mp_calling_function,
  16722 + s_op,variable_name._data,
  16723 + (ss - 4)>expr._data?"...":"",
  16724 + (ss - 4)>expr._data?ss - 4:expr._data,
  16725 + se<&expr.back()?"...":"");
14562 } 16726 }
14563 - static double mp_div(_cimg_math_parser& mp) {  
14564 - return mp.mem[mp.opcode(2)] / mp.mem[mp.opcode(3)]; 16727 +
  16728 + // Evaluation procedure.
  16729 + double operator()(const double x, const double y, const double z, const double c) {
  16730 + mem[_cimg_mp_x] = x; mem[_cimg_mp_y] = y; mem[_cimg_mp_z] = z; mem[_cimg_mp_c] = c;
  16731 + for (p_code = p_code_begin; p_code<p_code_end; ++p_code) {
  16732 + const CImg<uptrT> &op = *p_code;
  16733 + opcode._data = op._data; opcode._height = op._height;
  16734 + const uptrT target = opcode[1];
  16735 + mem[target] = _cimg_mp_defunc(*this);
  16736 + }
  16737 + return *result;
14565 } 16738 }
14566 - static double mp_minus(_cimg_math_parser& mp) {  
14567 - return -mp.mem[mp.opcode(2)]; 16739 +
  16740 + // Evaluation procedure (return output values in vector 'output').
  16741 + template<typename t>
  16742 + void operator()(const double x, const double y, const double z, const double c, t *const output) {
  16743 + mem[_cimg_mp_x] = x; mem[_cimg_mp_y] = y; mem[_cimg_mp_z] = z; mem[_cimg_mp_c] = c;
  16744 + for (p_code = p_code_begin; p_code<p_code_end; ++p_code) {
  16745 + const CImg<uptrT> &op = *p_code;
  16746 + opcode._data = op._data; opcode._height = op._height;
  16747 + const uptrT target = opcode[1];
  16748 + mem[target] = _cimg_mp_defunc(*this);
  16749 + }
  16750 + if (result_dim) {
  16751 + const double *ptrs = result + 1;
  16752 + t *ptrd = output;
  16753 + for (unsigned int k = 0; k<result_dim; ++k) *(ptrd++) = (t)*(ptrs++);
  16754 + } else *output = (t)*result;
14568 } 16755 }
14569 - static double mp_logical_not(_cimg_math_parser& mp) {  
14570 - return !mp.mem[mp.opcode(2)]; 16756 +
  16757 + // Return type of a memory element as a string.
  16758 + CImg<charT> s_type(const unsigned int arg) const {
  16759 + CImg<charT> res;
  16760 + if (_cimg_mp_is_vector(arg)) { // Vector
  16761 + CImg<charT>::string("vectorXXXXXXXXXXXXXXXX").move_to(res);
  16762 + std::sprintf(res._data + 6,"%u",_cimg_mp_vector_size(arg));
  16763 + } else CImg<charT>::string("scalar").move_to(res);
  16764 + return res;
14571 } 16765 }
14572 - static double mp_bitwise_not(_cimg_math_parser& mp) {  
14573 - return ~(unsigned long)mp.mem[mp.opcode(2)]; 16766 +
  16767 + // Insert constant value in memory.
  16768 + unsigned int constant(const double val) {
  16769 + if (val==(double)(int)val) {
  16770 + if (val>=0 && val<=9) return (unsigned int)val;
  16771 + if (val<0 && val>=-5) return (unsigned int)(10 - val);
  16772 + }
  16773 + if (val==0.5) return 16;
  16774 + if (cimg::type<double>::is_nan(val)) return 28;
  16775 + if (mempos>=mem._width) { mem.resize(-200,1,1,1,0); memtype.resize(-200,1,1,1,0); }
  16776 + const unsigned int pos = mempos++;
  16777 + mem[pos] = val;
  16778 + memtype[pos] = 1; // Set constant property
  16779 + return pos;
14574 } 16780 }
14575 - static double mp_modulo(_cimg_math_parser& mp) {  
14576 - return cimg::mod(mp.mem[mp.opcode(2)],mp.mem[mp.opcode(3)]); 16781 +
  16782 + // Insert code instructions for processing scalars.
  16783 + unsigned int scalar() { // Insert new scalar in memory.
  16784 + if (mempos>=mem._width) { mem.resize(-200,1,1,1,0); memtype.resize(mem._width,1,1,1,0); }
  16785 + return mempos++;
14577 } 16786 }
14578 - static double mp_bitwise_and(_cimg_math_parser& mp) {  
14579 - return ((unsigned long)mp.mem[mp.opcode(2)] & (unsigned long)mp.mem[mp.opcode(3)]); 16787 +
  16788 + unsigned int scalar0(const mp_func op) {
  16789 + const unsigned int pos = scalar();
  16790 + CImg<uptrT>::vector((uptrT)op,pos).move_to(code);
  16791 + return pos;
14580 } 16792 }
14581 - static double mp_bitwise_or(_cimg_math_parser& mp) {  
14582 - return ((unsigned long)mp.mem[mp.opcode(2)] | (unsigned long)mp.mem[mp.opcode(3)]); 16793 +
  16794 + unsigned int scalar1(const mp_func op, const unsigned int arg1) {
  16795 + const unsigned int pos =
  16796 + arg1>_cimg_mp_c && _cimg_mp_is_temp(arg1)?arg1:scalar();
  16797 + CImg<uptrT>::vector((uptrT)op,pos,arg1).move_to(code);
  16798 + return pos;
14583 } 16799 }
14584 - static double mp_pow(_cimg_math_parser& mp) {  
14585 - const double v = mp.mem[mp.opcode(2)], p = mp.mem[mp.opcode(3)];  
14586 - if (p==0) return 1;  
14587 - if (p==0.5) return std::sqrt(v);  
14588 - if (p==1) return v;  
14589 - if (p==2) return v*v;  
14590 - if (p==3) return v*v*v;  
14591 - if (p==4) return v*v*v*v;  
14592 - return std::pow(v,p); 16800 +
  16801 + unsigned int scalar2(const mp_func op, const unsigned int arg1, const unsigned int arg2) {
  16802 + const unsigned int pos =
  16803 + arg1>_cimg_mp_c && _cimg_mp_is_temp(arg1)?arg1:
  16804 + arg2>_cimg_mp_c && _cimg_mp_is_temp(arg2)?arg2:scalar();
  16805 + CImg<uptrT>::vector((uptrT)op,pos,arg1,arg2).move_to(code);
  16806 + return pos;
14593 } 16807 }
14594 - static double mp_sin(_cimg_math_parser& mp) {  
14595 - return std::sin(mp.mem[mp.opcode(2)]); 16808 +
  16809 + unsigned int scalar3(const mp_func op,
  16810 + const unsigned int arg1, const unsigned int arg2, const unsigned int arg3) {
  16811 + const unsigned int pos =
  16812 + arg1>_cimg_mp_c && _cimg_mp_is_temp(arg1)?arg1:
  16813 + arg2>_cimg_mp_c && _cimg_mp_is_temp(arg2)?arg2:
  16814 + arg3>_cimg_mp_c && _cimg_mp_is_temp(arg3)?arg3:scalar();
  16815 + CImg<uptrT>::vector((uptrT)op,pos,arg1,arg2,arg3).move_to(code);
  16816 + return pos;
14596 } 16817 }
14597 - static double mp_cos(_cimg_math_parser& mp) {  
14598 - return std::cos(mp.mem[mp.opcode(2)]); 16818 +
  16819 + unsigned int scalar6(const mp_func op,
  16820 + const unsigned int arg1, const unsigned int arg2, const unsigned int arg3,
  16821 + const unsigned int arg4, const unsigned int arg5, const unsigned int arg6) {
  16822 + const unsigned int pos =
  16823 + arg1>_cimg_mp_c && _cimg_mp_is_temp(arg1)?arg1:
  16824 + arg2>_cimg_mp_c && _cimg_mp_is_temp(arg2)?arg2:
  16825 + arg3>_cimg_mp_c && _cimg_mp_is_temp(arg3)?arg3:
  16826 + arg4>_cimg_mp_c && _cimg_mp_is_temp(arg4)?arg4:
  16827 + arg5>_cimg_mp_c && _cimg_mp_is_temp(arg5)?arg5:
  16828 + arg6>_cimg_mp_c && _cimg_mp_is_temp(arg6)?arg6:scalar();
  16829 + CImg<uptrT>::vector((uptrT)op,pos,arg1,arg2,arg3,arg4,arg5,arg6).move_to(code);
  16830 + return pos;
14599 } 16831 }
14600 - static double mp_tan(_cimg_math_parser& mp) {  
14601 - return std::tan(mp.mem[mp.opcode(2)]); 16832 +
  16833 + unsigned int scalar7(const mp_func op,
  16834 + const unsigned int arg1, const unsigned int arg2, const unsigned int arg3,
  16835 + const unsigned int arg4, const unsigned int arg5, const unsigned int arg6,
  16836 + const unsigned int arg7) {
  16837 + const unsigned int pos =
  16838 + arg1>_cimg_mp_c && _cimg_mp_is_temp(arg1)?arg1:
  16839 + arg2>_cimg_mp_c && _cimg_mp_is_temp(arg2)?arg2:
  16840 + arg3>_cimg_mp_c && _cimg_mp_is_temp(arg3)?arg3:
  16841 + arg4>_cimg_mp_c && _cimg_mp_is_temp(arg4)?arg4:
  16842 + arg5>_cimg_mp_c && _cimg_mp_is_temp(arg5)?arg5:
  16843 + arg6>_cimg_mp_c && _cimg_mp_is_temp(arg6)?arg6:
  16844 + arg7>_cimg_mp_c && _cimg_mp_is_temp(arg7)?arg7:scalar();
  16845 + CImg<uptrT>::vector((uptrT)op,pos,arg1,arg2,arg3,arg4,arg5,arg6,arg7).move_to(code);
  16846 + return pos;
14602 } 16847 }
14603 - static double mp_asin(_cimg_math_parser& mp) {  
14604 - return std::asin(mp.mem[mp.opcode(2)]); 16848 +
  16849 + // Return a string that defines the calling function + the user-defined function scope.
  16850 + CImg<charT> calling_function_s() const {
  16851 + CImg<charT> res;
  16852 + const unsigned int
  16853 + l1 = calling_function?std::strlen(calling_function):0,
  16854 + l2 = user_function?std::strlen(user_function):0;
  16855 + if (l2) {
  16856 + res.assign(l1 + l2 + 48);
  16857 + cimg_snprintf(res,res._width,"%s(): When substituting function '%s()'",calling_function,user_function);
  16858 + } else {
  16859 + res.assign(l1 + l2 + 4);
  16860 + cimg_snprintf(res,res._width,"%s()",calling_function);
  16861 + }
  16862 + return res;
14605 } 16863 }
  16864 +
  16865 + // Return true if specified argument can be a part of an allowed variable name.
  16866 + bool is_varchar(const char c) const {
  16867 + return (c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9') || c=='_';
  16868 + }
  16869 +
  16870 + // Insert code instructions for processing vectors.
  16871 + bool is_tmp_vector(const unsigned int arg) const {
  16872 + unsigned int siz = _cimg_mp_vector_size(arg);
  16873 + if (siz>8) return false;
  16874 + const int *ptr = memtype.data(arg + 1);
  16875 + bool is_tmp = true;
  16876 + while (siz-->0) if (*(ptr++)) { is_tmp = false; break; }
  16877 + return is_tmp;
  16878 + }
  16879 +
  16880 + void set_variable_vector(const unsigned int arg) {
  16881 + unsigned int siz = _cimg_mp_vector_size(arg);
  16882 + int *ptr = memtype.data(arg + 1);
  16883 + while (siz-->0) *(ptr++) = -1;
  16884 + }
  16885 +
  16886 + unsigned int vector(const unsigned int siz) { // Insert new vector of specified size in memory.
  16887 + if (mempos + siz>=mem._width) {
  16888 + mem.resize(2*mem._width + siz,1,1,1,0);
  16889 + memtype.resize(mem._width,1,1,1,0);
  16890 + }
  16891 + const unsigned int pos = mempos++;
  16892 + mem[pos] = cimg::type<double>::nan();
  16893 + memtype[pos] = siz + 1;
  16894 + mempos+=siz;
  16895 + return pos;
  16896 + }
  16897 +
  16898 + unsigned int vector_copy(const unsigned int arg) { // Insert new copy of specified vector in memory.
  16899 + const unsigned int
  16900 + siz = _cimg_mp_vector_size(arg),
  16901 + pos = vector(siz);
  16902 + CImg<uptrT>::vector((uptrT)mp_vector_copy,pos,arg,siz).move_to(code);
  16903 + return pos;
  16904 + }
  16905 +
  16906 + unsigned int vector1_v(const mp_func op, const unsigned int arg1) {
  16907 + const unsigned int
  16908 + siz = _cimg_mp_vector_size(arg1),
  16909 + pos = is_tmp_vector(arg1)?arg1:vector(siz);
  16910 + CImg<uptrT>::vector((uptrT)mp_vector_map_v,pos,siz,(uptrT)op,arg1).move_to(code);
  16911 + return pos;
  16912 + }
  16913 +
  16914 + unsigned int vector2_vv(const mp_func op, const unsigned int arg1, const unsigned int arg2) {
  16915 + const unsigned int
  16916 + siz = _cimg_mp_vector_size(arg1),
  16917 + pos = is_tmp_vector(arg1)?arg1:is_tmp_vector(arg2)?arg2:vector(siz);
  16918 + CImg<uptrT>::vector((uptrT)mp_vector_map_vv,pos,siz,(uptrT)op,arg1,arg2).move_to(code);
  16919 + return pos;
  16920 + }
  16921 +
  16922 + unsigned int vector2_vs(const mp_func op, const unsigned int arg1, const unsigned int arg2) {
  16923 + const unsigned int
  16924 + siz = _cimg_mp_vector_size(arg1),
  16925 + pos = is_tmp_vector(arg1)?arg1:vector(siz);
  16926 + CImg<uptrT>::vector((uptrT)mp_vector_map_vs,pos,siz,(uptrT)op,arg1,arg2).move_to(code);
  16927 + return pos;
  16928 + }
  16929 +
  16930 + unsigned int vector2_sv(const mp_func op, const unsigned int arg1, const unsigned int arg2) {
  16931 + const unsigned int
  16932 + siz = _cimg_mp_vector_size(arg2),
  16933 + pos = is_tmp_vector(arg2)?arg2:vector(siz);
  16934 + CImg<uptrT>::vector((uptrT)mp_vector_map_sv,pos,siz,(uptrT)op,arg1,arg2).move_to(code);
  16935 + return pos;
  16936 + }
  16937 +
  16938 + unsigned int vector3_vss(const mp_func op, const unsigned int arg1, const unsigned int arg2,
  16939 + const unsigned int arg3) {
  16940 + const unsigned int
  16941 + siz = _cimg_mp_vector_size(arg1),
  16942 + pos = is_tmp_vector(arg1)?arg1:vector(siz);
  16943 + CImg<uptrT>::vector((uptrT)mp_vector_map_vss,pos,siz,(uptrT)op,arg1,arg2,arg3).move_to(code);
  16944 + return pos;
  16945 + }
  16946 +
  16947 + // Check if a memory slot is a positive integer constant scalar value.
  16948 + void check_constant(const unsigned int arg, const unsigned int n_arg, const char *const s_op,
  16949 + const bool is_strictly_positive,
  16950 + const char *const ss, char *const se, const char saved_char) {
  16951 + _cimg_mp_check_type(arg,n_arg,s_op,1,0);
  16952 + if (!_cimg_mp_is_constant(arg) || mem[arg]<(is_strictly_positive?1:0) || (double)(int)mem[arg]!=mem[arg]) {
  16953 + const char *s_arg = !n_arg?"":n_arg==1?"First ":n_arg==2?"Second ":n_arg==3?"Third ":"One ";
  16954 + *se = saved_char; cimg::strellipsize(expr,64);
  16955 + throw CImgArgumentException("[_cimg_math_parser] "
  16956 + "CImg<%s>::%s(): %s: %s%s (of type '%s') is not a %spositive integer constant, "
  16957 + "in expression '%s%s%s'.",
  16958 + pixel_type(),_cimg_mp_calling_function,s_op,
  16959 + s_arg,*s_arg?"argument":"Argument",s_type(arg)._data,
  16960 + is_strictly_positive?"strictly ":"",
  16961 + (ss - 4)>expr._data?"...":"",
  16962 + (ss - 4)>expr._data?ss - 4:expr._data,
  16963 + se<&expr.back()?"...":"");
  16964 + }
  16965 + }
  16966 +
  16967 + // Check a matrix is square.
  16968 + void check_matrix_square(const unsigned int arg, const unsigned int n_arg, const char *const s_op,
  16969 + const char *const ss, char *const se, const char saved_char) {
  16970 + _cimg_mp_check_type(arg,n_arg,s_op,2,0);
  16971 + const unsigned int
  16972 + siz = _cimg_mp_vector_size(arg),
  16973 + n = (unsigned int)std::sqrt((float)siz);
  16974 + if (n*n!=siz) {
  16975 + const char *s_arg;
  16976 + if (*s_op!='F') s_arg = !n_arg?"":n_arg==1?"Left-hand ":"Right-hand ";
  16977 + else s_arg = !n_arg?"":n_arg==1?"First ":n_arg==2?"Second ":n_arg==3?"Third ":"One ";
  16978 + *se = saved_char; cimg::strellipsize(expr,64);
  16979 + throw CImgArgumentException("[_cimg_math_parser] "
  16980 + "CImg<%s>::%s(): %s: %s%s (of type '%s') "
  16981 + "cannot be considered as a square matrix, in expression '%s%s%s'.",
  16982 + pixel_type(),_cimg_mp_calling_function,s_op,
  16983 + s_arg,*s_op=='F'?(*s_arg?"argument":"Argument"):(*s_arg?"operand":"Operand"),
  16984 + s_type(arg)._data,
  16985 + (ss - 4)>expr._data?"...":"",
  16986 + (ss - 4)>expr._data?ss - 4:expr._data,
  16987 + se<&expr.back()?"...":"");
  16988 + }
  16989 + }
  16990 +
  16991 + // Check type compatibility for one argument.
  16992 + // Bits of 'mode' tells what types are allowed:
  16993 + // { 1 = scalar | 2 = vectorN }.
  16994 + // If 'N' is not zero, it also restricts the vectors to be of size N only.
  16995 + void check_type(const unsigned int arg, const unsigned int n_arg, const char *const s_op,
  16996 + const unsigned int mode, const unsigned int N,
  16997 + const char *const ss, char *const se, const char saved_char) {
  16998 + const bool
  16999 + is_scalar = _cimg_mp_is_scalar(arg),
  17000 + is_vector = _cimg_mp_is_vector(arg) && (!N || _cimg_mp_vector_size(arg)==N);
  17001 + bool cond = false;
  17002 + if (mode&1) cond|=is_scalar;
  17003 + if (mode&2) cond|=is_vector;
  17004 + if (!cond) {
  17005 + const char *s_arg;
  17006 + if (*s_op!='F') s_arg = !n_arg?"":n_arg==1?"Left-hand ":"Right-hand ";
  17007 + else s_arg = !n_arg?"":n_arg==1?"First ":n_arg==2?"Second ":n_arg==3?"Third ":"One ";
  17008 + CImg<charT> sb_type(32);
  17009 + if (mode==1) cimg_snprintf(sb_type,sb_type._width,"'scalar'");
  17010 + else if (mode==2) {
  17011 + if (N) cimg_snprintf(sb_type,sb_type._width,"'vector%u'",N);
  17012 + else cimg_snprintf(sb_type,sb_type._width,"'vector'");
  17013 + } else {
  17014 + if (N) cimg_snprintf(sb_type,sb_type._width,"'scalar' or 'vector%u'",N);
  17015 + else cimg_snprintf(sb_type,sb_type._width,"'scalar' or 'vector'");
  17016 + }
  17017 + *se = saved_char; cimg::strellipsize(expr,64);
  17018 + throw CImgArgumentException("[_cimg_math_parser] "
  17019 + "CImg<%s>::%s(): %s: %s%s has invalid type '%s' (should be %s), "
  17020 + "in expression '%s%s%s'.",
  17021 + pixel_type(),_cimg_mp_calling_function,s_op,
  17022 + s_arg,*s_op=='F'?(*s_arg?"argument":"Argument"):(*s_arg?"operand":"Operand"),
  17023 + s_type(arg)._data,sb_type._data,
  17024 + (ss - 4)>expr._data?"...":"",
  17025 + (ss - 4)>expr._data?ss - 4:expr._data,
  17026 + se<&expr.back()?"...":"");
  17027 + }
  17028 + }
  17029 +
  17030 + // Check a vector is not 0-dimensional, or with unknown dimension at compile time.
  17031 + void check_vector0(const unsigned int dim, const char *const s_op,
  17032 + const char *const ss, char *const se, const char saved_char) {
  17033 + if (!dim) {
  17034 + *se = saved_char; cimg::strellipsize(expr,64);
  17035 + throw CImgArgumentException("[_cimg_math_parser] "
  17036 + "CImg<%s>::%s(): %s: Invalid construction of a 0-dimensional vector, "
  17037 + "in expression '%s%s%s'.",
  17038 + pixel_type(),_cimg_mp_calling_function,s_op,
  17039 + (ss - 4)>expr._data?"...":"",
  17040 + (ss - 4)>expr._data?ss - 4:expr._data,
  17041 + se<&expr.back()?"...":"");
  17042 + } else if (dim==~0U) {
  17043 + *se = saved_char; cimg::strellipsize(expr,64);
  17044 + throw CImgArgumentException("[_cimg_math_parser] "
  17045 + "CImg<%s>::%s(): %s: Invalid construction of a vector with dynamic size, "
  17046 + "in expression '%s%s%s'.",
  17047 + pixel_type(),_cimg_mp_calling_function,s_op,
  17048 + (ss - 4)>expr._data?"...":"",
  17049 + (ss - 4)>expr._data?ss - 4:expr._data,
  17050 + se<&expr.back()?"...":"");
  17051 + }
  17052 + }
  17053 +
  17054 + // Evaluation functions, known by the parser.
  17055 + // Defining these functions 'static' ensures that sizeof(mp_func)==sizeof(uptrT),
  17056 + // so we can store pointers to them directly in the opcode vectors.
  17057 +#ifdef _mp_arg
  17058 +#undef _mp_arg
  17059 +#endif
  17060 +#define _mp_arg(x) mp.mem[mp.opcode[x]]
  17061 +
  17062 + static double mp_abs(_cimg_math_parser& mp) {
  17063 + return cimg::abs(_mp_arg(2));
  17064 + }
  17065 +
  17066 + static double mp_add(_cimg_math_parser& mp) {
  17067 + return _mp_arg(2) + _mp_arg(3);
  17068 + }
  17069 +
14606 static double mp_acos(_cimg_math_parser& mp) { 17070 static double mp_acos(_cimg_math_parser& mp) {
14607 - return std::acos(mp.mem[mp.opcode(2)]); 17071 + return std::acos(_mp_arg(2));
14608 } 17072 }
14609 - static double mp_atan(_cimg_math_parser& mp) {  
14610 - return std::atan(mp.mem[mp.opcode(2)]); 17073 +
  17074 + static double mp_arg(_cimg_math_parser& mp) {
  17075 + const int _ind = (int)_mp_arg(2);
  17076 + const unsigned int nb_args = mp.opcode._height - 2, ind = _ind<0?_ind + nb_args:(unsigned int)_ind;
  17077 + if (ind>=nb_args) return 0;
  17078 + return _mp_arg(ind + 2);
14611 } 17079 }
14612 - static double mp_sinh(_cimg_math_parser& mp) {  
14613 - return std::sinh(mp.mem[mp.opcode(2)]); 17080 +
  17081 + static double mp_argmin(_cimg_math_parser& mp) {
  17082 + double val = _mp_arg(2);
  17083 + unsigned int argval = 0;
  17084 + for (unsigned int i = 3; i<mp.opcode._height; ++i) {
  17085 + const double _val = _mp_arg(i);
  17086 + if (_val<val) { val = _val; argval = i - 2; }
  17087 + }
  17088 + return (double)argval;
14614 } 17089 }
14615 - static double mp_cosh(_cimg_math_parser& mp) {  
14616 - return std::cosh(mp.mem[mp.opcode(2)]); 17090 +
  17091 + static double mp_argmax(_cimg_math_parser& mp) {
  17092 + double val = _mp_arg(2);
  17093 + unsigned int argval = 0;
  17094 + for (unsigned int i = 3; i<mp.opcode._height; ++i) {
  17095 + const double _val = _mp_arg(i);
  17096 + if (_val>val) { val = _val; argval = i - 2; }
  17097 + }
  17098 + return (double)argval;
14617 } 17099 }
14618 - static double mp_tanh(_cimg_math_parser& mp) {  
14619 - return std::tanh(mp.mem[mp.opcode(2)]); 17100 +
  17101 + static double mp_asin(_cimg_math_parser& mp) {
  17102 + return std::asin(_mp_arg(2));
14620 } 17103 }
14621 - static double mp_log10(_cimg_math_parser& mp) {  
14622 - return std::log10(mp.mem[mp.opcode(2)]); 17104 +
  17105 + static double mp_atan(_cimg_math_parser& mp) {
  17106 + return std::atan(_mp_arg(2));
14623 } 17107 }
14624 - static double mp_log2(_cimg_math_parser& mp) {  
14625 - return cimg::log2(mp.mem[mp.opcode(2)]); 17108 +
  17109 + static double mp_atan2(_cimg_math_parser& mp) {
  17110 + return std::atan2(_mp_arg(2),_mp_arg(3));
14626 } 17111 }
14627 - static double mp_log(_cimg_math_parser& mp) {  
14628 - return std::log(mp.mem[mp.opcode(2)]); 17112 +
  17113 + static double mp_bitwise_and(_cimg_math_parser& mp) {
  17114 + return (double)((unsigned long)_mp_arg(2) & (unsigned long)_mp_arg(3));
14629 } 17115 }
14630 - static double mp_exp(_cimg_math_parser& mp) {  
14631 - return std::exp(mp.mem[mp.opcode(2)]); 17116 +
  17117 + static double mp_bitwise_left_shift(_cimg_math_parser& mp) {
  17118 + return (double)((long)_mp_arg(2)<<(unsigned int)_mp_arg(3));
14632 } 17119 }
14633 - static double mp_sqr(_cimg_math_parser& mp) {  
14634 - return cimg::sqr(mp.mem[mp.opcode(2)]); 17120 +
  17121 + static double mp_bitwise_not(_cimg_math_parser& mp) {
  17122 + return (double)~(unsigned long)_mp_arg(2);
14635 } 17123 }
14636 - static double mp_sqrt(_cimg_math_parser& mp) {  
14637 - return std::sqrt(mp.mem[mp.opcode(2)]); 17124 +
  17125 + static double mp_bitwise_or(_cimg_math_parser& mp) {
  17126 + return (double)((unsigned long)_mp_arg(2) | (unsigned long)_mp_arg(3));
14638 } 17127 }
  17128 +
  17129 + static double mp_bitwise_right_shift(_cimg_math_parser& mp) {
  17130 + return (double)((long)_mp_arg(2)>>(unsigned int)_mp_arg(3));
  17131 + }
  17132 +
14639 static double mp_cbrt(_cimg_math_parser& mp) { 17133 static double mp_cbrt(_cimg_math_parser& mp) {
14640 - return std::pow(mp.mem[mp.opcode(2)],1.0/3); 17134 + return std::pow(_mp_arg(2),1.0/3);
14641 } 17135 }
14642 - static double mp_hypot(_cimg_math_parser& mp) {  
14643 - double  
14644 - x = cimg::abs(mp.mem[mp.opcode(2)]),  
14645 - y = cimg::abs(mp.mem[mp.opcode(3)]),  
14646 - t;  
14647 - if (x<y) { t = x; x = y; } else t = y;  
14648 - if (x>0) { t/=x; return x*std::sqrt(1+t*t); }  
14649 - return 0; 17136 +
  17137 + static double mp_complex_conj(_cimg_math_parser& mp) {
  17138 + const double *ptrs = &_mp_arg(2) + 1;
  17139 + double *ptrd = &_mp_arg(1) + 1;
  17140 + *(ptrd++) = *(ptrs++);
  17141 + *ptrd = -*(ptrs);
  17142 + return cimg::type<double>::nan();
14650 } 17143 }
14651 - static double mp_norm(_cimg_math_parser& mp) {  
14652 - const unsigned int norm_type = (unsigned int)mp.opcode(2);  
14653 - double res = 0;  
14654 - switch (norm_type) {  
14655 - case 0 : // L0-norm.  
14656 - for (unsigned int i = 3; i<mp.opcode._height; ++i)  
14657 - res+=mp.mem[mp.opcode(i)]==0?0:1;  
14658 - break;  
14659 - case 1 : // L1-norm.  
14660 - for (unsigned int i = 3; i<mp.opcode._height; ++i)  
14661 - res+=cimg::abs(mp.mem[mp.opcode(i)]);  
14662 - break;  
14663 - case 2 : // L2-norm.  
14664 - for (unsigned int i = 3; i<mp.opcode._height; ++i) {  
14665 - const double val = mp.mem[mp.opcode(i)];  
14666 - res+=val*val;  
14667 - }  
14668 - res = std::sqrt(res);  
14669 - break;  
14670 - case ~0U : // Linf-norm.  
14671 - for (unsigned int i = 3; i<mp.opcode._height; ++i) {  
14672 - const double val = cimg::abs(mp.mem[mp.opcode(i)]);  
14673 - if (val>res) res = val;  
14674 - }  
14675 - break;  
14676 - default: // Lp-norm.  
14677 - for (unsigned int i = 3; i<mp.opcode._height; ++i)  
14678 - res+=std::pow(cimg::abs(mp.mem[mp.opcode(i)]),(double)norm_type);  
14679 - res = std::pow(res,1.0/norm_type); 17144 +
  17145 + static double mp_complex_div_sv(_cimg_math_parser& mp) {
  17146 + const double
  17147 + *ptr2 = &_mp_arg(3) + 1,
  17148 + r1 = _mp_arg(2),
  17149 + r2 = *(ptr2++), i2 = *ptr2;
  17150 + double *ptrd = &_mp_arg(1) + 1;
  17151 + const double denom = r2*r2 + i2*i2;
  17152 + *(ptrd++) = r1*r2/denom;
  17153 + *ptrd = -r1*i2/denom;
  17154 + return cimg::type<double>::nan();
  17155 + }
  17156 +
  17157 + static double mp_complex_div_vv(_cimg_math_parser& mp) {
  17158 + const double
  17159 + *ptr1 = &_mp_arg(2) + 1, *ptr2 = &_mp_arg(3) + 1,
  17160 + r1 = *(ptr1++), i1 = *ptr1,
  17161 + r2 = *(ptr2++), i2 = *ptr2;
  17162 + double *ptrd = &_mp_arg(1) + 1;
  17163 + const double denom = r2*r2 + i2*i2;
  17164 + *(ptrd++) = (r1*r2 + i1*i2)/denom;
  17165 + *ptrd = (r2*i1 - r1*i2)/denom;
  17166 + return cimg::type<double>::nan();
  17167 + }
  17168 +
  17169 + static double mp_complex_exp(_cimg_math_parser& mp) {
  17170 + double *ptrd = &_mp_arg(1) + 1;
  17171 + const double *ptrs = &_mp_arg(2) + 1, r = *(ptrs++), i = *(ptrs), er = std::exp(r);
  17172 + *(ptrd++) = er*std::cos(i);
  17173 + *(ptrd++) = er*std::sin(i);
  17174 + return cimg::type<double>::nan();
  17175 + }
  17176 +
  17177 + static double mp_complex_log(_cimg_math_parser& mp) {
  17178 + double *ptrd = &_mp_arg(1) + 1;
  17179 + const double *ptrs = &_mp_arg(2) + 1, r = *(ptrs++), i = *(ptrs);
  17180 + *(ptrd++) = std::log(std::sqrt(r*r + i*i));
  17181 + *(ptrd++) = std::atan2(i,r);
  17182 + return cimg::type<double>::nan();
  17183 + }
  17184 +
  17185 + static double mp_complex_mul(_cimg_math_parser& mp) {
  17186 + const double
  17187 + *ptr1 = &_mp_arg(2) + 1, *ptr2 = &_mp_arg(3) + 1,
  17188 + r1 = *(ptr1++), i1 = *ptr1,
  17189 + r2 = *(ptr2++), i2 = *ptr2;
  17190 + double *ptrd = &_mp_arg(1) + 1;
  17191 + *(ptrd++) = r1*r2 - i1*i2;
  17192 + *(ptrd++) = r1*i2 + r2*i1;
  17193 + return cimg::type<double>::nan();
  17194 + }
  17195 +
  17196 + static void _mp_complex_pow(const double r1, const double i1,
  17197 + const double r2, const double i2,
  17198 + double *ptrd) {
  17199 + double ro, io;
  17200 + if (cimg::abs(i2)<1e-15) { // Exponent is real
  17201 + if (cimg::abs(r1)<1e-15 && cimg::abs(i1)<1e-15) {
  17202 + if (cimg::abs(r2)<1e-15) { ro = 1; io = 0; }
  17203 + else ro = io = 0;
  17204 + } else {
  17205 + const double
  17206 + mod1_2 = r1*r1 + i1*i1,
  17207 + phi1 = std::atan2(i1,r1),
  17208 + modo = std::pow(mod1_2,0.5*r2),
  17209 + phio = r2*phi1;
  17210 + ro = modo*std::cos(phio);
  17211 + io = modo*std::sin(phio);
  17212 + }
  17213 + } else { // Exponent is complex
  17214 + if (cimg::abs(r1)<1e-15 && cimg::abs(i1)<1e-15) ro = io = 0;
  17215 + const double
  17216 + mod1_2 = r1*r1 + i1*i1,
  17217 + phi1 = std::atan2(i1,r1),
  17218 + modo = std::pow(mod1_2,0.5*r2)*std::exp(-i2*phi1),
  17219 + phio = r2*phi1 + 0.5*i2*std::log(mod1_2);
  17220 + ro = modo*std::cos(phio);
  17221 + io = modo*std::sin(phio);
14680 } 17222 }
14681 - return res>0?res:0.0; 17223 + *(ptrd++) = ro;
  17224 + *ptrd = io;
14682 } 17225 }
14683 - static double mp_sign(_cimg_math_parser& mp) {  
14684 - return cimg::sign(mp.mem[mp.opcode(2)]); 17226 +
  17227 + static double mp_complex_pow_sv(_cimg_math_parser& mp) {
  17228 + const double val1 = _mp_arg(2), *ptr2 = &_mp_arg(3) + 1;
  17229 + double *ptrd = &_mp_arg(1) + 1;
  17230 + _mp_complex_pow(val1,0,ptr2[0],ptr2[1],ptrd);
  17231 + return cimg::type<double>::nan();
  17232 + }
  17233 +
  17234 + static double mp_complex_pow_vs(_cimg_math_parser& mp) {
  17235 + const double *ptr1 = &_mp_arg(2) + 1, val2 = _mp_arg(3);
  17236 + double *ptrd = &_mp_arg(1) + 1;
  17237 + _mp_complex_pow(ptr1[0],ptr1[1],val2,0,ptrd);
  17238 + return cimg::type<double>::nan();
  17239 + }
  17240 +
  17241 + static double mp_complex_pow_vv(_cimg_math_parser& mp) {
  17242 + const double *ptr1 = &_mp_arg(2) + 1, *ptr2 = &_mp_arg(3) + 1;
  17243 + double *ptrd = &_mp_arg(1) + 1;
  17244 + _mp_complex_pow(ptr1[0],ptr1[1],ptr2[0],ptr2[1],ptrd);
  17245 + return cimg::type<double>::nan();
  17246 + }
  17247 +
  17248 + static double mp_cos(_cimg_math_parser& mp) {
  17249 + return std::cos(_mp_arg(2));
14685 } 17250 }
14686 - static double mp_time(_cimg_math_parser& mp) { 17251 +
  17252 + static double mp_cosh(_cimg_math_parser& mp) {
  17253 + return std::cosh(_mp_arg(2));
  17254 + }
  17255 +
  17256 + static double mp_cross(_cimg_math_parser& mp) {
  17257 + CImg<doubleT>
  17258 + vout(&_mp_arg(1) + 1,1,3,1,1,true),
  17259 + v1(&_mp_arg(2) + 1,1,3,1,1,true),
  17260 + v2(&_mp_arg(3) + 1,1,3,1,1,true);
  17261 + (vout = v1).cross(v2);
  17262 + return cimg::type<double>::nan();
  17263 + }
  17264 +
  17265 + static double mp_cut(_cimg_math_parser& mp) {
  17266 + double val = _mp_arg(2), cmin = _mp_arg(3), cmax = _mp_arg(4);
  17267 + return val<cmin?cmin:val>cmax?cmax:val;
  17268 + }
  17269 +
  17270 + static double mp_debug(_cimg_math_parser& mp) {
  17271 +#ifdef cimg_use_openmp
  17272 + const unsigned int n_thread = omp_get_thread_num();
  17273 +#else
  17274 + const unsigned int n_thread = 0;
  17275 +#endif
  17276 + CImg<charT> expr(mp.opcode._height - 3);
  17277 + const uptrT *ptrs = mp.opcode._data + 3;
  17278 + cimg_for(expr,ptrd,char) *ptrd = (char)*(ptrs++);
  17279 + cimg::strellipsize(expr);
  17280 + const uptrT g_target = mp.opcode[1];
  17281 + std::fprintf(cimg::output(),
  17282 + "\n[_cimg_math_parser] %p[thread #%u]:%*c"
  17283 + "Start debugging expression '%s', code length %u -> mem[%u] (memsize: %u)",
  17284 + (void*)&mp,n_thread,mp.debug_indent,' ',
  17285 + expr._data,(unsigned int)mp.opcode[2],(unsigned int)g_target,mp.mem._width);
  17286 + std::fflush(cimg::output());
  17287 + const CImg<uptrT> *const p_end = (++mp.p_code) + mp.opcode[2];
  17288 + CImg<uptrT> _op;
  17289 + mp.debug_indent+=3;
  17290 + for ( ; mp.p_code<p_end; ++mp.p_code) {
  17291 + const CImg<uptrT> &op = *mp.p_code;
  17292 + mp.opcode._data = op._data; mp.opcode._height = op._height;
  17293 +
  17294 + _op.assign(1,op._height - 1);
  17295 + const uptrT *ptrs = op._data + 1;
  17296 + for (uptrT *ptrd = _op._data, *const ptrde = _op._data + _op._height; ptrd<ptrde; ++ptrd)
  17297 + *ptrd = *(ptrs++);
  17298 +
  17299 + const uptrT target = mp.opcode[1];
  17300 + mp.mem[target] = _cimg_mp_defunc(mp);
  17301 + std::fprintf(cimg::output(),
  17302 + "\n[_cimg_math_parser] %p[thread #%u]:%*c"
  17303 + "Opcode %p = [ %p,%s ] -> mem[%u] = %g",
  17304 + (void*)&mp,n_thread,mp.debug_indent,' ',
  17305 + (void*)mp.opcode._data,(void*)*mp.opcode,_op.value_string().data(),
  17306 + (unsigned int)target,mp.mem[target]);
  17307 + std::fflush(cimg::output());
  17308 + }
  17309 + mp.debug_indent-=3;
  17310 + std::fprintf(cimg::output(),
  17311 + "\n[_cimg_math_parser] %p[thread #%u]:%*c"
  17312 + "End debugging expression '%s' -> mem[%u] = %g (memsize: %u)",
  17313 + (void*)&mp,n_thread,mp.debug_indent,' ',
  17314 + expr._data,(unsigned int)g_target,mp.mem[g_target],mp.mem._width);
  17315 + std::fflush(cimg::output());
  17316 + --mp.p_code;
  17317 + return mp.mem[g_target];
  17318 + }
  17319 +
  17320 + static double mp_decrement(_cimg_math_parser& mp) {
  17321 + return _mp_arg(2) - 1;
  17322 + }
  17323 +
  17324 + static double mp_dot(_cimg_math_parser& mp) {
  17325 + const unsigned int siz = (unsigned int)mp.opcode[4];
  17326 + return CImg<doubleT>(&_mp_arg(2) + 1,1,siz,1,1,true).
  17327 + dot(CImg<doubleT>(&_mp_arg(3) + 1,1,siz,1,1,true));
  17328 + }
  17329 +
  17330 + static double mp_dowhile(_cimg_math_parser& mp) {
  17331 + const uptrT
  17332 + mem_proc = mp.opcode[1],
  17333 + mem_cond = mp.opcode[2];
  17334 + const CImg<uptrT>
  17335 + *const p_proc = ++mp.p_code,
  17336 + *const p_end = p_proc + mp.opcode[3];
  17337 + do {
  17338 + for (mp.p_code = p_proc; mp.p_code<p_end; ++mp.p_code) { // Evaluate loop iteration + condition
  17339 + const CImg<uptrT> &op = *mp.p_code;
  17340 + mp.opcode._data = op._data; mp.opcode._height = op._height;
  17341 + const uptrT target = mp.opcode[1];
  17342 + mp.mem[target] = _cimg_mp_defunc(mp);
  17343 + }
  17344 + } while (mp.mem[mem_cond]);
  17345 + --mp.p_code;
  17346 + return mp.mem[mem_proc];
  17347 + }
  17348 +
  17349 + static double mp_div(_cimg_math_parser& mp) {
  17350 + return _mp_arg(2)/_mp_arg(3);
  17351 + }
  17352 +
  17353 + static double mp_eq(_cimg_math_parser& mp) {
  17354 + return (double)(_mp_arg(2)==_mp_arg(3));
  17355 + }
  17356 +
  17357 + static double mp_exp(_cimg_math_parser& mp) {
  17358 + return std::exp(_mp_arg(2));
  17359 + }
  17360 +
  17361 + static double mp_g(_cimg_math_parser& mp) {
14687 cimg::unused(mp); 17362 cimg::unused(mp);
14688 - return (double)cimg::time(); 17363 + return cimg::grand();
14689 } 17364 }
14690 - static double mp_abs(_cimg_math_parser& mp) {  
14691 - return cimg::abs(mp.mem[mp.opcode(2)]); 17365 +
  17366 + static double mp_gauss(_cimg_math_parser& mp) {
  17367 + const double x = _mp_arg(2), s = _mp_arg(3);
  17368 + return std::exp(-x*x/(2*s*s))/std::sqrt(2*s*s*cimg::PI);
14692 } 17369 }
14693 - static double mp_atan2(_cimg_math_parser& mp) {  
14694 - return std::atan2(mp.mem[mp.opcode(2)],mp.mem[mp.opcode(3)]); 17370 +
  17371 + static double mp_gt(_cimg_math_parser& mp) {
  17372 + return (double)(_mp_arg(2)>_mp_arg(3));
14695 } 17373 }
  17374 +
  17375 + static double mp_gte(_cimg_math_parser& mp) {
  17376 + return (double)(_mp_arg(2)>=_mp_arg(3));
  17377 + }
  17378 +
  17379 + static double mp_hypot(_cimg_math_parser& mp) {
  17380 + return cimg::hypot(_mp_arg(2),_mp_arg(3));
  17381 + }
  17382 +
  17383 + static double mp_i(_cimg_math_parser& mp) {
  17384 + return (double)mp.imgin.atXYZC((int)mp.mem[_cimg_mp_x],(int)mp.mem[_cimg_mp_y],
  17385 + (int)mp.mem[_cimg_mp_z],(int)mp.mem[_cimg_mp_c],0);
  17386 + }
  17387 +
14696 static double mp_if(_cimg_math_parser& mp) { 17388 static double mp_if(_cimg_math_parser& mp) {
14697 - const bool is_cond = (bool)mp.mem[mp.opcode(2)];  
14698 - const unsigned int mem_A = (unsigned int)mp.opcode(3), mem_B = (unsigned int)mp.opcode(4);  
14699 - const CImg<longT>  
14700 - *const pB = ++mp.p_code + mp.opcode(5),  
14701 - *const pE = pB + mp.opcode(6);  
14702 - if (is_cond) { // Evaluate on-the-fly only the correct argument.  
14703 - for ( ; mp.p_code<pB; ++mp.p_code) {  
14704 - const CImg<longT> &op = *mp.p_code; 17389 + const bool is_cond = (bool)_mp_arg(2);
  17390 + const uptrT
  17391 + mem_left = mp.opcode[3],
  17392 + mem_right = mp.opcode[4];
  17393 + const CImg<uptrT>
  17394 + *const p_right = ++mp.p_code + mp.opcode[5],
  17395 + *const p_end = p_right + mp.opcode[6];
  17396 + const unsigned int vtarget = mp.opcode[1], vsiz = mp.opcode[7];
  17397 + if (is_cond) {
  17398 + for ( ; mp.p_code<p_right; ++mp.p_code) {
  17399 + const CImg<uptrT> &op = *mp.p_code;
14705 mp.opcode._data = op._data; mp.opcode._height = op._height; 17400 mp.opcode._data = op._data; mp.opcode._height = op._height;
14706 - const unsigned int target = (unsigned int)mp.opcode[1]; 17401 + const uptrT target = mp.opcode[1];
14707 mp.mem[target] = _cimg_mp_defunc(mp); 17402 mp.mem[target] = _cimg_mp_defunc(mp);
14708 } 17403 }
14709 - mp.p_code = pE - 1;  
14710 - return mp.mem[mem_A]; 17404 + mp.p_code = p_end - 1;
  17405 + if (vsiz) std::memcpy(&mp.mem[vtarget] + 1,&mp.mem[mem_left] + 1,sizeof(double)*vsiz);
  17406 + return mp.mem[mem_left];
14711 } 17407 }
14712 - for (mp.p_code = pB; mp.p_code<pE; ++mp.p_code) {  
14713 - const CImg<longT> &op = *mp.p_code; 17408 + for (mp.p_code = p_right; mp.p_code<p_end; ++mp.p_code) {
  17409 + const CImg<uptrT> &op = *mp.p_code;
14714 mp.opcode._data = op._data; mp.opcode._height = op._height; 17410 mp.opcode._data = op._data; mp.opcode._height = op._height;
14715 - const unsigned int target = (unsigned int)mp.opcode[1]; 17411 + const uptrT target = mp.opcode[1];
14716 mp.mem[target] = _cimg_mp_defunc(mp); 17412 mp.mem[target] = _cimg_mp_defunc(mp);
14717 } 17413 }
14718 --mp.p_code; 17414 --mp.p_code;
14719 - return mp.mem[mem_B]; 17415 + if (vsiz) std::memcpy(&mp.mem[vtarget] + 1,&mp.mem[mem_right] + 1,sizeof(double)*vsiz);
  17416 + return mp.mem[mem_right];
14720 } 17417 }
14721 - static double mp_round(_cimg_math_parser& mp) {  
14722 - return cimg::round(mp.mem[mp.opcode(2)],mp.mem[mp.opcode(3)],(int)mp.mem[mp.opcode(4)]); 17418 +
  17419 + static double mp_increment(_cimg_math_parser& mp) {
  17420 + return _mp_arg(2) + 1;
  17421 + }
  17422 +
  17423 + static double mp_int(_cimg_math_parser& mp) {
  17424 + return (double)(long)_mp_arg(2);
  17425 + }
  17426 +
  17427 + static double mp_ioff(_cimg_math_parser& mp) {
  17428 + const unsigned int
  17429 + boundary_conditions = (unsigned int)_mp_arg(3);
  17430 + const CImg<T> &img = mp.imgin;
  17431 + const long
  17432 + off = (long)_mp_arg(2),
  17433 + whds = (long)img.size();
  17434 + if (off<0 || off>=whds)
  17435 + switch (boundary_conditions) {
  17436 + case 2 : // Periodic boundary
  17437 + if (img) return (double)img[cimg::mod(off,whds)];
  17438 + return 0;
  17439 + case 1 : // Neumann boundary
  17440 + if (img) return (double)(off<0?*img:img.back());
  17441 + return 0;
  17442 + default : // Dirichet boundary
  17443 + return 0;
  17444 + }
  17445 + return (double)img[off];
  17446 + }
  17447 +
  17448 + static double mp_isbool(_cimg_math_parser& mp) {
  17449 + const double val = _mp_arg(2);
  17450 + return (double)(val==0.0 || val==1.0);
  17451 + }
  17452 +
  17453 + static double mp_isin(_cimg_math_parser& mp) {
  17454 + const double val = _mp_arg(2);
  17455 + for (unsigned int i = 3; i<mp.opcode._height; ++i)
  17456 + if (val==_mp_arg(i)) return 1.0;
  17457 + return 0.0;
  17458 + }
  17459 +
  17460 + static double mp_isinf(_cimg_math_parser& mp) {
  17461 + return (double)cimg::type<double>::is_inf(_mp_arg(2));
  17462 + }
  17463 +
  17464 + static double mp_isint(_cimg_math_parser& mp) {
  17465 + return (double)(cimg::mod(_mp_arg(2),1.0)==0);
  17466 + }
  17467 +
  17468 + static double mp_isnan(_cimg_math_parser& mp) {
  17469 + return (double)cimg::type<double>::is_nan(_mp_arg(2));
14723 } 17470 }
  17471 +
14724 static double mp_ixyzc(_cimg_math_parser& mp) { 17472 static double mp_ixyzc(_cimg_math_parser& mp) {
  17473 + const unsigned int
  17474 + interpolation = (unsigned int)_mp_arg(6),
  17475 + boundary_conditions = (unsigned int)_mp_arg(7);
  17476 + const CImg<T> &img = mp.imgin;
14725 const double 17477 const double
14726 - x = mp.mem[mp.opcode(2)], y = mp.mem[mp.opcode(3)], z = mp.mem[mp.opcode(4)], c = mp.mem[mp.opcode(5)];  
14727 - const int i = (int)mp.mem[mp.opcode(6)], b = (int)mp.mem[mp.opcode(7)];  
14728 - if (i==0) { // Nearest neighbor interpolation.  
14729 - if (b==2) return (double)mp.reference.atXYZC(cimg::mod((int)x,mp.reference.width()),  
14730 - cimg::mod((int)y,mp.reference.height()),  
14731 - cimg::mod((int)z,mp.reference.depth()),  
14732 - cimg::mod((int)c,mp.reference.spectrum()));  
14733 - if (b==1) return (double)mp.reference.atXYZC((int)x,(int)y,(int)z,(int)c);  
14734 - return (double)mp.reference.atXYZC((int)x,(int)y,(int)z,(int)c,0);  
14735 - } else { // Linear interpolation.  
14736 - if (b==2) return (double)mp.reference.linear_atXYZC(cimg::mod((float)x,(float)mp.reference.width()),  
14737 - cimg::mod((float)y,(float)mp.reference.height()),  
14738 - cimg::mod((float)z,(float)mp.reference.depth()),  
14739 - cimg::mod((float)c,(float)mp.reference.spectrum()));  
14740 - if (b==1) return (double)mp.reference.linear_atXYZC((float)x,(float)y,(float)z,(float)c);  
14741 - return (double)mp.reference.linear_atXYZC((float)x,(float)y,(float)z,(float)c,0); 17478 + x = _mp_arg(2), y = _mp_arg(3),
  17479 + z = _mp_arg(4), c = _mp_arg(5);
  17480 + if (interpolation==0) { // Nearest neighbor interpolation
  17481 + if (boundary_conditions==2)
  17482 + return (double)img.atXYZC(cimg::mod((int)x,img.width()),
  17483 + cimg::mod((int)y,img.height()),
  17484 + cimg::mod((int)z,img.depth()),
  17485 + cimg::mod((int)c,img.spectrum()));
  17486 + if (boundary_conditions==1)
  17487 + return (double)img.atXYZC((int)x,(int)y,(int)z,(int)c);
  17488 + return (double)img.atXYZC((int)x,(int)y,(int)z,(int)c,0);
  17489 + } else { // Linear interpolation
  17490 + if (boundary_conditions==2)
  17491 + return (double)img.linear_atXYZC(cimg::mod((float)x,(float)img.width()),
  17492 + cimg::mod((float)y,(float)img.height()),
  17493 + cimg::mod((float)z,(float)img.depth()),
  17494 + cimg::mod((float)c,(float)img.spectrum()));
  17495 + if (boundary_conditions==1)
  17496 + return (double)img.linear_atXYZC((float)x,(float)y,(float)z,(float)c);
  17497 + return (double)img.linear_atXYZC((float)x,(float)y,(float)z,(float)c,0);
14742 } 17498 }
14743 } 17499 }
  17500 +
  17501 + static double mp_joff(_cimg_math_parser& mp) {
  17502 + const unsigned int
  17503 + boundary_conditions = (unsigned int)_mp_arg(3);
  17504 + const int
  17505 + ox = (int)mp.mem[_cimg_mp_x], oy = (int)mp.mem[_cimg_mp_y],
  17506 + oz = (int)mp.mem[_cimg_mp_z], oc = (int)mp.mem[_cimg_mp_c];
  17507 + const CImg<T> &img = mp.imgin;
  17508 + const long
  17509 + off = img.offset(ox,oy,oz,oc) + (long)_mp_arg(2),
  17510 + whds = (long)img.size();
  17511 + if (off<0 || off>=whds)
  17512 + switch (boundary_conditions) {
  17513 + case 2 : // Periodic boundary
  17514 + if (img) return (double)img[cimg::mod(off,whds)];
  17515 + return 0;
  17516 + case 1 : // Neumann boundary
  17517 + if (img) return (double)(off<0?*img:img.back());
  17518 + return 0;
  17519 + default : // Dirichet boundary
  17520 + return 0;
  17521 + }
  17522 + return (double)img[off];
  17523 + }
  17524 +
14744 static double mp_jxyzc(_cimg_math_parser& mp) { 17525 static double mp_jxyzc(_cimg_math_parser& mp) {
14745 - const double x = mp.mem[16], y = mp.mem[17], z = mp.mem[18], c = mp.mem[19]; 17526 + const unsigned int
  17527 + interpolation = (unsigned int)_mp_arg(6),
  17528 + boundary_conditions = (unsigned int)_mp_arg(7);
  17529 + const CImg<T> &img = mp.imgin;
14746 const double 17530 const double
14747 - dx = mp.mem[mp.opcode(2)], dy = mp.mem[mp.opcode(3)], dz = mp.mem[mp.opcode(4)], dc = mp.mem[mp.opcode(5)];  
14748 - const int i = (int)mp.mem[mp.opcode(6)], b = (int)mp.mem[mp.opcode(7)];  
14749 - if (i==0) { // Nearest neighbor interpolation.  
14750 - if (b==2) return (double)mp.reference.atXYZC(cimg::mod((int)(x + dx),mp.reference.width()),  
14751 - cimg::mod((int)(y + dy),mp.reference.height()),  
14752 - cimg::mod((int)(z + dz),mp.reference.depth()),  
14753 - cimg::mod((int)(c + dc),mp.reference.spectrum()));  
14754 - if (b==1) return (double)mp.reference.atXYZC((int)(x + dx),(int)(y + dy),(int)(z + dz),(int)(c + dc));  
14755 - return (double)mp.reference.atXYZC((int)(x + dx),(int)(y + dy),(int)(z + dz),(int)(c + dc),0);  
14756 - } else { // Linear interpolation.  
14757 - if (b==2)  
14758 - return (double)mp.reference.linear_atXYZC(cimg::mod((float)(x + dx),(float)mp.reference.width()),  
14759 - cimg::mod((float)(y + dy),(float)mp.reference.height()),  
14760 - cimg::mod((float)(z + dz),(float)mp.reference.depth()),  
14761 - cimg::mod((float)(c + dc),(float)mp.reference.spectrum()));  
14762 - if (b==1) return (double)mp.reference.linear_atXYZC((float)(x + dx),(float)(y + dy),  
14763 - (float)(z + dz),(float)(c + dc));  
14764 - return (double)mp.reference.linear_atXYZC((float)(x + dx),(float)(y + dy),(float)(z + dz),(float)(c + dc),0); 17531 + ox = mp.mem[_cimg_mp_x], oy = mp.mem[_cimg_mp_y],
  17532 + oz = mp.mem[_cimg_mp_z], oc = mp.mem[_cimg_mp_c],
  17533 + x = ox + _mp_arg(2), y = oy + _mp_arg(3),
  17534 + z = oz + _mp_arg(4), c = oc + _mp_arg(5);
  17535 + if (interpolation==0) { // Nearest neighbor interpolation
  17536 + if (boundary_conditions==2)
  17537 + return (double)img.atXYZC(cimg::mod((int)x,img.width()),
  17538 + cimg::mod((int)y,img.height()),
  17539 + cimg::mod((int)z,img.depth()),
  17540 + cimg::mod((int)c,img.spectrum()));
  17541 + if (boundary_conditions==1)
  17542 + return (double)img.atXYZC((int)x,(int)y,(int)z,(int)c);
  17543 + return (double)img.atXYZC((int)x,(int)y,(int)z,(int)c,0);
  17544 + } else { // Linear interpolation
  17545 + if (boundary_conditions==2)
  17546 + return (double)img.linear_atXYZC(cimg::mod((float)x,(float)img.width()),
  17547 + cimg::mod((float)y,(float)img.height()),
  17548 + cimg::mod((float)z,(float)img.depth()),
  17549 + cimg::mod((float)c,(float)img.spectrum()));
  17550 + if (boundary_conditions==1)
  17551 + return (double)img.linear_atXYZC((float)x,(float)y,(float)z,(float)c);
  17552 + return (double)img.linear_atXYZC((float)x,(float)y,(float)z,(float)c,0);
14765 } 17553 }
14766 } 17554 }
14767 - static double mp_min(_cimg_math_parser& mp) {  
14768 - double val = mp.mem[mp.opcode(2)];  
14769 - for (unsigned int i = 3; i<mp.opcode._height; ++i) val = cimg::min(val,mp.mem[mp.opcode(i)]); 17555 +
  17556 + static double mp_kth(_cimg_math_parser& mp) {
  17557 + CImg<doubleT> vals(mp.opcode._height - 3);
  17558 + double *p = vals.data();
  17559 + for (unsigned int i = 3; i<mp.opcode._height; ++i) *(p++) = _mp_arg(i);
  17560 + int ind = (int)cimg::round(_mp_arg(2));
  17561 + if (ind<0) ind+=vals.width() + 1;
  17562 + ind = cimg::max(1,cimg::min(vals.width(),ind));
  17563 + return vals.kth_smallest(ind - 1);
  17564 + }
  17565 +
  17566 + static double mp_list_depth(_cimg_math_parser& mp) {
  17567 + const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
  17568 + return (double)mp.listin[ind]._depth;
  17569 + }
  17570 +
  17571 + static double mp_list_height(_cimg_math_parser& mp) {
  17572 + const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
  17573 + return (double)mp.listin[ind]._height;
  17574 + }
  17575 +
  17576 + static double mp_list_ioff(_cimg_math_parser& mp) {
  17577 + const unsigned int
  17578 + ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()),
  17579 + boundary_conditions = (unsigned int)_mp_arg(4);
  17580 + const CImg<T> &img = mp.listin[ind];
  17581 + const long
  17582 + off = (long)_mp_arg(3),
  17583 + whds = (long)img.size();
  17584 + if (off<0 || off>=whds)
  17585 + switch (boundary_conditions) {
  17586 + case 2 : // Periodic boundary
  17587 + if (img) return (double)img[cimg::mod(off,whds)];
  17588 + return 0;
  17589 + case 1 : // Neumann boundary
  17590 + if (img) return (double)(off<0?*img:img.back());
  17591 + return 0;
  17592 + default : // Dirichet boundary
  17593 + return 0;
  17594 + }
  17595 + return (double)img[off];
  17596 + }
  17597 +
  17598 + static double mp_list_is_shared(_cimg_math_parser& mp) {
  17599 + const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
  17600 + return (double)mp.listin[ind]._is_shared;
  17601 + }
  17602 +
  17603 + static double mp_list_ixyzc(_cimg_math_parser& mp) {
  17604 + const unsigned int
  17605 + ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()),
  17606 + interpolation = (unsigned int)_mp_arg(7),
  17607 + boundary_conditions = (unsigned int)_mp_arg(8);
  17608 + const CImg<T> &img = mp.listin[ind];
  17609 + const double
  17610 + x = _mp_arg(3), y = _mp_arg(4),
  17611 + z = _mp_arg(5), c = _mp_arg(6);
  17612 + if (interpolation==0) { // Nearest neighbor interpolation
  17613 + if (boundary_conditions==2)
  17614 + return (double)img.atXYZC(cimg::mod((int)x,img.width()),
  17615 + cimg::mod((int)y,img.height()),
  17616 + cimg::mod((int)z,img.depth()),
  17617 + cimg::mod((int)c,img.spectrum()));
  17618 + if (boundary_conditions==1)
  17619 + return (double)img.atXYZC((int)x,(int)y,(int)z,(int)c);
  17620 + return (double)img.atXYZC((int)x,(int)y,(int)z,(int)c,0);
  17621 + } else { // Linear interpolation
  17622 + if (boundary_conditions==2)
  17623 + return (double)img.linear_atXYZC(cimg::mod((float)x,(float)img.width()),
  17624 + cimg::mod((float)y,(float)img.height()),
  17625 + cimg::mod((float)z,(float)img.depth()),
  17626 + cimg::mod((float)c,(float)img.spectrum()));
  17627 + if (boundary_conditions==1)
  17628 + return (double)img.linear_atXYZC((float)x,(float)y,(float)z,(float)c);
  17629 + return (double)img.linear_atXYZC((float)x,(float)y,(float)z,(float)c,0);
  17630 + }
  17631 + }
  17632 +
  17633 + static double mp_list_joff(_cimg_math_parser& mp) {
  17634 + const unsigned int
  17635 + ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()),
  17636 + boundary_conditions = (unsigned int)_mp_arg(4);
  17637 + const int
  17638 + ox = (int)mp.mem[_cimg_mp_x], oy = (int)mp.mem[_cimg_mp_y],
  17639 + oz = (int)mp.mem[_cimg_mp_z], oc = (int)mp.mem[_cimg_mp_c];
  17640 + const CImg<T> &img = mp.listin[ind];
  17641 + const long
  17642 + off = img.offset(ox,oy,oz,oc) + (long)_mp_arg(3),
  17643 + whds = (long)img.size();
  17644 + if (off<0 || off>=whds)
  17645 + switch (boundary_conditions) {
  17646 + case 2 : // Periodic boundary
  17647 + if (img) return (double)img(ind,cimg::mod(off,whds));
  17648 + return 0;
  17649 + case 1 : // Neumann boundary
  17650 + if (img) return (double)(off<0?*img:img.back());
  17651 + return 0;
  17652 + default : // Dirichet boundary
  17653 + return 0;
  17654 + }
  17655 + return (double)img[off];
  17656 + }
  17657 +
  17658 + static double mp_list_jxyzc(_cimg_math_parser& mp) {
  17659 + const unsigned int
  17660 + ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()),
  17661 + interpolation = (unsigned int)_mp_arg(7),
  17662 + boundary_conditions = (unsigned int)_mp_arg(8);
  17663 + const CImg<T> &img = mp.listin[ind];
  17664 + const double
  17665 + ox = mp.mem[_cimg_mp_x], oy = mp.mem[_cimg_mp_y],
  17666 + oz = mp.mem[_cimg_mp_z], oc = mp.mem[_cimg_mp_c],
  17667 + x = ox + _mp_arg(3), y = oy + _mp_arg(4),
  17668 + z = oz + _mp_arg(5), c = oc + _mp_arg(6);
  17669 + if (interpolation==0) { // Nearest neighbor interpolation
  17670 + if (boundary_conditions==2)
  17671 + return (double)img.atXYZC(cimg::mod((int)x,img.width()),
  17672 + cimg::mod((int)y,img.height()),
  17673 + cimg::mod((int)z,img.depth()),
  17674 + cimg::mod((int)c,img.spectrum()));
  17675 + if (boundary_conditions==1)
  17676 + return (double)img.atXYZC((int)x,(int)y,(int)z,(int)c);
  17677 + return (double)img.atXYZC((int)x,(int)y,(int)z,(int)c,0);
  17678 + } else { // Linear interpolation
  17679 + if (boundary_conditions==2)
  17680 + return (double)img.linear_atXYZC(cimg::mod((float)x,(float)img.width()),
  17681 + cimg::mod((float)y,(float)img.height()),
  17682 + cimg::mod((float)z,(float)img.depth()),
  17683 + cimg::mod((float)c,(float)img.spectrum()));
  17684 + if (boundary_conditions==1)
  17685 + return (double)img.linear_atXYZC((float)x,(float)y,(float)z,(float)c);
  17686 + return (double)img.linear_atXYZC((float)x,(float)y,(float)z,(float)c,0);
  17687 + }
  17688 + }
  17689 +
  17690 + static double mp_list_median(_cimg_math_parser& mp) {
  17691 + const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
  17692 + if (!mp.list_median) mp.list_median.assign(mp.listin._width);
  17693 + if (!mp.list_median[ind]) CImg<doubleT>::vector(mp.listin[ind].median()).move_to(mp.list_median[ind]);
  17694 + return *mp.list_median[ind];
  17695 + }
  17696 +
  17697 + static double mp_list_set_ioff(_cimg_math_parser& mp) {
  17698 + const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
  17699 + CImg<T> &img = mp.listout[ind];
  17700 + const long
  17701 + off = (long)_mp_arg(3),
  17702 + whds = (long)img.size();
  17703 + const double val = _mp_arg(1);
  17704 + if (off>=0 && off<whds) img[off] = (T)val;
  17705 + return val;
  17706 + }
  17707 +
  17708 + static double mp_list_set_ixyzc(_cimg_math_parser& mp) {
  17709 + const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
  17710 + CImg<T> &img = mp.listout[ind];
  17711 + const int
  17712 + x = (int)_mp_arg(3), y = (int)_mp_arg(4),
  17713 + z = (int)_mp_arg(5), c = (int)_mp_arg(6);
  17714 + const double val = _mp_arg(1);
  17715 + if (x>=0 && x<img.width() && y>=0 && y<img.height() &&
  17716 + z>=0 && z<img.depth() && c>=0 && c<img.spectrum()) {
  17717 + img(x,y,z,c) = (T)val;
  17718 + }
  17719 + return val;
  17720 + }
  17721 +
  17722 + static double mp_list_set_joff(_cimg_math_parser& mp) {
  17723 + const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
  17724 + CImg<T> &img = mp.listout[ind];
  17725 + const int
  17726 + ox = (int)mp.mem[_cimg_mp_x], oy = (int)mp.mem[_cimg_mp_y],
  17727 + oz = (int)mp.mem[_cimg_mp_z], oc = (int)mp.mem[_cimg_mp_c];
  17728 + const long
  17729 + off = img.offset(ox,oy,oz,oc) + (long)_mp_arg(3),
  17730 + whds = (long)img.size();
  17731 + const double val = _mp_arg(1);
  17732 + if (off>=0 && off<whds) img[off] = (T)val;
14770 return val; 17733 return val;
14771 } 17734 }
  17735 +
  17736 + static double mp_list_set_jxyzc(_cimg_math_parser& mp) {
  17737 + const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
  17738 + CImg<T> &img = mp.listout[ind];
  17739 + const double
  17740 + ox = mp.mem[_cimg_mp_x], oy = mp.mem[_cimg_mp_y],
  17741 + oz = mp.mem[_cimg_mp_z], oc = mp.mem[_cimg_mp_c];
  17742 + const int
  17743 + x = (int)(ox + _mp_arg(3)), y = (int)(oy + _mp_arg(4)),
  17744 + z = (int)(oz + _mp_arg(5)), c = (int)(oc + _mp_arg(6));
  17745 + const double val = _mp_arg(1);
  17746 + if (x>=0 && x<img.width() && y>=0 && y<img.height() &&
  17747 + z>=0 && z<img.depth() && c>=0 && c<img.spectrum()) {
  17748 + img(x,y,z,c) = (T)val;
  17749 + }
  17750 + return val;
  17751 + }
  17752 +
  17753 + static double mp_list_set_Ioff_s(_cimg_math_parser& mp) {
  17754 + const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
  17755 + CImg<T> &img = mp.listout[ind];
  17756 + const long
  17757 + off = (long)_mp_arg(3),
  17758 + whd = img.width()*img.height()*img.depth();
  17759 + const T val = (T)_mp_arg(1);
  17760 + if (off>=0 && off<whd) {
  17761 + T *ptrd = &img[off];
  17762 + cimg_forC(img,c) { *ptrd = val; ptrd+=whd; }
  17763 + }
  17764 + return _mp_arg(1);
  17765 + }
  17766 +
  17767 + static double mp_list_set_Ioff_v(_cimg_math_parser& mp) {
  17768 + const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
  17769 + CImg<T> &img = mp.listout[ind];
  17770 + const long
  17771 + off = (long)_mp_arg(3),
  17772 + whd = img.width()*img.height()*img.depth();
  17773 + const double *ptrs = &_mp_arg(1) + 1;
  17774 + if (off>=0 && off<whd) {
  17775 + T *ptrd = &img[off];
  17776 + cimg_forC(img,c) { *ptrd = (T)*(ptrs++); ptrd+=whd; }
  17777 + }
  17778 + return cimg::type<double>::nan();
  17779 + }
  17780 +
  17781 + static double mp_list_set_Ixyz_s(_cimg_math_parser& mp) {
  17782 + const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
  17783 + CImg<T> &img = mp.listout[ind];
  17784 + const int x = (int)_mp_arg(3), y = (int)_mp_arg(4), z = (int)_mp_arg(5);
  17785 + const T val = (T)_mp_arg(1);
  17786 + if (x>=0 && x<img.width() && y>=0 && y<img.height() && z>=0 && z<img.depth()) {
  17787 + T *ptrd = &img(x,y,z);
  17788 + const unsigned long whd = img._width*img._height*img._depth;
  17789 + cimg_forC(img,c) { *ptrd = val; ptrd+=whd; }
  17790 + }
  17791 + return _mp_arg(1);
  17792 + }
  17793 +
  17794 + static double mp_list_set_Ixyz_v(_cimg_math_parser& mp) {
  17795 + const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
  17796 + CImg<T> &img = mp.listout[ind];
  17797 + const int x = (int)_mp_arg(3), y = (int)_mp_arg(4), z = (int)_mp_arg(5);
  17798 + const double *ptrs = &_mp_arg(1) + 1;
  17799 + if (x>=0 && x<img.width() && y>=0 && y<img.height() && z>=0 && z<img.depth()) {
  17800 + T *ptrd = &img(x,y,z);
  17801 + const unsigned long whd = img._width*img._height*img._depth;
  17802 + cimg_forC(img,c) { *ptrd = (T)*(ptrs++); ptrd+=whd; }
  17803 + }
  17804 + return cimg::type<double>::nan();
  17805 + }
  17806 +
  17807 + static double mp_list_set_Joff_s(_cimg_math_parser& mp) {
  17808 + const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
  17809 + CImg<T> &img = mp.listout[ind];
  17810 + const int
  17811 + ox = (int)mp.mem[_cimg_mp_x], oy = (int)mp.mem[_cimg_mp_y],
  17812 + oz = (int)mp.mem[_cimg_mp_z], oc = (int)mp.mem[_cimg_mp_c];
  17813 + const long
  17814 + off = img.offset(ox,oy,oz,oc) + (long)_mp_arg(3),
  17815 + whd = img.width()*img.height()*img.depth();
  17816 + const T val = (T)_mp_arg(1);
  17817 + if (off>=0 && off<whd) {
  17818 + T *ptrd = &img[off];
  17819 + cimg_forC(img,c) { *ptrd = val; ptrd+=whd; }
  17820 + }
  17821 + return _mp_arg(1);
  17822 + }
  17823 +
  17824 + static double mp_list_set_Joff_v(_cimg_math_parser& mp) {
  17825 + const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
  17826 + CImg<T> &img = mp.listout[ind];
  17827 + const int
  17828 + ox = (int)mp.mem[_cimg_mp_x], oy = (int)mp.mem[_cimg_mp_y],
  17829 + oz = (int)mp.mem[_cimg_mp_z], oc = (int)mp.mem[_cimg_mp_c];
  17830 + const long
  17831 + off = img.offset(ox,oy,oz,oc) + (long)_mp_arg(3),
  17832 + whd = img.width()*img.height()*img.depth();
  17833 + const double *ptrs = &_mp_arg(1) + 1;
  17834 + if (off>=0 && off<whd) {
  17835 + T *ptrd = &img[off];
  17836 + cimg_forC(img,c) { *ptrd = (T)*(ptrs++); ptrd+=whd; }
  17837 + }
  17838 + return cimg::type<double>::nan();
  17839 + }
  17840 +
  17841 + static double mp_list_set_Jxyz_s(_cimg_math_parser& mp) {
  17842 + const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
  17843 + CImg<T> &img = mp.listout[ind];
  17844 + const double ox = mp.mem[_cimg_mp_x], oy = mp.mem[_cimg_mp_y], oz = mp.mem[_cimg_mp_z];
  17845 + const int x = (int)(ox + _mp_arg(3)), y = (int)(oy + _mp_arg(4)), z = (int)(oz + _mp_arg(5));
  17846 + const T val = (T)_mp_arg(1);
  17847 + if (x>=0 && x<img.width() && y>=0 && y<img.height() && z>=0 && z<img.depth()) {
  17848 + T *ptrd = &img(x,y,z);
  17849 + const unsigned long whd = img._width*img._height*img._depth;
  17850 + cimg_forC(img,c) { *ptrd = val; ptrd+=whd; }
  17851 + }
  17852 + return _mp_arg(1);
  17853 + }
  17854 +
  17855 + static double mp_list_set_Jxyz_v(_cimg_math_parser& mp) {
  17856 + const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
  17857 + CImg<T> &img = mp.listout[ind];
  17858 + const double ox = mp.mem[_cimg_mp_x], oy = mp.mem[_cimg_mp_y], oz = mp.mem[_cimg_mp_z];
  17859 + const int x = (int)(ox + _mp_arg(3)), y = (int)(oy + _mp_arg(4)), z = (int)(oz + _mp_arg(5));
  17860 + const double *ptrs = &_mp_arg(1) + 1;
  17861 + if (x>=0 && x<img.width() && y>=0 && y<img.height() && z>=0 && z<img.depth()) {
  17862 + T *ptrd = &img(x,y,z);
  17863 + const unsigned long whd = img._width*img._height*img._depth;
  17864 + cimg_forC(img,c) { *ptrd = (T)*(ptrs++); ptrd+=whd; }
  17865 + }
  17866 + return cimg::type<double>::nan();
  17867 + }
  17868 +
  17869 + static double mp_list_spectrum(_cimg_math_parser& mp) {
  17870 + const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
  17871 + return (double)mp.listin[ind]._spectrum;
  17872 + }
  17873 +
  17874 + static double mp_list_stats(_cimg_math_parser& mp) {
  17875 + const unsigned int
  17876 + ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()),
  17877 + k = (unsigned int)_mp_arg(3);
  17878 + if (!mp.list_stats) mp.list_stats.assign(mp.listin._width);
  17879 + if (!mp.list_stats[ind]) mp.list_stats[ind].assign(1,14,1,1,0).fill(mp.listin[ind].get_stats(),false);
  17880 + return mp.list_stats(ind,k);
  17881 + }
  17882 +
  17883 + static double mp_list_wh(_cimg_math_parser& mp) {
  17884 + const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
  17885 + return (double)mp.listin[ind]._width*mp.listin[ind]._height;
  17886 + }
  17887 +
  17888 + static double mp_list_whd(_cimg_math_parser& mp) {
  17889 + const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
  17890 + return (double)mp.listin[ind]._width*mp.listin[ind]._height*mp.listin[ind]._depth;
  17891 + }
  17892 +
  17893 + static double mp_list_whds(_cimg_math_parser& mp) {
  17894 + const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
  17895 + return (double)mp.listin[ind]._width*mp.listin[ind]._height*mp.listin[ind]._depth*mp.listin[ind]._spectrum;
  17896 + }
  17897 +
  17898 + static double mp_list_width(_cimg_math_parser& mp) {
  17899 + const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width());
  17900 + return (double)mp.listin[ind]._width;
  17901 + }
  17902 +
  17903 + static double mp_list_Ioff(_cimg_math_parser& mp) {
  17904 + double *ptrd = &_mp_arg(1) + 1;
  17905 + const unsigned int
  17906 + ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()),
  17907 + boundary_conditions = (unsigned int)_mp_arg(4);
  17908 + const CImg<T> &img = mp.listin[ind];
  17909 + const long
  17910 + off = (long)_mp_arg(3),
  17911 + whd = img.width()*img.height()*img.depth();
  17912 + const T *ptrs;
  17913 + if (off<0 || off>=whd)
  17914 + switch (boundary_conditions) {
  17915 + case 2 : // Periodic boundary
  17916 + if (!img) {
  17917 + ptrs = &img[cimg::mod(off,whd)];
  17918 + cimg_forC(img,c) { *(ptrd++) = *ptrs; ptrs+=whd; }
  17919 + } else std::memset(ptrd,0,img._spectrum*sizeof(double));
  17920 + return cimg::type<double>::nan();
  17921 + case 1 : // Neumann boundary
  17922 + if (img) {
  17923 + ptrs = off<0?img._data:&img.back();
  17924 + cimg_forC(img,c) { *(ptrd++) = *ptrs; ptrs+=whd; }
  17925 + } else std::memset(ptrd,0,img._spectrum*sizeof(double));
  17926 + return cimg::type<double>::nan();
  17927 + default : // Dirichet boundary
  17928 + std::memset(ptrd,0,img._spectrum*sizeof(double));
  17929 + return cimg::type<double>::nan();
  17930 + }
  17931 + ptrs = &img[off];
  17932 + cimg_forC(img,c) { *(ptrd++) = *ptrs; ptrs+=whd; }
  17933 + return cimg::type<double>::nan();
  17934 + }
  17935 +
  17936 + static double mp_list_Ixyz(_cimg_math_parser& mp) {
  17937 + double *ptrd = &_mp_arg(1) + 1;
  17938 + const unsigned int
  17939 + ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()),
  17940 + interpolation = (unsigned int)_mp_arg(6),
  17941 + boundary_conditions = (unsigned int)_mp_arg(7);
  17942 + const CImg<T> &img = mp.listin[ind];
  17943 + const double x = _mp_arg(3), y = _mp_arg(4), z = _mp_arg(5);
  17944 + if (interpolation==0) { // Nearest neighbor interpolation
  17945 + if (boundary_conditions==2)
  17946 + cimg_forC(img,c)
  17947 + *(ptrd++) = (double)img.atXYZ(cimg::mod((int)x,img.width()),
  17948 + cimg::mod((int)y,img.height()),
  17949 + cimg::mod((int)z,img.depth()),
  17950 + c);
  17951 + else if (boundary_conditions==1)
  17952 + cimg_forC(img,c)
  17953 + *(ptrd++) = (double)img.atXYZ((int)x,(int)y,(int)z,c);
  17954 + else
  17955 + cimg_forC(img,c)
  17956 + *(ptrd++) = (double)img.atXYZ((int)x,(int)y,(int)z,c,0);
  17957 + } else { // Linear interpolation
  17958 + if (boundary_conditions==2)
  17959 + cimg_forC(img,c)
  17960 + *(ptrd++) = (double)img.linear_atXYZ(cimg::mod((float)x,(float)img.width()),
  17961 + cimg::mod((float)y,(float)img.height()),
  17962 + cimg::mod((float)z,(float)img.depth()),c);
  17963 + else if (boundary_conditions==1)
  17964 + cimg_forC(img,c)
  17965 + *(ptrd++) = (double)img.linear_atXYZ((float)x,(float)y,(float)z,c);
  17966 + else
  17967 + cimg_forC(img,c)
  17968 + *(ptrd++) = (double)img.linear_atXYZ((float)x,(float)y,(float)z,c,0);
  17969 + }
  17970 + return cimg::type<double>::nan();
  17971 + }
  17972 +
  17973 + static double mp_list_Joff(_cimg_math_parser& mp) {
  17974 + double *ptrd = &_mp_arg(1) + 1;
  17975 + const unsigned int
  17976 + ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()),
  17977 + boundary_conditions = (unsigned int)_mp_arg(4);
  17978 + const int
  17979 + ox = (int)mp.mem[_cimg_mp_x], oy = (int)mp.mem[_cimg_mp_y], oz = (int)mp.mem[_cimg_mp_z];
  17980 + const CImg<T> &img = mp.listin[ind];
  17981 + const long
  17982 + off = img.offset(ox,oy,oz) + (long)_mp_arg(3),
  17983 + whd = img.width()*img.height()*img.depth();
  17984 + const T *ptrs;
  17985 + if (off<0 || off>=whd)
  17986 + switch (boundary_conditions) {
  17987 + case 2 : // Periodic boundary
  17988 + if (!img) {
  17989 + ptrs = &img[cimg::mod(off,whd)];
  17990 + cimg_forC(img,c) { *(ptrd++) = *ptrs; ptrs+=whd; }
  17991 + } else std::memset(ptrd,0,img._spectrum*sizeof(double));
  17992 + return cimg::type<double>::nan();
  17993 + case 1 : // Neumann boundary
  17994 + if (img) {
  17995 + ptrs = off<0?img._data:&img.back();
  17996 + cimg_forC(img,c) { *(ptrd++) = *ptrs; ptrs+=whd; }
  17997 + } else std::memset(ptrd,0,img._spectrum*sizeof(double));
  17998 + return cimg::type<double>::nan();
  17999 + default : // Dirichet boundary
  18000 + std::memset(ptrd,0,img._spectrum*sizeof(double));
  18001 + return cimg::type<double>::nan();
  18002 + }
  18003 + ptrs = &img[off];
  18004 + cimg_forC(img,c) { *(ptrd++) = *ptrs; ptrs+=whd; }
  18005 + return cimg::type<double>::nan();
  18006 + }
  18007 +
  18008 + static double mp_list_Jxyz(_cimg_math_parser& mp) {
  18009 + double *ptrd = &_mp_arg(1) + 1;
  18010 + const unsigned int
  18011 + ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.listin.width()),
  18012 + interpolation = (unsigned int)_mp_arg(6),
  18013 + boundary_conditions = (unsigned int)_mp_arg(7);
  18014 + const CImg<T> &img = mp.listin[ind];
  18015 + const double
  18016 + ox = mp.mem[_cimg_mp_x], oy = mp.mem[_cimg_mp_y], oz = mp.mem[_cimg_mp_z],
  18017 + x = ox + _mp_arg(3), y = oy + _mp_arg(4), z = oz + _mp_arg(5);
  18018 + if (interpolation==0) { // Nearest neighbor interpolation
  18019 + if (boundary_conditions==2)
  18020 + cimg_forC(img,c)
  18021 + *(ptrd++) = (double)img.atXYZ(cimg::mod((int)x,img.width()),
  18022 + cimg::mod((int)y,img.height()),
  18023 + cimg::mod((int)z,img.depth()),
  18024 + c);
  18025 + else if (boundary_conditions==1)
  18026 + cimg_forC(img,c)
  18027 + *(ptrd++) = (double)img.atXYZ((int)x,(int)y,(int)z,c);
  18028 + else
  18029 + cimg_forC(img,c)
  18030 + *(ptrd++) = (double)img.atXYZ((int)x,(int)y,(int)z,c,0);
  18031 + } else { // Linear interpolation
  18032 + if (boundary_conditions==2)
  18033 + cimg_forC(img,c)
  18034 + *(ptrd++) = (double)img.linear_atXYZ(cimg::mod((float)x,(float)img.width()),
  18035 + cimg::mod((float)y,(float)img.height()),
  18036 + cimg::mod((float)z,(float)img.depth()),c);
  18037 + else if (boundary_conditions==1)
  18038 + cimg_forC(img,c)
  18039 + *(ptrd++) = (double)img.linear_atXYZ((float)x,(float)y,(float)z,c);
  18040 + else
  18041 + cimg_forC(img,c)
  18042 + *(ptrd++) = (double)img.linear_atXYZ((float)x,(float)y,(float)z,c,0);
  18043 + }
  18044 + return cimg::type<double>::nan();
  18045 + }
  18046 +
  18047 + static double mp_log(_cimg_math_parser& mp) {
  18048 + return std::log(_mp_arg(2));
  18049 + }
  18050 +
  18051 + static double mp_log10(_cimg_math_parser& mp) {
  18052 + return std::log10(_mp_arg(2));
  18053 + }
  18054 +
  18055 + static double mp_log2(_cimg_math_parser& mp) {
  18056 + return cimg::log2(_mp_arg(2));
  18057 + }
  18058 +
  18059 + static double mp_logical_and(_cimg_math_parser& mp) {
  18060 + const bool val_left = (bool)_mp_arg(2);
  18061 + const CImg<uptrT> *const p_end = ++mp.p_code + mp.opcode[4];
  18062 + if (!val_left) { mp.p_code = p_end - 1; return 0; }
  18063 + const uptrT mem_right = mp.opcode[3];
  18064 + for ( ; mp.p_code<p_end; ++mp.p_code) {
  18065 + const CImg<uptrT> &op = *mp.p_code;
  18066 + mp.opcode._data = op._data; mp.opcode._height = op._height;
  18067 + const uptrT target = mp.opcode[1];
  18068 + mp.mem[target] = _cimg_mp_defunc(mp);
  18069 + }
  18070 + --mp.p_code;
  18071 + return (double)(bool)mp.mem[mem_right];
  18072 + }
  18073 +
  18074 + static double mp_logical_not(_cimg_math_parser& mp) {
  18075 + return (double)!_mp_arg(2);
  18076 + }
  18077 +
  18078 + static double mp_logical_or(_cimg_math_parser& mp) {
  18079 + const bool val_left = (bool)_mp_arg(2);
  18080 + const CImg<uptrT> *const p_end = ++mp.p_code + mp.opcode[4];
  18081 + if (val_left) { mp.p_code = p_end - 1; return 1; }
  18082 + const uptrT mem_right = mp.opcode[3];
  18083 + for ( ; mp.p_code<p_end; ++mp.p_code) {
  18084 + const CImg<uptrT> &op = *mp.p_code;
  18085 + mp.opcode._data = op._data; mp.opcode._height = op._height;
  18086 + const uptrT target = mp.opcode[1];
  18087 + mp.mem[target] = _cimg_mp_defunc(mp);
  18088 + }
  18089 + --mp.p_code;
  18090 + return (double)(bool)mp.mem[mem_right];
  18091 + }
  18092 +
  18093 +
  18094 + static double mp_lt(_cimg_math_parser& mp) {
  18095 + return (double)(_mp_arg(2)<_mp_arg(3));
  18096 + }
  18097 +
  18098 + static double mp_lte(_cimg_math_parser& mp) {
  18099 + return (double)(_mp_arg(2)<=_mp_arg(3));
  18100 + }
  18101 +
  18102 + static double mp_matrix_det(_cimg_math_parser& mp) {
  18103 + const double *ptrs = &_mp_arg(2) + 1;
  18104 + const unsigned int k = (unsigned int)mp.opcode(3);
  18105 + return CImg<double>(ptrs,k,k,1,1,true).det();
  18106 + }
  18107 +
  18108 + static double mp_matrix_diag(_cimg_math_parser& mp) {
  18109 + double *ptrd = &_mp_arg(1) + 1;
  18110 + const double *ptrs = &_mp_arg(2) + 1;
  18111 + const unsigned int k = (unsigned int)mp.opcode(3);
  18112 + CImg<double>(ptrd,k,k,1,1,true) = CImg<double>(ptrs,1,k,1,1,true).get_diagonal();
  18113 + return cimg::type<double>::nan();
  18114 + }
  18115 +
  18116 + static double mp_matrix_eig(_cimg_math_parser& mp) {
  18117 + double *ptrd = &_mp_arg(1) + 1;
  18118 + const double *ptr1 = &_mp_arg(2) + 1;
  18119 + const unsigned int k = (unsigned int)mp.opcode(3);
  18120 + CImg<double> val, vec;
  18121 + CImg<double>(ptr1,k,k,1,1,true).symmetric_eigen(val,vec);
  18122 + CImg<double>(ptrd,k,1,1,1,true) = val.unroll('x');
  18123 + CImg<double>(ptrd + k,k,k,1,1,true) = vec.get_transpose();
  18124 + return cimg::type<double>::nan();
  18125 + }
  18126 +
  18127 + static double mp_matrix_eye(_cimg_math_parser& mp) {
  18128 + double *ptrd = &_mp_arg(1) + 1;
  18129 + const unsigned int k = (unsigned int)mp.opcode(2);
  18130 + CImg<double>(ptrd,k,k,1,1,true).identity_matrix();
  18131 + return cimg::type<double>::nan();
  18132 + }
  18133 +
  18134 + static double mp_matrix_inv(_cimg_math_parser& mp) {
  18135 + double *ptrd = &_mp_arg(1) + 1;
  18136 + const double *ptr1 = &_mp_arg(2) + 1;
  18137 + const unsigned int k = (unsigned int)mp.opcode(3);
  18138 + CImg<double>(ptrd,k,k,1,1,true) = CImg<double>(ptr1,k,k,1,1,true).get_invert();
  18139 + return cimg::type<double>::nan();
  18140 + }
  18141 +
  18142 + static double mp_matrix_mul(_cimg_math_parser& mp) {
  18143 + double *ptrd = &_mp_arg(1) + 1;
  18144 + const double
  18145 + *ptr1 = &_mp_arg(2) + 1,
  18146 + *ptr2 = &_mp_arg(3) + 1;
  18147 + const unsigned int
  18148 + k = (unsigned int)mp.opcode(4),
  18149 + l = (unsigned int)mp.opcode(5),
  18150 + m = (unsigned int)mp.opcode(6);
  18151 + CImg<double>(ptrd,m,k,1,1,true) = CImg<double>(ptr1,l,k,1,1,true)*CImg<double>(ptr2,m,l,1,1,true);
  18152 + return cimg::type<double>::nan();
  18153 + }
  18154 +
  18155 + static double mp_matrix_rot(_cimg_math_parser& mp) {
  18156 + double *ptrd = &_mp_arg(1) + 1;
  18157 + const float x = (float)_mp_arg(2), y = (float)_mp_arg(3), z = (float)_mp_arg(4), theta = (float)_mp_arg(5);
  18158 + CImg<double>(ptrd,3,3,1,1,true) = CImg<double>::rotation_matrix(x,y,z,theta);
  18159 + return cimg::type<double>::nan();
  18160 + }
  18161 +
  18162 + static double mp_matrix_solve(_cimg_math_parser& mp) {
  18163 + double *ptrd = &_mp_arg(1) + 1;
  18164 + const double
  18165 + *ptr1 = &_mp_arg(2) + 1,
  18166 + *ptr2 = &_mp_arg(3) + 1;
  18167 + const unsigned int
  18168 + k = (unsigned int)mp.opcode(4),
  18169 + l = (unsigned int)mp.opcode(5),
  18170 + m = (unsigned int)mp.opcode(6);
  18171 + CImg<double>(ptrd,m,l,1,1,true) = CImg<double>(ptr2,m,k,1,1,true).get_solve(CImg<double>(ptr1,l,k,1,1,true));
  18172 + return cimg::type<double>::nan();
  18173 + }
  18174 +
  18175 + static double mp_matrix_trace(_cimg_math_parser& mp) {
  18176 + const double *ptrs = &_mp_arg(2) + 1;
  18177 + const unsigned int k = (unsigned int)mp.opcode(3);
  18178 + return CImg<double>(ptrs,k,k,1,1,true).trace();
  18179 + }
  18180 +
  18181 + static double mp_matrix_trans(_cimg_math_parser& mp) {
  18182 + double *ptrd = &_mp_arg(1) + 1;
  18183 + const double *ptr1 = &_mp_arg(2) + 1;
  18184 + const unsigned int
  18185 + k = (unsigned int)mp.opcode(3),
  18186 + l = (unsigned int)mp.opcode(4);
  18187 + CImg<double>(ptrd,l,k,1,1,true) = CImg<double>(ptr1,k,l,1,1,true).get_transpose();
  18188 + return cimg::type<double>::nan();
  18189 + }
  18190 +
14772 static double mp_max(_cimg_math_parser& mp) { 18191 static double mp_max(_cimg_math_parser& mp) {
14773 - double val = mp.mem[mp.opcode(2)];  
14774 - for (unsigned int i = 3; i<mp.opcode._height; ++i) val = cimg::max(val,mp.mem[mp.opcode(i)]); 18192 + double val = _mp_arg(2);
  18193 + for (unsigned int i = 3; i<mp.opcode._height; ++i) val = cimg::max(val,_mp_arg(i));
14775 return val; 18194 return val;
14776 } 18195 }
  18196 +
  18197 + static double mp_min(_cimg_math_parser& mp) {
  18198 + double val = _mp_arg(2);
  18199 + for (unsigned int i = 3; i<mp.opcode._height; ++i) val = cimg::min(val,_mp_arg(i));
  18200 + return val;
  18201 + }
  18202 +
  18203 + static double mp_minus(_cimg_math_parser& mp) {
  18204 + return -_mp_arg(2);
  18205 + }
  18206 +
14777 static double mp_med(_cimg_math_parser& mp) { 18207 static double mp_med(_cimg_math_parser& mp) {
14778 - CImg<doubleT> values(mp.opcode._height - 2);  
14779 - double *p = values.data();  
14780 - for (unsigned int i = 2; i<mp.opcode._height; ++i) *(p++) = mp.mem[mp.opcode(i)];  
14781 - return values.median(); 18208 + CImg<doubleT> vals(mp.opcode._height - 2);
  18209 + double *p = vals.data();
  18210 + for (unsigned int i = 2; i<mp.opcode._height; ++i) *(p++) = _mp_arg(i);
  18211 + return vals.median();
14782 } 18212 }
14783 - static double mp_kth(_cimg_math_parser& mp) {  
14784 - CImg<doubleT> values(mp.opcode._height - 3);  
14785 - double *p = values.data();  
14786 - for (unsigned int i = 3; i<mp.opcode._height; ++i) *(p++) = mp.mem[mp.opcode(i)];  
14787 - int ind = (int)cimg::round(mp.mem[mp.opcode(2)]);  
14788 - if (ind<0) ind+=values.width() + 1;  
14789 - ind = cimg::max(1,cimg::min(values.width(),ind));  
14790 - return values.kth_smallest(ind - 1); 18213 +
  18214 + static double mp_modulo(_cimg_math_parser& mp) {
  18215 + return cimg::mod(_mp_arg(2),_mp_arg(3));
14791 } 18216 }
14792 - static double mp_isin(_cimg_math_parser& mp) {  
14793 - double value = mp.mem[mp.opcode(2)]; 18217 +
  18218 + static double mp_mul(_cimg_math_parser& mp) {
  18219 + return _mp_arg(2)*_mp_arg(3);
  18220 + }
  18221 +
  18222 + static double mp_neq(_cimg_math_parser& mp) {
  18223 + return (double)(_mp_arg(2)!=_mp_arg(3));
  18224 + }
  18225 +
  18226 + static double mp_norm0(_cimg_math_parser& mp) {
  18227 + double res = 0;
  18228 + for (unsigned int i = 2; i<mp.opcode._height; ++i)
  18229 + res+=_mp_arg(i)==0?0:1;
  18230 + return res;
  18231 + }
  18232 +
  18233 + static double mp_norm1(_cimg_math_parser& mp) {
  18234 + double res = 0;
  18235 + for (unsigned int i = 2; i<mp.opcode._height; ++i)
  18236 + res+=cimg::abs(_mp_arg(i));
  18237 + return res;
  18238 + }
  18239 +
  18240 + static double mp_norm2(_cimg_math_parser& mp) {
  18241 + double res = 0;
  18242 + for (unsigned int i = 2; i<mp.opcode._height; ++i)
  18243 + res+=cimg::sqr(_mp_arg(i));
  18244 + return std::sqrt(res);
  18245 + }
  18246 +
  18247 + static double mp_norminf(_cimg_math_parser& mp) {
  18248 + double res = 0;
  18249 + for (unsigned int i = 2; i<mp.opcode._height; ++i) {
  18250 + const double val = cimg::abs(_mp_arg(i));
  18251 + if (val>res) res = val;
  18252 + }
  18253 + return res;
  18254 + }
  18255 +
  18256 + static double mp_normp(_cimg_math_parser& mp) {
  18257 + const double p = (double)mp.opcode[2];
  18258 + double res = 0;
14794 for (unsigned int i = 3; i<mp.opcode._height; ++i) 18259 for (unsigned int i = 3; i<mp.opcode._height; ++i)
14795 - if (value==mp.mem[mp.opcode(i)]) return 1.0;  
14796 - return 0.0; 18260 + res+=std::pow(cimg::abs(_mp_arg(i)),p);
  18261 + res = std::pow(res,1/p);
  18262 + return res>0?res:0.0;
14797 } 18263 }
14798 - static double mp_isnan(_cimg_math_parser& mp) {  
14799 - const double val = mp.mem[mp.opcode(2)];  
14800 - return cimg::type<double>::is_nan(val); 18264 +
  18265 + static double mp_pow(_cimg_math_parser& mp) {
  18266 + const double v = _mp_arg(2), p = _mp_arg(3);
  18267 + return std::pow(v,p);
14801 } 18268 }
14802 - static double mp_isinf(_cimg_math_parser& mp) {  
14803 - const double val = mp.mem[mp.opcode(2)];  
14804 - return cimg::type<double>::is_inf(val); 18269 +
  18270 + static double mp_pow3(_cimg_math_parser& mp) {
  18271 + const double val = _mp_arg(2);
  18272 + return val*val*val;
14805 } 18273 }
14806 - static double mp_isint(_cimg_math_parser& mp) {  
14807 - const double val = mp.mem[mp.opcode(2)];  
14808 - return (double)(cimg::mod(val,1.0)==0); 18274 +
  18275 + static double mp_pow4(_cimg_math_parser& mp) {
  18276 + const double val = _mp_arg(2);
  18277 + return val*val*val*val;
14809 } 18278 }
14810 - static double mp_isbool(_cimg_math_parser& mp) {  
14811 - const double val = mp.mem[mp.opcode(2)];  
14812 - return (val==0.0 || val==1.0); 18279 +
  18280 + static double mp_print(_cimg_math_parser& mp) {
  18281 + CImg<charT> expr(mp.opcode._height - 2);
  18282 + const uptrT *ptrs = mp.opcode._data + 2;
  18283 + cimg_for(expr,ptrd,char) *ptrd = (char)*(ptrs++);
  18284 + cimg::strellipsize(expr);
  18285 + const double val = _mp_arg(1);
  18286 + std::fprintf(cimg::output(),"\n[_cimg_math_parser] %s = %g",expr._data,val);
  18287 + std::fflush(cimg::output());
  18288 + return val;
14813 } 18289 }
  18290 +
  18291 + static double mp_copy(_cimg_math_parser& mp) {
  18292 + return _mp_arg(2);
  18293 + }
  18294 +
14814 static double mp_rol(_cimg_math_parser& mp) { 18295 static double mp_rol(_cimg_math_parser& mp) {
14815 - return cimg::rol(mp.mem[mp.opcode(2)],(unsigned int)mp.mem[mp.opcode(3)]); 18296 + return cimg::rol(_mp_arg(2),(unsigned int)_mp_arg(3));
14816 } 18297 }
  18298 +
14817 static double mp_ror(_cimg_math_parser& mp) { 18299 static double mp_ror(_cimg_math_parser& mp) {
14818 - return cimg::ror(mp.mem[mp.opcode(2)],(unsigned int)mp.mem[mp.opcode(3)]); 18300 + return cimg::ror(_mp_arg(2),(unsigned int)_mp_arg(3));
14819 } 18301 }
14820 - static double mp_lsl(_cimg_math_parser& mp) {  
14821 - return (long)mp.mem[mp.opcode(2)]<<(unsigned int)mp.mem[mp.opcode(3)]; 18302 +
  18303 + static double mp_round(_cimg_math_parser& mp) {
  18304 + return cimg::round(_mp_arg(2),_mp_arg(3),(int)_mp_arg(4));
14822 } 18305 }
14823 - static double mp_lsr(_cimg_math_parser& mp) {  
14824 - return (long)mp.mem[mp.opcode(2)]>>(unsigned int)mp.mem[mp.opcode(3)]; 18306 +
  18307 + static double mp_self_add(_cimg_math_parser& mp) {
  18308 + return _mp_arg(1)+=_mp_arg(2);
14825 } 18309 }
14826 - static double mp_sinc(_cimg_math_parser& mp) {  
14827 - return cimg::sinc(mp.mem[mp.opcode(2)]); 18310 +
  18311 + static double mp_self_bitwise_and(_cimg_math_parser& mp) {
  18312 + double &val = _mp_arg(1);
  18313 + return val = (double)((unsigned long)val & (unsigned long)_mp_arg(2));
14828 } 18314 }
14829 - static double mp_im(_cimg_math_parser& mp) {  
14830 - return mp.reference_stats?mp.reference_stats[0]:0; 18315 +
  18316 + static double mp_self_bitwise_left_shift(_cimg_math_parser& mp) {
  18317 + double &val = _mp_arg(1);
  18318 + return val = (double)((long)val<<(unsigned int)_mp_arg(2));
14831 } 18319 }
14832 - static double mp_iM(_cimg_math_parser& mp) {  
14833 - return mp.reference_stats?mp.reference_stats[1]:0; 18320 +
  18321 + static double mp_self_bitwise_or(_cimg_math_parser& mp) {
  18322 + double &val = _mp_arg(1);
  18323 + return val = (double)((unsigned long)val | (unsigned long)_mp_arg(2));
14834 } 18324 }
14835 - static double mp_ia(_cimg_math_parser& mp) {  
14836 - return mp.reference_stats?mp.reference_stats[2]:0; 18325 +
  18326 + static double mp_self_bitwise_right_shift(_cimg_math_parser& mp) {
  18327 + double &val = _mp_arg(1);
  18328 + return val = (double)((long)val>>(unsigned int)_mp_arg(2));
14837 } 18329 }
14838 - static double mp_iv(_cimg_math_parser& mp) {  
14839 - return mp.reference_stats?mp.reference_stats[3]:0; 18330 +
  18331 + static double mp_self_decrement(_cimg_math_parser& mp) {
  18332 + return --_mp_arg(1);
14840 } 18333 }
14841 - static double mp_is(_cimg_math_parser& mp) {  
14842 - return mp.reference_stats?mp.reference_stats[12]:0; 18334 +
  18335 + static double mp_self_increment(_cimg_math_parser& mp) {
  18336 + return ++_mp_arg(1);
14843 } 18337 }
14844 - static double mp_ip(_cimg_math_parser& mp) {  
14845 - return mp.reference_stats?mp.reference_stats[13]:0; 18338 +
  18339 + static double mp_self_map_vector_s(_cimg_math_parser& mp) { // Vector += scalar
  18340 + unsigned int
  18341 + ptrd = (unsigned int)mp.opcode[1] + 1,
  18342 + siz = (unsigned int)mp.opcode[2];
  18343 + mp_func op = (mp_func)mp.opcode[3];
  18344 + CImg<uptrT> l_opcode(1,3);
  18345 + l_opcode[2] = mp.opcode[4]; // Scalar argument.
  18346 + l_opcode.swap(mp.opcode);
  18347 + uptrT &target = mp.opcode[1];
  18348 + while (siz-->0) { target = ptrd++; (*op)(mp); }
  18349 + l_opcode.swap(mp.opcode);
  18350 + return cimg::type<double>::nan();
14846 } 18351 }
14847 - static double mp_ic(_cimg_math_parser& mp) {  
14848 - return mp.is_median_value?mp.median_value:0; 18352 +
  18353 + static double mp_self_map_vector_v(_cimg_math_parser& mp) { // Vector += vector
  18354 + unsigned int
  18355 + ptrd = (unsigned int)mp.opcode[1] + 1,
  18356 + siz = (unsigned int)mp.opcode[2],
  18357 + ptrs = (unsigned int)mp.opcode[4] + 1;
  18358 + mp_func op = (mp_func)mp.opcode[3];
  18359 + CImg<uptrT> l_opcode(1,4);
  18360 + l_opcode.swap(mp.opcode);
  18361 + uptrT &target = mp.opcode[1], &argument = mp.opcode[2];
  18362 + while (siz-->0) { target = ptrd++; argument = ptrs++; (*op)(mp); }
  18363 + l_opcode.swap(mp.opcode);
  18364 + return cimg::type<double>::nan();
14849 } 18365 }
14850 - static double mp_xm(_cimg_math_parser& mp) {  
14851 - return mp.reference_stats?mp.reference_stats[4]:0; 18366 +
  18367 + static double mp_self_mul(_cimg_math_parser& mp) {
  18368 + return _mp_arg(1)*=_mp_arg(2);
14852 } 18369 }
14853 - static double mp_ym(_cimg_math_parser& mp) {  
14854 - return mp.reference_stats?mp.reference_stats[5]:0; 18370 +
  18371 + static double mp_self_div(_cimg_math_parser& mp) {
  18372 + return _mp_arg(1)/=_mp_arg(2);
14855 } 18373 }
14856 - static double mp_zm(_cimg_math_parser& mp) {  
14857 - return mp.reference_stats?mp.reference_stats[6]:0; 18374 +
  18375 + static double mp_self_modulo(_cimg_math_parser& mp) {
  18376 + double &val = _mp_arg(1);
  18377 + return val = cimg::mod(val,_mp_arg(2));
14858 } 18378 }
14859 - static double mp_cm(_cimg_math_parser& mp) {  
14860 - return mp.reference_stats?mp.reference_stats[7]:0; 18379 +
  18380 + static double mp_self_pow(_cimg_math_parser& mp) {
  18381 + double &val = _mp_arg(1);
  18382 + return val = std::pow(val,_mp_arg(2));
14861 } 18383 }
14862 - static double mp_xM(_cimg_math_parser& mp) {  
14863 - return mp.reference_stats?mp.reference_stats[8]:0; 18384 +
  18385 + static double mp_self_sub(_cimg_math_parser& mp) {
  18386 + return _mp_arg(1)-=_mp_arg(2);
14864 } 18387 }
14865 - static double mp_yM(_cimg_math_parser& mp) {  
14866 - return mp.reference_stats?mp.reference_stats[9]:0; 18388 +
  18389 + static double mp_set_ioff(_cimg_math_parser& mp) {
  18390 + CImg<T> &img = mp.imgout;
  18391 + const long
  18392 + off = (long)_mp_arg(2),
  18393 + whds = (long)img.size();
  18394 + const double val = _mp_arg(1);
  18395 + if (off>=0 && off<whds) img[off] = (T)val;
  18396 + return val;
14867 } 18397 }
14868 - static double mp_zM(_cimg_math_parser& mp) {  
14869 - return mp.reference_stats?mp.reference_stats[10]:0; 18398 +
  18399 + static double mp_set_ixyzc(_cimg_math_parser& mp) {
  18400 + CImg<T> &img = mp.imgout;
  18401 + const int
  18402 + x = (int)_mp_arg(2), y = (int)_mp_arg(3),
  18403 + z = (int)_mp_arg(4), c = (int)_mp_arg(5);
  18404 + const double val = _mp_arg(1);
  18405 + if (x>=0 && x<img.width() && y>=0 && y<img.height() &&
  18406 + z>=0 && z<img.depth() && c>=0 && c<img.spectrum()) {
  18407 + img(x,y,z,c) = (T)val;
  18408 + }
  18409 + return val;
14870 } 18410 }
14871 - static double mp_cM(_cimg_math_parser& mp) {  
14872 - return mp.reference_stats?mp.reference_stats[11]:0; 18411 +
  18412 + static double mp_set_joff(_cimg_math_parser& mp) {
  18413 + CImg<T> &img = mp.imgout;
  18414 + const int
  18415 + ox = (int)mp.mem[_cimg_mp_x], oy = (int)mp.mem[_cimg_mp_y],
  18416 + oz = (int)mp.mem[_cimg_mp_z], oc = (int)mp.mem[_cimg_mp_c];
  18417 + const long
  18418 + off = img.offset(ox,oy,oz,oc) + (long)_mp_arg(2),
  18419 + whds = (long)img.size();
  18420 + const double val = _mp_arg(1);
  18421 + if (off>=0 && off<whds) img[off] = (T)val;
  18422 + return val;
14873 } 18423 }
14874 - static double mp_arg(_cimg_math_parser& mp) {  
14875 - const int _ind = (int)mp.mem[mp.opcode(2)];  
14876 - const unsigned int nb_args = mp.opcode._height - 2, ind = _ind<0?_ind + nb_args:(unsigned int)_ind;  
14877 - if (ind>=nb_args) return 0;  
14878 - return mp.mem[mp.opcode(ind + 2)]; 18424 +
  18425 + static double mp_set_jxyzc(_cimg_math_parser& mp) {
  18426 + CImg<T> &img = mp.imgout;
  18427 + const double
  18428 + ox = mp.mem[_cimg_mp_x], oy = mp.mem[_cimg_mp_y],
  18429 + oz = mp.mem[_cimg_mp_z], oc = mp.mem[_cimg_mp_c];
  18430 + const int
  18431 + x = (int)(ox + _mp_arg(2)), y = (int)(oy + _mp_arg(3)),
  18432 + z = (int)(oz + _mp_arg(4)), c = (int)(oc + _mp_arg(5));
  18433 + const double val = _mp_arg(1);
  18434 + if (x>=0 && x<img.width() && y>=0 && y<img.height() &&
  18435 + z>=0 && z<img.depth() && c>=0 && c<img.spectrum()) {
  18436 + img(x,y,z,c) = (T)val;
  18437 + }
  18438 + return val;
14879 } 18439 }
14880 - static double mp_int(_cimg_math_parser& mp) {  
14881 - return (double)(long)mp.mem[mp.opcode(2)]; 18440 +
  18441 + static double mp_set_Ioff_s(_cimg_math_parser& mp) {
  18442 + CImg<T> &img = mp.imgout;
  18443 + const long
  18444 + off = (long)_mp_arg(2),
  18445 + whd = img.width()*img.height()*img.depth();
  18446 + const T val = (T)_mp_arg(1);
  18447 + if (off>=0 && off<whd) {
  18448 + T *ptrd = &img[off];
  18449 + cimg_forC(img,c) { *ptrd = val; ptrd+=whd; }
  18450 + }
  18451 + return _mp_arg(1);
14882 } 18452 }
14883 - static double mp_ioff(_cimg_math_parser& mp) {  
14884 - const unsigned long off = (unsigned long)mp.mem[mp.opcode(2)];  
14885 - if (off>=mp.reference.size()) return 0;  
14886 - return (double)mp.reference[off]; 18453 +
  18454 + static double mp_set_Ioff_v(_cimg_math_parser& mp) {
  18455 + CImg<T> &img = mp.imgout;
  18456 + const long
  18457 + off = (long)_mp_arg(2),
  18458 + whd = img.width()*img.height()*img.depth();
  18459 + const double *ptrs = &_mp_arg(1) + 1;
  18460 + if (off>=0 && off<whd) {
  18461 + T *ptrd = &img[off];
  18462 + cimg_forC(img,c) { *ptrd = (T)*(ptrs++); ptrd+=whd; }
  18463 + }
  18464 + return cimg::type<double>::nan();
14887 } 18465 }
14888 - static double mp_joff(_cimg_math_parser& mp) {  
14889 - const int x = (int)mp.mem[16], y = (int)mp.mem[17], z = (int)mp.mem[18], c = (int)mp.mem[19];  
14890 - const unsigned long off = mp.reference.offset(x,y,z,c) + (unsigned long)(mp.mem[mp.opcode(2)]);  
14891 - if (off>=mp.reference.size()) return 0;  
14892 - return (double)mp.reference[off]; 18466 +
  18467 + static double mp_set_Ixyz_s(_cimg_math_parser& mp) {
  18468 + CImg<T> &img = mp.imgout;
  18469 + const int x = (int)_mp_arg(2), y = (int)_mp_arg(3), z = (int)_mp_arg(4);
  18470 + const T val = (T)_mp_arg(1);
  18471 + if (x>=0 && x<img.width() && y>=0 && y<img.height() && z>=0 && z<img.depth()) {
  18472 + T *ptrd = &img(x,y,z);
  18473 + const unsigned long whd = img._width*img._height*img._depth;
  18474 + cimg_forC(img,c) { *ptrd = val; ptrd+=whd; }
  18475 + }
  18476 + return _mp_arg(1);
14893 } 18477 }
14894 18478
14895 - // Evaluation procedure, with image data.  
14896 - double operator()(const double x, const double y, const double z, const double c) {  
14897 - if (!mem) return 0;  
14898 - mem[16] = x; mem[17] = y; mem[18] = z; mem[19] = c;  
14899 - opcode._is_shared = true; opcode._width = opcode._depth = opcode._spectrum = 1; 18479 + static double mp_set_Ixyz_v(_cimg_math_parser& mp) {
  18480 + CImg<T> &img = mp.imgout;
  18481 + const int x = (int)_mp_arg(2), y = (int)_mp_arg(3), z = (int)_mp_arg(4);
  18482 + const double *ptrs = &_mp_arg(1) + 1;
  18483 + if (x>=0 && x<img.width() && y>=0 && y<img.height() && z>=0 && z<img.depth()) {
  18484 + T *ptrd = &img(x,y,z);
  18485 + const unsigned long whd = img._width*img._height*img._depth;
  18486 + cimg_forC(img,c) { *ptrd = (T)*(ptrs++); ptrd+=whd; }
  18487 + }
  18488 + return cimg::type<double>::nan();
  18489 + }
14900 18490
14901 - for (p_code = code._data; p_code<code.end(); ++p_code) {  
14902 - const CImg<longT> &op = *p_code;  
14903 - // Allows to avoid parameter passing to evaluation functions.  
14904 - opcode._data = op._data; opcode._height = op._height;  
14905 - const unsigned int target = (unsigned int)opcode[1];  
14906 - mem[target] = _cimg_mp_defunc(*this); 18491 + static double mp_set_Joff_s(_cimg_math_parser& mp) {
  18492 + CImg<T> &img = mp.imgout;
  18493 + const int
  18494 + ox = (int)mp.mem[_cimg_mp_x], oy = (int)mp.mem[_cimg_mp_y],
  18495 + oz = (int)mp.mem[_cimg_mp_z], oc = (int)mp.mem[_cimg_mp_c];
  18496 + const long
  18497 + off = img.offset(ox,oy,oz,oc) + (long)_mp_arg(2),
  18498 + whd = img.width()*img.height()*img.depth();
  18499 + const T val = (T)_mp_arg(1);
  18500 + if (off>=0 && off<whd) {
  18501 + T *ptrd = &img[off];
  18502 + cimg_forC(img,c) { *ptrd = val; ptrd+=whd; }
14907 } 18503 }
14908 - return mem[result]; 18504 + return _mp_arg(1);
  18505 + }
  18506 +
  18507 + static double mp_set_Joff_v(_cimg_math_parser& mp) {
  18508 + CImg<T> &img = mp.imgout;
  18509 + const int
  18510 + ox = (int)mp.mem[_cimg_mp_x], oy = (int)mp.mem[_cimg_mp_y],
  18511 + oz = (int)mp.mem[_cimg_mp_z], oc = (int)mp.mem[_cimg_mp_c];
  18512 + const long
  18513 + off = img.offset(ox,oy,oz,oc) + (long)_mp_arg(2),
  18514 + whd = img.width()*img.height()*img.depth();
  18515 + const double *ptrs = &_mp_arg(1) + 1;
  18516 + if (off>=0 && off<whd) {
  18517 + T *ptrd = &img[off];
  18518 + cimg_forC(img,c) { *ptrd = (T)*(ptrs++); ptrd+=whd; }
  18519 + }
  18520 + return cimg::type<double>::nan();
  18521 + }
  18522 +
  18523 + static double mp_set_Jxyz_s(_cimg_math_parser& mp) {
  18524 + CImg<T> &img = mp.imgout;
  18525 + const double ox = mp.mem[_cimg_mp_x], oy = mp.mem[_cimg_mp_y], oz = mp.mem[_cimg_mp_z];
  18526 + const int x = (int)(ox + _mp_arg(2)), y = (int)(oy + _mp_arg(3)), z = (int)(oz + _mp_arg(4));
  18527 + const T val = (T)_mp_arg(1);
  18528 + if (x>=0 && x<img.width() && y>=0 && y<img.height() && z>=0 && z<img.depth()) {
  18529 + T *ptrd = &img(x,y,z);
  18530 + const unsigned long whd = img._width*img._height*img._depth;
  18531 + cimg_forC(img,c) { *ptrd = val; ptrd+=whd; }
  18532 + }
  18533 + return _mp_arg(1);
  18534 + }
  18535 +
  18536 + static double mp_set_Jxyz_v(_cimg_math_parser& mp) {
  18537 + CImg<T> &img = mp.imgout;
  18538 + const double ox = mp.mem[_cimg_mp_x], oy = mp.mem[_cimg_mp_y], oz = mp.mem[_cimg_mp_z];
  18539 + const int x = (int)(ox + _mp_arg(2)), y = (int)(oy + _mp_arg(3)), z = (int)(oz + _mp_arg(4));
  18540 + const double *ptrs = &_mp_arg(1) + 1;
  18541 + if (x>=0 && x<img.width() && y>=0 && y<img.height() && z>=0 && z<img.depth()) {
  18542 + T *ptrd = &img(x,y,z);
  18543 + const unsigned long whd = img._width*img._height*img._depth;
  18544 + cimg_forC(img,c) { *ptrd = (T)*(ptrs++); ptrd+=whd; }
  18545 + }
  18546 + return cimg::type<double>::nan();
  18547 + }
  18548 +
  18549 + static double mp_sign(_cimg_math_parser& mp) {
  18550 + return cimg::sign(_mp_arg(2));
  18551 + }
  18552 +
  18553 + static double mp_sin(_cimg_math_parser& mp) {
  18554 + return std::sin(_mp_arg(2));
  18555 + }
  18556 +
  18557 + static double mp_sinc(_cimg_math_parser& mp) {
  18558 + return cimg::sinc(_mp_arg(2));
  18559 + }
  18560 +
  18561 + static double mp_sinh(_cimg_math_parser& mp) {
  18562 + return std::sinh(_mp_arg(2));
  18563 + }
  18564 +
  18565 + static double mp_sqr(_cimg_math_parser& mp) {
  18566 + return cimg::sqr(_mp_arg(2));
14909 } 18567 }
14910 - }; 18568 +
  18569 + static double mp_sqrt(_cimg_math_parser& mp) {
  18570 + return std::sqrt(_mp_arg(2));
  18571 + }
  18572 +
  18573 + static double mp_sub(_cimg_math_parser& mp) {
  18574 + return _mp_arg(2) - _mp_arg(3);
  18575 + }
  18576 +
  18577 + static double mp_tan(_cimg_math_parser& mp) {
  18578 + return std::tan(_mp_arg(2));
  18579 + }
  18580 +
  18581 + static double mp_tanh(_cimg_math_parser& mp) {
  18582 + return std::tanh(_mp_arg(2));
  18583 + }
  18584 +
  18585 + static double mp_u(_cimg_math_parser& mp) {
  18586 + return cimg::rand(_mp_arg(2),_mp_arg(3));
  18587 + }
  18588 +
  18589 + static double mp_vector_copy(_cimg_math_parser& mp) {
  18590 + std::memcpy(&_mp_arg(1) + 1,&_mp_arg(2) + 1,sizeof(double)*mp.opcode[3]);
  18591 + return cimg::type<double>::nan();
  18592 + }
  18593 +
  18594 + static double mp_vector_crop(_cimg_math_parser& mp) {
  18595 + double *const ptrd = &_mp_arg(1) + 1;
  18596 + const double *const ptrs = &_mp_arg(2) + 1;
  18597 + const unsigned int p1 = mp.opcode[3], p2 = mp.opcode[4];
  18598 + std::memcpy(ptrd,ptrs + p1,p2*sizeof(double));
  18599 + return cimg::type<double>::nan();
  18600 + }
  18601 +
  18602 + static double mp_vector_init(_cimg_math_parser& mp) {
  18603 + unsigned int
  18604 + ptrs = 3U,
  18605 + ptrd = (unsigned int)mp.opcode[1] + 1,
  18606 + siz = (unsigned int)mp.opcode[2];
  18607 + switch (mp.opcode._height) {
  18608 + case 3 : std::memset(mp.mem._data + ptrd,0,siz*sizeof(double)); break; // 0 values given
  18609 + case 4 : { const double val = _mp_arg(ptrs); while (siz-->0) mp.mem[ptrd++] = val; } break;
  18610 + default : while (siz-->0) { mp.mem[ptrd++] = _mp_arg(ptrs++); if (ptrs>=mp.opcode._height) ptrs = 3U; }
  18611 + }
  18612 + return cimg::type<double>::nan();
  18613 + }
  18614 +
  18615 + static double mp_vector_map_sv(_cimg_math_parser& mp) { // Operator(scalar,vector)
  18616 + unsigned int
  18617 + siz = (unsigned int)mp.opcode[2],
  18618 + ptrs = (unsigned int)mp.opcode[5] + 1;
  18619 + double *ptrd = &_mp_arg(1) + 1;
  18620 + mp_func op = (mp_func)mp.opcode[3];
  18621 + CImg<uptrT> l_opcode(4);
  18622 + l_opcode[2] = mp.opcode[4]; // Scalar argument1
  18623 + l_opcode.swap(mp.opcode);
  18624 + uptrT &argument2 = mp.opcode[3];
  18625 + while (siz-->0) { argument2 = ptrs++; *(ptrd++) = (*op)(mp); }
  18626 + l_opcode.swap(mp.opcode);
  18627 + return cimg::type<double>::nan();
  18628 + }
  18629 +
  18630 + static double mp_vector_map_v(_cimg_math_parser& mp) { // Operator(vector)
  18631 + unsigned int
  18632 + siz = (unsigned int)mp.opcode[2],
  18633 + ptrs = (unsigned int)mp.opcode[4] + 1;
  18634 + double *ptrd = &_mp_arg(1) + 1;
  18635 + mp_func op = (mp_func)mp.opcode[3];
  18636 + CImg<uptrT> l_opcode(1,3);
  18637 + l_opcode.swap(mp.opcode);
  18638 + uptrT &argument = mp.opcode[2];
  18639 + while (siz-->0) { argument = ptrs++; *(ptrd++) = (*op)(mp); }
  18640 + l_opcode.swap(mp.opcode);
  18641 + return cimg::type<double>::nan();
  18642 + }
  18643 +
  18644 + static double mp_vector_map_vs(_cimg_math_parser& mp) { // Operator(vector,scalar)
  18645 + unsigned int
  18646 + siz = (unsigned int)mp.opcode[2],
  18647 + ptrs = (unsigned int)mp.opcode[4] + 1;
  18648 + double *ptrd = &_mp_arg(1) + 1;
  18649 + mp_func op = (mp_func)mp.opcode[3];
  18650 + CImg<uptrT> l_opcode(1,4);
  18651 + l_opcode[3] = mp.opcode[5]; // Scalar argument2
  18652 + l_opcode.swap(mp.opcode);
  18653 + uptrT &argument1 = mp.opcode[2];
  18654 + while (siz-->0) { argument1 = ptrs++; *(ptrd++) = (*op)(mp); }
  18655 + l_opcode.swap(mp.opcode);
  18656 + return cimg::type<double>::nan();
  18657 + }
  18658 +
  18659 + static double mp_vector_map_vss(_cimg_math_parser& mp) { // Operator(vector,scalar,scalar)
  18660 + unsigned int
  18661 + siz = (unsigned int)mp.opcode[2],
  18662 + ptrs = (unsigned int)mp.opcode[4] + 1;
  18663 + double *ptrd = &_mp_arg(1) + 1;
  18664 + mp_func op = (mp_func)mp.opcode[3];
  18665 + CImg<uptrT> l_opcode(1,5);
  18666 + l_opcode[3] = mp.opcode[5]; // Scalar argument2
  18667 + l_opcode[4] = mp.opcode[6]; // Scalar argument3
  18668 + l_opcode.swap(mp.opcode);
  18669 + uptrT &argument1 = mp.opcode[2];
  18670 + while (siz-->0) { argument1 = ptrs++; *(ptrd++) = (*op)(mp); }
  18671 + l_opcode.swap(mp.opcode);
  18672 + return cimg::type<double>::nan();
  18673 + }
  18674 +
  18675 + static double mp_vector_map_vv(_cimg_math_parser& mp) { // Operator(vector,vector)
  18676 + unsigned int
  18677 + siz = (unsigned int)mp.opcode[2],
  18678 + ptrs1 = (unsigned int)mp.opcode[4] + 1,
  18679 + ptrs2 = (unsigned int)mp.opcode[5] + 1;
  18680 + double *ptrd = &_mp_arg(1) + 1;
  18681 + mp_func op = (mp_func)mp.opcode[3];
  18682 + CImg<uptrT> l_opcode(1,4);
  18683 + l_opcode.swap(mp.opcode);
  18684 + uptrT &argument1 = mp.opcode[2], &argument2 = mp.opcode[3];
  18685 + while (siz-->0) { argument1 = ptrs1++; argument2 = ptrs2++; *(ptrd++) = (*op)(mp); }
  18686 + l_opcode.swap(mp.opcode);
  18687 + return cimg::type<double>::nan();
  18688 + }
  18689 +
  18690 + static double mp_vector_off(_cimg_math_parser& mp) {
  18691 + const unsigned int
  18692 + ptr = mp.opcode[2] + 1,
  18693 + siz = (int)mp.opcode[3];
  18694 + const int off = (int)_mp_arg(4);
  18695 + return off>=0 && off<(int)siz?mp.mem[ptr + off]:cimg::type<double>::nan();
  18696 + }
  18697 +
  18698 + static double mp_vector_set_off(_cimg_math_parser& mp) {
  18699 + const unsigned int
  18700 + ptr = mp.opcode[2] + 1,
  18701 + siz = mp.opcode[3];
  18702 + const int off = (int)_mp_arg(4);
  18703 + if (off>=0 && off<(int)siz) mp.mem[ptr + off] = _mp_arg(5);
  18704 + return _mp_arg(5);
  18705 + }
  18706 +
  18707 + static double mp_vector_sort(_cimg_math_parser& mp) {
  18708 + double *const ptrd = &_mp_arg(1) + 1;
  18709 + const double *const ptrs = &_mp_arg(2) + 1;
  18710 + const unsigned int siz = mp.opcode[3];
  18711 + const bool is_increasing = (bool)_mp_arg(4);
  18712 + CImg<doubleT>(ptrd,1,siz,1,1,true) = CImg<doubleT>(ptrs,1,siz,1,1,true).get_sort(is_increasing);
  18713 + return cimg::type<double>::nan();
  18714 + }
  18715 +
  18716 + static double mp_vector_print(_cimg_math_parser& mp) {
  18717 + CImg<charT> expr(mp.opcode._height - 3);
  18718 + const uptrT *ptrs = mp.opcode._data + 3;
  18719 + cimg_for(expr,ptrd,char) *ptrd = (char)*(ptrs++);
  18720 + cimg::strellipsize(expr);
  18721 + unsigned int
  18722 + ptr = mp.opcode[1] + 1,
  18723 + siz = mp.opcode[2];
  18724 + std::fprintf(cimg::output(),"\n[_cimg_math_parser] %s = [",expr._data);
  18725 + while (siz-->0) std::fprintf(cimg::output(),"%g%s",mp.mem[ptr++],siz?",":"");
  18726 + std::fputc(']',cimg::output());
  18727 + std::fflush(cimg::output());
  18728 + return cimg::type<double>::nan();
  18729 + }
  18730 +
  18731 + static double mp_whiledo(_cimg_math_parser& mp) { // Used also by 'for()'
  18732 + const uptrT
  18733 + mem_proc = mp.opcode[1],
  18734 + mem_cond = mp.opcode[2];
  18735 + const CImg<uptrT>
  18736 + *const p_cond = ++mp.p_code,
  18737 + *const p_proc = p_cond + mp.opcode[3],
  18738 + *const p_end = p_proc + mp.opcode[4];
  18739 + const unsigned int vsiz = mp.opcode[5];
  18740 + bool is_first_iter = true, is_cond = false;
  18741 + do {
  18742 + for (mp.p_code = p_cond; mp.p_code<p_proc; ++mp.p_code) { // Evaluate loop condition
  18743 + const CImg<uptrT> &op = *mp.p_code;
  18744 + mp.opcode._data = op._data; mp.opcode._height = op._height;
  18745 + const uptrT target = mp.opcode[1];
  18746 + mp.mem[target] = _cimg_mp_defunc(mp);
  18747 + }
  18748 + is_cond = (bool)mp.mem[mem_cond];
  18749 + if (is_cond) { // Evaluate loop iteration
  18750 + for ( ; mp.p_code<p_end; ++mp.p_code) {
  18751 + const CImg<uptrT> &op = *mp.p_code;
  18752 + mp.opcode._data = op._data; mp.opcode._height = op._height;
  18753 + const uptrT target = mp.opcode[1];
  18754 + mp.mem[target] = _cimg_mp_defunc(mp);
  18755 + }
  18756 + is_first_iter = false;
  18757 + }
  18758 + } while (is_cond);
  18759 + mp.p_code = p_end - 1;
  18760 + if (vsiz && is_first_iter) std::memset(&mp.mem[mem_proc] + 1,0,vsiz*sizeof(double));
  18761 + return is_first_iter?0:mp.mem[mem_proc];
  18762 + }
  18763 +
  18764 + static double mp_Ioff(_cimg_math_parser& mp) {
  18765 + double *ptrd = &_mp_arg(1) + 1;
  18766 + const unsigned int
  18767 + boundary_conditions = (unsigned int)_mp_arg(3);
  18768 + const CImg<T> &img = mp.imgin;
  18769 + const long
  18770 + off = (long)_mp_arg(2),
  18771 + whd = img.width()*img.height()*img.depth();
  18772 + const T *ptrs;
  18773 + if (off<0 || off>=whd)
  18774 + switch (boundary_conditions) {
  18775 + case 2 : // Periodic boundary
  18776 + if (!img) {
  18777 + ptrs = &img[cimg::mod(off,whd)];
  18778 + cimg_forC(img,c) { *(ptrd++) = *ptrs; ptrs+=whd; }
  18779 + } else std::memset(ptrd,0,img._spectrum*sizeof(double));
  18780 + return cimg::type<double>::nan();
  18781 + case 1 : // Neumann boundary
  18782 + if (img) {
  18783 + ptrs = off<0?img._data:&img.back();
  18784 + cimg_forC(img,c) { *(ptrd++) = *ptrs; ptrs+=whd; }
  18785 + } else std::memset(ptrd,0,img._spectrum*sizeof(double));
  18786 + return cimg::type<double>::nan();
  18787 + default : // Dirichet boundary
  18788 + std::memset(ptrd,0,img._spectrum*sizeof(double));
  18789 + return cimg::type<double>::nan();
  18790 + }
  18791 + ptrs = &img[off];
  18792 + cimg_forC(img,c) { *(ptrd++) = *ptrs; ptrs+=whd; }
  18793 + return cimg::type<double>::nan();
  18794 + }
  18795 +
  18796 + static double mp_Ixyz(_cimg_math_parser& mp) {
  18797 + double *ptrd = &_mp_arg(1) + 1;
  18798 + const unsigned int
  18799 + interpolation = (unsigned int)_mp_arg(5),
  18800 + boundary_conditions = (unsigned int)_mp_arg(6);
  18801 + const CImg<T> &img = mp.imgin;
  18802 + const double x = _mp_arg(2), y = _mp_arg(3), z = _mp_arg(4);
  18803 + if (interpolation==0) { // Nearest neighbor interpolation
  18804 + if (boundary_conditions==2)
  18805 + cimg_forC(img,c)
  18806 + *(ptrd++) = (double)img.atXYZ(cimg::mod((int)x,img.width()),
  18807 + cimg::mod((int)y,img.height()),
  18808 + cimg::mod((int)z,img.depth()),
  18809 + c);
  18810 + else if (boundary_conditions==1)
  18811 + cimg_forC(img,c)
  18812 + *(ptrd++) = (double)img.atXYZ((int)x,(int)y,(int)z,c);
  18813 + else
  18814 + cimg_forC(img,c)
  18815 + *(ptrd++) = (double)img.atXYZ((int)x,(int)y,(int)z,c,0);
  18816 + } else { // Linear interpolation
  18817 + if (boundary_conditions==2)
  18818 + cimg_forC(img,c)
  18819 + *(ptrd++) = (double)img.linear_atXYZ(cimg::mod((float)x,(float)img.width()),
  18820 + cimg::mod((float)y,(float)img.height()),
  18821 + cimg::mod((float)z,(float)img.depth()),c);
  18822 + else if (boundary_conditions==1)
  18823 + cimg_forC(img,c)
  18824 + *(ptrd++) = (double)img.linear_atXYZ((float)x,(float)y,(float)z,c);
  18825 + else
  18826 + cimg_forC(img,c)
  18827 + *(ptrd++) = (double)img.linear_atXYZ((float)x,(float)y,(float)z,c,0);
  18828 + }
  18829 + return cimg::type<double>::nan();
  18830 + }
  18831 +
  18832 + static double mp_Joff(_cimg_math_parser& mp) {
  18833 + double *ptrd = &_mp_arg(1) + 1;
  18834 + const unsigned int
  18835 + boundary_conditions = (unsigned int)_mp_arg(3);
  18836 + const CImg<T> &img = mp.imgin;
  18837 + const int ox = (int)mp.mem[_cimg_mp_x], oy = (int)mp.mem[_cimg_mp_y], oz = (int)mp.mem[_cimg_mp_z];
  18838 + const long
  18839 + off = img.offset(ox,oy,oz) + (long)_mp_arg(2),
  18840 + whd = img.width()*img.height()*img.depth();
  18841 + const T *ptrs;
  18842 + if (off<0 || off>=whd)
  18843 + switch (boundary_conditions) {
  18844 + case 2 : // Periodic boundary
  18845 + if (!img) {
  18846 + ptrs = &img[cimg::mod(off,whd)];
  18847 + cimg_forC(img,c) { *(ptrd++) = *ptrs; ptrs+=whd; }
  18848 + } else std::memset(ptrd,0,img._spectrum*sizeof(double));
  18849 + return cimg::type<double>::nan();
  18850 + case 1 : // Neumann boundary
  18851 + if (img) {
  18852 + ptrs = off<0?img._data:&img.back();
  18853 + cimg_forC(img,c) { *(ptrd++) = *ptrs; ptrs+=whd; }
  18854 + } else std::memset(ptrd,0,img._spectrum*sizeof(double));
  18855 + return cimg::type<double>::nan();
  18856 + default : // Dirichet boundary
  18857 + std::memset(ptrd,0,img._spectrum*sizeof(double));
  18858 + return cimg::type<double>::nan();
  18859 + }
  18860 + ptrs = &img[off];
  18861 + cimg_forC(img,c) { *(ptrd++) = *ptrs; ptrs+=whd; }
  18862 + return cimg::type<double>::nan();
  18863 + }
  18864 +
  18865 + static double mp_Jxyz(_cimg_math_parser& mp) {
  18866 + double *ptrd = &_mp_arg(1) + 1;
  18867 + const unsigned int
  18868 + interpolation = (unsigned int)_mp_arg(5),
  18869 + boundary_conditions = (unsigned int)_mp_arg(6);
  18870 + const CImg<T> &img = mp.imgin;
  18871 + const double
  18872 + ox = mp.mem[_cimg_mp_x], oy = mp.mem[_cimg_mp_y], oz = mp.mem[_cimg_mp_z],
  18873 + x = ox + _mp_arg(2), y = oy + _mp_arg(3), z = oz + _mp_arg(4);
  18874 + if (interpolation==0) { // Nearest neighbor interpolation
  18875 + if (boundary_conditions==2)
  18876 + cimg_forC(img,c)
  18877 + *(ptrd++) = (double)img.atXYZ(cimg::mod((int)x,img.width()),
  18878 + cimg::mod((int)y,img.height()),
  18879 + cimg::mod((int)z,img.depth()),
  18880 + c);
  18881 + else if (boundary_conditions==1)
  18882 + cimg_forC(img,c)
  18883 + *(ptrd++) = (double)img.atXYZ((int)x,(int)y,(int)z,c);
  18884 + else
  18885 + cimg_forC(img,c)
  18886 + *(ptrd++) = (double)img.atXYZ((int)x,(int)y,(int)z,c,0);
  18887 + } else { // Linear interpolation
  18888 + if (boundary_conditions==2)
  18889 + cimg_forC(img,c)
  18890 + *(ptrd++) = (double)img.linear_atXYZ(cimg::mod((float)x,(float)img.width()),
  18891 + cimg::mod((float)y,(float)img.height()),
  18892 + cimg::mod((float)z,(float)img.depth()),c);
  18893 + else if (boundary_conditions==1)
  18894 + cimg_forC(img,c)
  18895 + *(ptrd++) = (double)img.linear_atXYZ((float)x,(float)y,(float)z,c);
  18896 + else
  18897 + cimg_forC(img,c)
  18898 + *(ptrd++) = (double)img.linear_atXYZ((float)x,(float)y,(float)z,c,0);
  18899 + }
  18900 + return cimg::type<double>::nan();
  18901 + }
  18902 +
  18903 +#undef _mp_arg
  18904 +
  18905 + }; // struct _cimg_math_parser {}
14911 18906
14912 //! Compute the square value of each pixel value. 18907 //! Compute the square value of each pixel value.
14913 /** 18908 /**
@@ -14925,7 +18920,7 @@ namespace cimg_library_suffixed { @@ -14925,7 +18920,7 @@ namespace cimg_library_suffixed {
14925 CImg<T>& sqr() { 18920 CImg<T>& sqr() {
14926 if (is_empty()) return *this; 18921 if (is_empty()) return *this;
14927 #ifdef cimg_use_openmp 18922 #ifdef cimg_use_openmp
14928 -#pragma omp parallel for if (size()>=524288) 18923 +#pragma omp parallel for cimg_openmp_if(size()>=524288)
14929 #endif 18924 #endif
14930 cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = (T)(val*val); }; 18925 cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = (T)(val*val); };
14931 return *this; 18926 return *this;
@@ -14952,7 +18947,7 @@ namespace cimg_library_suffixed { @@ -14952,7 +18947,7 @@ namespace cimg_library_suffixed {
14952 CImg<T>& sqrt() { 18947 CImg<T>& sqrt() {
14953 if (is_empty()) return *this; 18948 if (is_empty()) return *this;
14954 #ifdef cimg_use_openmp 18949 #ifdef cimg_use_openmp
14955 -#pragma omp parallel for if (size()>=8192) 18950 +#pragma omp parallel for cimg_openmp_if(size()>=8192)
14956 #endif 18951 #endif
14957 cimg_rof(*this,ptrd,T) *ptrd = (T)std::sqrt((double)*ptrd); 18952 cimg_rof(*this,ptrd,T) *ptrd = (T)std::sqrt((double)*ptrd);
14958 return *this; 18953 return *this;
@@ -14973,7 +18968,7 @@ namespace cimg_library_suffixed { @@ -14973,7 +18968,7 @@ namespace cimg_library_suffixed {
14973 CImg<T>& exp() { 18968 CImg<T>& exp() {
14974 if (is_empty()) return *this; 18969 if (is_empty()) return *this;
14975 #ifdef cimg_use_openmp 18970 #ifdef cimg_use_openmp
14976 -#pragma omp parallel for if (size()>=4096) 18971 +#pragma omp parallel for cimg_openmp_if(size()>=4096)
14977 #endif 18972 #endif
14978 cimg_rof(*this,ptrd,T) *ptrd = (T)std::exp((double)*ptrd); 18973 cimg_rof(*this,ptrd,T) *ptrd = (T)std::exp((double)*ptrd);
14979 return *this; 18974 return *this;
@@ -14995,7 +18990,7 @@ namespace cimg_library_suffixed { @@ -14995,7 +18990,7 @@ namespace cimg_library_suffixed {
14995 CImg<T>& log() { 18990 CImg<T>& log() {
14996 if (is_empty()) return *this; 18991 if (is_empty()) return *this;
14997 #ifdef cimg_use_openmp 18992 #ifdef cimg_use_openmp
14998 -#pragma omp parallel for if (size()>=262144) 18993 +#pragma omp parallel for cimg_openmp_if(size()>=262144)
14999 #endif 18994 #endif
15000 cimg_rof(*this,ptrd,T) *ptrd = (T)std::log((double)*ptrd); 18995 cimg_rof(*this,ptrd,T) *ptrd = (T)std::log((double)*ptrd);
15001 return *this; 18996 return *this;
@@ -15017,7 +19012,7 @@ namespace cimg_library_suffixed { @@ -15017,7 +19012,7 @@ namespace cimg_library_suffixed {
15017 CImg<T>& log2() { 19012 CImg<T>& log2() {
15018 if (is_empty()) return *this; 19013 if (is_empty()) return *this;
15019 #ifdef cimg_use_openmp 19014 #ifdef cimg_use_openmp
15020 -#pragma omp parallel for if (size()>=4096) 19015 +#pragma omp parallel for cimg_openmp_if(size()>=4096)
15021 #endif 19016 #endif
15022 cimg_rof(*this,ptrd,T) *ptrd = (T)cimg::log2((double)*ptrd); 19017 cimg_rof(*this,ptrd,T) *ptrd = (T)cimg::log2((double)*ptrd);
15023 return *this; 19018 return *this;
@@ -15039,7 +19034,7 @@ namespace cimg_library_suffixed { @@ -15039,7 +19034,7 @@ namespace cimg_library_suffixed {
15039 CImg<T>& log10() { 19034 CImg<T>& log10() {
15040 if (is_empty()) return *this; 19035 if (is_empty()) return *this;
15041 #ifdef cimg_use_openmp 19036 #ifdef cimg_use_openmp
15042 -#pragma omp parallel for if (size()>=4096) 19037 +#pragma omp parallel for cimg_openmp_if(size()>=4096)
15043 #endif 19038 #endif
15044 cimg_rof(*this,ptrd,T) *ptrd = (T)std::log10((double)*ptrd); 19039 cimg_rof(*this,ptrd,T) *ptrd = (T)std::log10((double)*ptrd);
15045 return *this; 19040 return *this;
@@ -15060,7 +19055,7 @@ namespace cimg_library_suffixed { @@ -15060,7 +19055,7 @@ namespace cimg_library_suffixed {
15060 CImg<T>& abs() { 19055 CImg<T>& abs() {
15061 if (is_empty()) return *this; 19056 if (is_empty()) return *this;
15062 #ifdef cimg_use_openmp 19057 #ifdef cimg_use_openmp
15063 -#pragma omp parallel for if (size()>=524288) 19058 +#pragma omp parallel for cimg_openmp_if(size()>=524288)
15064 #endif 19059 #endif
15065 cimg_rof(*this,ptrd,T) *ptrd = cimg::abs(*ptrd); 19060 cimg_rof(*this,ptrd,T) *ptrd = cimg::abs(*ptrd);
15066 return *this; 19061 return *this;
@@ -15086,7 +19081,7 @@ namespace cimg_library_suffixed { @@ -15086,7 +19081,7 @@ namespace cimg_library_suffixed {
15086 CImg<T>& sign() { 19081 CImg<T>& sign() {
15087 if (is_empty()) return *this; 19082 if (is_empty()) return *this;
15088 #ifdef cimg_use_openmp 19083 #ifdef cimg_use_openmp
15089 -#pragma omp parallel for if (size()>=32768) 19084 +#pragma omp parallel for cimg_openmp_if(size()>=32768)
15090 #endif 19085 #endif
15091 cimg_rof(*this,ptrd,T) *ptrd = cimg::sign(*ptrd); 19086 cimg_rof(*this,ptrd,T) *ptrd = cimg::sign(*ptrd);
15092 return *this; 19087 return *this;
@@ -15108,7 +19103,7 @@ namespace cimg_library_suffixed { @@ -15108,7 +19103,7 @@ namespace cimg_library_suffixed {
15108 CImg<T>& cos() { 19103 CImg<T>& cos() {
15109 if (is_empty()) return *this; 19104 if (is_empty()) return *this;
15110 #ifdef cimg_use_openmp 19105 #ifdef cimg_use_openmp
15111 -#pragma omp parallel for if (size()>=8192) 19106 +#pragma omp parallel for cimg_openmp_if(size()>=8192)
15112 #endif 19107 #endif
15113 cimg_rof(*this,ptrd,T) *ptrd = (T)std::cos((double)*ptrd); 19108 cimg_rof(*this,ptrd,T) *ptrd = (T)std::cos((double)*ptrd);
15114 return *this; 19109 return *this;
@@ -15130,7 +19125,7 @@ namespace cimg_library_suffixed { @@ -15130,7 +19125,7 @@ namespace cimg_library_suffixed {
15130 CImg<T>& sin() { 19125 CImg<T>& sin() {
15131 if (is_empty()) return *this; 19126 if (is_empty()) return *this;
15132 #ifdef cimg_use_openmp 19127 #ifdef cimg_use_openmp
15133 -#pragma omp parallel for if (size()>=8192) 19128 +#pragma omp parallel for cimg_openmp_if(size()>=8192)
15134 #endif 19129 #endif
15135 cimg_rof(*this,ptrd,T) *ptrd = (T)std::sin((double)*ptrd); 19130 cimg_rof(*this,ptrd,T) *ptrd = (T)std::sin((double)*ptrd);
15136 return *this; 19131 return *this;
@@ -15153,7 +19148,7 @@ namespace cimg_library_suffixed { @@ -15153,7 +19148,7 @@ namespace cimg_library_suffixed {
15153 CImg<T>& sinc() { 19148 CImg<T>& sinc() {
15154 if (is_empty()) return *this; 19149 if (is_empty()) return *this;
15155 #ifdef cimg_use_openmp 19150 #ifdef cimg_use_openmp
15156 -#pragma omp parallel for if (size()>=2048) 19151 +#pragma omp parallel for cimg_openmp_if(size()>=2048)
15157 #endif 19152 #endif
15158 cimg_rof(*this,ptrd,T) *ptrd = (T)cimg::sinc((double)*ptrd); 19153 cimg_rof(*this,ptrd,T) *ptrd = (T)cimg::sinc((double)*ptrd);
15159 return *this; 19154 return *this;
@@ -15175,7 +19170,7 @@ namespace cimg_library_suffixed { @@ -15175,7 +19170,7 @@ namespace cimg_library_suffixed {
15175 CImg<T>& tan() { 19170 CImg<T>& tan() {
15176 if (is_empty()) return *this; 19171 if (is_empty()) return *this;
15177 #ifdef cimg_use_openmp 19172 #ifdef cimg_use_openmp
15178 -#pragma omp parallel for if (size()>=2048) 19173 +#pragma omp parallel for cimg_openmp_if(size()>=2048)
15179 #endif 19174 #endif
15180 cimg_rof(*this,ptrd,T) *ptrd = (T)std::tan((double)*ptrd); 19175 cimg_rof(*this,ptrd,T) *ptrd = (T)std::tan((double)*ptrd);
15181 return *this; 19176 return *this;
@@ -15197,7 +19192,7 @@ namespace cimg_library_suffixed { @@ -15197,7 +19192,7 @@ namespace cimg_library_suffixed {
15197 CImg<T>& cosh() { 19192 CImg<T>& cosh() {
15198 if (is_empty()) return *this; 19193 if (is_empty()) return *this;
15199 #ifdef cimg_use_openmp 19194 #ifdef cimg_use_openmp
15200 -#pragma omp parallel for if (size()>=2048) 19195 +#pragma omp parallel for cimg_openmp_if(size()>=2048)
15201 #endif 19196 #endif
15202 cimg_rof(*this,ptrd,T) *ptrd = (T)std::cosh((double)*ptrd); 19197 cimg_rof(*this,ptrd,T) *ptrd = (T)std::cosh((double)*ptrd);
15203 return *this; 19198 return *this;
@@ -15219,7 +19214,7 @@ namespace cimg_library_suffixed { @@ -15219,7 +19214,7 @@ namespace cimg_library_suffixed {
15219 CImg<T>& sinh() { 19214 CImg<T>& sinh() {
15220 if (is_empty()) return *this; 19215 if (is_empty()) return *this;
15221 #ifdef cimg_use_openmp 19216 #ifdef cimg_use_openmp
15222 -#pragma omp parallel for if (size()>=2048) 19217 +#pragma omp parallel for cimg_openmp_if(size()>=2048)
15223 #endif 19218 #endif
15224 cimg_rof(*this,ptrd,T) *ptrd = (T)std::sinh((double)*ptrd); 19219 cimg_rof(*this,ptrd,T) *ptrd = (T)std::sinh((double)*ptrd);
15225 return *this; 19220 return *this;
@@ -15241,7 +19236,7 @@ namespace cimg_library_suffixed { @@ -15241,7 +19236,7 @@ namespace cimg_library_suffixed {
15241 CImg<T>& tanh() { 19236 CImg<T>& tanh() {
15242 if (is_empty()) return *this; 19237 if (is_empty()) return *this;
15243 #ifdef cimg_use_openmp 19238 #ifdef cimg_use_openmp
15244 -#pragma omp parallel for if (size()>=2048) 19239 +#pragma omp parallel for cimg_openmp_if(size()>=2048)
15245 #endif 19240 #endif
15246 cimg_rof(*this,ptrd,T) *ptrd = (T)std::tanh((double)*ptrd); 19241 cimg_rof(*this,ptrd,T) *ptrd = (T)std::tanh((double)*ptrd);
15247 return *this; 19242 return *this;
@@ -15263,7 +19258,7 @@ namespace cimg_library_suffixed { @@ -15263,7 +19258,7 @@ namespace cimg_library_suffixed {
15263 CImg<T>& acos() { 19258 CImg<T>& acos() {
15264 if (is_empty()) return *this; 19259 if (is_empty()) return *this;
15265 #ifdef cimg_use_openmp 19260 #ifdef cimg_use_openmp
15266 -#pragma omp parallel for if (size()>=8192) 19261 +#pragma omp parallel for cimg_openmp_if(size()>=8192)
15267 #endif 19262 #endif
15268 cimg_rof(*this,ptrd,T) *ptrd = (T)std::acos((double)*ptrd); 19263 cimg_rof(*this,ptrd,T) *ptrd = (T)std::acos((double)*ptrd);
15269 return *this; 19264 return *this;
@@ -15285,7 +19280,7 @@ namespace cimg_library_suffixed { @@ -15285,7 +19280,7 @@ namespace cimg_library_suffixed {
15285 CImg<T>& asin() { 19280 CImg<T>& asin() {
15286 if (is_empty()) return *this; 19281 if (is_empty()) return *this;
15287 #ifdef cimg_use_openmp 19282 #ifdef cimg_use_openmp
15288 -#pragma omp parallel for if (size()>=8192) 19283 +#pragma omp parallel for cimg_openmp_if(size()>=8192)
15289 #endif 19284 #endif
15290 cimg_rof(*this,ptrd,T) *ptrd = (T)std::asin((double)*ptrd); 19285 cimg_rof(*this,ptrd,T) *ptrd = (T)std::asin((double)*ptrd);
15291 return *this; 19286 return *this;
@@ -15307,7 +19302,7 @@ namespace cimg_library_suffixed { @@ -15307,7 +19302,7 @@ namespace cimg_library_suffixed {
15307 CImg<T>& atan() { 19302 CImg<T>& atan() {
15308 if (is_empty()) return *this; 19303 if (is_empty()) return *this;
15309 #ifdef cimg_use_openmp 19304 #ifdef cimg_use_openmp
15310 -#pragma omp parallel for if (size()>=8192) 19305 +#pragma omp parallel for cimg_openmp_if(size()>=8192)
15311 #endif 19306 #endif
15312 cimg_rof(*this,ptrd,T) *ptrd = (T)std::atan((double)*ptrd); 19307 cimg_rof(*this,ptrd,T) *ptrd = (T)std::atan((double)*ptrd);
15313 return *this; 19308 return *this;
@@ -15436,35 +19431,35 @@ namespace cimg_library_suffixed { @@ -15436,35 +19431,35 @@ namespace cimg_library_suffixed {
15436 if (is_empty()) return *this; 19431 if (is_empty()) return *this;
15437 if (p==-4) { 19432 if (p==-4) {
15438 #ifdef cimg_use_openmp 19433 #ifdef cimg_use_openmp
15439 -#pragma omp parallel for if (size()>=32768) 19434 +#pragma omp parallel for cimg_openmp_if(size()>=32768)
15440 #endif 19435 #endif
15441 cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = (T)(1.0/(val*val*val*val)); } 19436 cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = (T)(1.0/(val*val*val*val)); }
15442 return *this; 19437 return *this;
15443 } 19438 }
15444 if (p==-3) { 19439 if (p==-3) {
15445 #ifdef cimg_use_openmp 19440 #ifdef cimg_use_openmp
15446 -#pragma omp parallel for if (size()>=32768) 19441 +#pragma omp parallel for cimg_openmp_if(size()>=32768)
15447 #endif 19442 #endif
15448 cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = (T)(1.0/(val*val*val)); } 19443 cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = (T)(1.0/(val*val*val)); }
15449 return *this; 19444 return *this;
15450 } 19445 }
15451 if (p==-2) { 19446 if (p==-2) {
15452 #ifdef cimg_use_openmp 19447 #ifdef cimg_use_openmp
15453 -#pragma omp parallel for if (size()>=32768) 19448 +#pragma omp parallel for cimg_openmp_if(size()>=32768)
15454 #endif 19449 #endif
15455 cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = (T)(1.0/(val*val)); } 19450 cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = (T)(1.0/(val*val)); }
15456 return *this; 19451 return *this;
15457 } 19452 }
15458 if (p==-1) { 19453 if (p==-1) {
15459 #ifdef cimg_use_openmp 19454 #ifdef cimg_use_openmp
15460 -#pragma omp parallel for if (size()>=32768) 19455 +#pragma omp parallel for cimg_openmp_if(size()>=32768)
15461 #endif 19456 #endif
15462 cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = (T)(1.0/val); } 19457 cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = (T)(1.0/val); }
15463 return *this; 19458 return *this;
15464 } 19459 }
15465 if (p==-0.5) { 19460 if (p==-0.5) {
15466 #ifdef cimg_use_openmp 19461 #ifdef cimg_use_openmp
15467 -#pragma omp parallel for if (size()>=8192) 19462 +#pragma omp parallel for cimg_openmp_if(size()>=8192)
15468 #endif 19463 #endif
15469 cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = (T)(1/std::sqrt((double)val)); } 19464 cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = (T)(1/std::sqrt((double)val)); }
15470 return *this; 19465 return *this;
@@ -15475,20 +19470,20 @@ namespace cimg_library_suffixed { @@ -15475,20 +19470,20 @@ namespace cimg_library_suffixed {
15475 if (p==2) return sqr(); 19470 if (p==2) return sqr();
15476 if (p==3) { 19471 if (p==3) {
15477 #ifdef cimg_use_openmp 19472 #ifdef cimg_use_openmp
15478 -#pragma omp parallel for if (size()>=262144) 19473 +#pragma omp parallel for cimg_openmp_if(size()>=262144)
15479 #endif 19474 #endif
15480 cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = val*val*val; } 19475 cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = val*val*val; }
15481 return *this; 19476 return *this;
15482 } 19477 }
15483 if (p==4) { 19478 if (p==4) {
15484 #ifdef cimg_use_openmp 19479 #ifdef cimg_use_openmp
15485 -#pragma omp parallel for if (size()>=131072) 19480 +#pragma omp parallel for cimg_openmp_if(size()>=131072)
15486 #endif 19481 #endif
15487 cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = val*val*val*val; } 19482 cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = val*val*val*val; }
15488 return *this; 19483 return *this;
15489 } 19484 }
15490 #ifdef cimg_use_openmp 19485 #ifdef cimg_use_openmp
15491 -#pragma omp parallel for if (size()>=1024) 19486 +#pragma omp parallel for cimg_openmp_if(size()>=1024)
15492 #endif 19487 #endif
15493 cimg_rof(*this,ptrd,T) *ptrd = (T)std::pow((double)*ptrd,p); 19488 cimg_rof(*this,ptrd,T) *ptrd = (T)std::pow((double)*ptrd,p);
15494 return *this; 19489 return *this;
@@ -15504,44 +19499,7 @@ namespace cimg_library_suffixed { @@ -15504,44 +19499,7 @@ namespace cimg_library_suffixed {
15504 Similar to operator+=(const char*), except it performs a pointwise exponentiation instead of an addition. 19499 Similar to operator+=(const char*), except it performs a pointwise exponentiation instead of an addition.
15505 **/ 19500 **/
15506 CImg<T>& pow(const char *const expression) { 19501 CImg<T>& pow(const char *const expression) {
15507 - if (is_empty()) return *this;  
15508 - const unsigned int omode = cimg::exception_mode();  
15509 - cimg::exception_mode(0);  
15510 - try {  
15511 - const CImg<T> _base = cimg::_is_self_expr(expression)?+*this:CImg<T>(), &base = _base?_base:*this;  
15512 - _cimg_math_parser mp(base,expression + (*expression=='>' || *expression=='<'?1:0),"pow");  
15513 - T *ptrd = *expression=='<'?end() - 1:_data;  
15514 - if (*expression=='<') cimg_rofXYZC(*this,x,y,z,c) { *ptrd = (T)std::pow((double)*ptrd,mp(x,y,z,c)); --ptrd; }  
15515 - else if (*expression=='>')  
15516 - cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)std::pow((double)*ptrd,mp(x,y,z,c)); ++ptrd; }  
15517 - else {  
15518 -#ifdef cimg_use_openmp  
15519 - if (_width>=512 && _height*_depth*_spectrum>=2 && std::strlen(expression)>=6)  
15520 -#pragma omp parallel  
15521 - {  
15522 - _cimg_math_parser _mp = omp_get_thread_num()?mp:_cimg_math_parser(), &lmp = omp_get_thread_num()?_mp:mp;  
15523 -#pragma omp for collapse(3)  
15524 - cimg_forYZC(*this,y,z,c) {  
15525 - T *ptrd = data(0,y,z,c);  
15526 - cimg_forX(*this,x) { *ptrd = (T)std::pow((double)*ptrd,lmp(x,y,z,c)); ++ptrd; }  
15527 - }  
15528 - }  
15529 - else  
15530 -#endif  
15531 - cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)std::pow((double)*ptrd,mp(x,y,z,c)); ++ptrd; }  
15532 - }  
15533 - } catch (CImgException&) {  
15534 - CImg<Tfloat> values(_width,_height,_depth,_spectrum);  
15535 - try {  
15536 - values.fill(expression,true);  
15537 - } catch (CImgException&) {  
15538 - cimg::exception_mode(omode);  
15539 - values.load(expression);  
15540 - }  
15541 - pow(values);  
15542 - }  
15543 - cimg::exception_mode(omode);  
15544 - return *this; 19502 + return pow((+*this)._fill(expression,true,true,0,0,"pow",this));
15545 } 19503 }
15546 19504
15547 //! Raise each pixel value to a power, specified from an expression \newinstance. 19505 //! Raise each pixel value to a power, specified from an expression \newinstance.
@@ -15580,7 +19538,7 @@ namespace cimg_library_suffixed { @@ -15580,7 +19538,7 @@ namespace cimg_library_suffixed {
15580 CImg<T>& rol(const unsigned int n=1) { 19538 CImg<T>& rol(const unsigned int n=1) {
15581 if (is_empty()) return *this; 19539 if (is_empty()) return *this;
15582 #ifdef cimg_use_openmp 19540 #ifdef cimg_use_openmp
15583 -#pragma omp parallel for if (size()>=32768) 19541 +#pragma omp parallel for cimg_openmp_if(size()>=32768)
15584 #endif 19542 #endif
15585 cimg_rof(*this,ptrd,T) *ptrd = (T)cimg::rol(*ptrd,n); 19543 cimg_rof(*this,ptrd,T) *ptrd = (T)cimg::rol(*ptrd,n);
15586 return *this; 19544 return *this;
@@ -15596,45 +19554,7 @@ namespace cimg_library_suffixed { @@ -15596,45 +19554,7 @@ namespace cimg_library_suffixed {
15596 Similar to operator<<=(const char*), except that it performs a left rotation instead of a left shift. 19554 Similar to operator<<=(const char*), except that it performs a left rotation instead of a left shift.
15597 **/ 19555 **/
15598 CImg<T>& rol(const char *const expression) { 19556 CImg<T>& rol(const char *const expression) {
15599 - if (is_empty()) return *this;  
15600 - const unsigned int omode = cimg::exception_mode();  
15601 - cimg::exception_mode(0);  
15602 - try {  
15603 - const CImg<T> _base = cimg::_is_self_expr(expression)?+*this:CImg<T>(), &base = _base?_base:*this;  
15604 - _cimg_math_parser mp(base,expression + (*expression=='>' || *expression=='<'?1:0),"rol");  
15605 - T *ptrd = *expression=='<'?end() - 1:_data;  
15606 - if (*expression=='<')  
15607 - cimg_rofXYZC(*this,x,y,z,c) { *ptrd = (T)cimg::rol(*ptrd,(unsigned int)mp(x,y,z,c)); --ptrd; }  
15608 - else if (*expression=='>')  
15609 - cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)cimg::rol(*ptrd,(unsigned int)mp(x,y,z,c)); ++ptrd; }  
15610 - else {  
15611 -#ifdef cimg_use_openmp  
15612 - if (_width>=512 && _height*_depth*_spectrum>=2 && std::strlen(expression)>=6)  
15613 -#pragma omp parallel  
15614 - {  
15615 - _cimg_math_parser _mp = omp_get_thread_num()?mp:_cimg_math_parser(), &lmp = omp_get_thread_num()?_mp:mp;  
15616 -#pragma omp for collapse(3)  
15617 - cimg_forYZC(*this,y,z,c) {  
15618 - T *ptrd = data(0,y,z,c);  
15619 - cimg_forX(*this,x) { *ptrd = (T)cimg::rol(*ptrd,(unsigned int)lmp(x,y,z,c)); ++ptrd; }  
15620 - }  
15621 - }  
15622 - else  
15623 -#endif  
15624 - cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)cimg::rol(*ptrd,(unsigned int)mp(x,y,z,c)); ++ptrd; }  
15625 - }  
15626 - } catch (CImgException&) {  
15627 - CImg<Tfloat> values(_width,_height,_depth,_spectrum);  
15628 - try {  
15629 - values.fill(expression,true);  
15630 - } catch (CImgException&) {  
15631 - cimg::exception_mode(omode);  
15632 - values.load(expression);  
15633 - }  
15634 - rol(values);  
15635 - }  
15636 - cimg::exception_mode(omode);  
15637 - return *this; 19557 + return rol((+*this)._fill(expression,true,true,0,0,"rol",this));
15638 } 19558 }
15639 19559
15640 //! Compute the bitwise left rotation of each pixel value \newinstance. 19560 //! Compute the bitwise left rotation of each pixel value \newinstance.
@@ -15673,7 +19593,7 @@ namespace cimg_library_suffixed { @@ -15673,7 +19593,7 @@ namespace cimg_library_suffixed {
15673 CImg<T>& ror(const unsigned int n=1) { 19593 CImg<T>& ror(const unsigned int n=1) {
15674 if (is_empty()) return *this; 19594 if (is_empty()) return *this;
15675 #ifdef cimg_use_openmp 19595 #ifdef cimg_use_openmp
15676 -#pragma omp parallel for if (size()>=32768) 19596 +#pragma omp parallel for cimg_openmp_if(size()>=32768)
15677 #endif 19597 #endif
15678 cimg_rof(*this,ptrd,T) *ptrd = (T)cimg::ror(*ptrd,n); 19598 cimg_rof(*this,ptrd,T) *ptrd = (T)cimg::ror(*ptrd,n);
15679 return *this; 19599 return *this;
@@ -15689,45 +19609,7 @@ namespace cimg_library_suffixed { @@ -15689,45 +19609,7 @@ namespace cimg_library_suffixed {
15689 Similar to operator>>=(const char*), except that it performs a right rotation instead of a right shift. 19609 Similar to operator>>=(const char*), except that it performs a right rotation instead of a right shift.
15690 **/ 19610 **/
15691 CImg<T>& ror(const char *const expression) { 19611 CImg<T>& ror(const char *const expression) {
15692 - if (is_empty()) return *this;  
15693 - const unsigned int omode = cimg::exception_mode();  
15694 - cimg::exception_mode(0);  
15695 - try {  
15696 - const CImg<T> _base = cimg::_is_self_expr(expression)?+*this:CImg<T>(), &base = _base?_base:*this;  
15697 - _cimg_math_parser mp(base,expression + (*expression=='>' || *expression=='<'?1:0),"ror");  
15698 - T *ptrd = *expression=='<'?end() - 1:_data;  
15699 - if (*expression=='<')  
15700 - cimg_rofXYZC(*this,x,y,z,c) { *ptrd = (T)cimg::ror(*ptrd,(unsigned int)mp(x,y,z,c)); --ptrd; }  
15701 - else if (*expression=='>')  
15702 - cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)cimg::ror(*ptrd,(unsigned int)mp(x,y,z,c)); ++ptrd; }  
15703 - else {  
15704 -#ifdef cimg_use_openmp  
15705 - if (_width>=512 && _height*_depth*_spectrum>=2 && std::strlen(expression)>=6)  
15706 -#pragma omp parallel  
15707 - {  
15708 - _cimg_math_parser _mp = omp_get_thread_num()?mp:_cimg_math_parser(), &lmp = omp_get_thread_num()?_mp:mp;  
15709 -#pragma omp for collapse(3)  
15710 - cimg_forYZC(*this,y,z,c) {  
15711 - T *ptrd = data(0,y,z,c);  
15712 - cimg_forX(*this,x) { *ptrd = (T)cimg::ror(*ptrd,(unsigned int)lmp(x,y,z,c)); ++ptrd; }  
15713 - }  
15714 - }  
15715 - else  
15716 -#endif  
15717 - cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)cimg::ror(*ptrd,(unsigned int)mp(x,y,z,c)); ++ptrd; }  
15718 - }  
15719 - } catch (CImgException&) {  
15720 - CImg<Tfloat> values(_width,_height,_depth,_spectrum);  
15721 - try {  
15722 - values.fill(expression,true);  
15723 - } catch (CImgException&) {  
15724 - cimg::exception_mode(omode);  
15725 - values.load(expression);  
15726 - }  
15727 - ror(values);  
15728 - }  
15729 - cimg::exception_mode(omode);  
15730 - return *this; 19612 + return ror((+*this)._fill(expression,true,true,0,0,"ror",this));
15731 } 19613 }
15732 19614
15733 //! Compute the bitwise right rotation of each pixel value \newinstance. 19615 //! Compute the bitwise right rotation of each pixel value \newinstance.
@@ -15768,7 +19650,7 @@ namespace cimg_library_suffixed { @@ -15768,7 +19650,7 @@ namespace cimg_library_suffixed {
15768 CImg<T>& min(const T& val) { 19650 CImg<T>& min(const T& val) {
15769 if (is_empty()) return *this; 19651 if (is_empty()) return *this;
15770 #ifdef cimg_use_openmp 19652 #ifdef cimg_use_openmp
15771 -#pragma omp parallel for if (size()>=65536) 19653 +#pragma omp parallel for cimg_openmp_if(size()>=65536)
15772 #endif 19654 #endif
15773 cimg_rof(*this,ptrd,T) *ptrd = cimg::min(*ptrd,val); 19655 cimg_rof(*this,ptrd,T) *ptrd = cimg::min(*ptrd,val);
15774 return *this; 19656 return *this;
@@ -15812,43 +19694,7 @@ namespace cimg_library_suffixed { @@ -15812,43 +19694,7 @@ namespace cimg_library_suffixed {
15812 \f$\mathrm{min}(I_{(x,y,z,c)},\mathrm{expr}_{(x,y,z,c)})\f$. 19694 \f$\mathrm{min}(I_{(x,y,z,c)},\mathrm{expr}_{(x,y,z,c)})\f$.
15813 **/ 19695 **/
15814 CImg<T>& min(const char *const expression) { 19696 CImg<T>& min(const char *const expression) {
15815 - if (is_empty()) return *this;  
15816 - const unsigned int omode = cimg::exception_mode();  
15817 - cimg::exception_mode(0);  
15818 - try {  
15819 - const CImg<T> _base = cimg::_is_self_expr(expression)?+*this:CImg<T>(), &base = _base?_base:*this;  
15820 - _cimg_math_parser mp(base,expression + (*expression=='>' || *expression=='<'?1:0),"min");  
15821 - T *ptrd = *expression=='<'?end() - 1:_data;  
15822 - if (*expression=='<') cimg_rofXYZC(*this,x,y,z,c) { *ptrd = (T)cimg::min(*ptrd,(T)mp(x,y,z,c)); --ptrd; }  
15823 - else if (*expression=='>') cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)cimg::min(*ptrd,(T)mp(x,y,z,c)); ++ptrd; }  
15824 - else {  
15825 -#ifdef cimg_use_openmp  
15826 - if (_width>=512 && _height*_depth*_spectrum>=2 && std::strlen(expression)>=6)  
15827 -#pragma omp parallel  
15828 - {  
15829 - _cimg_math_parser _mp = omp_get_thread_num()?mp:_cimg_math_parser(), &lmp = omp_get_thread_num()?_mp:mp;  
15830 -#pragma omp for collapse(3)  
15831 - cimg_forYZC(*this,y,z,c) {  
15832 - T *ptrd = data(0,y,z,c);  
15833 - cimg_forX(*this,x) { *ptrd = (T)cimg::min(*ptrd,(T)lmp(x,y,z,c)); ++ptrd; }  
15834 - }  
15835 - }  
15836 - else  
15837 -#endif  
15838 - cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)cimg::min(*ptrd,(T)mp(x,y,z,c)); ++ptrd; }  
15839 - }  
15840 - } catch (CImgException&) {  
15841 - CImg<T> values(_width,_height,_depth,_spectrum);  
15842 - try {  
15843 - values.fill(expression,true);  
15844 - } catch (CImgException&) {  
15845 - cimg::exception_mode(omode);  
15846 - values.load(expression);  
15847 - }  
15848 - min(values);  
15849 - }  
15850 - cimg::exception_mode(omode);  
15851 - return *this; 19697 + return min((+*this)._fill(expression,true,true,0,0,"min",this));
15852 } 19698 }
15853 19699
15854 //! Pointwise min operator between an image and an expression \newinstance. 19700 //! Pointwise min operator between an image and an expression \newinstance.
@@ -15865,7 +19711,7 @@ namespace cimg_library_suffixed { @@ -15865,7 +19711,7 @@ namespace cimg_library_suffixed {
15865 CImg<T>& max(const T& val) { 19711 CImg<T>& max(const T& val) {
15866 if (is_empty()) return *this; 19712 if (is_empty()) return *this;
15867 #ifdef cimg_use_openmp 19713 #ifdef cimg_use_openmp
15868 -#pragma omp parallel for if (size()>=65536) 19714 +#pragma omp parallel for cimg_openmp_if(size()>=65536)
15869 #endif 19715 #endif
15870 cimg_rof(*this,ptrd,T) *ptrd = cimg::max(*ptrd,val); 19716 cimg_rof(*this,ptrd,T) *ptrd = cimg::max(*ptrd,val);
15871 return *this; 19717 return *this;
@@ -15909,43 +19755,7 @@ namespace cimg_library_suffixed { @@ -15909,43 +19755,7 @@ namespace cimg_library_suffixed {
15909 \f$\mathrm{max}(I_{(x,y,z,c)},\mathrm{expr}_{(x,y,z,c)})\f$. 19755 \f$\mathrm{max}(I_{(x,y,z,c)},\mathrm{expr}_{(x,y,z,c)})\f$.
15910 **/ 19756 **/
15911 CImg<T>& max(const char *const expression) { 19757 CImg<T>& max(const char *const expression) {
15912 - if (is_empty()) return *this;  
15913 - const unsigned int omode = cimg::exception_mode();  
15914 - cimg::exception_mode(0);  
15915 - try {  
15916 - const CImg<T> _base = cimg::_is_self_expr(expression)?+*this:CImg<T>(), &base = _base?_base:*this;  
15917 - _cimg_math_parser mp(base,expression + (*expression=='>' || *expression=='<'?1:0),"max");  
15918 - T *ptrd = *expression=='<'?end() - 1:_data;  
15919 - if (*expression=='<') cimg_rofXYZC(*this,x,y,z,c) { *ptrd = (T)cimg::max(*ptrd,(T)mp(x,y,z,c)); --ptrd; }  
15920 - else if (*expression=='>') cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)cimg::max(*ptrd,(T)mp(x,y,z,c)); ++ptrd; }  
15921 - else {  
15922 -#ifdef cimg_use_openmp  
15923 - if (_width>=512 && _height*_depth*_spectrum>=2 && std::strlen(expression)>=6)  
15924 -#pragma omp parallel  
15925 - {  
15926 - _cimg_math_parser _mp = omp_get_thread_num()?mp:_cimg_math_parser(), &lmp = omp_get_thread_num()?_mp:mp;  
15927 -#pragma omp for collapse(3)  
15928 - cimg_forYZC(*this,y,z,c) {  
15929 - T *ptrd = data(0,y,z,c);  
15930 - cimg_forX(*this,x) { *ptrd = (T)cimg::max(*ptrd,(T)lmp(x,y,z,c)); ++ptrd; }  
15931 - }  
15932 - }  
15933 - else  
15934 -#endif  
15935 - cimg_forXYZC(*this,x,y,z,c) { *ptrd = (T)cimg::max(*ptrd,(T)mp(x,y,z,c)); ++ptrd; }  
15936 - }  
15937 - } catch (CImgException&) {  
15938 - CImg<T> values(_width,_height,_depth,_spectrum);  
15939 - try {  
15940 - values.fill(expression,true);  
15941 - } catch (CImgException&) {  
15942 - cimg::exception_mode(omode);  
15943 - values.load(expression);  
15944 - }  
15945 - max(values);  
15946 - }  
15947 - cimg::exception_mode(omode);  
15948 - return *this; 19758 + return max((+*this)._fill(expression,true,true,0,0,"max",this));
15949 } 19759 }
15950 19760
15951 //! Pointwise max operator between an image and an expression \newinstance. 19761 //! Pointwise max operator between an image and an expression \newinstance.
@@ -16094,7 +19904,7 @@ namespace cimg_library_suffixed { @@ -16094,7 +19904,7 @@ namespace cimg_library_suffixed {
16094 cimg_instance); 19904 cimg_instance);
16095 CImg<T> arr(*this); 19905 CImg<T> arr(*this);
16096 unsigned int l = 0, ir = size() - 1; 19906 unsigned int l = 0, ir = size() - 1;
16097 - for (;;) { 19907 + for ( ; ; ) {
16098 if (ir<=l + 1) { 19908 if (ir<=l + 1) {
16099 if (ir==l + 1 && arr[ir]<arr[l]) cimg::swap(arr[l],arr[ir]); 19909 if (ir==l + 1 && arr[ir]<arr[l]) cimg::swap(arr[l],arr[ir]);
16100 return arr[k]; 19910 return arr[k];
@@ -16106,7 +19916,7 @@ namespace cimg_library_suffixed { @@ -16106,7 +19916,7 @@ namespace cimg_library_suffixed {
16106 if (arr[l]>arr[l + 1]) cimg::swap(arr[l],arr[l + 1]); 19916 if (arr[l]>arr[l + 1]) cimg::swap(arr[l],arr[l + 1]);
16107 unsigned int i = l + 1, j = ir; 19917 unsigned int i = l + 1, j = ir;
16108 const T pivot = arr[l + 1]; 19918 const T pivot = arr[l + 1];
16109 - for (;;) { 19919 + for ( ; ; ) {
16110 do ++i; while (arr[i]<pivot); 19920 do ++i; while (arr[i]<pivot);
16111 do --j; while (arr[j]>pivot); 19921 do --j; while (arr[j]>pivot);
16112 if (j<i) break; 19922 if (j<i) break;
@@ -16256,7 +20066,7 @@ namespace cimg_library_suffixed { @@ -16256,7 +20066,7 @@ namespace cimg_library_suffixed {
16256 if (_depth==1) { 20066 if (_depth==1) {
16257 const double cste = 1.0/std::sqrt(20.0); // Depends on how the Laplacian is computed. 20067 const double cste = 1.0/std::sqrt(20.0); // Depends on how the Laplacian is computed.
16258 #ifdef cimg_use_openmp 20068 #ifdef cimg_use_openmp
16259 -#pragma omp parallel for if (_width*_height>=262144 && _spectrum>=2) 20069 +#pragma omp parallel for cimg_openmp_if(_width*_height>=262144 && _spectrum>=2)
16260 #endif 20070 #endif
16261 cimg_forC(*this,c) { 20071 cimg_forC(*this,c) {
16262 CImg_3x3(I,T); 20072 CImg_3x3(I,T);
@@ -16268,7 +20078,7 @@ namespace cimg_library_suffixed { @@ -16268,7 +20078,7 @@ namespace cimg_library_suffixed {
16268 } else { 20078 } else {
16269 const double cste = 1.0/std::sqrt(42.0); // Depends on how the Laplacian is computed. 20079 const double cste = 1.0/std::sqrt(42.0); // Depends on how the Laplacian is computed.
16270 #ifdef cimg_use_openmp 20080 #ifdef cimg_use_openmp
16271 -#pragma omp parallel for if (_width*_height*_depth>=262144 && _spectrum>=2) 20081 +#pragma omp parallel for cimg_openmp_if(_width*_height*_depth>=262144 && _spectrum>=2)
16272 #endif 20082 #endif
16273 cimg_forC(*this,c) { 20083 cimg_forC(*this,c) {
16274 CImg_3x3x3(I,T); 20084 CImg_3x3x3(I,T);
@@ -16348,9 +20158,25 @@ namespace cimg_library_suffixed { @@ -16348,9 +20158,25 @@ namespace cimg_library_suffixed {
16348 \param y Value of the pre-defined variable \c y. 20158 \param y Value of the pre-defined variable \c y.
16349 \param z Value of the pre-defined variable \c z. 20159 \param z Value of the pre-defined variable \c z.
16350 \param c Value of the pre-defined variable \c c. 20160 \param c Value of the pre-defined variable \c c.
  20161 + \param list_inputs A list of input images attached to the specified math formula.
  20162 + \param list_outputs A pointer to a list of output images attached to the specified math formula.
16351 **/ 20163 **/
16352 double eval(const char *const expression, 20164 double eval(const char *const expression,
16353 - const double x=0, const double y=0, const double z=0, const double c=0) const { 20165 + const double x=0, const double y=0, const double z=0, const double c=0,
  20166 + const CImgList<T> *const list_inputs=0, CImgList<T> *const list_outputs=0) {
  20167 + return _eval(this,expression,x,y,z,c,list_inputs,list_outputs);
  20168 + }
  20169 +
  20170 + //! Evaluate math formula \const.
  20171 + double eval(const char *const expression,
  20172 + const double x=0, const double y=0, const double z=0, const double c=0,
  20173 + const CImgList<T> *const list_inputs=0, CImgList<T> *const list_outputs=0) const {
  20174 + return _eval(0,expression,x,y,z,c,list_inputs,list_outputs);
  20175 + }
  20176 +
  20177 + double _eval(CImg<T> *const img_output, const char *const expression,
  20178 + const double x, const double y, const double z, const double c,
  20179 + const CImgList<T> *const list_inputs, CImgList<T> *const list_outputs) const {
16354 if (!expression) return 0; 20180 if (!expression) return 0;
16355 if (!expression[1]) switch (*expression) { // Single-char optimization. 20181 if (!expression[1]) switch (*expression) { // Single-char optimization.
16356 case 'w' : return (double)_width; 20182 case 'w' : return (double)_width;
@@ -16359,7 +20185,54 @@ namespace cimg_library_suffixed { @@ -16359,7 +20185,54 @@ namespace cimg_library_suffixed {
16359 case 's' : return (double)_spectrum; 20185 case 's' : return (double)_spectrum;
16360 case 'r' : return (double)_is_shared; 20186 case 'r' : return (double)_is_shared;
16361 } 20187 }
16362 - return _cimg_math_parser(*this,expression,"eval")(x,y,z,c); 20188 + _cimg_math_parser mp(expression + (*expression=='>' || *expression=='<' || *expression=='*'?1:0),"eval",
  20189 + *this,img_output,list_inputs,list_outputs);
  20190 + return mp(x,y,z,c);
  20191 + }
  20192 +
  20193 + //! Evaluate math formula.
  20194 + /**
  20195 + \param[out] output Contains values of output vector returned by the evaluated expression
  20196 + (or is empty if the returned type is scalar).
  20197 + \param expression Math formula, as a C-string.
  20198 + \param x Value of the pre-defined variable \c x.
  20199 + \param y Value of the pre-defined variable \c y.
  20200 + \param z Value of the pre-defined variable \c z.
  20201 + \param c Value of the pre-defined variable \c c.
  20202 + \param list_inputs A list of input images attached to the specified math formula.
  20203 + \param list_outputs A pointer to a list of output images attached to the specified math formula.
  20204 + **/
  20205 + template<typename t>
  20206 + void eval(CImg<t> &output, const char *const expression,
  20207 + const double x=0, const double y=0, const double z=0, const double c=0,
  20208 + const CImgList<T> *const list_inputs=0, CImgList<T> *const list_outputs=0) {
  20209 + _eval(output,this,expression,x,y,z,c,list_inputs,list_outputs);
  20210 + }
  20211 +
  20212 + //! Evaluate math formula \const.
  20213 + template<typename t>
  20214 + void eval(CImg<t>& output, const char *const expression,
  20215 + const double x=0, const double y=0, const double z=0, const double c=0,
  20216 + const CImgList<T> *const list_inputs=0, CImgList<T> *const list_outputs=0) const {
  20217 + _eval(output,0,expression,x,y,z,c,list_inputs,list_outputs);
  20218 + }
  20219 +
  20220 + template<typename t>
  20221 + void _eval(CImg<t>& output, CImg<T> *const img_output, const char *const expression,
  20222 + const double x, const double y, const double z, const double c,
  20223 + const CImgList<T> *const list_inputs, CImgList<T> *const list_outputs) const {
  20224 + if (!expression) { output.assign(1); *output = 0; }
  20225 + if (!expression[1]) switch (*expression) { // Single-char optimization.
  20226 + case 'w' : output.assign(1); *output = (t)_width;
  20227 + case 'h' : output.assign(1); *output = (t)_height;
  20228 + case 'd' : output.assign(1); *output = (t)_depth;
  20229 + case 's' : output.assign(1); *output = (t)_spectrum;
  20230 + case 'r' : output.assign(1); *output = (t)_is_shared;
  20231 + }
  20232 + _cimg_math_parser mp(expression + (*expression=='>' || *expression=='<' || *expression=='*'?1:0),"eval",
  20233 + *this,img_output,list_inputs,list_outputs);
  20234 + output.assign(1,cimg::max(1U,mp.result_dim));
  20235 + mp(x,y,z,c,output._data);
16363 } 20236 }
16364 20237
16365 //! Evaluate math formula on a set of variables. 20238 //! Evaluate math formula on a set of variables.
@@ -16368,10 +20241,24 @@ namespace cimg_library_suffixed { @@ -16368,10 +20241,24 @@ namespace cimg_library_suffixed {
16368 \param xyzc Set of values (x,y,z,c) used for the evaluation. 20241 \param xyzc Set of values (x,y,z,c) used for the evaluation.
16369 **/ 20242 **/
16370 template<typename t> 20243 template<typename t>
16371 - CImg<doubleT> eval(const char *const expression, const CImg<t>& xyzc) const { 20244 + CImg<doubleT> eval(const char *const expression, const CImg<t>& xyzc,
  20245 + const CImgList<T> *const list_inputs=0, CImgList<T> *const list_outputs=0) {
  20246 + return _eval(this,expression,xyzc,list_inputs,list_outputs);
  20247 + }
  20248 +
  20249 + //! Evaluate math formula on a set of variables \const.
  20250 + template<typename t>
  20251 + CImg<doubleT> eval(const char *const expression, const CImg<t>& xyzc,
  20252 + const CImgList<T> *const list_inputs=0, CImgList<T> *const list_outputs=0) const {
  20253 + return _eval(0,expression,xyzc,list_inputs,list_outputs);
  20254 + }
  20255 +
  20256 + template<typename t>
  20257 + CImg<doubleT> _eval(CImg<T> *const output, const char *const expression, const CImg<t>& xyzc,
  20258 + const CImgList<T> *const list_inputs=0, CImgList<T> *const list_outputs=0) const {
16372 CImg<doubleT> res(1,xyzc.size()/4); 20259 CImg<doubleT> res(1,xyzc.size()/4);
16373 if (!expression) return res.fill(0); 20260 if (!expression) return res.fill(0);
16374 - _cimg_math_parser mp(*this,expression,"eval"); 20261 + _cimg_math_parser mp(expression,"eval",*this,output,list_inputs,list_outputs);
16375 #ifdef cimg_use_openmp 20262 #ifdef cimg_use_openmp
16376 #pragma omp parallel if (res._height>=512 && std::strlen(expression)>=6) 20263 #pragma omp parallel if (res._height>=512 && std::strlen(expression)>=6)
16377 { 20264 {
@@ -18496,36 +22383,95 @@ namespace cimg_library_suffixed { @@ -18496,36 +22383,95 @@ namespace cimg_library_suffixed {
18496 \param expression C-string describing a math formula, or a list of values. 22383 \param expression C-string describing a math formula, or a list of values.
18497 \param repeat_values In case a list of values is provided, tells if this list must be repeated for the filling. 22384 \param repeat_values In case a list of values is provided, tells if this list must be repeated for the filling.
18498 \param allow_formula tells if a formula is allowed or only a list of values. 22385 \param allow_formula tells if a formula is allowed or only a list of values.
  22386 + \param list_inputs In case of a mathematical expression, attach a list of images to the specified expression.
  22387 + \param list_outputs In case of a mathematical expression, attach a list of images to the specified expression.
18499 **/ 22388 **/
18500 - CImg<T>& fill(const char *const expression, const bool repeat_values, const bool allow_formula=true) { 22389 + CImg<T>& fill(const char *const expression, const bool repeat_values, const bool allow_formula=true,
  22390 + const CImgList<T> *const list_inputs=0, CImgList<T> *const list_outputs=0) {
  22391 + return _fill(expression,repeat_values,allow_formula,list_inputs,list_outputs,"fill",0);
  22392 + }
  22393 +
  22394 + CImg<T>& _fill(const char *const expression, const bool repeat_values, const bool allow_formula,
  22395 + const CImgList<T> *const list_inputs, CImgList<T> *const list_outputs,
  22396 + const char *const calling_function, const CImg<T> *provide_base) {
18501 if (is_empty() || !expression || !*expression) return *this; 22397 if (is_empty() || !expression || !*expression) return *this;
18502 const unsigned int omode = cimg::exception_mode(); 22398 const unsigned int omode = cimg::exception_mode();
18503 cimg::exception_mode(0); 22399 cimg::exception_mode(0);
18504 CImg<charT> is_error; 22400 CImg<charT> is_error;
18505 22401
18506 - if (allow_formula) try { // Try to fill values according to a formula.  
18507 - const CImg<T> _base = cimg::_is_self_expr(expression)?+*this:CImg<T>(), &base = _base?_base:*this;  
18508 - _cimg_math_parser mp(base,expression + (*expression=='>' || *expression=='<'?1:0),"fill");  
18509 - T *ptrd = *expression=='<'?end() - 1:_data;  
18510 - if (*expression=='<') cimg_rofXYZC(*this,x,y,z,c) *(ptrd--) = (T)mp(x,y,z,c);  
18511 - else if (*expression=='>') cimg_forXYZC(*this,x,y,z,c) *(ptrd++) = (T)mp(x,y,z,c);  
18512 - else { 22402 + if (allow_formula) try { // Try to fill values according to a formula
  22403 + bool is_parallelizable = true;
  22404 + const CImg<T>
  22405 + _base = _cimg_math_parser::needs_input_copy(expression,is_parallelizable)?
  22406 + (provide_base?*provide_base:+*this):CImg<T>(),
  22407 + &base = provide_base?*provide_base:_base?_base:*this;
  22408 + _cimg_math_parser mp(expression + (*expression=='>' || *expression=='<' || *expression=='*'?1:0),
  22409 + calling_function,base,this,list_inputs,list_outputs);
  22410 + bool do_in_parallel = false;
  22411 +#ifdef cimg_use_openmp
  22412 + cimg_openmp_if(*expression=='*' ||
  22413 + (is_parallelizable && _width>=320 && _height*_depth*_spectrum>=2 &&
  22414 + std::strlen(expression)>=6))
  22415 + do_in_parallel = true;
  22416 +#endif
  22417 + if (mp.result_dim) { // Vector-valued expression
  22418 + const unsigned int N = cimg::min(mp.result_dim,_spectrum);
  22419 + const unsigned long whd = _width*_height*_depth;
  22420 + T *ptrd = *expression=='<'?_data + _width*_height*_depth - 1:_data;
  22421 + if (*expression=='<') {
  22422 + CImg<doubleT> res(1,mp.result_dim);
  22423 + cimg_rofXYZ(*this,x,y,z) {
  22424 + mp(x,y,z,0,res._data);
  22425 + const double *ptrs = res._data;
  22426 + T *_ptrd = ptrd--; for (unsigned int n = N; n>0; --n) { *_ptrd = (T)(*ptrs++); _ptrd+=whd; }
  22427 + }
  22428 + } else if (*expression=='>' || !do_in_parallel) {
  22429 + CImg<doubleT> res(1,mp.result_dim);
  22430 + cimg_forXYZ(*this,x,y,z) {
  22431 + mp(x,y,z,0,res._data);
  22432 + const double *ptrs = res._data;
  22433 + T *_ptrd = ptrd++; for (unsigned int n = N; n>0; --n) { *_ptrd = (T)(*ptrs++); _ptrd+=whd; }
  22434 + }
  22435 + } else {
18513 #ifdef cimg_use_openmp 22436 #ifdef cimg_use_openmp
18514 - if (_width>=512 && _height*_depth*_spectrum>=2 && std::strlen(expression)>=6)  
18515 #pragma omp parallel 22437 #pragma omp parallel
18516 - {  
18517 - _cimg_math_parser _mp = omp_get_thread_num()?mp:_cimg_math_parser(), &lmp = omp_get_thread_num()?_mp:mp;  
18518 -#pragma omp for collapse(3)  
18519 - cimg_forYZC(*this,y,z,c) {  
18520 - T *ptrd = data(0,y,z,c);  
18521 - cimg_forX(*this,x) *ptrd++ = (T)lmp(x,y,z,c); 22438 + {
  22439 + _cimg_math_parser _mp = omp_get_thread_num()?mp:_cimg_math_parser(), &lmp = omp_get_thread_num()?_mp:mp;
  22440 +#pragma omp for collapse(2)
  22441 + cimg_forYZ(*this,y,z) {
  22442 + CImg<doubleT> res(1,lmp.result_dim);
  22443 + T *ptrd = data(0,y,z,0);
  22444 + cimg_forX(*this,x) {
  22445 + lmp(x,y,z,0,res._data);
  22446 + const double *ptrs = res._data;
  22447 + T *_ptrd = ptrd++; for (unsigned int n = N; n>0; --n) { *_ptrd = (T)(*ptrs++); _ptrd+=whd; }
  22448 + }
  22449 + }
18522 } 22450 }
  22451 +#endif
18523 } 22452 }
18524 - else 22453 +
  22454 + } else { // Scalar-valued expression
  22455 + T *ptrd = *expression=='<'?end() - 1:_data;
  22456 + if (*expression=='<')
  22457 + cimg_rofXYZC(*this,x,y,z,c) *(ptrd--) = (T)mp(x,y,z,c);
  22458 + else if (*expression=='>' || !do_in_parallel)
  22459 + cimg_forXYZC(*this,x,y,z,c) *(ptrd++) = (T)mp(x,y,z,c);
  22460 + else {
  22461 +#ifdef cimg_use_openmp
  22462 +#pragma omp parallel
  22463 + {
  22464 + _cimg_math_parser _mp = omp_get_thread_num()?mp:_cimg_math_parser(), &lmp = omp_get_thread_num()?_mp:mp;
  22465 +#pragma omp for collapse(3)
  22466 + cimg_forYZC(*this,y,z,c) {
  22467 + T *ptrd = data(0,y,z,c);
  22468 + cimg_forX(*this,x) *ptrd++ = (T)lmp(x,y,z,c);
  22469 + }
  22470 + }
18525 #endif 22471 #endif
18526 - cimg_forXYZC(*this,x,y,z,c) *(ptrd++) = (T)mp(x,y,z,c);  
18527 - }  
18528 - } catch (CImgException& e) { CImg<charT>::string(e._message).move_to(is_error); } 22472 + }
  22473 + }
  22474 + } catch (CImgException& e) { CImg<charT>::string(e._message).move_to(is_error); }
18529 22475
18530 // If failed, try to recognize a list of values. 22476 // If failed, try to recognize a list of values.
18531 if (!allow_formula || is_error) { 22477 if (!allow_formula || is_error) {
@@ -18547,8 +22493,8 @@ namespace cimg_library_suffixed { @@ -18547,8 +22493,8 @@ namespace cimg_library_suffixed {
18547 if (nb<siz && (sep || *nexpression)) { 22493 if (nb<siz && (sep || *nexpression)) {
18548 if (is_error) throw CImgArgumentException("%s",is_error._data); 22494 if (is_error) throw CImgArgumentException("%s",is_error._data);
18549 else throw CImgArgumentException(_cimg_instance 22495 else throw CImgArgumentException(_cimg_instance
18550 - "fill(): Invalid sequence of filling values '%s'.",  
18551 - cimg_instance,expression); 22496 + "%s(): Invalid sequence of filling values '%s'.",
  22497 + cimg_instance,calling_function,expression);
18552 } 22498 }
18553 if (repeat_values && nb && nb<siz) 22499 if (repeat_values && nb && nb<siz)
18554 for (T *ptrs = _data, *const ptre = _data + siz; ptrd<ptre; ++ptrs) *(ptrd++) = *ptrs; 22500 for (T *ptrs = _data, *const ptre = _data + siz; ptrd<ptre; ++ptrs) *(ptrd++) = *ptrs;
@@ -18558,8 +22504,9 @@ namespace cimg_library_suffixed { @@ -18558,8 +22504,9 @@ namespace cimg_library_suffixed {
18558 } 22504 }
18559 22505
18560 //! Fill sequentially pixel values according to a given expression \newinstance. 22506 //! Fill sequentially pixel values according to a given expression \newinstance.
18561 - CImg<T> get_fill(const char *const values, const bool repeat_values, const bool allow_formula=true) const {  
18562 - return (+*this).fill(values,repeat_values,allow_formula); 22507 + CImg<T> get_fill(const char *const expression, const bool repeat_values, const bool allow_formula=true,
  22508 + const CImgList<T> *const list_inputs=0, CImgList<T> *const list_outputs=0) const {
  22509 + return (+*this).fill(expression,repeat_values,allow_formula,list_inputs,list_outputs);
18563 } 22510 }
18564 22511
18565 //! Fill sequentially pixel values according to the values found in another image. 22512 //! Fill sequentially pixel values according to the values found in another image.
@@ -18811,9 +22758,9 @@ namespace cimg_library_suffixed { @@ -18811,9 +22758,9 @@ namespace cimg_library_suffixed {
18811 22758
18812 //! Fill image with random values in specified range. 22759 //! Fill image with random values in specified range.
18813 /** 22760 /**
18814 - \param val_min Minimal random value.  
18815 - \param val_max Maximal random value.  
18816 - \note Random samples are following a uniform distribution. 22761 + \param val_min Minimal authorized random value.
  22762 + \param val_max Maximal authorized random value.
  22763 + \note Random variables are uniformely distributed in [val_min,val_max].
18817 **/ 22764 **/
18818 CImg<T>& rand(const T& val_min, const T& val_max) { 22765 CImg<T>& rand(const T& val_min, const T& val_max) {
18819 const float delta = (float)val_max - (float)val_min + (cimg::type<T>::is_float()?0:1); 22766 const float delta = (float)val_max - (float)val_min + (cimg::type<T>::is_float()?0:1);
@@ -18838,7 +22785,7 @@ namespace cimg_library_suffixed { @@ -18838,7 +22785,7 @@ namespace cimg_library_suffixed {
18838 CImg<T>& round(const double y=1, const int rounding_type=0) { 22785 CImg<T>& round(const double y=1, const int rounding_type=0) {
18839 if (y>0) 22786 if (y>0)
18840 #ifdef cimg_use_openmp 22787 #ifdef cimg_use_openmp
18841 -#pragma omp parallel for if (size()>=8192) 22788 +#pragma omp parallel for cimg_openmp_if(size()>=8192)
18842 #endif 22789 #endif
18843 cimg_rof(*this,ptrd,T) *ptrd = cimg::round(*ptrd,y,rounding_type); 22790 cimg_rof(*this,ptrd,T) *ptrd = cimg::round(*ptrd,y,rounding_type);
18844 return *this; 22791 return *this;
@@ -18885,7 +22832,7 @@ namespace cimg_library_suffixed { @@ -18885,7 +22832,7 @@ namespace cimg_library_suffixed {
18885 } break; 22832 } break;
18886 case 1 : { // Uniform noise 22833 case 1 : { // Uniform noise
18887 cimg_rof(*this,ptrd,T) { 22834 cimg_rof(*this,ptrd,T) {
18888 - Tfloat val = (Tfloat)(*ptrd + nsigma*cimg::crand()); 22835 + Tfloat val = (Tfloat)(*ptrd + nsigma*cimg::rand(-1,1));
18889 if (val>vmax) val = vmax; 22836 if (val>vmax) val = vmax;
18890 if (val<vmin) val = vmin; 22837 if (val<vmin) val = vmin;
18891 *ptrd = (T)val; 22838 *ptrd = (T)val;
@@ -18894,7 +22841,7 @@ namespace cimg_library_suffixed { @@ -18894,7 +22841,7 @@ namespace cimg_library_suffixed {
18894 case 2 : { // Salt & Pepper noise 22841 case 2 : { // Salt & Pepper noise
18895 if (nsigma<0) nsigma = -nsigma; 22842 if (nsigma<0) nsigma = -nsigma;
18896 if (M==m) { m = 0; M = (Tfloat)(cimg::type<T>::is_float()?1:cimg::type<T>::max()); } 22843 if (M==m) { m = 0; M = (Tfloat)(cimg::type<T>::is_float()?1:cimg::type<T>::max()); }
18897 - cimg_rof(*this,ptrd,T) if (cimg::rand()*100<nsigma) *ptrd = (T)(cimg::rand()<0.5?M:m); 22844 + cimg_rof(*this,ptrd,T) if (cimg::rand(100)<nsigma) *ptrd = (T)(cimg::rand()<0.5?M:m);
18898 } break; 22845 } break;
18899 case 3 : { // Poisson Noise 22846 case 3 : { // Poisson Noise
18900 cimg_rof(*this,ptrd,T) *ptrd = (T)cimg::prand(*ptrd); 22847 cimg_rof(*this,ptrd,T) *ptrd = (T)cimg::prand(*ptrd);
@@ -18946,7 +22893,7 @@ namespace cimg_library_suffixed { @@ -18946,7 +22893,7 @@ namespace cimg_library_suffixed {
18946 if (m==M) return fill(min_value); 22893 if (m==M) return fill(min_value);
18947 if (m!=a || M!=b) 22894 if (m!=a || M!=b)
18948 #ifdef cimg_use_openmp 22895 #ifdef cimg_use_openmp
18949 -#pragma omp parallel for if (size()>=65536) 22896 +#pragma omp parallel for cimg_openmp_if(size()>=65536)
18950 #endif 22897 #endif
18951 cimg_rof(*this,ptrd,T) *ptrd = (T)((*ptrd - fm)/(fM - fm)*(b - a) + a); 22898 cimg_rof(*this,ptrd,T) *ptrd = (T)((*ptrd - fm)/(fM - fm)*(b - a) + a);
18952 return *this; 22899 return *this;
@@ -19112,7 +23059,7 @@ namespace cimg_library_suffixed { @@ -19112,7 +23059,7 @@ namespace cimg_library_suffixed {
19112 if (is_empty()) return *this; 23059 if (is_empty()) return *this;
19113 const T a = min_value<max_value?min_value:max_value, b = min_value<max_value?max_value:min_value; 23060 const T a = min_value<max_value?min_value:max_value, b = min_value<max_value?max_value:min_value;
19114 #ifdef cimg_use_openmp 23061 #ifdef cimg_use_openmp
19115 -#pragma omp parallel for if (size()>=32768) 23062 +#pragma omp parallel for cimg_openmp_if(size()>=32768)
19116 #endif 23063 #endif
19117 cimg_rof(*this,ptrd,T) *ptrd = (*ptrd<a)?a:((*ptrd>b)?b:*ptrd); 23064 cimg_rof(*this,ptrd,T) *ptrd = (*ptrd<a)?a:((*ptrd>b)?b:*ptrd);
19118 return *this; 23065 return *this;
@@ -19145,14 +23092,14 @@ namespace cimg_library_suffixed { @@ -19145,14 +23092,14 @@ namespace cimg_library_suffixed {
19145 if (range>0) { 23092 if (range>0) {
19146 if (keep_range) 23093 if (keep_range)
19147 #ifdef cimg_use_openmp 23094 #ifdef cimg_use_openmp
19148 -#pragma omp parallel for if (size()>=32768) 23095 +#pragma omp parallel for cimg_openmp_if(size()>=32768)
19149 #endif 23096 #endif
19150 cimg_rof(*this,ptrd,T) { 23097 cimg_rof(*this,ptrd,T) {
19151 const unsigned int val = (unsigned int)((*ptrd-m)*nb_levels/range); 23098 const unsigned int val = (unsigned int)((*ptrd-m)*nb_levels/range);
19152 *ptrd = (T)(m + cimg::min(val,nb_levels - 1)*range/nb_levels); 23099 *ptrd = (T)(m + cimg::min(val,nb_levels - 1)*range/nb_levels);
19153 } else 23100 } else
19154 #ifdef cimg_use_openmp 23101 #ifdef cimg_use_openmp
19155 -#pragma omp parallel for if (size()>=32768) 23102 +#pragma omp parallel for cimg_openmp_if(size()>=32768)
19156 #endif 23103 #endif
19157 cimg_rof(*this,ptrd,T) { 23104 cimg_rof(*this,ptrd,T) {
19158 const unsigned int val = (unsigned int)((*ptrd-m)*nb_levels/range); 23105 const unsigned int val = (unsigned int)((*ptrd-m)*nb_levels/range);
@@ -19184,7 +23131,7 @@ namespace cimg_library_suffixed { @@ -19184,7 +23131,7 @@ namespace cimg_library_suffixed {
19184 if (strict_threshold) { 23131 if (strict_threshold) {
19185 if (soft_threshold) 23132 if (soft_threshold)
19186 #ifdef cimg_use_openmp 23133 #ifdef cimg_use_openmp
19187 -#pragma omp parallel for if (size()>=32768) 23134 +#pragma omp parallel for cimg_openmp_if(size()>=32768)
19188 #endif 23135 #endif
19189 cimg_rof(*this,ptrd,T) { 23136 cimg_rof(*this,ptrd,T) {
19190 const T v = *ptrd; 23137 const T v = *ptrd;
@@ -19192,13 +23139,13 @@ namespace cimg_library_suffixed { @@ -19192,13 +23139,13 @@ namespace cimg_library_suffixed {
19192 } 23139 }
19193 else 23140 else
19194 #ifdef cimg_use_openmp 23141 #ifdef cimg_use_openmp
19195 -#pragma omp parallel for if (size()>=65536) 23142 +#pragma omp parallel for cimg_openmp_if(size()>=65536)
19196 #endif 23143 #endif
19197 cimg_rof(*this,ptrd,T) *ptrd = *ptrd>value?(T)1:(T)0; 23144 cimg_rof(*this,ptrd,T) *ptrd = *ptrd>value?(T)1:(T)0;
19198 } else { 23145 } else {
19199 if (soft_threshold) 23146 if (soft_threshold)
19200 #ifdef cimg_use_openmp 23147 #ifdef cimg_use_openmp
19201 -#pragma omp parallel for if (size()>=32768) 23148 +#pragma omp parallel for cimg_openmp_if(size()>=32768)
19202 #endif 23149 #endif
19203 cimg_rof(*this,ptrd,T) { 23150 cimg_rof(*this,ptrd,T) {
19204 const T v = *ptrd; 23151 const T v = *ptrd;
@@ -19206,7 +23153,7 @@ namespace cimg_library_suffixed { @@ -19206,7 +23153,7 @@ namespace cimg_library_suffixed {
19206 } 23153 }
19207 else 23154 else
19208 #ifdef cimg_use_openmp 23155 #ifdef cimg_use_openmp
19209 -#pragma omp parallel for if (size()>=65536) 23156 +#pragma omp parallel for cimg_openmp_if(size()>=65536)
19210 #endif 23157 #endif
19211 cimg_rof(*this,ptrd,T) *ptrd = *ptrd>=value?(T)1:(T)0; 23158 cimg_rof(*this,ptrd,T) *ptrd = *ptrd>=value?(T)1:(T)0;
19212 } 23159 }
@@ -19290,7 +23237,7 @@ namespace cimg_library_suffixed { @@ -19290,7 +23237,7 @@ namespace cimg_library_suffixed {
19290 cimg_forX(hist,pos) { cumul+=hist[pos]; hist[pos] = cumul; } 23237 cimg_forX(hist,pos) { cumul+=hist[pos]; hist[pos] = cumul; }
19291 if (!cumul) cumul = 1; 23238 if (!cumul) cumul = 1;
19292 #ifdef cimg_use_openmp 23239 #ifdef cimg_use_openmp
19293 -#pragma omp parallel for if (size()>=1048576) 23240 +#pragma omp parallel for cimg_openmp_if(size()>=1048576)
19294 #endif 23241 #endif
19295 cimg_rof(*this,ptrd,T) { 23242 cimg_rof(*this,ptrd,T) {
19296 const int pos = (int)((*ptrd-vmin)*(nb_levels - 1.)/(vmax-vmin)); 23243 const int pos = (int)((*ptrd-vmin)*(nb_levels - 1.)/(vmax-vmin));
@@ -20903,7 +24850,7 @@ namespace cimg_library_suffixed { @@ -20903,7 +24850,7 @@ namespace cimg_library_suffixed {
20903 cc = (int)(centering_c*((int)sc - spectrum())); 24850 cc = (int)(centering_c*((int)sc - spectrum()));
20904 24851
20905 switch (boundary_conditions) { 24852 switch (boundary_conditions) {
20906 - case 2 : { // Periodic borders. 24853 + case 2 : { // Periodic boundary.
20907 res.assign(sx,sy,sz,sc); 24854 res.assign(sx,sy,sz,sc);
20908 const int 24855 const int
20909 x0 = ((int)xc%width()) - width(), 24856 x0 = ((int)xc%width()) - width(),
@@ -20919,7 +24866,7 @@ namespace cimg_library_suffixed { @@ -20919,7 +24866,7 @@ namespace cimg_library_suffixed {
20919 for (int x = x0; x<(int)sx; x+=width()) 24866 for (int x = x0; x<(int)sx; x+=width())
20920 res.draw_image(x,y,z,c,*this); 24867 res.draw_image(x,y,z,c,*this);
20921 } break; 24868 } break;
20922 - case 1 : { // Neumann borders. 24869 + case 1 : { // Neumann boundary.
20923 res.assign(sx,sy,sz,sc).draw_image(xc,yc,zc,cc,*this); 24870 res.assign(sx,sy,sz,sc).draw_image(xc,yc,zc,cc,*this);
20924 CImg<T> sprite; 24871 CImg<T> sprite;
20925 if (xc>0) { // X-backward 24872 if (xc>0) { // X-backward
@@ -20957,7 +24904,7 @@ namespace cimg_library_suffixed { @@ -20957,7 +24904,7 @@ namespace cimg_library_suffixed {
20957 for (int c = cc + spectrum(); c<(int)sc; ++c) res.draw_image(0,0,0,c,sprite); 24904 for (int c = cc + spectrum(); c<(int)sc; ++c) res.draw_image(0,0,0,c,sprite);
20958 } 24905 }
20959 } break; 24906 } break;
20960 - default : // Dirichlet borders. 24907 + default : // Dirichlet boundary.
20961 res.assign(sx,sy,sz,sc,0).draw_image(xc,yc,zc,cc,*this); 24908 res.assign(sx,sy,sz,sc,0).draw_image(xc,yc,zc,cc,*this);
20962 } 24909 }
20963 break; 24910 break;
@@ -21028,17 +24975,17 @@ namespace cimg_library_suffixed { @@ -21028,17 +24975,17 @@ namespace cimg_library_suffixed {
21028 cimg_forX(res,x) { *(ptrd++) = *ptrx; ptrx+=*(poff_x++); } 24975 cimg_forX(res,x) { *(ptrd++) = *ptrx; ptrx+=*(poff_x++); }
21029 ++y; 24976 ++y;
21030 unsigned long dy = *(poff_y++); 24977 unsigned long dy = *(poff_y++);
21031 - for (;!dy && y<dy; std::memcpy(ptrd,ptrd - sx,sizeof(T)*sx), ++y, ptrd+=sx, dy = *(poff_y++)) {} 24978 + for ( ; !dy && y<dy; std::memcpy(ptrd,ptrd - sx,sizeof(T)*sx), ++y, ptrd+=sx, dy = *(poff_y++)) {}
21032 ptry+=dy; 24979 ptry+=dy;
21033 } 24980 }
21034 ++z; 24981 ++z;
21035 unsigned long dz = *(poff_z++); 24982 unsigned long dz = *(poff_z++);
21036 - for (;!dz && z<dz; std::memcpy(ptrd,ptrd-sxy,sizeof(T)*sxy), ++z, ptrd+=sxy, dz = *(poff_z++)) {} 24983 + for ( ; !dz && z<dz; std::memcpy(ptrd,ptrd-sxy,sizeof(T)*sxy), ++z, ptrd+=sxy, dz = *(poff_z++)) {}
21037 ptrz+=dz; 24984 ptrz+=dz;
21038 } 24985 }
21039 ++c; 24986 ++c;
21040 unsigned long dc = *(poff_c++); 24987 unsigned long dc = *(poff_c++);
21041 - for (;!dc && c<dc; std::memcpy(ptrd,ptrd-sxyz,sizeof(T)*sxyz), ++c, ptrd+=sxyz, dc = *(poff_c++)) {} 24988 + for ( ; !dc && c<dc; std::memcpy(ptrd,ptrd-sxyz,sizeof(T)*sxyz), ++c, ptrd+=sxyz, dc = *(poff_c++)) {}
21042 ptrc+=dc; 24989 ptrc+=dc;
21043 } 24990 }
21044 } break; 24991 } break;
@@ -21822,11 +25769,10 @@ namespace cimg_library_suffixed { @@ -21822,11 +25769,10 @@ namespace cimg_library_suffixed {
21822 //! Resize image to half-size along XY axes, using an optimized filter \newinstance. 25769 //! Resize image to half-size along XY axes, using an optimized filter \newinstance.
21823 CImg<T> get_resize_halfXY() const { 25770 CImg<T> get_resize_halfXY() const {
21824 if (is_empty()) return *this; 25771 if (is_empty()) return *this;
21825 - const Tfloat mask[9] = { 0.07842776544f, 0.1231940459f, 0.07842776544f,  
21826 - 0.1231940459f, 0.1935127547f, 0.1231940459f,  
21827 - 0.07842776544f, 0.1231940459f, 0.07842776544f };  
21828 - T I[9] = { 0 };  
21829 - CImg<T> res(_width/2,_height/2,_depth,_spectrum); 25772 + static const Tfloat mask[9] = { 0.07842776544f, 0.1231940459f, 0.07842776544f,
  25773 + 0.1231940459f, 0.1935127547f, 0.1231940459f,
  25774 + 0.07842776544f, 0.1231940459f, 0.07842776544f };
  25775 + CImg<T> I(9), res(_width/2,_height/2,_depth,_spectrum);
21830 T *ptrd = res._data; 25776 T *ptrd = res._data;
21831 cimg_forZC(*this,z,c) cimg_for3x3(*this,x,y,z,c,I,T) 25777 cimg_forZC(*this,z,c) cimg_for3x3(*this,x,y,z,c,I,T)
21832 if (x%2 && y%2) *(ptrd++) = (T) 25778 if (x%2 && y%2) *(ptrd++) = (T)
@@ -22895,7 +26841,7 @@ namespace cimg_library_suffixed { @@ -22895,7 +26841,7 @@ namespace cimg_library_suffixed {
22895 cimg_forX(res,x) *(ptrd++) = atX(x - (int)*(ptrs0++),y,z,c,0); 26841 cimg_forX(res,x) *(ptrd++) = atX(x - (int)*(ptrs0++),y,z,c,0);
22896 } 26842 }
22897 } 26843 }
22898 - } else { // Absolute warp. 26844 + } else { // Backward-absolute warp.
22899 if (interpolation==2) { // Cubic interpolation. 26845 if (interpolation==2) { // Cubic interpolation.
22900 if (boundary_conditions==2) // Periodic boundaries. 26846 if (boundary_conditions==2) // Periodic boundaries.
22901 #ifdef cimg_use_openmp 26847 #ifdef cimg_use_openmp
@@ -23073,7 +27019,7 @@ namespace cimg_library_suffixed { @@ -23073,7 +27019,7 @@ namespace cimg_library_suffixed {
23073 cimg_forX(res,x) *(ptrd++) = atXY(x - (int)*(ptrs0++),y - (int)*(ptrs1++),z,c,0); 27019 cimg_forX(res,x) *(ptrd++) = atXY(x - (int)*(ptrs0++),y - (int)*(ptrs1++),z,c,0);
23074 } 27020 }
23075 } 27021 }
23076 - } else { // Absolute warp. 27022 + } else { // Backward-absolute warp.
23077 if (interpolation==2) { // Cubic interpolation. 27023 if (interpolation==2) { // Cubic interpolation.
23078 if (boundary_conditions==2) // Periodic boundaries. 27024 if (boundary_conditions==2) // Periodic boundaries.
23079 #ifdef cimg_use_openmp 27025 #ifdef cimg_use_openmp
@@ -23146,7 +27092,7 @@ namespace cimg_library_suffixed { @@ -23146,7 +27092,7 @@ namespace cimg_library_suffixed {
23146 } 27092 }
23147 } 27093 }
23148 27094
23149 - } else if (warp._spectrum==3) { // 3d warping. 27095 + } else { // 3d warping.
23150 if (mode>=3) { // Forward-relative warp. 27096 if (mode>=3) { // Forward-relative warp.
23151 res.fill(0); 27097 res.fill(0);
23152 if (interpolation>=1) // Linear interpolation. 27098 if (interpolation>=1) // Linear interpolation.
@@ -23275,7 +27221,7 @@ namespace cimg_library_suffixed { @@ -23275,7 +27221,7 @@ namespace cimg_library_suffixed {
23275 cimg_forX(res,x) *(ptrd++) = atXYZ(x - (int)*(ptrs0++),y - (int)*(ptrs1++),z - (int)*(ptrs2++),c,0); 27221 cimg_forX(res,x) *(ptrd++) = atXYZ(x - (int)*(ptrs0++),y - (int)*(ptrs1++),z - (int)*(ptrs2++),c,0);
23276 } 27222 }
23277 } 27223 }
23278 - } else { // Absolute warp. 27224 + } else { // Backward-absolute warp.
23279 if (interpolation==2) { // Cubic interpolation. 27225 if (interpolation==2) { // Cubic interpolation.
23280 if (boundary_conditions==2) // Periodic boundaries. 27226 if (boundary_conditions==2) // Periodic boundaries.
23281 #ifdef cimg_use_openmp 27227 #ifdef cimg_use_openmp
@@ -23989,7 +27935,7 @@ namespace cimg_library_suffixed { @@ -23989,7 +27935,7 @@ namespace cimg_library_suffixed {
23989 _cimg_math_parser *mp; 27935 _cimg_math_parser *mp;
23990 ~_functor4d_streamline_expr() { delete mp; } 27936 ~_functor4d_streamline_expr() { delete mp; }
23991 _functor4d_streamline_expr(const char *const expr):mp(0) { 27937 _functor4d_streamline_expr(const char *const expr):mp(0) {
23992 - mp = new _cimg_math_parser(CImg<T>::empty(),expr,"streamline"); 27938 + mp = new _cimg_math_parser(expr,"streamline",CImg<T>::const_empty(),0);
23993 } 27939 }
23994 float operator()(const float x, const float y, const float z, const unsigned int c) const { 27940 float operator()(const float x, const float y, const float z, const unsigned int c) const {
23995 return (float)(*mp)(x,y,z,c); 27941 return (float)(*mp)(x,y,z,c);
@@ -24214,7 +28160,7 @@ namespace cimg_library_suffixed { @@ -24214,7 +28160,7 @@ namespace cimg_library_suffixed {
24214 res.assign(_width/dp + (_width%dp?1:0),1,1); 28160 res.assign(_width/dp + (_width%dp?1:0),1,1);
24215 const unsigned int pe = _width - dp; 28161 const unsigned int pe = _width - dp;
24216 #ifdef cimg_use_openmp 28162 #ifdef cimg_use_openmp
24217 -#pragma omp parallel for if (res._width>=128 && _height*_depth*_spectrum>=128) 28163 +#pragma omp parallel for cimg_openmp_if(res._width>=128 && _height*_depth*_spectrum>=128)
24218 #endif 28164 #endif
24219 for (unsigned int p = 0; p<pe; p+=dp) 28165 for (unsigned int p = 0; p<pe; p+=dp)
24220 get_crop(p,0,0,0,p + dp - 1,_height - 1,_depth - 1,_spectrum - 1).move_to(res[p/dp]); 28166 get_crop(p,0,0,0,p + dp - 1,_height - 1,_depth - 1,_spectrum - 1).move_to(res[p/dp]);
@@ -24226,7 +28172,7 @@ namespace cimg_library_suffixed { @@ -24226,7 +28172,7 @@ namespace cimg_library_suffixed {
24226 res.assign(_height/dp + (_height%dp?1:0),1,1); 28172 res.assign(_height/dp + (_height%dp?1:0),1,1);
24227 const unsigned int pe = _height - dp; 28173 const unsigned int pe = _height - dp;
24228 #ifdef cimg_use_openmp 28174 #ifdef cimg_use_openmp
24229 -#pragma omp parallel for if (res._width>=128 && _width*_depth*_spectrum>=128) 28175 +#pragma omp parallel for cimg_openmp_if(res._width>=128 && _width*_depth*_spectrum>=128)
24230 #endif 28176 #endif
24231 for (unsigned int p = 0; p<pe; p+=dp) 28177 for (unsigned int p = 0; p<pe; p+=dp)
24232 get_crop(0,p,0,0,_width - 1,p + dp - 1,_depth - 1,_spectrum - 1).move_to(res[p/dp]); 28178 get_crop(0,p,0,0,_width - 1,p + dp - 1,_depth - 1,_spectrum - 1).move_to(res[p/dp]);
@@ -24238,7 +28184,7 @@ namespace cimg_library_suffixed { @@ -24238,7 +28184,7 @@ namespace cimg_library_suffixed {
24238 res.assign(_depth/dp + (_depth%dp?1:0),1,1); 28184 res.assign(_depth/dp + (_depth%dp?1:0),1,1);
24239 const unsigned int pe = _depth - dp; 28185 const unsigned int pe = _depth - dp;
24240 #ifdef cimg_use_openmp 28186 #ifdef cimg_use_openmp
24241 -#pragma omp parallel for if (res._width>=128 && _width*_height*_spectrum>=128) 28187 +#pragma omp parallel for cimg_openmp_if(res._width>=128 && _width*_height*_spectrum>=128)
24242 #endif 28188 #endif
24243 for (unsigned int p = 0; p<pe; p+=dp) 28189 for (unsigned int p = 0; p<pe; p+=dp)
24244 get_crop(0,0,p,0,_width - 1,_height - 1,p + dp - 1,_spectrum - 1).move_to(res[p/dp]); 28190 get_crop(0,0,p,0,_width - 1,_height - 1,p + dp - 1,_spectrum - 1).move_to(res[p/dp]);
@@ -24250,7 +28196,7 @@ namespace cimg_library_suffixed { @@ -24250,7 +28196,7 @@ namespace cimg_library_suffixed {
24250 res.assign(_spectrum/dp + (_spectrum%dp?1:0),1,1); 28196 res.assign(_spectrum/dp + (_spectrum%dp?1:0),1,1);
24251 const unsigned int pe = _spectrum - dp; 28197 const unsigned int pe = _spectrum - dp;
24252 #ifdef cimg_use_openmp 28198 #ifdef cimg_use_openmp
24253 -#pragma omp parallel for if (res._width>=128 && _width*_height*_depth>=128) 28199 +#pragma omp parallel for cimg_openmp_if(res._width>=128 && _width*_height*_depth>=128)
24254 #endif 28200 #endif
24255 for (unsigned int p = 0; p<pe; p+=dp) 28201 for (unsigned int p = 0; p<pe; p+=dp)
24256 get_crop(0,0,0,p,_width - 1,_height - 1,_depth - 1,p + dp - 1).move_to(res[p/dp]); 28202 get_crop(0,0,0,p,_width - 1,_height - 1,_depth - 1,p + dp - 1).move_to(res[p/dp]);
@@ -24558,10 +28504,12 @@ namespace cimg_library_suffixed { @@ -24558,10 +28504,12 @@ namespace cimg_library_suffixed {
24558 ((mask._depth==1 && mask._width<=5) || (mask._depth==mask._width && mask._width<=3))) { 28504 ((mask._depth==1 && mask._width<=5) || (mask._depth==mask._width && mask._width<=3))) {
24559 // A special optimization is done for 2x2, 3x3, 4x4, 5x5, 2x2x2 and 3x3x3 mask (with boundary_conditions=1) 28505 // A special optimization is done for 2x2, 3x3, 4x4, 5x5, 2x2x2 and 3x3x3 mask (with boundary_conditions=1)
24560 Ttfloat *ptrd = res._data; 28506 Ttfloat *ptrd = res._data;
  28507 + CImg<T> I;
24561 switch (mask._depth) { 28508 switch (mask._depth) {
24562 case 3 : { 28509 case 3 : {
24563 - T I[27] = { 0 }; 28510 + I.assign(27);
24564 cimg_forC(res,c) { 28511 cimg_forC(res,c) {
  28512 + cimg_test_abort();
24565 const CImg<T> _img = get_shared_channel(c%_spectrum); 28513 const CImg<T> _img = get_shared_channel(c%_spectrum);
24566 const CImg<t> _mask = mask.get_shared_channel(c%mask._spectrum); 28514 const CImg<t> _mask = mask.get_shared_channel(c%mask._spectrum);
24567 if (is_normalized) { 28515 if (is_normalized) {
@@ -24599,8 +28547,9 @@ namespace cimg_library_suffixed { @@ -24599,8 +28547,9 @@ namespace cimg_library_suffixed {
24599 } 28547 }
24600 } break; 28548 } break;
24601 case 2 : { 28549 case 2 : {
24602 - T I[8] = { 0 }; 28550 + I.assign(8);
24603 cimg_forC(res,c) { 28551 cimg_forC(res,c) {
  28552 + cimg_test_abort();
24604 const CImg<T> _img = get_shared_channel(c%_spectrum); 28553 const CImg<T> _img = get_shared_channel(c%_spectrum);
24605 const CImg<t> _mask = mask.get_shared_channel(c%mask._spectrum); 28554 const CImg<t> _mask = mask.get_shared_channel(c%mask._spectrum);
24606 if (is_normalized) { 28555 if (is_normalized) {
@@ -24626,8 +28575,9 @@ namespace cimg_library_suffixed { @@ -24626,8 +28575,9 @@ namespace cimg_library_suffixed {
24626 case 1 : 28575 case 1 :
24627 switch (mask._width) { 28576 switch (mask._width) {
24628 case 6 : { 28577 case 6 : {
24629 - T I[36] = { 0 }; 28578 + I.assign(36);
24630 cimg_forC(res,c) { 28579 cimg_forC(res,c) {
  28580 + cimg_test_abort();
24631 const CImg<T> _img = get_shared_channel(c%_spectrum); 28581 const CImg<T> _img = get_shared_channel(c%_spectrum);
24632 const CImg<t> _mask = mask.get_shared_channel(c%mask._spectrum); 28582 const CImg<t> _mask = mask.get_shared_channel(c%mask._spectrum);
24633 if (is_normalized) { 28583 if (is_normalized) {
@@ -24665,8 +28615,9 @@ namespace cimg_library_suffixed { @@ -24665,8 +28615,9 @@ namespace cimg_library_suffixed {
24665 } 28615 }
24666 } break; 28616 } break;
24667 case 5 : { 28617 case 5 : {
24668 - T I[25] = { 0 }; 28618 + I.assign(25);
24669 cimg_forC(res,c) { 28619 cimg_forC(res,c) {
  28620 + cimg_test_abort();
24670 const CImg<T> _img = get_shared_channel(c%_spectrum); 28621 const CImg<T> _img = get_shared_channel(c%_spectrum);
24671 const CImg<t> _mask = mask.get_shared_channel(c%mask._spectrum); 28622 const CImg<t> _mask = mask.get_shared_channel(c%mask._spectrum);
24672 if (is_normalized) { 28623 if (is_normalized) {
@@ -24696,8 +28647,9 @@ namespace cimg_library_suffixed { @@ -24696,8 +28647,9 @@ namespace cimg_library_suffixed {
24696 } 28647 }
24697 } break; 28648 } break;
24698 case 4 : { 28649 case 4 : {
24699 - T I[16] = { 0 }; 28650 + I.assign(16);
24700 cimg_forC(res,c) { 28651 cimg_forC(res,c) {
  28652 + cimg_test_abort();
24701 const CImg<T> _img = get_shared_channel(c%_spectrum); 28653 const CImg<T> _img = get_shared_channel(c%_spectrum);
24702 const CImg<t> _mask = mask.get_shared_channel(c%mask._spectrum); 28654 const CImg<t> _mask = mask.get_shared_channel(c%mask._spectrum);
24703 if (is_normalized) { 28655 if (is_normalized) {
@@ -24721,8 +28673,9 @@ namespace cimg_library_suffixed { @@ -24721,8 +28673,9 @@ namespace cimg_library_suffixed {
24721 } 28673 }
24722 } break; 28674 } break;
24723 case 3 : { 28675 case 3 : {
24724 - T I[9] = { 0 }; 28676 + I.assign(9);
24725 cimg_forC(res,c) { 28677 cimg_forC(res,c) {
  28678 + cimg_test_abort();
24726 const CImg<T> _img = get_shared_channel(c%_spectrum); 28679 const CImg<T> _img = get_shared_channel(c%_spectrum);
24727 const CImg<t> _mask = mask.get_shared_channel(c%mask._spectrum); 28680 const CImg<t> _mask = mask.get_shared_channel(c%mask._spectrum);
24728 if (is_normalized) { 28681 if (is_normalized) {
@@ -24742,8 +28695,9 @@ namespace cimg_library_suffixed { @@ -24742,8 +28695,9 @@ namespace cimg_library_suffixed {
24742 } 28695 }
24743 } break; 28696 } break;
24744 case 2 : { 28697 case 2 : {
24745 - T I[4] = { 0 }; 28698 + I.assign(4);
24746 cimg_forC(res,c) { 28699 cimg_forC(res,c) {
  28700 + cimg_test_abort();
24747 const CImg<T> _img = get_shared_channel(c%_spectrum); 28701 const CImg<T> _img = get_shared_channel(c%_spectrum);
24748 const CImg<t> _mask = mask.get_shared_channel(c%mask._spectrum); 28702 const CImg<t> _mask = mask.get_shared_channel(c%mask._spectrum);
24749 if (is_normalized) { 28703 if (is_normalized) {
@@ -24762,6 +28716,7 @@ namespace cimg_library_suffixed { @@ -24762,6 +28716,7 @@ namespace cimg_library_suffixed {
24762 case 1 : 28716 case 1 :
24763 if (is_normalized) res.fill(1); 28717 if (is_normalized) res.fill(1);
24764 else cimg_forC(res,c) { 28718 else cimg_forC(res,c) {
  28719 + cimg_test_abort();
24765 const CImg<T> _img = get_shared_channel(c%_spectrum); 28720 const CImg<T> _img = get_shared_channel(c%_spectrum);
24766 const CImg<t> _mask = mask.get_shared_channel(c%mask._spectrum); 28721 const CImg<t> _mask = mask.get_shared_channel(c%mask._spectrum);
24767 res.get_shared_channel(c).assign(_img)*=_mask[0]; 28722 res.get_shared_channel(c).assign(_img)*=_mask[0];
@@ -24769,15 +28724,16 @@ namespace cimg_library_suffixed { @@ -24769,15 +28724,16 @@ namespace cimg_library_suffixed {
24769 break; 28724 break;
24770 } 28725 }
24771 } 28726 }
24772 - } else { // Generic version for other masks and borders conditions. 28727 + } else { // Generic version for other masks and boundary conditions.
24773 const int 28728 const int
24774 mx2 = mask.width()/2, my2 = mask.height()/2, mz2 = mask.depth()/2, 28729 mx2 = mask.width()/2, my2 = mask.height()/2, mz2 = mask.depth()/2,
24775 mx1 = mx2 - 1 + (mask.width()%2), my1 = my2 - 1 + (mask.height()%2), mz1 = mz2 - 1 + (mask.depth()%2), 28730 mx1 = mx2 - 1 + (mask.width()%2), my1 = my2 - 1 + (mask.height()%2), mz1 = mz2 - 1 + (mask.depth()%2),
24776 mxe = width() - mx2, mye = height() - my2, mze = depth() - mz2; 28731 mxe = width() - mx2, mye = height() - my2, mze = depth() - mz2;
24777 #ifdef cimg_use_openmp 28732 #ifdef cimg_use_openmp
24778 -#pragma omp parallel for if (res._spectrum>=2) 28733 +#pragma omp parallel for cimg_openmp_if(res._spectrum>=2)
24779 #endif 28734 #endif
24780 cimg_forC(res,c) { 28735 cimg_forC(res,c) {
  28736 + cimg_test_abort();
24781 const CImg<T> _img = get_shared_channel(c%_spectrum); 28737 const CImg<T> _img = get_shared_channel(c%_spectrum);
24782 const CImg<t> _mask = mask.get_shared_channel(c%mask._spectrum); 28738 const CImg<t> _mask = mask.get_shared_channel(c%mask._spectrum);
24783 if (is_normalized) { // Normalized correlation. 28739 if (is_normalized) { // Normalized correlation.
@@ -25009,9 +28965,10 @@ namespace cimg_library_suffixed { @@ -25009,9 +28965,10 @@ namespace cimg_library_suffixed {
25009 mx1 = mx2 - 1 + (mask.width()%2), my1 = my2 - 1 + (mask.height()%2), mz1 = mz2 - 1 + (mask.depth()%2), 28965 mx1 = mx2 - 1 + (mask.width()%2), my1 = my2 - 1 + (mask.height()%2), mz1 = mz2 - 1 + (mask.depth()%2),
25010 mxe = width() - mx2, mye = height() - my2, mze = depth() - mz2; 28966 mxe = width() - mx2, mye = height() - my2, mze = depth() - mz2;
25011 #ifdef cimg_use_openmp 28967 #ifdef cimg_use_openmp
25012 -#pragma omp parallel for if (_spectrum>=2) 28968 +#pragma omp parallel for cimg_openmp_if(_spectrum>=2)
25013 #endif 28969 #endif
25014 cimg_forC(*this,c) { 28970 cimg_forC(*this,c) {
  28971 + cimg_test_abort();
25015 const CImg<T> _img = get_shared_channel(c%_spectrum); 28972 const CImg<T> _img = get_shared_channel(c%_spectrum);
25016 const CImg<t> _mask = mask.get_shared_channel(c%mask._spectrum); 28973 const CImg<t> _mask = mask.get_shared_channel(c%mask._spectrum);
25017 if (is_normalized) { // Normalized erosion. 28974 if (is_normalized) { // Normalized erosion.
@@ -25298,9 +29255,10 @@ namespace cimg_library_suffixed { @@ -25298,9 +29255,10 @@ namespace cimg_library_suffixed {
25298 mx1 = mx2 - 1 + (mask.width()%2), my1 = my2 - 1 + (mask.height()%2), mz1 = mz2 - 1 + (mask.depth()%2), 29255 mx1 = mx2 - 1 + (mask.width()%2), my1 = my2 - 1 + (mask.height()%2), mz1 = mz2 - 1 + (mask.depth()%2),
25299 mxe = width() - mx2, mye = height() - my2, mze = depth() - mz2; 29256 mxe = width() - mx2, mye = height() - my2, mze = depth() - mz2;
25300 #ifdef cimg_use_openmp 29257 #ifdef cimg_use_openmp
25301 -#pragma omp parallel for if (_spectrum>=2) 29258 +#pragma omp parallel for cimg_openmp_if(_spectrum>=2)
25302 #endif 29259 #endif
25303 cimg_forC(*this,c) { 29260 cimg_forC(*this,c) {
  29261 + cimg_test_abort();
25304 const CImg<T> _img = get_shared_channel(c%_spectrum); 29262 const CImg<T> _img = get_shared_channel(c%_spectrum);
25305 const CImg<t> _mask = mask.get_shared_channel(c%mask._spectrum); 29263 const CImg<t> _mask = mask.get_shared_channel(c%mask._spectrum);
25306 if (is_normalized) { // Normalized dilation. 29264 if (is_normalized) { // Normalized dilation.
@@ -25614,44 +29572,44 @@ namespace cimg_library_suffixed { @@ -25614,44 +29572,44 @@ namespace cimg_library_suffixed {
25614 29572
25615 // Check labels of the neighbors. 29573 // Check labels of the neighbors.
25616 bool is_same_label = true; 29574 bool is_same_label = true;
25617 - unsigned int label = 0; 29575 + T label = 0;
25618 if (x - 1>=0) { 29576 if (x - 1>=0) {
25619 if ((*this)(x - 1,y,z)) { 29577 if ((*this)(x - 1,y,z)) {
25620 - if (!label) label = (unsigned int)(*this)(x - 1,y,z); 29578 + if (!label) label = (*this)(x - 1,y,z);
25621 else if (label!=(*this)(x - 1,y,z)) is_same_label = false; 29579 else if (label!=(*this)(x - 1,y,z)) is_same_label = false;
25622 } else Q._priority_queue_insert(is_queued,sizeQ,priority(x - 1,y,z),x - 1,y,z); 29580 } else Q._priority_queue_insert(is_queued,sizeQ,priority(x - 1,y,z),x - 1,y,z);
25623 } 29581 }
25624 if (x + 1<width()) { 29582 if (x + 1<width()) {
25625 if ((*this)(x + 1,y,z)) { 29583 if ((*this)(x + 1,y,z)) {
25626 - if (!label) label = (unsigned int)(*this)(x + 1,y,z); 29584 + if (!label) label = (*this)(x + 1,y,z);
25627 else if (label!=(*this)(x + 1,y,z)) is_same_label = false; 29585 else if (label!=(*this)(x + 1,y,z)) is_same_label = false;
25628 } else Q._priority_queue_insert(is_queued,sizeQ,priority(x + 1,y,z),x + 1,y,z); 29586 } else Q._priority_queue_insert(is_queued,sizeQ,priority(x + 1,y,z),x + 1,y,z);
25629 } 29587 }
25630 if (y - 1>=0) { 29588 if (y - 1>=0) {
25631 if ((*this)(x,y - 1,z)) { 29589 if ((*this)(x,y - 1,z)) {
25632 - if (!label) label = (unsigned int)(*this)(x,y - 1,z); 29590 + if (!label) label = (*this)(x,y - 1,z);
25633 else if (label!=(*this)(x,y - 1,z)) is_same_label = false; 29591 else if (label!=(*this)(x,y - 1,z)) is_same_label = false;
25634 } else Q._priority_queue_insert(is_queued,sizeQ,priority(x,y - 1,z),x,y - 1,z); 29592 } else Q._priority_queue_insert(is_queued,sizeQ,priority(x,y - 1,z),x,y - 1,z);
25635 } 29593 }
25636 if (y + 1<height()) { 29594 if (y + 1<height()) {
25637 if ((*this)(x,y + 1,z)) { 29595 if ((*this)(x,y + 1,z)) {
25638 - if (!label) label = (unsigned int)(*this)(x,y + 1,z); 29596 + if (!label) label = (*this)(x,y + 1,z);
25639 else if (label!=(*this)(x,y + 1,z)) is_same_label = false; 29597 else if (label!=(*this)(x,y + 1,z)) is_same_label = false;
25640 } else Q._priority_queue_insert(is_queued,sizeQ,priority(x,y + 1,z),x,y + 1,z); 29598 } else Q._priority_queue_insert(is_queued,sizeQ,priority(x,y + 1,z),x,y + 1,z);
25641 } 29599 }
25642 if (z - 1>=0) { 29600 if (z - 1>=0) {
25643 if ((*this)(x,y,z - 1)) { 29601 if ((*this)(x,y,z - 1)) {
25644 - if (!label) label = (unsigned int)(*this)(x,y,z - 1); 29602 + if (!label) label = (*this)(x,y,z - 1);
25645 else if (label!=(*this)(x,y,z - 1)) is_same_label = false; 29603 else if (label!=(*this)(x,y,z - 1)) is_same_label = false;
25646 } else Q._priority_queue_insert(is_queued,sizeQ,priority(x,y,z - 1),x,y,z - 1); 29604 } else Q._priority_queue_insert(is_queued,sizeQ,priority(x,y,z - 1),x,y,z - 1);
25647 } 29605 }
25648 if (z + 1<depth()) { 29606 if (z + 1<depth()) {
25649 if ((*this)(x,y,z + 1)) { 29607 if ((*this)(x,y,z + 1)) {
25650 - if (!label) label = (unsigned int)(*this)(x,y,z + 1); 29608 + if (!label) label = (*this)(x,y,z + 1);
25651 else if (label!=(*this)(x,y,z + 1)) is_same_label = false; 29609 else if (label!=(*this)(x,y,z + 1)) is_same_label = false;
25652 } else Q._priority_queue_insert(is_queued,sizeQ,priority(x,y,z + 1),x,y,z + 1); 29610 } else Q._priority_queue_insert(is_queued,sizeQ,priority(x,y,z + 1),x,y,z + 1);
25653 } 29611 }
25654 - if (is_same_label) (*this)(x,y,z) = (T)label; 29612 + if (is_same_label) (*this)(x,y,z) = label;
25655 } 29613 }
25656 29614
25657 // Fill lines. 29615 // Fill lines.
@@ -26181,6 +30139,7 @@ namespace cimg_library_suffixed { @@ -26181,6 +30139,7 @@ namespace cimg_library_suffixed {
26181 Tfloat *ptrd = velocity._data, veloc_max = 0; 30139 Tfloat *ptrd = velocity._data, veloc_max = 0;
26182 if (is_3d) // 3d version 30140 if (is_3d) // 3d version
26183 cimg_forC(*this,c) { 30141 cimg_forC(*this,c) {
  30142 + cimg_test_abort();
26184 CImg_3x3x3(I,Tfloat); 30143 CImg_3x3x3(I,Tfloat);
26185 cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) { 30144 cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) {
26186 const Tfloat 30145 const Tfloat
@@ -26198,6 +30157,7 @@ namespace cimg_library_suffixed { @@ -26198,6 +30157,7 @@ namespace cimg_library_suffixed {
26198 } 30157 }
26199 else // 2d version 30158 else // 2d version
26200 cimg_forZC(*this,z,c) { 30159 cimg_forZC(*this,z,c) {
  30160 + cimg_test_abort();
26201 CImg_3x3(I,Tfloat); 30161 CImg_3x3(I,Tfloat);
26202 cimg_for3x3(*this,x,y,z,c,I,Tfloat) { 30162 cimg_for3x3(*this,x,y,z,c,I,Tfloat) {
26203 const Tfloat 30163 const Tfloat
@@ -26245,6 +30205,7 @@ namespace cimg_library_suffixed { @@ -26245,6 +30205,7 @@ namespace cimg_library_suffixed {
26245 *(pd3++) = (Tfloat)n; 30205 *(pd3++) = (Tfloat)n;
26246 } 30206 }
26247 30207
  30208 + cimg_test_abort();
26248 #ifdef cimg_use_openmp 30209 #ifdef cimg_use_openmp
26249 #pragma omp parallel for collapse(2) if (_width>=256 && _height*_depth>=2) firstprivate(val) 30210 #pragma omp parallel for collapse(2) if (_width>=256 && _height*_depth>=2) firstprivate(val)
26250 #endif 30211 #endif
@@ -26338,8 +30299,9 @@ namespace cimg_library_suffixed { @@ -26338,8 +30299,9 @@ namespace cimg_library_suffixed {
26338 *(pd2++) = (Tfloat)n; 30299 *(pd2++) = (Tfloat)n;
26339 } 30300 }
26340 30301
  30302 + cimg_test_abort();
26341 #ifdef cimg_use_openmp 30303 #ifdef cimg_use_openmp
26342 -#pragma omp parallel for if (_width>=256 && _height>=2) firstprivate(val) 30304 +#pragma omp parallel for cimg_openmp_if(_width>=256 && _height>=2) firstprivate(val)
26343 #endif 30305 #endif
26344 cimg_forXY(*this,x,y) { 30306 cimg_forXY(*this,x,y) {
26345 val.fill(0); 30307 val.fill(0);
@@ -27017,7 +30979,7 @@ namespace cimg_library_suffixed { @@ -27017,7 +30979,7 @@ namespace cimg_library_suffixed {
27017 const int psize2 = (int)patch_size/2, psize1 = (int)patch_size - psize2 - 1; 30979 const int psize2 = (int)patch_size/2, psize1 = (int)patch_size - psize2 - 1;
27018 if (is_fast_approx) 30980 if (is_fast_approx)
27019 #ifdef cimg_use_openmp 30981 #ifdef cimg_use_openmp
27020 -#pragma omp parallel for if (res._width>=32 && res._height>=4) firstprivate(P,Q) 30982 +#pragma omp parallel for cimg_openmp_if(res._width>=32 && res._height>=4) firstprivate(P,Q)
27021 #endif 30983 #endif
27022 cimg_forXY(res,x,y) { // 2d fast approximation. 30984 cimg_forXY(res,x,y) { // 2d fast approximation.
27023 P = img.get_crop(x - psize1,y - psize1,x + psize2,y + psize2,true); 30985 P = img.get_crop(x - psize1,y - psize1,x + psize2,y + psize2,true);
@@ -27036,7 +30998,7 @@ namespace cimg_library_suffixed { @@ -27036,7 +30998,7 @@ namespace cimg_library_suffixed {
27036 else cimg_forC(res,c) res(x,y,c) = (Tfloat)((*this)(x,y,c)); 30998 else cimg_forC(res,c) res(x,y,c) = (Tfloat)((*this)(x,y,c));
27037 } else 30999 } else
27038 #ifdef cimg_use_openmp 31000 #ifdef cimg_use_openmp
27039 -#pragma omp parallel for if (res._width>=32 && res._height>=4) firstprivate(P,Q) 31001 +#pragma omp parallel for cimg_openmp_if(res._width>=32 && res._height>=4) firstprivate(P,Q)
27040 #endif 31002 #endif
27041 cimg_forXY(res,x,y) { // 2d exact algorithm. 31003 cimg_forXY(res,x,y) { // 2d exact algorithm.
27042 P = img.get_crop(x - psize1,y - psize1,x + psize2,y + psize2,true); 31004 P = img.get_crop(x - psize1,y - psize1,x + psize2,y + psize2,true);
@@ -27130,7 +31092,7 @@ namespace cimg_library_suffixed { @@ -27130,7 +31092,7 @@ namespace cimg_library_suffixed {
27130 else switch (n) { // Without threshold. 31092 else switch (n) { // Without threshold.
27131 case 3 : { 31093 case 3 : {
27132 #ifdef cimg_use_openmp 31094 #ifdef cimg_use_openmp
27133 -#pragma omp parallel for if (_spectrum>=2) 31095 +#pragma omp parallel for cimg_openmp_if(_spectrum>=2)
27134 #endif 31096 #endif
27135 cimg_forC(*this,c) { 31097 cimg_forC(*this,c) {
27136 T I[9] = { 0 }; 31098 T I[9] = { 0 };
@@ -27150,7 +31112,7 @@ namespace cimg_library_suffixed { @@ -27150,7 +31112,7 @@ namespace cimg_library_suffixed {
27150 } break; 31112 } break;
27151 case 5 : { 31113 case 5 : {
27152 #ifdef cimg_use_openmp 31114 #ifdef cimg_use_openmp
27153 -#pragma omp parallel for if (_spectrum>=2) 31115 +#pragma omp parallel for cimg_openmp_if(_spectrum>=2)
27154 #endif 31116 #endif
27155 cimg_forC(*this,c) { 31117 cimg_forC(*this,c) {
27156 T I[25] = { 0 }; 31118 T I[25] = { 0 };
@@ -27209,9 +31171,10 @@ namespace cimg_library_suffixed { @@ -27209,9 +31171,10 @@ namespace cimg_library_suffixed {
27209 } 31171 }
27210 } else { // 1d 31172 } else { // 1d
27211 31173
  31174 + CImg<T> I;
27212 if (threshold>0) 31175 if (threshold>0)
27213 #ifdef cimg_use_openmp 31176 #ifdef cimg_use_openmp
27214 -#pragma omp parallel for if (_width>=16 && _spectrum>=2) 31177 +#pragma omp parallel for cimg_openmp_if(_width>=16 && _spectrum>=2)
27215 #endif 31178 #endif
27216 cimg_forXC(*this,x,c) { // With threshold. 31179 cimg_forXC(*this,x,c) { // With threshold.
27217 const int 31180 const int
@@ -27228,26 +31191,26 @@ namespace cimg_library_suffixed { @@ -27228,26 +31191,26 @@ namespace cimg_library_suffixed {
27228 else switch (n) { // Without threshold. 31191 else switch (n) { // Without threshold.
27229 case 2 : { 31192 case 2 : {
27230 #ifdef cimg_use_openmp 31193 #ifdef cimg_use_openmp
27231 -#pragma omp parallel for if (_spectrum>=2) 31194 +#pragma omp parallel for cimg_openmp_if(_spectrum>=2)
27232 #endif 31195 #endif
27233 cimg_forC(*this,c) { 31196 cimg_forC(*this,c) {
27234 - T I[4] = { 0 }; 31197 + I.assign(4);
27235 cimg_for2x2(*this,x,y,0,c,I,T) res(x,c) = (T)(0.5f*(I[0] + I[1])); 31198 cimg_for2x2(*this,x,y,0,c,I,T) res(x,c) = (T)(0.5f*(I[0] + I[1]));
27236 } 31199 }
27237 } break; 31200 } break;
27238 case 3 : { 31201 case 3 : {
27239 #ifdef cimg_use_openmp 31202 #ifdef cimg_use_openmp
27240 -#pragma omp parallel for if (_spectrum>=2) 31203 +#pragma omp parallel for cimg_openmp_if(_spectrum>=2)
27241 #endif 31204 #endif
27242 cimg_forC(*this,c) { 31205 cimg_forC(*this,c) {
27243 - T I[9] = { 0 }; 31206 + I.assign(9);
27244 cimg_for3x3(*this,x,y,0,c,I,T) 31207 cimg_for3x3(*this,x,y,0,c,I,T)
27245 res(x,c) = I[3]<I[4]?(I[4]<I[5]?I[4]:(I[3]<I[5]?I[5]:I[3])):(I[3]<I[5]?I[3]:(I[4]<I[5]?I[5]:I[4])); 31208 res(x,c) = I[3]<I[4]?(I[4]<I[5]?I[4]:(I[3]<I[5]?I[5]:I[3])):(I[3]<I[5]?I[3]:(I[4]<I[5]?I[5]:I[4]));
27246 } 31209 }
27247 } break; 31210 } break;
27248 default : { 31211 default : {
27249 #ifdef cimg_use_openmp 31212 #ifdef cimg_use_openmp
27250 -#pragma omp parallel for if (_width>=16 && _spectrum>=2) 31213 +#pragma omp parallel for cimg_openmp_if(_width>=16 && _spectrum>=2)
27251 #endif 31214 #endif
27252 cimg_forXC(*this,x,c) { 31215 cimg_forXC(*this,x,c) {
27253 const int 31216 const int
@@ -27300,7 +31263,7 @@ namespace cimg_library_suffixed { @@ -27300,7 +31263,7 @@ namespace cimg_library_suffixed {
27300 } 31263 }
27301 } 31264 }
27302 #ifdef cimg_use_openmp 31265 #ifdef cimg_use_openmp
27303 -#pragma omp parallel for if (_width*_height*_depth>=512 && _spectrum>=2) 31266 +#pragma omp parallel for cimg_openmp_if(_width*_height*_depth>=512 && _spectrum>=2)
27304 #endif 31267 #endif
27305 cimg_forC(*this,c) { 31268 cimg_forC(*this,c) {
27306 Tfloat *ptrd = velocity.data(0,0,0,c), veloc_max = 0; 31269 Tfloat *ptrd = velocity.data(0,0,0,c), veloc_max = 0;
@@ -27347,7 +31310,7 @@ namespace cimg_library_suffixed { @@ -27347,7 +31310,7 @@ namespace cimg_library_suffixed {
27347 CImg<Tfloat> G = (alpha>0?get_blur(alpha).get_structure_tensors():get_structure_tensors()); 31310 CImg<Tfloat> G = (alpha>0?get_blur(alpha).get_structure_tensors():get_structure_tensors());
27348 if (sigma>0) G.blur(sigma); 31311 if (sigma>0) G.blur(sigma);
27349 #ifdef cimg_use_openmp 31312 #ifdef cimg_use_openmp
27350 -#pragma omp parallel for if (_width>=32 && _height>=16) 31313 +#pragma omp parallel for cimg_openmp_if(_width>=32 && _height>=16)
27351 #endif 31314 #endif
27352 cimg_forY(G,y) { 31315 cimg_forY(G,y) {
27353 CImg<Tfloat> val, vec; 31316 CImg<Tfloat> val, vec;
@@ -27362,7 +31325,7 @@ namespace cimg_library_suffixed { @@ -27362,7 +31325,7 @@ namespace cimg_library_suffixed {
27362 } 31325 }
27363 } 31326 }
27364 #ifdef cimg_use_openmp 31327 #ifdef cimg_use_openmp
27365 -#pragma omp parallel for if (_width*_height>=512 && _spectrum>=2) 31328 +#pragma omp parallel for cimg_openmp_if(_width*_height>=512 && _spectrum>=2)
27366 #endif 31329 #endif
27367 cimg_forC(*this,c) { 31330 cimg_forC(*this,c) {
27368 Tfloat *ptrd = velocity.data(0,0,0,c), veloc_max = 0; 31331 Tfloat *ptrd = velocity.data(0,0,0,c), veloc_max = 0;
@@ -27444,7 +31407,7 @@ namespace cimg_library_suffixed { @@ -27444,7 +31407,7 @@ namespace cimg_library_suffixed {
27444 switch (scheme) { // 3d. 31407 switch (scheme) { // 3d.
27445 case -1 : { // Backward finite differences. 31408 case -1 : { // Backward finite differences.
27446 #ifdef cimg_use_openmp 31409 #ifdef cimg_use_openmp
27447 -#pragma omp parallel for if (_width*_height*_depth>=1048576 && _spectrum>=2) 31410 +#pragma omp parallel for cimg_openmp_if(_width*_height*_depth>=1048576 && _spectrum>=2)
27448 #endif 31411 #endif
27449 cimg_forC(*this,c) { 31412 cimg_forC(*this,c) {
27450 const unsigned long off = c*_width*_height*_depth; 31413 const unsigned long off = c*_width*_height*_depth;
@@ -27459,7 +31422,7 @@ namespace cimg_library_suffixed { @@ -27459,7 +31422,7 @@ namespace cimg_library_suffixed {
27459 } break; 31422 } break;
27460 case 1 : { // Forward finite differences. 31423 case 1 : { // Forward finite differences.
27461 #ifdef cimg_use_openmp 31424 #ifdef cimg_use_openmp
27462 -#pragma omp parallel for if (_width*_height*_depth>=1048576 && _spectrum>=2) 31425 +#pragma omp parallel for cimg_openmp_if(_width*_height*_depth>=1048576 && _spectrum>=2)
27463 #endif 31426 #endif
27464 cimg_forC(*this,c) { 31427 cimg_forC(*this,c) {
27465 const unsigned long off = c*_width*_height*_depth; 31428 const unsigned long off = c*_width*_height*_depth;
@@ -27484,7 +31447,7 @@ namespace cimg_library_suffixed { @@ -27484,7 +31447,7 @@ namespace cimg_library_suffixed {
27484 } break; 31447 } break;
27485 default : { // Central finite differences. 31448 default : { // Central finite differences.
27486 #ifdef cimg_use_openmp 31449 #ifdef cimg_use_openmp
27487 -#pragma omp parallel for if (_width*_height*_depth>=1048576 && _spectrum>=2) 31450 +#pragma omp parallel for cimg_openmp_if(_width*_height*_depth>=1048576 && _spectrum>=2)
27488 #endif 31451 #endif
27489 cimg_forC(*this,c) { 31452 cimg_forC(*this,c) {
27490 const unsigned long off = c*_width*_height*_depth; 31453 const unsigned long off = c*_width*_height*_depth;
@@ -27612,7 +31575,7 @@ namespace cimg_library_suffixed { @@ -27612,7 +31575,7 @@ namespace cimg_library_suffixed {
27612 if (!cimg::strcasecmp(naxes,def_axes3d)) { // 3d 31575 if (!cimg::strcasecmp(naxes,def_axes3d)) { // 3d
27613 31576
27614 #ifdef cimg_use_openmp 31577 #ifdef cimg_use_openmp
27615 -#pragma omp parallel for if (_width*_height*_depth>=1048576 && _spectrum>=2) 31578 +#pragma omp parallel for cimg_openmp_if(_width*_height*_depth>=1048576 && _spectrum>=2)
27616 #endif 31579 #endif
27617 cimg_forC(*this,c) { 31580 cimg_forC(*this,c) {
27618 const unsigned long off = c*_width*_height*_depth; 31581 const unsigned long off = c*_width*_height*_depth;
@@ -27673,7 +31636,7 @@ namespace cimg_library_suffixed { @@ -27673,7 +31636,7 @@ namespace cimg_library_suffixed {
27673 else if (axis1=='x' && axis2=='z') { // Ixz 31636 else if (axis1=='x' && axis2=='z') { // Ixz
27674 valid_axis = true; 31637 valid_axis = true;
27675 #ifdef cimg_use_openmp 31638 #ifdef cimg_use_openmp
27676 -#pragma omp parallel for if (_width*_height*_depth>=1048576 && _spectrum>=2) 31639 +#pragma omp parallel for cimg_openmp_if(_width*_height*_depth>=1048576 && _spectrum>=2)
27677 #endif 31640 #endif
27678 cimg_forC(*this,c) { 31641 cimg_forC(*this,c) {
27679 Tfloat *ptrd = res[l2].data(0,0,0,c); 31642 Tfloat *ptrd = res[l2].data(0,0,0,c);
@@ -27695,7 +31658,7 @@ namespace cimg_library_suffixed { @@ -27695,7 +31658,7 @@ namespace cimg_library_suffixed {
27695 else if (axis1=='y' && axis2=='z') { // Iyz 31658 else if (axis1=='y' && axis2=='z') { // Iyz
27696 valid_axis = true; 31659 valid_axis = true;
27697 #ifdef cimg_use_openmp 31660 #ifdef cimg_use_openmp
27698 -#pragma omp parallel for if (_width*_height*_depth>=1048576 && _spectrum>=2) 31661 +#pragma omp parallel for cimg_openmp_if(_width*_height*_depth>=1048576 && _spectrum>=2)
27699 #endif 31662 #endif
27700 cimg_forC(*this,c) { 31663 cimg_forC(*this,c) {
27701 Tfloat *ptrd = res[l2].data(0,0,0,c); 31664 Tfloat *ptrd = res[l2].data(0,0,0,c);
@@ -27706,7 +31669,7 @@ namespace cimg_library_suffixed { @@ -27706,7 +31669,7 @@ namespace cimg_library_suffixed {
27706 else if (axis1=='z' && axis2=='z') { // Izz 31669 else if (axis1=='z' && axis2=='z') { // Izz
27707 valid_axis = true; 31670 valid_axis = true;
27708 #ifdef cimg_use_openmp 31671 #ifdef cimg_use_openmp
27709 -#pragma omp parallel for if (_width*_height*_depth>=1048576 && _spectrum>=2) 31672 +#pragma omp parallel for cimg_openmp_if(_width*_height*_depth>=1048576 && _spectrum>=2)
27710 #endif 31673 #endif
27711 cimg_forC(*this,c) { 31674 cimg_forC(*this,c) {
27712 Tfloat *ptrd = res[l2].data(0,0,0,c); 31675 Tfloat *ptrd = res[l2].data(0,0,0,c);
@@ -27734,7 +31697,7 @@ namespace cimg_library_suffixed { @@ -27734,7 +31697,7 @@ namespace cimg_library_suffixed {
27734 CImg<Tfloat> res(_width,_height,_depth,_spectrum); 31697 CImg<Tfloat> res(_width,_height,_depth,_spectrum);
27735 if (_depth>1) { // 3d 31698 if (_depth>1) { // 3d
27736 #ifdef cimg_use_openmp 31699 #ifdef cimg_use_openmp
27737 -#pragma omp parallel for if (_width*_height*_depth>=1048576 && _spectrum>=2) 31700 +#pragma omp parallel for cimg_openmp_if(_width*_height*_depth>=1048576 && _spectrum>=2)
27738 #endif 31701 #endif
27739 cimg_forC(*this,c) { 31702 cimg_forC(*this,c) {
27740 Tfloat *ptrd = res.data(0,0,0,c); 31703 Tfloat *ptrd = res.data(0,0,0,c);
@@ -27743,7 +31706,7 @@ namespace cimg_library_suffixed { @@ -27743,7 +31706,7 @@ namespace cimg_library_suffixed {
27743 } 31706 }
27744 } else if (_height>1) { // 2d 31707 } else if (_height>1) { // 2d
27745 #ifdef cimg_use_openmp 31708 #ifdef cimg_use_openmp
27746 -#pragma omp parallel for if (_width*_height>=1048576 && _depth*_spectrum>=2) 31709 +#pragma omp parallel for cimg_openmp_if(_width*_height>=1048576 && _depth*_spectrum>=2)
27747 #endif 31710 #endif
27748 cimg_forC(*this,c) { 31711 cimg_forC(*this,c) {
27749 Tfloat *ptrd = res.data(0,0,0,c); 31712 Tfloat *ptrd = res.data(0,0,0,c);
@@ -27752,7 +31715,7 @@ namespace cimg_library_suffixed { @@ -27752,7 +31715,7 @@ namespace cimg_library_suffixed {
27752 } 31715 }
27753 } else { // 1d 31716 } else { // 1d
27754 #ifdef cimg_use_openmp 31717 #ifdef cimg_use_openmp
27755 -#pragma omp parallel for if (_width>=1048576 && _height*_depth*_spectrum>=2) 31718 +#pragma omp parallel for cimg_openmp_if(_width>=1048576 && _height*_depth*_spectrum>=2)
27756 #endif 31719 #endif
27757 cimg_forC(*this,c) { 31720 cimg_forC(*this,c) {
27758 Tfloat *ptrd = res.data(0,0,0,c); 31721 Tfloat *ptrd = res.data(0,0,0,c);
@@ -27765,22 +31728,21 @@ namespace cimg_library_suffixed { @@ -27765,22 +31728,21 @@ namespace cimg_library_suffixed {
27765 31728
27766 //! Compute the structure tensor field of an image. 31729 //! Compute the structure tensor field of an image.
27767 /** 31730 /**
27768 - \param scheme Numerical scheme. Can be <tt>{ 0=central | 1=fwd/bwd1 | 2=fwd/bwd2 }</tt> 31731 + \param is_fwbw_scheme scheme. Can be <tt>{ false=centered | true=forward-backward }</tt>
27769 **/ 31732 **/
27770 - CImg<T>& structure_tensors(const unsigned int scheme=2) {  
27771 - return get_structure_tensors(scheme).move_to(*this); 31733 + CImg<T>& structure_tensors(const bool is_fwbw_scheme=false) {
  31734 + return get_structure_tensors(is_fwbw_scheme).move_to(*this);
27772 } 31735 }
27773 31736
27774 //! Compute the structure tensor field of an image \newinstance. 31737 //! Compute the structure tensor field of an image \newinstance.
27775 - CImg<Tfloat> get_structure_tensors(const unsigned int scheme=2) const { 31738 + CImg<Tfloat> get_structure_tensors(const bool is_fwbw_scheme=false) const {
27776 if (is_empty()) return *this; 31739 if (is_empty()) return *this;
27777 CImg<Tfloat> res; 31740 CImg<Tfloat> res;
27778 if (_depth>1) { // 3d 31741 if (_depth>1) { // 3d
27779 res.assign(_width,_height,_depth,6,0); 31742 res.assign(_width,_height,_depth,6,0);
27780 - switch (scheme) {  
27781 - case 0 : { // classical central finite differences 31743 + if (!is_fwbw_scheme) { // Classical central finite differences
27782 #ifdef cimg_use_openmp 31744 #ifdef cimg_use_openmp
27783 -#pragma omp parallel for if (_width*_height*_depth>=1048576 && _spectrum>=2) 31745 +#pragma omp parallel for cimg_openmp_if(_width*_height*_depth>=1048576 && _spectrum>=2)
27784 #endif 31746 #endif
27785 cimg_forC(*this,c) { 31747 cimg_forC(*this,c) {
27786 Tfloat 31748 Tfloat
@@ -27800,33 +31762,9 @@ namespace cimg_library_suffixed { @@ -27800,33 +31762,9 @@ namespace cimg_library_suffixed {
27800 *(ptrd5++)+=iz*iz; 31762 *(ptrd5++)+=iz*iz;
27801 } 31763 }
27802 } 31764 }
27803 - } break;  
27804 - case 1 : { // Forward/backward finite differences (version 1).  
27805 -#ifdef cimg_use_openmp  
27806 -#pragma omp parallel for if (_width*_height*_depth>=1048576 && _spectrum>=2)  
27807 -#endif  
27808 - cimg_forC(*this,c) {  
27809 - Tfloat  
27810 - *ptrd0 = res.data(0,0,0,0), *ptrd1 = res.data(0,0,0,1), *ptrd2 = res.data(0,0,0,2),  
27811 - *ptrd3 = res.data(0,0,0,3), *ptrd4 = res.data(0,0,0,4), *ptrd5 = res.data(0,0,0,5);  
27812 - CImg_3x3x3(I,Tfloat);  
27813 - cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) {  
27814 - const Tfloat  
27815 - ixf = Incc - Iccc, ixb = Iccc - Ipcc,  
27816 - iyf = Icnc - Iccc, iyb = Iccc - Icpc,  
27817 - izf = Iccn - Iccc, izb = Iccc - Iccp;  
27818 - *(ptrd0++)+=(ixf*ixf + 2*ixf*ixb + ixb*ixb)/4;  
27819 - *(ptrd1++)+=(ixf*iyf + ixf*iyb + ixb*iyf + ixb*iyb)/4;  
27820 - *(ptrd2++)+=(ixf*izf + ixf*izb + ixb*izf + ixb*izb)/4;  
27821 - *(ptrd3++)+=(iyf*iyf + 2*iyf*iyb + iyb*iyb)/4;  
27822 - *(ptrd4++)+=(iyf*izf + iyf*izb + iyb*izf + iyb*izb)/4;  
27823 - *(ptrd5++)+=(izf*izf + 2*izf*izb + izb*izb)/4;  
27824 - }  
27825 - }  
27826 - } break;  
27827 - default : { // Forward/backward finite differences (version 2). 31765 + } else { // Forward/backward finite differences.
27828 #ifdef cimg_use_openmp 31766 #ifdef cimg_use_openmp
27829 -#pragma omp parallel for if (_width*_height*_depth>=1048576 && _spectrum>=2) 31767 +#pragma omp parallel for cimg_openmp_if(_width*_height*_depth>=1048576 && _spectrum>=2)
27830 #endif 31768 #endif
27831 cimg_forC(*this,c) { 31769 cimg_forC(*this,c) {
27832 Tfloat 31770 Tfloat
@@ -27846,14 +31784,12 @@ namespace cimg_library_suffixed { @@ -27846,14 +31784,12 @@ namespace cimg_library_suffixed {
27846 *(ptrd5++)+=(izf*izf + izb*izb)/2; 31784 *(ptrd5++)+=(izf*izf + izb*izb)/2;
27847 } 31785 }
27848 } 31786 }
27849 - } break;  
27850 } 31787 }
27851 } else { // 2d 31788 } else { // 2d
27852 res.assign(_width,_height,_depth,3,0); 31789 res.assign(_width,_height,_depth,3,0);
27853 - switch (scheme) {  
27854 - case 0 : { // classical central finite differences 31790 + if (!is_fwbw_scheme) { // Classical central finite differences
27855 #ifdef cimg_use_openmp 31791 #ifdef cimg_use_openmp
27856 -#pragma omp parallel for if (_width*_height>=1048576 && _depth*_spectrum>=2) 31792 +#pragma omp parallel for cimg_openmp_if(_width*_height>=1048576 && _depth*_spectrum>=2)
27857 #endif 31793 #endif
27858 cimg_forC(*this,c) { 31794 cimg_forC(*this,c) {
27859 Tfloat *ptrd0 = res.data(0,0,0,0), *ptrd1 = res.data(0,0,0,1), *ptrd2 = res.data(0,0,0,2); 31795 Tfloat *ptrd0 = res.data(0,0,0,0), *ptrd1 = res.data(0,0,0,1), *ptrd2 = res.data(0,0,0,2);
@@ -27867,27 +31803,9 @@ namespace cimg_library_suffixed { @@ -27867,27 +31803,9 @@ namespace cimg_library_suffixed {
27867 *(ptrd2++)+=iy*iy; 31803 *(ptrd2++)+=iy*iy;
27868 } 31804 }
27869 } 31805 }
27870 - } break;  
27871 - case 1 : { // Forward/backward finite differences (version 1). 31806 + } else { // Forward/backward finite differences (version 2).
27872 #ifdef cimg_use_openmp 31807 #ifdef cimg_use_openmp
27873 -#pragma omp parallel for if (_width*_height>=1048576 && _depth*_spectrum>=2)  
27874 -#endif  
27875 - cimg_forC(*this,c) {  
27876 - Tfloat *ptrd0 = res.data(0,0,0,0), *ptrd1 = res.data(0,0,0,1), *ptrd2 = res.data(0,0,0,2);  
27877 - CImg_3x3(I,Tfloat);  
27878 - cimg_for3x3(*this,x,y,0,c,I,Tfloat) {  
27879 - const Tfloat  
27880 - ixf = Inc - Icc, ixb = Icc - Ipc,  
27881 - iyf = Icn - Icc, iyb = Icc - Icp;  
27882 - *(ptrd0++)+=(ixf*ixf + 2*ixf*ixb + ixb*ixb)/4;  
27883 - *(ptrd1++)+=(ixf*iyf + ixf*iyb + ixb*iyf + ixb*iyb)/4;  
27884 - *(ptrd2++)+=(iyf*iyf + 2*iyf*iyb + iyb*iyb)/4;  
27885 - }  
27886 - }  
27887 - } break;  
27888 - default : { // Forward/backward finite differences (version 2).  
27889 -#ifdef cimg_use_openmp  
27890 -#pragma omp parallel for if (_width*_height>=1048576 && _depth*_spectrum>=2) 31808 +#pragma omp parallel for cimg_openmp_if(_width*_height>=1048576 && _depth*_spectrum>=2)
27891 #endif 31809 #endif
27892 cimg_forC(*this,c) { 31810 cimg_forC(*this,c) {
27893 Tfloat *ptrd0 = res.data(0,0,0,0), *ptrd1 = res.data(0,0,0,1), *ptrd2 = res.data(0,0,0,2); 31811 Tfloat *ptrd0 = res.data(0,0,0,0), *ptrd1 = res.data(0,0,0,1), *ptrd2 = res.data(0,0,0,2);
@@ -27901,7 +31819,6 @@ namespace cimg_library_suffixed { @@ -27901,7 +31819,6 @@ namespace cimg_library_suffixed {
27901 *(ptrd2++)+=(iyf*iyf + iyb*iyb)/2; 31819 *(ptrd2++)+=(iyf*iyf + iyb*iyb)/2;
27902 } 31820 }
27903 } 31821 }
27904 - } break;  
27905 } 31822 }
27906 } 31823 }
27907 return res; 31824 return res;
@@ -27992,14 +31909,15 @@ namespace cimg_library_suffixed { @@ -27992,14 +31909,15 @@ namespace cimg_library_suffixed {
27992 \param nb_scales Number of scales used to estimate the displacement field. 31909 \param nb_scales Number of scales used to estimate the displacement field.
27993 \param iteration_max Maximum number of iterations allowed for one scale. 31910 \param iteration_max Maximum number of iterations allowed for one scale.
27994 \param is_backward If false, match I2(X + U(X)) = I1(X), else match I2(X) = I1(X - U(X)). 31911 \param is_backward If false, match I2(X + U(X)) = I1(X), else match I2(X) = I1(X - U(X)).
27995 - \param constraints A list of constrained pixels (as a Nx4 or Nx6 image), i.e defining N points  
27996 - of the estimated flow having a known value. 31912 + \param guide Image used as the initial correspondence estimate for the algorithm.
  31913 + 'guide' may have a last channel with boolean values (0=false | other=true) that
  31914 + tells for each pixel if its correspondence vector is constrained to its initial value (constraint mask).
27997 **/ 31915 **/
27998 CImg<T>& displacement(const CImg<T>& source, const float smoothness=0.1f, const float precision=5.0f, 31916 CImg<T>& displacement(const CImg<T>& source, const float smoothness=0.1f, const float precision=5.0f,
27999 const unsigned int nb_scales=0, const unsigned int iteration_max=10000, 31917 const unsigned int nb_scales=0, const unsigned int iteration_max=10000,
28000 const bool is_backward=false, 31918 const bool is_backward=false,
28001 - const CImg<floatT>& constraints=CImg<floatT>::empty()) {  
28002 - return get_displacement(source,smoothness,precision,nb_scales,iteration_max,is_backward,constraints). 31919 + const CImg<floatT>& guide=CImg<floatT>::const_empty()) {
  31920 + return get_displacement(source,smoothness,precision,nb_scales,iteration_max,is_backward,guide).
28003 move_to(*this); 31921 move_to(*this);
28004 } 31922 }
28005 31923
@@ -28008,7 +31926,7 @@ namespace cimg_library_suffixed { @@ -28008,7 +31926,7 @@ namespace cimg_library_suffixed {
28008 const float smoothness=0.1f, const float precision=5.0f, 31926 const float smoothness=0.1f, const float precision=5.0f,
28009 const unsigned int nb_scales=0, const unsigned int iteration_max=10000, 31927 const unsigned int nb_scales=0, const unsigned int iteration_max=10000,
28010 const bool is_backward=false, 31928 const bool is_backward=false,
28011 - const CImg<floatT>& constraints=CImg<floatT>::empty()) const { 31929 + const CImg<floatT>& guide=CImg<floatT>::const_empty()) const {
28012 if (is_empty() || !source) return +*this; 31930 if (is_empty() || !source) return +*this;
28013 if (!is_sameXYZC(source)) 31931 if (!is_sameXYZC(source))
28014 throw CImgArgumentException(_cimg_instance 31932 throw CImgArgumentException(_cimg_instance
@@ -28022,7 +31940,18 @@ namespace cimg_library_suffixed { @@ -28022,7 +31940,18 @@ namespace cimg_library_suffixed {
28022 "(should be >=0)", 31940 "(should be >=0)",
28023 cimg_instance, 31941 cimg_instance,
28024 precision); 31942 precision);
  31943 +
28025 const bool is_3d = source._depth>1; 31944 const bool is_3d = source._depth>1;
  31945 + const unsigned int constraint = is_3d?3:2;
  31946 +
  31947 + if (guide &&
  31948 + (guide._width!=_width || guide._height!=_height || guide._depth!=_depth || guide._spectrum<constraint))
  31949 + throw CImgArgumentException(_cimg_instance
  31950 + "displacement(): Specified guide (%u,%u,%u,%u,%p) "
  31951 + "has invalid dimensions.",
  31952 + cimg_instance,
  31953 + guide._width,guide._height,guide._depth,guide._spectrum,guide._data);
  31954 +
28026 const unsigned int 31955 const unsigned int
28027 mins = is_3d?cimg::min(_width,_height,_depth):cimg::min(_width,_height), 31956 mins = is_3d?cimg::min(_width,_height,_depth):cimg::min(_width,_height),
28028 _nb_scales = nb_scales>0?nb_scales: 31957 _nb_scales = nb_scales>0?nb_scales:
@@ -28032,14 +31961,7 @@ namespace cimg_library_suffixed { @@ -28032,14 +31961,7 @@ namespace cimg_library_suffixed {
28032 float sm, sM = source.max_min(sm), tm, tM = max_min(tm); 31961 float sm, sM = source.max_min(sm), tm, tM = max_min(tm);
28033 const float sdelta = sm==sM?1:(sM - sm), tdelta = tm==tM?1:(tM - tm); 31962 const float sdelta = sm==sM?1:(sM - sm), tdelta = tm==tM?1:(tM - tm);
28034 31963
28035 - if (constraints && (constraints.height()!=4 || is_3d) && (constraints.height()!=6 || !is_3d))  
28036 - throw CImgArgumentException(_cimg_instance  
28037 - "displacement(): Invalid specified constraints image (%u,%u,%u,%u,%p) "  
28038 - " (should be a Nx4 or Nx6 image).",  
28039 - cimg_instance,  
28040 - constraints._width,constraints._height,constraints._depth,constraints._spectrum,  
28041 - constraints._data);  
28042 - CImg<floatT> U; 31964 + CImg<floatT> U, V;
28043 floatT bound = 0; 31965 floatT bound = 0;
28044 for (int scale = (int)_nb_scales - 1; scale>=0; --scale) { 31966 for (int scale = (int)_nb_scales - 1; scale>=0; --scale) {
28045 const float factor = (float)std::pow(1.5,(double)scale); 31967 const float factor = (float)std::pow(1.5,(double)scale);
@@ -28051,36 +31973,21 @@ namespace cimg_library_suffixed { @@ -28051,36 +31973,21 @@ namespace cimg_library_suffixed {
28051 const CImg<Tfloat> 31973 const CImg<Tfloat>
28052 I1 = (source.get_resize(sw,sh,sd,-100,2)-=sm)/=sdelta, 31974 I1 = (source.get_resize(sw,sh,sd,-100,2)-=sm)/=sdelta,
28053 I2 = (get_resize(I1,2)-=tm)/=tdelta; 31975 I2 = (get_resize(I1,2)-=tm)/=tdelta;
  31976 + if (guide._spectrum>constraint) guide.get_resize(I2._width,I2._height,I2._depth,-100,1).move_to(V);
28054 if (U) (U*=1.5f).resize(I2._width,I2._height,I2._depth,-100,3); 31977 if (U) (U*=1.5f).resize(I2._width,I2._height,I2._depth,-100,3);
28055 - else U.assign(I2._width,I2._height,I2._depth,is_3d?3:2,0);  
28056 - if (constraints) {  
28057 - if (is_3d) cimg_forX(constraints,k) {  
28058 - const int  
28059 - cx = (int)(constraints(k,0)*U.width()/width()),  
28060 - cy = (int)(constraints(k,1)*U.height()/height()),  
28061 - cz = (int)(constraints(k,2)*U.depth()/depth());  
28062 - if (U.contains(U(cx,cy,cz))) {  
28063 - U(cx,cy,cz,0) = (float)(constraints(k,3)/factor);  
28064 - U(cx,cy,cz,1) = (float)(constraints(k,4)/factor);  
28065 - U(cx,cy,cz,2) = (float)(constraints(k,5)/factor);  
28066 - }  
28067 - }  
28068 - else cimg_forX(constraints,k) {  
28069 - const int  
28070 - cx = (int)(constraints(k,0)*U.width()/width()),  
28071 - cy = (int)(constraints(k,1)*U.height()/height());  
28072 - if (U.contains(U(cx,cy))) {  
28073 - U(cx,cy,0) = (float)(constraints(k,2)/factor);  
28074 - U(cx,cy,1) = (float)(constraints(k,3)/factor);  
28075 - }  
28076 - } 31978 + else {
  31979 + if (guide)
  31980 + guide.get_shared_channels(0,is_3d?2:1).get_resize(I2._width,I2._height,I2._depth,-100,2).move_to(U);
  31981 + else U.assign(I2._width,I2._height,I2._depth,is_3d?3:2,0);
28077 } 31982 }
28078 31983
28079 float dt = 2, energy = cimg::type<float>::max(); 31984 float dt = 2, energy = cimg::type<float>::max();
28080 const CImgList<Tfloat> dI = is_backward?I1.get_gradient():I2.get_gradient(); 31985 const CImgList<Tfloat> dI = is_backward?I1.get_gradient():I2.get_gradient();
28081 31986
28082 for (unsigned int iteration = 0; iteration<iteration_max; ++iteration) { 31987 for (unsigned int iteration = 0; iteration<iteration_max; ++iteration) {
  31988 + cimg_test_abort();
28083 float _energy = 0; 31989 float _energy = 0;
  31990 +
28084 if (is_3d) { // 3d version. 31991 if (is_3d) { // 3d version.
28085 if (smoothness>=0) // Isotropic regularization. 31992 if (smoothness>=0) // Isotropic regularization.
28086 #ifdef cimg_use_openmp 31993 #ifdef cimg_use_openmp
@@ -28127,6 +32034,11 @@ namespace cimg_library_suffixed { @@ -28127,6 +32034,11 @@ namespace cimg_library_suffixed {
28127 } 32034 }
28128 _energy+=delta_I*delta_I + smoothness*_energy_regul; 32035 _energy+=delta_I*delta_I + smoothness*_energy_regul;
28129 } 32036 }
  32037 + if (V) cimg_forXYZ(V,x,y,z) if (V(x,y,z,3)) { // Apply constraints.
  32038 + U(x,y,z,0) = V(x,y,z,0)/factor;
  32039 + U(x,y,z,1) = V(x,y,z,1)/factor;
  32040 + U(x,y,z,2) = V(x,y,z,2)/factor;
  32041 + }
28130 } else { // Anisotropic regularization. 32042 } else { // Anisotropic regularization.
28131 const float nsmoothness = -smoothness; 32043 const float nsmoothness = -smoothness;
28132 #ifdef cimg_use_openmp 32044 #ifdef cimg_use_openmp
@@ -28188,23 +32100,17 @@ namespace cimg_library_suffixed { @@ -28188,23 +32100,17 @@ namespace cimg_library_suffixed {
28188 } 32100 }
28189 _energy+=delta_I*delta_I + nsmoothness*_energy_regul; 32101 _energy+=delta_I*delta_I + nsmoothness*_energy_regul;
28190 } 32102 }
  32103 + if (V) cimg_forXYZ(V,x,y,z) if (V(x,y,z,3)) { // Apply constraints.
  32104 + U(x,y,z,0) = V(x,y,z,0)/factor;
  32105 + U(x,y,z,1) = V(x,y,z,1)/factor;
  32106 + U(x,y,z,2) = V(x,y,z,2)/factor;
  32107 + }
28191 } 32108 }
28192 } 32109 }
28193 - if (constraints) cimg_forX(constraints,k) {  
28194 - const int  
28195 - cx = (int)(constraints(k,0)*U.width()/width()),  
28196 - cy = (int)(constraints(k,1)*U.height()/height()),  
28197 - cz = (int)(constraints(k,2)*U.depth()/depth());  
28198 - if (U.contains(U(cx,cy,cz))) {  
28199 - U(cx,cy,cz,0) = (float)(constraints(k,3)/factor);  
28200 - U(cx,cy,cz,1) = (float)(constraints(k,4)/factor);  
28201 - U(cx,cy,cz,2) = (float)(constraints(k,5)/factor);  
28202 - }  
28203 - }  
28204 } else { // 2d version. 32110 } else { // 2d version.
28205 if (smoothness>=0) // Isotropic regularization. 32111 if (smoothness>=0) // Isotropic regularization.
28206 #ifdef cimg_use_openmp 32112 #ifdef cimg_use_openmp
28207 -#pragma omp parallel for if (_height>=8 && _width>=16) reduction(+:_energy) 32113 +#pragma omp parallel for cimg_openmp_if(_height>=8 && _width>=16) reduction(+:_energy)
28208 #endif 32114 #endif
28209 cimg_forY(U,y) { 32115 cimg_forY(U,y) {
28210 const int _p1y = y?y - 1:0, _n1y = y<U.height() - 1?y + 1:y; 32116 const int _p1y = y?y - 1:0, _n1y = y<U.height() - 1?y + 1:y;
@@ -28238,10 +32144,14 @@ namespace cimg_library_suffixed { @@ -28238,10 +32144,14 @@ namespace cimg_library_suffixed {
28238 } 32144 }
28239 _energy+=delta_I*delta_I + smoothness*_energy_regul; 32145 _energy+=delta_I*delta_I + smoothness*_energy_regul;
28240 } 32146 }
  32147 + if (V) cimg_forX(V,x) if (V(x,y,2)) { // Apply constraints.
  32148 + U(x,y,0) = V(x,y,0)/factor;
  32149 + U(x,y,1) = V(x,y,1)/factor;
  32150 + }
28241 } else { // Anisotropic regularization. 32151 } else { // Anisotropic regularization.
28242 const float nsmoothness = -smoothness; 32152 const float nsmoothness = -smoothness;
28243 #ifdef cimg_use_openmp 32153 #ifdef cimg_use_openmp
28244 -#pragma omp parallel for if (_height>=8 && _width>=16) reduction(+:_energy) 32154 +#pragma omp parallel for cimg_openmp_if(_height>=8 && _width>=16) reduction(+:_energy)
28245 #endif 32155 #endif
28246 cimg_forY(U,y) { 32156 cimg_forY(U,y) {
28247 const int _p1y = y?y - 1:0, _n1y = y<U.height() - 1?y + 1:y; 32157 const int _p1y = y?y - 1:0, _n1y = y<U.height() - 1?y + 1:y;
@@ -28283,17 +32193,12 @@ namespace cimg_library_suffixed { @@ -28283,17 +32193,12 @@ namespace cimg_library_suffixed {
28283 } 32193 }
28284 _energy+=delta_I*delta_I + nsmoothness*_energy_regul; 32194 _energy+=delta_I*delta_I + nsmoothness*_energy_regul;
28285 } 32195 }
  32196 + if (V) cimg_forX(V,x) if (V(x,y,2)) { // Apply constraints.
  32197 + U(x,y,0) = V(x,y,0)/factor;
  32198 + U(x,y,1) = V(x,y,1)/factor;
  32199 + }
28286 } 32200 }
28287 } 32201 }
28288 - if (constraints) cimg_forX(constraints,k) {  
28289 - const int  
28290 - cx = (int)(constraints(k,0)*U.width()/width()),  
28291 - cy = (int)(constraints(k,1)*U.height()/height());  
28292 - if (U.contains(U(cx,cy))) {  
28293 - U(cx,cy,0) = (float)(constraints(k,2)/factor);  
28294 - U(cx,cy,1) = (float)(constraints(k,3)/factor);  
28295 - }  
28296 - }  
28297 } 32202 }
28298 const float d_energy = (_energy - energy)/(sw*sh*sd); 32203 const float d_energy = (_energy - energy)/(sw*sh*sd);
28299 if (d_energy<=0 && -d_energy<_precision) break; 32204 if (d_energy<=0 && -d_energy<_precision) break;
@@ -28304,6 +32209,481 @@ namespace cimg_library_suffixed { @@ -28304,6 +32209,481 @@ namespace cimg_library_suffixed {
28304 return U; 32209 return U;
28305 } 32210 }
28306 32211
  32212 + //! Compute correspondence map between two images, using the patch-match algorithm.
  32213 + /**
  32214 + \param patch_image The image containing the reference patches to match with the instance image.
  32215 + \param patch_width Width of the patch used for matching.
  32216 + \param patch_height Height of the patch used for matching.
  32217 + \param patch_depth Depth of the patch used for matching.
  32218 + \param nb_iterations Number of patch-match iterations.
  32219 + \param nb_randoms Number of randomization attempts (per pixel).
  32220 + \param guide Image used as the initial correspondence estimate for the algorithm.
  32221 + 'guide' may have a last channel with boolean values (0=false | other=true) that
  32222 + tells for each pixel if its correspondence vector is constrained to its initial value (constraint mask).
  32223 + \param[out] matching_score Returned as the image of matching scores.
  32224 + \note
  32225 + The patch-match algorithm is described in this paper:
  32226 + Connelly Barnes, Eli Shechtman, Adam Finkelstein, Dan B Goldman(2009),
  32227 + PatchMatch: A Randomized Correspondence Algorithm for Structural Image Editing
  32228 + **/
  32229 + template<typename t1, typename t2>
  32230 + CImg<T>& patchmatch(const CImg<T>& patch_image,
  32231 + const unsigned int patch_width,
  32232 + const unsigned int patch_height,
  32233 + const unsigned int patch_depth,
  32234 + const unsigned int nb_iterations,
  32235 + const unsigned int nb_randoms,
  32236 + const CImg<t1> &guide,
  32237 + CImg<t2> &matching_score) {
  32238 + return get_patchmatch(patch_image,patch_width,patch_height,patch_depth,
  32239 + nb_iterations,nb_randoms,guide,matching_score).move_to(*this);
  32240 + }
  32241 +
  32242 + //! Compute correspondence map between two images, using the patch-match algorithm \newinstance.
  32243 + template<typename t1, typename t2>
  32244 + CImg<intT> get_patchmatch(const CImg<T>& patch_image,
  32245 + const unsigned int patch_width,
  32246 + const unsigned int patch_height,
  32247 + const unsigned int patch_depth,
  32248 + const unsigned int nb_iterations,
  32249 + const unsigned int nb_randoms,
  32250 + const CImg<t1> &guide,
  32251 + CImg<t2> &matching_score) const {
  32252 + return _get_patchmatch(patch_image,patch_width,patch_height,patch_depth,
  32253 + nb_iterations,nb_randoms,
  32254 + guide,true,matching_score);
  32255 + }
  32256 +
  32257 + //! Compute correspondence map between two images, using the patch-match algorithm \overloading.
  32258 + template<typename t>
  32259 + CImg<T>& patchmatch(const CImg<T>& patch_image,
  32260 + const unsigned int patch_width,
  32261 + const unsigned int patch_height,
  32262 + const unsigned int patch_depth,
  32263 + const unsigned int nb_iterations,
  32264 + const unsigned int nb_randoms,
  32265 + const CImg<t> &guide) {
  32266 + return get_patchmatch(patch_image,patch_width,patch_height,patch_depth,
  32267 + nb_iterations,nb_randoms,guide).move_to(*this);
  32268 + }
  32269 +
  32270 + //! Compute correspondence map between two images, using the patch-match algorithm \overloading.
  32271 + template<typename t>
  32272 + CImg<intT> get_patchmatch(const CImg<T>& patch_image,
  32273 + const unsigned int patch_width,
  32274 + const unsigned int patch_height,
  32275 + const unsigned int patch_depth,
  32276 + const unsigned int nb_iterations,
  32277 + const unsigned int nb_randoms,
  32278 + const CImg<t> &guide) const {
  32279 + return _get_patchmatch(patch_image,patch_width,patch_height,patch_depth,
  32280 + nb_iterations,nb_randoms,
  32281 + guide,false,CImg<T>::empty());
  32282 + }
  32283 +
  32284 + //! Compute correspondence map between two images, using the patch-match algorithm \overloading.
  32285 + CImg<T>& patchmatch(const CImg<T>& patch_image,
  32286 + const unsigned int patch_width,
  32287 + const unsigned int patch_height,
  32288 + const unsigned int patch_depth=1,
  32289 + const unsigned int nb_iterations=5,
  32290 + const unsigned int nb_randoms=5) {
  32291 + return get_patchmatch(patch_image,patch_width,patch_height,patch_depth,
  32292 + nb_iterations,nb_randoms).move_to(*this);
  32293 + }
  32294 +
  32295 + //! Compute correspondence map between two images, using the patch-match algorithm \overloading.
  32296 + CImg<intT> get_patchmatch(const CImg<T>& patch_image,
  32297 + const unsigned int patch_width,
  32298 + const unsigned int patch_height,
  32299 + const unsigned int patch_depth=1,
  32300 + const unsigned int nb_iterations=5,
  32301 + const unsigned int nb_randoms=5) const {
  32302 + return _get_patchmatch(patch_image,patch_width,patch_height,patch_depth,
  32303 + nb_iterations,nb_randoms,
  32304 + CImg<T>::const_empty(),
  32305 + false,CImg<T>::empty());
  32306 + }
  32307 +
  32308 + template<typename t1, typename t2>
  32309 + CImg<intT> _get_patchmatch(const CImg<T>& patch_image,
  32310 + const unsigned int patch_width,
  32311 + const unsigned int patch_height,
  32312 + const unsigned int patch_depth,
  32313 + const unsigned int nb_iterations,
  32314 + const unsigned int nb_randoms,
  32315 + const CImg<t1> &guide,
  32316 + const bool is_matching_score,
  32317 + CImg<t2> &matching_score) const {
  32318 + if (is_empty()) return CImg<intT>::const_empty();
  32319 + if (patch_image._spectrum!=_spectrum)
  32320 + throw CImgArgumentException(_cimg_instance
  32321 + "patchmatch(): Instance image and specified patch image (%u,%u,%u,%u,%p) "
  32322 + "have different spectrums.",
  32323 + cimg_instance,
  32324 + patch_image._width,patch_image._height,patch_image._depth,patch_image._spectrum,
  32325 + patch_image._data);
  32326 + if (patch_width>_width || patch_height>_height || patch_depth>_depth)
  32327 + throw CImgArgumentException(_cimg_instance
  32328 + "patchmatch(): Specified patch size %ux%ux%u is bigger than the dimensions "
  32329 + "of the instance image.",
  32330 + cimg_instance,patch_width,patch_height,patch_depth);
  32331 + if (patch_width>patch_image._width || patch_height>patch_image._height || patch_depth>patch_image._depth)
  32332 + throw CImgArgumentException(_cimg_instance
  32333 + "patchmatch(): Specified patch size %ux%ux%u is bigger than the dimensions "
  32334 + "of the patch image image (%u,%u,%u,%u,%p).",
  32335 + cimg_instance,patch_width,patch_height,patch_depth,
  32336 + patch_image._width,patch_image._height,patch_image._depth,patch_image._spectrum,
  32337 + patch_image._data);
  32338 + const unsigned int
  32339 + _constraint = patch_image._depth>1?3:2,
  32340 + constraint = guide._spectrum>_constraint?_constraint:0;
  32341 +
  32342 + if (guide &&
  32343 + (guide._width!=_width || guide._height!=_height || guide._depth!=_depth || guide._spectrum<_constraint))
  32344 + throw CImgArgumentException(_cimg_instance
  32345 + "patchmatch(): Specified guide (%u,%u,%u,%u,%p) has invalid dimensions "
  32346 + "considering instance and patch image image (%u,%u,%u,%u,%p).",
  32347 + cimg_instance,
  32348 + guide._width,guide._height,guide._depth,guide._spectrum,guide._data,
  32349 + patch_image._width,patch_image._height,patch_image._depth,patch_image._spectrum,
  32350 + patch_image._data);
  32351 +
  32352 + CImg<intT> map(_width,_height,_depth,patch_image._depth>1?3:2);
  32353 + CImg<floatT> score(_width,_height,_depth);
  32354 + const int
  32355 + psizew = (int)patch_width, psizew1 = psizew/2, psizew2 = psizew - psizew1 - 1,
  32356 + psizeh = (int)patch_height, psizeh1 = psizeh/2, psizeh2 = psizeh - psizeh1 - 1,
  32357 + psized = (int)patch_depth, psized1 = psized/2, psized2 = psized - psized1 - 1;
  32358 +
  32359 + if (_depth>1 || patch_image._depth>1) { // 3d version.
  32360 +
  32361 + // Initialize correspondence map.
  32362 + if (guide) cimg_forXYZ(*this,x,y,z) { // User-defined initialization.
  32363 + const int
  32364 + cx1 = x<=psizew1?x:(x<width() - psizew2?psizew1:psizew + x - width()), cx2 = psizew - cx1 - 1,
  32365 + cy1 = y<=psizeh1?y:(y<height() - psizeh2?psizeh1:psizeh + y - height()), cy2 = psizeh - cy1 - 1,
  32366 + cz1 = z<=psized1?z:(z<depth() - psized2?psized1:psized + z - depth()), cz2 = psized - cz1 - 1,
  32367 + u = cimg::min(cimg::max((int)guide(x,y,z,0),cx1),patch_image.width() - 1 - cx2),
  32368 + v = cimg::min(cimg::max((int)guide(x,y,z,1),cy1),patch_image.height() - 1 - cy2),
  32369 + w = cimg::min(cimg::max((int)guide(x,y,z,2),cz1),patch_image.depth() - 1 - cz2);
  32370 + map(x,y,z,0) = u;
  32371 + map(x,y,z,1) = v;
  32372 + map(x,y,z,2) = w;
  32373 + score(x,y,z) = _patchmatch(*this,patch_image,patch_width,patch_height,patch_depth,
  32374 + x - cx1,y - cy1,z - cz1,
  32375 + u - cx1,v - cy1,w - cz1,cimg::type<float>::inf());
  32376 + } else cimg_forXYZ(*this,x,y,z) { // Random initialization.
  32377 + const int
  32378 + cx1 = x<=psizew1?x:(x<width() - psizew2?psizew1:psizew + x - width()), cx2 = psizew - cx1 - 1,
  32379 + cy1 = y<=psizeh1?y:(y<height() - psizeh2?psizeh1:psizeh + y - height()), cy2 = psizeh - cy1 - 1,
  32380 + cz1 = z<=psized1?z:(z<depth() - psized2?psized1:psized + z - depth()), cz2 = psized - cz1 - 1,
  32381 + u = (int)cimg::round(cimg::rand(cx1,patch_image.width() - 1 - cx2)),
  32382 + v = (int)cimg::round(cimg::rand(cy1,patch_image.height() - 1 - cy2)),
  32383 + w = (int)cimg::round(cimg::rand(cz1,patch_image.depth() - 1 - cz2));
  32384 + map(x,y,z,0) = u;
  32385 + map(x,y,z,1) = v;
  32386 + map(x,y,z,2) = w;
  32387 + score(x,y,z) = _patchmatch(*this,patch_image,patch_width,patch_height,patch_depth,
  32388 + x - cx1,y - cy1,z - cz1,
  32389 + u - cx1,v - cy1,w - cz1,cimg::type<float>::inf());
  32390 + }
  32391 +
  32392 + // Start iteration loop.
  32393 + for (unsigned int iter = 0; iter<nb_iterations; ++iter) {
  32394 + cimg_test_abort();
  32395 + const bool is_even = !(iter%2);
  32396 +
  32397 +#ifdef cimg_use_openmp
  32398 +#pragma omp parallel for collapse(2) if (_width>64 && iter<nb_iterations-2)
  32399 +#endif
  32400 + cimg_forXYZ(*this,X,Y,Z) {
  32401 + const int
  32402 + x = is_even?X:width() - 1 - X,
  32403 + y = is_even?Y:height() - 1 - Y,
  32404 + z = is_even?Z:depth() - 1 - Z;
  32405 + if (score(x,y,z)<=1e-5 || (constraint && guide(x,y,z,constraint)!=0)) continue;
  32406 + const int
  32407 + cx1 = x<=psizew1?x:(x<width() - psizew2?psizew1:psizew + x - width()), cx2 = psizew - cx1 - 1,
  32408 + cy1 = y<=psizeh1?y:(y<height() - psizeh2?psizeh1:psizeh + y - height()), cy2 = psizeh - cy1 - 1,
  32409 + cz1 = z<=psized1?z:(z<depth() - psized2?psized1:psized + z - depth()), cz2 = psized - cz1 - 1,
  32410 + xp = x - cx1,
  32411 + yp = y - cy1,
  32412 + zp = z - cz1;
  32413 +
  32414 + // Propagation.
  32415 + if (is_even) {
  32416 + if (x>0) { // Compare with left neighbor.
  32417 + const int u = map(x - 1,y,z,0), v = map(x - 1,y,z,1), w = map(x - 1,y,z,2);
  32418 + if (u>=cx1 - 1 && u<patch_image.width() - 1 - cx2 &&
  32419 + v>=cy1 && v<patch_image.height() - cy2 &&
  32420 + w>=cz1 && w<patch_image.depth() - cz2) {
  32421 + const float
  32422 + current_score = score(x,y,z),
  32423 + D = _patchmatch(*this,patch_image,patch_width,patch_height,patch_depth,
  32424 + xp,yp,zp,u + 1 - cx1,v - cy1,w - cz1,current_score);
  32425 + if (D<current_score) { score(x,y,z) = D; map(x,y,z,0) = u + 1; map(x,y,z,1) = v; map(x,y,z,2) = w; }
  32426 + }
  32427 + }
  32428 + if (y>0) { // Compare with up neighbor.
  32429 + const int u = map(x,y - 1,z,0), v = map(x,y - 1,z,1), w = map(x,y - 1,z,2);
  32430 + if (u>=cx1 && u<patch_image.width() - cx2 &&
  32431 + v>=cy1 - 1 && v<patch_image.height() - 1 - cy2 &&
  32432 + w>=cz1 && w<patch_image.depth() - cx2) {
  32433 + const float
  32434 + current_score = score(x,y,z),
  32435 + D = _patchmatch(*this,patch_image,patch_width,patch_height,patch_depth,
  32436 + xp,yp,zp,u - cx1,v + 1 - cy1,w - cz1,current_score);
  32437 + if (D<current_score) { score(x,y,z) = D; map(x,y,z,0) = u; map(x,y,z,1) = v + 1; map(x,y,z,2) = w; }
  32438 + }
  32439 + }
  32440 + if (z>0) { // Compare with backward neighbor.
  32441 + const int u = map(x,y,z - 1,0), v = map(x,y,z - 1,1), w = map(x,y,z - 1,2);
  32442 + if (u>=cx1 && u<patch_image.width() - cx2 &&
  32443 + v>=cy1 && v<patch_image.height() - cy2 &&
  32444 + w>=cz1 - 1 && w<patch_image.depth() - 1 - cz2) {
  32445 + const float
  32446 + current_score = score(x,y,z),
  32447 + D = _patchmatch(*this,patch_image,patch_width,patch_height,patch_depth,
  32448 + xp,yp,zp,u - cx1,v - cy1,w + 1 - cz1,current_score);
  32449 + if (D<current_score) { score(x,y,z) = D; map(x,y,z,0) = u; map(x,y,z,1) = v; map(x,y,z,2) = w + 1; }
  32450 + }
  32451 + }
  32452 + } else {
  32453 + if (x<width() - 1) { // Compare with right neighbor.
  32454 + const int u = map(x + 1,y,z,0), v = map(x + 1,y,z,1), w = map(x + 1,y,z,2);
  32455 + if (u>=cx1 + 1 && u<patch_image.width() + 1 - cx2 &&
  32456 + v>=cy1 && v<patch_image.height() - cy2 &&
  32457 + w>=cz1 && w<patch_image.depth() - cz2) {
  32458 + const float
  32459 + current_score = score(x,y,z),
  32460 + D = _patchmatch(*this,patch_image,patch_width,patch_height,patch_depth,
  32461 + xp,yp,zp,u - 1 - cx1,v - cy1,w - cz1,current_score);
  32462 + if (D<current_score) { score(x,y,z) = D; map(x,y,z,0) = u - 1; map(x,y,z,1) = v; map(x,y,z,2) = w; }
  32463 + }
  32464 + }
  32465 + if (y<height() - 1) { // Compare with bottom neighbor.
  32466 + const int u = map(x,y + 1,z,0), v = map(x,y + 1,z,1), w = map(x,y + 1,z,2);
  32467 + if (u>=cx1 && u<patch_image.width() - cx2 &&
  32468 + v>=cy1 + 1 && v<patch_image.height() + 1 - cy2 &&
  32469 + w>=cz1 && w<patch_image.depth() - cz2) {
  32470 + const float
  32471 + current_score = score(x,y,z),
  32472 + D = _patchmatch(*this,patch_image,patch_width,patch_height,patch_depth,
  32473 + xp,yp,zp,u - cx1,v - 1 - cy1,w - cz1,current_score);
  32474 + if (D<current_score) { score(x,y,z) = D; map(x,y,z,0) = u; map(x,y,z,1) = v - 1; map(x,y,z,2) = w; }
  32475 + }
  32476 + }
  32477 + if (z<depth() - 1) { // Compare with forward neighbor.
  32478 + const int u = map(x,y,z + 1,0), v = map(x,y,z + 1,1), w = map(x,y,z + 1,2);
  32479 + if (u>=cx1 && u<patch_image.width() - cx2 &&
  32480 + v>=cy1 && v<patch_image.height() - cy2 &&
  32481 + w>=cz1 + 1 && w<patch_image.depth() + 1 - cz2) {
  32482 + const float
  32483 + current_score = score(x,y,z),
  32484 + D = _patchmatch(*this,patch_image,patch_width,patch_height,patch_depth,
  32485 + xp,yp,zp,u - cx1,v - cy1,w - 1 - cz1,current_score);
  32486 + if (D<current_score) { score(x,y,z) = D; map(x,y,z,0) = u; map(x,y,z,1) = v; map(x,y,z,2) = w - 1; }
  32487 + }
  32488 + }
  32489 + }
  32490 +
  32491 + // Randomization.
  32492 + const int u = map(x,y,z,0), v = map(x,y,z,1), w = map(x,y,z,2);
  32493 + float dw = (float)patch_image.width(), dh = (float)patch_image.height(), dd = (float)patch_image.depth();
  32494 + for (unsigned int i = 0; i<nb_randoms; ++i) {
  32495 + const int
  32496 + ui = (int)cimg::round(cimg::rand(cimg::max(cx1,u - dw),
  32497 + cimg::min(patch_image.width() - 1 - cx2,u + dw))),
  32498 + vi = (int)cimg::round(cimg::rand(cimg::max(cy1,v - dh),
  32499 + cimg::min(patch_image.height() - 1 - cy2,v + dh))),
  32500 + wi = (int)cimg::round(cimg::rand(cimg::max(cz1,w - dd),
  32501 + cimg::min(patch_image.depth() - 1 - cz2,w + dd)));
  32502 + if (ui!=u || vi!=v || wi!=w) {
  32503 + const float
  32504 + current_score = score(x,y,z),
  32505 + D = _patchmatch(*this,patch_image,patch_width,patch_height,patch_depth,
  32506 + xp,yp,zp,ui - cx1,vi - cy1,wi - cz1,current_score);
  32507 + if (D<current_score) { score(x,y,z) = D; map(x,y,z,0) = ui; map(x,y,z,1) = vi; map(x,y,z,2) = wi; }
  32508 + dw = cimg::max(5.0f,dw*0.5f); dh = cimg::max(5.0f,dh*0.5f); dd = cimg::max(5.0f,dd*0.5f);
  32509 + }
  32510 + }
  32511 + }
  32512 + }
  32513 +
  32514 + } else { // 2d version.
  32515 +
  32516 + // Initialize correspondence map.
  32517 + if (guide) cimg_forXY(*this,x,y) { // Random initialization.
  32518 + const int
  32519 + cx1 = x<=psizew1?x:(x<width() - psizew2?psizew1:psizew + x - width()), cx2 = psizew - cx1 - 1,
  32520 + cy1 = y<=psizeh1?y:(y<height() - psizeh2?psizeh1:psizeh + y - height()) , cy2 = psizeh - cy1 - 1,
  32521 + u = cimg::min(cimg::max((int)guide(x,y,0),cx1),patch_image.width() - 1 - cx2),
  32522 + v = cimg::min(cimg::max((int)guide(x,y,1),cy1),patch_image.height() - 1 - cy2);
  32523 + map(x,y,0) = u;
  32524 + map(x,y,1) = v;
  32525 + score(x,y) = _patchmatch(*this,patch_image,patch_width,patch_height,
  32526 + x - cx1,y - cy1,u - cx1,v - cy1,cimg::type<float>::inf());
  32527 + } else cimg_forXY(*this,x,y) { // Random initialization.
  32528 + const int
  32529 + cx1 = x<=psizew1?x:(x<width() - psizew2?psizew1:psizew + x - width()), cx2 = psizew - cx1 - 1,
  32530 + cy1 = y<=psizeh1?y:(y<height() - psizeh2?psizeh1:psizeh + y - height()) , cy2 = psizeh - cy1 - 1,
  32531 + u = (int)cimg::round(cimg::rand(cx1,patch_image.width() - 1 - cx2)),
  32532 + v = (int)cimg::round(cimg::rand(cy1,patch_image.height() - 1 - cy2));
  32533 + map(x,y,0) = u;
  32534 + map(x,y,1) = v;
  32535 + score(x,y) = _patchmatch(*this,patch_image,patch_width,patch_height,
  32536 + x - cx1,y - cy1,u - cx1,v - cy1,cimg::type<float>::inf());
  32537 + }
  32538 +
  32539 + // Start iteration loop.
  32540 + for (unsigned int iter = 0; iter<nb_iterations; ++iter) {
  32541 + const bool is_even = !(iter%2);
  32542 +
  32543 +#ifdef cimg_use_openmp
  32544 +#pragma omp parallel for cimg_openmp_if(_width>64 && iter<nb_iterations-2)
  32545 +#endif
  32546 + cimg_forXY(*this,X,Y) {
  32547 + const int
  32548 + x = is_even?X:width() - 1 - X,
  32549 + y = is_even?Y:height() - 1 - Y;
  32550 + if (score(x,y)<=1e-5 || (constraint && guide(x,y,constraint)!=0)) continue;
  32551 + const int
  32552 + cx1 = x<=psizew1?x:(x<width() - psizew2?psizew1:psizew + x - width()), cx2 = psizew - cx1 - 1,
  32553 + cy1 = y<=psizeh1?y:(y<height() - psizeh2?psizeh1:psizeh + y - height()) , cy2 = psizeh - cy1 - 1,
  32554 + xp = x - cx1,
  32555 + yp = y - cy1;
  32556 +
  32557 + // Propagation.
  32558 + if (is_even) {
  32559 + if (x>0) { // Compare with left neighbor.
  32560 + const int u = map(x - 1,y,0), v = map(x - 1,y,1);
  32561 + if (u>=cx1 - 1 && u<patch_image.width() - 1 - cx2 &&
  32562 + v>=cy1 && v<patch_image.height() - cy2) {
  32563 + const float
  32564 + current_score = score(x,y),
  32565 + D = _patchmatch(*this,patch_image,patch_width,patch_height,
  32566 + xp,yp,u + 1 - cx1,v - cy1,current_score);
  32567 + if (D<current_score) { score(x,y) = D; map(x,y,0) = u + 1; map(x,y,1) = v; }
  32568 + }
  32569 + }
  32570 + if (y>0) { // Compare with up neighbor.
  32571 + const int u = map(x,y - 1,0), v = map(x,y - 1,1);
  32572 + if (u>=cx1 && u<patch_image.width() - cx2 &&
  32573 + v>=cy1 - 1 && v<patch_image.height() - 1 - cy2) {
  32574 + const float
  32575 + current_score = score(x,y),
  32576 + D = _patchmatch(*this,patch_image,patch_width,patch_height,
  32577 + xp,yp,u - cx1,v + 1 - cy1,current_score);
  32578 + if (D<current_score) { score(x,y) = D; map(x,y,0) = u; map(x,y,1) = v + 1; }
  32579 + }
  32580 + }
  32581 + } else {
  32582 + if (x<width() - 1) { // Compare with right neighbor.
  32583 + const int u = map(x + 1,y,0), v = map(x + 1,y,1);
  32584 + if (u>=cx1 + 1 && u<patch_image.width() + 1 - cx2 &&
  32585 + v>=cy1 && v<patch_image.height() - cy2) {
  32586 + const float
  32587 + current_score = score(x,y),
  32588 + D = _patchmatch(*this,patch_image,patch_width,patch_height,
  32589 + xp,yp,u - 1 - cx1,v - cy1,current_score);
  32590 + if (D<current_score) { score(x,y) = D; map(x,y,0) = u - 1; map(x,y,1) = v; }
  32591 + }
  32592 + }
  32593 + if (y<height() - 1) { // Compare with bottom neighbor.
  32594 + const int u = map(x,y + 1,0), v = map(x,y + 1,1);
  32595 + if (u>=cx1 && u<patch_image.width() - cx2 &&
  32596 + v>=cy1 + 1 && v<patch_image.height() + 1 - cy2) {
  32597 + const float
  32598 + current_score = score(x,y),
  32599 + D = _patchmatch(*this,patch_image,patch_width,patch_height,
  32600 + xp,yp,u - cx1,v - 1 - cy1,current_score);
  32601 + if (D<current_score) { score(x,y) = D; map(x,y,0) = u; map(x,y,1) = v - 1; }
  32602 + }
  32603 + }
  32604 + }
  32605 +
  32606 + // Randomization.
  32607 + const int u = map(x,y,0), v = map(x,y,1);
  32608 + float dw = (float)patch_image.width(), dh = (float)patch_image.height();
  32609 + for (unsigned int i = 0; i<nb_randoms; ++i) {
  32610 + const int
  32611 + ui = (int)cimg::round(cimg::rand(cimg::max(cx1,u - dw),
  32612 + cimg::min(patch_image.width() - 1 - cx2,u + dw))),
  32613 + vi = (int)cimg::round(cimg::rand(cimg::max(cy1,v - dh),
  32614 + cimg::min(patch_image.height() - 1 - cy2,v + dh)));
  32615 + if (ui!=u || vi!=v) {
  32616 + const float
  32617 + current_score = score(x,y),
  32618 + D = _patchmatch(*this,patch_image,patch_width,patch_height,
  32619 + xp,yp,ui - cx1,vi - cy1,current_score);
  32620 + if (D<current_score) { score(x,y) = D; map(x,y,0) = ui; map(x,y,1) = vi; }
  32621 + dw = cimg::max(5.0f,dw*0.5f); dh = cimg::max(5.0f,dh*0.5f);
  32622 + }
  32623 + }
  32624 + }
  32625 + }
  32626 + }
  32627 + if (is_matching_score) score.move_to(matching_score);
  32628 + return map;
  32629 + }
  32630 +
  32631 + // Compute SSD between two patches in different images.
  32632 + static float _patchmatch(const CImg<T>& img1, const CImg<T>& img2,
  32633 + const unsigned int psizew, const unsigned int psizeh,
  32634 + const int x1, const int y1,
  32635 + const int x2, const int y2,
  32636 + const float max_ssd) { // 2d version.
  32637 + const T *p1 = img1.data(x1,y1), *p2 = img2.data(x2,y2);
  32638 + const unsigned long
  32639 + offx1 = (unsigned long)img1._width - psizew,
  32640 + offx2 = (unsigned long)img2._width - psizew,
  32641 + offy1 = (unsigned long)img1._width*img1._height - psizeh*img1._width,
  32642 + offy2 = (unsigned long)img2._width*img2._height - psizeh*img2._width;
  32643 + float ssd = 0;
  32644 + cimg_forC(img1,c) {
  32645 + for (unsigned int j = 0; j<psizeh; ++j) {
  32646 + for (unsigned int i = 0; i<psizew; ++i)
  32647 + ssd += cimg::sqr(*(p1++) - *(p2++));
  32648 + if (ssd>max_ssd) return max_ssd;
  32649 + p1+=offx1; p2+=offx2;
  32650 + }
  32651 + p1+=offy1; p2+=offy2;
  32652 + }
  32653 + return ssd;
  32654 + }
  32655 +
  32656 + static float _patchmatch(const CImg<T>& img1, const CImg<T>& img2,
  32657 + const unsigned int psizew, const unsigned int psizeh, const unsigned int psized,
  32658 + const int x1, const int y1, const int z1,
  32659 + const int x2, const int y2, const int z2,
  32660 + const float max_ssd) { // 3d version.
  32661 + const T *p1 = img1.data(x1,y1,z1), *p2 = img2.data(x2,y2,z2);
  32662 + const unsigned long
  32663 + offx1 = (unsigned long)img1._width - psizew,
  32664 + offx2 = (unsigned long)img2._width - psizew,
  32665 + offy1 = (unsigned long)img1._width*img1._height - psizeh*img1._width - psizew,
  32666 + offy2 = (unsigned long)img2._width*img2._height - psizeh*img2._width - psizew,
  32667 + offz1 = (unsigned long)img1._width*img1._height*img1._depth - psized*img1._width*img1._height -
  32668 + psizeh*img1._width - psizew,
  32669 + offz2 = (unsigned long)img2._width*img2._height*img2._depth - psized*img2._width*img2._height -
  32670 + psizeh*img2._width - psizew;
  32671 + float ssd = 0;
  32672 + cimg_forC(img1,c) {
  32673 + for (unsigned int k = 0; k<psized; ++k) {
  32674 + for (unsigned int j = 0; j<psizeh; ++j) {
  32675 + for (unsigned int i = 0; i<psizew; ++i)
  32676 + ssd += cimg::sqr(*(p1++) - *(p2++));
  32677 + if (ssd>max_ssd) return max_ssd;
  32678 + p1+=offx1; p2+=offx2;
  32679 + }
  32680 + p1+=offy1; p2+=offy2;
  32681 + }
  32682 + p1+=offz1; p2+=offz2;
  32683 + }
  32684 + return ssd;
  32685 + }
  32686 +
28307 //! Compute Euclidean distance function to a specified value. 32687 //! Compute Euclidean distance function to a specified value.
28308 /** 32688 /**
28309 \param value Reference value. 32689 \param value Reference value.
@@ -28388,7 +32768,7 @@ namespace cimg_library_suffixed { @@ -28388,7 +32768,7 @@ namespace cimg_library_suffixed {
28388 32768
28389 const unsigned long wh = (unsigned long)_width*_height; 32769 const unsigned long wh = (unsigned long)_width*_height;
28390 #if defined(cimg_use_openmp) && !cimg_is_gcc49x 32770 #if defined(cimg_use_openmp) && !cimg_is_gcc49x
28391 -#pragma omp parallel for if (_spectrum>=2) 32771 +#pragma omp parallel for cimg_openmp_if(_spectrum>=2)
28392 #endif 32772 #endif
28393 cimg_forC(*this,c) { 32773 cimg_forC(*this,c) {
28394 CImg<longT> g(_width), dt(_width), s(_width), t(_width); 32774 CImg<longT> g(_width), dt(_width), s(_width), t(_width);
@@ -28441,7 +32821,7 @@ namespace cimg_library_suffixed { @@ -28441,7 +32821,7 @@ namespace cimg_library_suffixed {
28441 if (!is_value) return fill(cimg::type<T>::max()); 32821 if (!is_value) return fill(cimg::type<T>::max());
28442 const unsigned long wh = (unsigned long)_width*_height; 32822 const unsigned long wh = (unsigned long)_width*_height;
28443 #ifdef cimg_use_openmp 32823 #ifdef cimg_use_openmp
28444 -#pragma omp parallel for if (_spectrum>=2) 32824 +#pragma omp parallel for cimg_openmp_if(_spectrum>=2)
28445 #endif 32825 #endif
28446 cimg_forC(*this,c) { 32826 cimg_forC(*this,c) {
28447 CImg<T> img = get_shared_channel(c); 32827 CImg<T> img = get_shared_channel(c);
@@ -28491,7 +32871,7 @@ namespace cimg_library_suffixed { @@ -28491,7 +32871,7 @@ namespace cimg_library_suffixed {
28491 return get_distance_dijkstra(value,metric,is_high_connectivity,return_path).move_to(*this); 32871 return get_distance_dijkstra(value,metric,is_high_connectivity,return_path).move_to(*this);
28492 } 32872 }
28493 32873
28494 - //! Compute distance map to a specified value, according to a custom metric (use dijkstra algorithm). \newinstance. 32874 + //! Compute distance map to a specified value, according to a custom metric (use dijkstra algorithm) \newinstance.
28495 template<typename t, typename to> 32875 template<typename t, typename to>
28496 CImg<typename cimg::superset<t,long>::type> 32876 CImg<typename cimg::superset<t,long>::type>
28497 get_distance_dijkstra(const T& value, const CImg<t>& metric, const bool is_high_connectivity, 32877 get_distance_dijkstra(const T& value, const CImg<t>& metric, const bool is_high_connectivity,
@@ -28695,7 +33075,7 @@ namespace cimg_library_suffixed { @@ -28695,7 +33075,7 @@ namespace cimg_library_suffixed {
28695 CImg<charT> state(_width,_height,_depth); // -1=far away, 0=narrow, 1=frozen. 33075 CImg<charT> state(_width,_height,_depth); // -1=far away, 0=narrow, 1=frozen.
28696 33076
28697 #ifdef cimg_use_openmp 33077 #ifdef cimg_use_openmp
28698 -#pragma omp parallel for if (_spectrum>=2) firstprivate(Q,state) 33078 +#pragma omp parallel for cimg_openmp_if(_spectrum>=2) firstprivate(Q,state)
28699 #endif 33079 #endif
28700 cimg_forC(*this,c) { 33080 cimg_forC(*this,c) {
28701 const CImg<T> img = get_shared_channel(c); 33081 const CImg<T> img = get_shared_channel(c);
@@ -29645,7 +34025,7 @@ namespace cimg_library_suffixed { @@ -29645,7 +34025,7 @@ namespace cimg_library_suffixed {
29645 **/ 34025 **/
29646 template<typename tp, typename tc, typename tt, typename tx> 34026 template<typename tp, typename tc, typename tt, typename tx>
29647 const CImg<T>& texturize_object3d(CImgList<tp>& primitives, CImgList<tc>& colors, 34027 const CImg<T>& texturize_object3d(CImgList<tp>& primitives, CImgList<tc>& colors,
29648 - const CImg<tt>& texture, const CImg<tx>& coords=CImg<tx>::empty()) const { 34028 + const CImg<tt>& texture, const CImg<tx>& coords=CImg<tx>::const_empty()) const {
29649 if (is_empty()) return *this; 34029 if (is_empty()) return *this;
29650 if (_height!=3) 34030 if (_height!=3)
29651 throw CImgInstanceException(_cimg_instance 34031 throw CImgInstanceException(_cimg_instance
@@ -30551,7 +34931,9 @@ namespace cimg_library_suffixed { @@ -30551,7 +34931,9 @@ namespace cimg_library_suffixed {
30551 34931
30552 struct _functor2d_expr { 34932 struct _functor2d_expr {
30553 _cimg_math_parser *mp; 34933 _cimg_math_parser *mp;
30554 - _functor2d_expr(const char *const expr):mp(0) { mp = new _cimg_math_parser(CImg<T>::empty(),expr,0); } 34934 + _functor2d_expr(const char *const expr):mp(0) {
  34935 + mp = new _cimg_math_parser(expr,0,CImg<T>::const_empty(),0);
  34936 + }
30555 ~_functor2d_expr() { delete mp; } 34937 ~_functor2d_expr() { delete mp; }
30556 float operator()(const float x, const float y) const { 34938 float operator()(const float x, const float y) const {
30557 return (float)(*mp)(x,y,0,0); 34939 return (float)(*mp)(x,y,0,0);
@@ -30577,7 +34959,9 @@ namespace cimg_library_suffixed { @@ -30577,7 +34959,9 @@ namespace cimg_library_suffixed {
30577 struct _functor3d_expr { 34959 struct _functor3d_expr {
30578 _cimg_math_parser *mp; 34960 _cimg_math_parser *mp;
30579 ~_functor3d_expr() { delete mp; } 34961 ~_functor3d_expr() { delete mp; }
30580 - _functor3d_expr(const char *const expr):mp(0) { mp = new _cimg_math_parser(CImg<T>::empty(),expr,0); } 34962 + _functor3d_expr(const char *const expr):mp(0) {
  34963 + mp = new _cimg_math_parser(expr,0,CImg<T>::const_empty(),0);
  34964 + }
30581 float operator()(const float x, const float y, const float z) const { 34965 float operator()(const float x, const float y, const float z) const {
30582 return (float)(*mp)(x,y,z,0); 34966 return (float)(*mp)(x,y,z,0);
30583 } 34967 }
@@ -35102,10 +39486,10 @@ namespace cimg_library_suffixed { @@ -35102,10 +39486,10 @@ namespace cimg_library_suffixed {
35102 const t 39486 const t
35103 *ptrs = sprite._data - 39487 *ptrs = sprite._data -
35104 (bx?x0:0) - 39488 (bx?x0:0) -
35105 - (by?y0*sprite.width():0) -  
35106 - (bz?z0*sprite.width()*sprite.height():0) -  
35107 - (bc?c0*sprite.width()*sprite.height()*sprite.depth():0);  
35108 - const unsigned long 39489 + (by?y0*(uptrT)sprite.width():0) -
  39490 + (bz?z0*(uptrT)sprite.width()*sprite.height():0) -
  39491 + (bc?c0*(uptrT)sprite.width()*sprite.height()*sprite.depth():0);
  39492 + const uptrT
35109 offX = (unsigned long)_width - lX, 39493 offX = (unsigned long)_width - lX,
35110 soffX = (unsigned long)sprite._width - lX, 39494 soffX = (unsigned long)sprite._width - lX,
35111 offY = (unsigned long)_width*(_height - lY), 39495 offY = (unsigned long)_width*(_height - lY),
@@ -35146,9 +39530,9 @@ namespace cimg_library_suffixed { @@ -35146,9 +39530,9 @@ namespace cimg_library_suffixed {
35146 const T 39530 const T
35147 *ptrs = sprite._data - 39531 *ptrs = sprite._data -
35148 (bx?x0:0) - 39532 (bx?x0:0) -
35149 - (by?y0*sprite.width():0) -  
35150 - (bz?z0*sprite.width()*sprite.height():0) -  
35151 - (bc?c0*sprite.width()*sprite.height()*sprite.depth():0); 39533 + (by?y0*(uptrT)sprite.width():0) -
  39534 + (bz?z0*(uptrT)sprite.width()*sprite.height():0) -
  39535 + (bc?c0*(uptrT)sprite.width()*sprite.height()*sprite.depth():0);
35152 const unsigned long 39536 const unsigned long
35153 offX = (unsigned long)_width - lX, 39537 offX = (unsigned long)_width - lX,
35154 soffX = (unsigned long)sprite._width - lX, 39538 soffX = (unsigned long)sprite._width - lX,
@@ -35238,12 +39622,14 @@ namespace cimg_library_suffixed { @@ -35238,12 +39622,14 @@ namespace cimg_library_suffixed {
35238 lY = sprite.height() - (y0 + sprite.height()>height()?y0 + sprite.height() - height():0) + (by?y0:0), 39622 lY = sprite.height() - (y0 + sprite.height()>height()?y0 + sprite.height() - height():0) + (by?y0:0),
35239 lZ = sprite.depth() - (z0 + sprite.depth()>depth()?z0 + sprite.depth() - depth():0) + (bz?z0:0), 39623 lZ = sprite.depth() - (z0 + sprite.depth()>depth()?z0 + sprite.depth() - depth():0) + (bz?z0:0),
35240 lC = sprite.spectrum() - (c0 + sprite.spectrum()>spectrum()?c0 + sprite.spectrum() - spectrum():0) + (bc?c0:0); 39624 lC = sprite.spectrum() - (c0 + sprite.spectrum()>spectrum()?c0 + sprite.spectrum() - spectrum():0) + (bc?c0:0);
35241 - const int  
35242 - coff = -(bx?x0:0) - (by?y0*mask.width():0) - (bz?z0*mask.width()*mask.height():0) -  
35243 - (bc?c0*mask.width()*mask.height()*mask.depth():0),  
35244 - ssize = mask.width()*mask.height()*mask.depth()*mask.spectrum(); 39625 + const uptrT
  39626 + coff = -(bx?x0:0) -
  39627 + (by?y0*(uptrT)mask.width():0) -
  39628 + (bz?z0*(uptrT)mask.width()*mask.height():0) -
  39629 + (bc?c0*(uptrT)mask.width()*mask.height()*mask.depth():0),
  39630 + ssize = (uptrT)mask.width()*mask.height()*mask.depth()*mask.spectrum();
35245 const ti *ptrs = sprite._data + coff; 39631 const ti *ptrs = sprite._data + coff;
35246 - const tm *ptrm = mask._data + coff; 39632 + const tm *ptrm = mask._data + coff;
35247 const unsigned long 39633 const unsigned long
35248 offX = (unsigned long)_width - lX, 39634 offX = (unsigned long)_width - lX,
35249 soffX = (unsigned long)sprite._width - lX, 39635 soffX = (unsigned long)sprite._width - lX,
@@ -35568,32 +39954,32 @@ namespace cimg_library_suffixed { @@ -35568,32 +39954,32 @@ namespace cimg_library_suffixed {
35568 if (is_empty()) return *this; 39954 if (is_empty()) return *this;
35569 const int yt = (y + 3 + font_height)<_height?y + 3:y - 2 - (int)font_height; 39955 const int yt = (y + 3 + font_height)<_height?y + 3:y - 2 - (int)font_height;
35570 const int siz = (int)values_x.size() - 1; 39956 const int siz = (int)values_x.size() - 1;
35571 - char txt[32] = { 0 }; 39957 + CImg<charT> txt(32);
35572 CImg<T> label; 39958 CImg<T> label;
35573 if (siz<=0) { // Degenerated case. 39959 if (siz<=0) { // Degenerated case.
35574 draw_line(0,y,_width - 1,y,color,opacity,pattern); 39960 draw_line(0,y,_width - 1,y,color,opacity,pattern);
35575 if (!siz) { 39961 if (!siz) {
35576 - cimg_snprintf(txt,sizeof(txt),"%g",(double)*values_x); 39962 + cimg_snprintf(txt,txt._width,"%g",(double)*values_x);
35577 label.assign().draw_text(0,0,txt,color,(tc*)0,opacity,font_height); 39963 label.assign().draw_text(0,0,txt,color,(tc*)0,opacity,font_height);
35578 const int 39964 const int
35579 _xt = (width() - label.width())/2, 39965 _xt = (width() - label.width())/2,
35580 xt = _xt<3?3:_xt + label.width()>=width() - 2?width() - 3 - label.width():_xt; 39966 xt = _xt<3?3:_xt + label.width()>=width() - 2?width() - 3 - label.width():_xt;
35581 draw_point(width()/2,y - 1,color,opacity).draw_point(width()/2,y + 1,color,opacity); 39967 draw_point(width()/2,y - 1,color,opacity).draw_point(width()/2,y + 1,color,opacity);
35582 - if (allow_zero || txt[0]!='0' || txt[1]!=0) 39968 + if (allow_zero || *txt!='0' || txt[1]!=0)
35583 draw_text(xt,yt,txt,color,(tc*)0,opacity,font_height); 39969 draw_text(xt,yt,txt,color,(tc*)0,opacity,font_height);
35584 } 39970 }
35585 } else { // Regular case. 39971 } else { // Regular case.
35586 if (values_x[0]<values_x[siz]) draw_arrow(0,y,_width - 1,y,color,opacity,30,5,pattern); 39972 if (values_x[0]<values_x[siz]) draw_arrow(0,y,_width - 1,y,color,opacity,30,5,pattern);
35587 else draw_arrow(_width - 1,y,0,y,color,opacity,30,5,pattern); 39973 else draw_arrow(_width - 1,y,0,y,color,opacity,30,5,pattern);
35588 cimg_foroff(values_x,x) { 39974 cimg_foroff(values_x,x) {
35589 - cimg_snprintf(txt,sizeof(txt),"%g",(double)values_x(x)); 39975 + cimg_snprintf(txt,txt._width,"%g",(double)values_x(x));
35590 label.assign().draw_text(0,0,txt,color,(tc*)0,opacity,font_height); 39976 label.assign().draw_text(0,0,txt,color,(tc*)0,opacity,font_height);
35591 const int 39977 const int
35592 xi = (int)(x*(_width - 1)/siz), 39978 xi = (int)(x*(_width - 1)/siz),
35593 _xt = xi - label.width()/2, 39979 _xt = xi - label.width()/2,
35594 xt = _xt<3?3:_xt + label.width()>=width() - 2?width() - 3 - label.width():_xt; 39980 xt = _xt<3?3:_xt + label.width()>=width() - 2?width() - 3 - label.width():_xt;
35595 draw_point(xi,y - 1,color,opacity).draw_point(xi,y + 1,color,opacity); 39981 draw_point(xi,y - 1,color,opacity).draw_point(xi,y + 1,color,opacity);
35596 - if (allow_zero || txt[0]!='0' || txt[1]!=0) 39982 + if (allow_zero || *txt!='0' || txt[1]!=0)
35597 draw_text(xt,yt,txt,color,(tc*)0,opacity,font_height); 39983 draw_text(xt,yt,txt,color,(tc*)0,opacity,font_height);
35598 } 39984 }
35599 } 39985 }
@@ -35617,12 +40003,12 @@ namespace cimg_library_suffixed { @@ -35617,12 +40003,12 @@ namespace cimg_library_suffixed {
35617 const bool allow_zero=true) { 40003 const bool allow_zero=true) {
35618 if (is_empty()) return *this; 40004 if (is_empty()) return *this;
35619 int siz = (int)values_y.size() - 1; 40005 int siz = (int)values_y.size() - 1;
35620 - char txt[32] = { 0 }; 40006 + CImg<charT> txt(32);
35621 CImg<T> label; 40007 CImg<T> label;
35622 if (siz<=0) { // Degenerated case. 40008 if (siz<=0) { // Degenerated case.
35623 draw_line(x,0,x,_height - 1,color,opacity,pattern); 40009 draw_line(x,0,x,_height - 1,color,opacity,pattern);
35624 if (!siz) { 40010 if (!siz) {
35625 - cimg_snprintf(txt,sizeof(txt),"%g",(double)*values_y); 40011 + cimg_snprintf(txt,txt._width,"%g",(double)*values_y);
35626 label.assign().draw_text(0,0,txt,color,(tc*)0,opacity,font_height); 40012 label.assign().draw_text(0,0,txt,color,(tc*)0,opacity,font_height);
35627 const int 40013 const int
35628 _yt = (height() - label.height())/2, 40014 _yt = (height() - label.height())/2,
@@ -35630,14 +40016,14 @@ namespace cimg_library_suffixed { @@ -35630,14 +40016,14 @@ namespace cimg_library_suffixed {
35630 _xt = x - 2 - label.width(), 40016 _xt = x - 2 - label.width(),
35631 xt = _xt>=0?_xt:x + 3; 40017 xt = _xt>=0?_xt:x + 3;
35632 draw_point(x - 1,height()/2,color,opacity).draw_point(x + 1,height()/2,color,opacity); 40018 draw_point(x - 1,height()/2,color,opacity).draw_point(x + 1,height()/2,color,opacity);
35633 - if (allow_zero || txt[0]!='0' || txt[1]!=0) 40019 + if (allow_zero || *txt!='0' || txt[1]!=0)
35634 draw_text(xt,yt,txt,color,(tc*)0,opacity,font_height); 40020 draw_text(xt,yt,txt,color,(tc*)0,opacity,font_height);
35635 } 40021 }
35636 } else { // Regular case. 40022 } else { // Regular case.
35637 if (values_y[0]<values_y[siz]) draw_arrow(x,0,x,_height - 1,color,opacity,30,5,pattern); 40023 if (values_y[0]<values_y[siz]) draw_arrow(x,0,x,_height - 1,color,opacity,30,5,pattern);
35638 else draw_arrow(x,_height - 1,x,0,color,opacity,30,5,pattern); 40024 else draw_arrow(x,_height - 1,x,0,color,opacity,30,5,pattern);
35639 cimg_foroff(values_y,y) { 40025 cimg_foroff(values_y,y) {
35640 - cimg_snprintf(txt,sizeof(txt),"%g",(double)values_y(y)); 40026 + cimg_snprintf(txt,txt._width,"%g",(double)values_y(y));
35641 label.assign().draw_text(0,0,txt,color,(tc*)0,opacity,font_height); 40027 label.assign().draw_text(0,0,txt,color,(tc*)0,opacity,font_height);
35642 const int 40028 const int
35643 yi = (int)(y*(_height - 1)/siz), 40029 yi = (int)(y*(_height - 1)/siz),
@@ -35646,7 +40032,7 @@ namespace cimg_library_suffixed { @@ -35646,7 +40032,7 @@ namespace cimg_library_suffixed {
35646 _xt = x - 2 - label.width(), 40032 _xt = x - 2 - label.width(),
35647 xt = _xt>=0?_xt:x + 3; 40033 xt = _xt>=0?_xt:x + 3;
35648 draw_point(x - 1,yi,color,opacity).draw_point(x + 1,yi,color,opacity); 40034 draw_point(x - 1,yi,color,opacity).draw_point(x + 1,yi,color,opacity);
35649 - if (allow_zero || txt[0]!='0' || txt[1]!=0) 40035 + if (allow_zero || *txt!='0' || txt[1]!=0)
35650 draw_text(xt,yt,txt,color,(tc*)0,opacity,font_height); 40036 draw_text(xt,yt,txt,color,(tc*)0,opacity,font_height);
35651 } 40037 }
35652 } 40038 }
@@ -36186,7 +40572,8 @@ namespace cimg_library_suffixed { @@ -36186,7 +40572,8 @@ namespace cimg_library_suffixed {
36186 for (int y0 = 0; y0<h; y0+=delta) 40572 for (int y0 = 0; y0<h; y0+=delta)
36187 for (int x0 = 0; x0<w; x0+=delta) { 40573 for (int x0 = 0; x0<w; x0+=delta) {
36188 const int x1 = (x0 + delta)%w, y1 = (y0 + delta)%h, xc = (x0 + delta2)%w, yc = (y0 + delta2)%h; 40574 const int x1 = (x0 + delta)%w, y1 = (y0 + delta)%h, xc = (x0 + delta2)%w, yc = (y0 + delta2)%h;
36189 - const Tfloat val = (Tfloat)(0.25f*(ref(x0,y0) + ref(x0,y1) + ref(x0,y1) + ref(x1,y1)) + r*cimg::crand()); 40575 + const Tfloat val = (Tfloat)(0.25f*(ref(x0,y0) + ref(x0,y1) + ref(x0,y1) + ref(x1,y1)) +
  40576 + r*cimg::rand(-1,1));
36190 ref(xc,yc) = (T)(val<m?m:val>M?M:val); 40577 ref(xc,yc) = (T)(val<m?m:val>M?M:val);
36191 } 40578 }
36192 40579
@@ -36195,21 +40582,24 @@ namespace cimg_library_suffixed { @@ -36195,21 +40582,24 @@ namespace cimg_library_suffixed {
36195 for (int x0=0; x0<w; x0+=delta) { 40582 for (int x0=0; x0<w; x0+=delta) {
36196 const int y0 = cimg::mod(y,h), x1 = (x0 + delta)%w, y1 = (y + delta)%h, 40583 const int y0 = cimg::mod(y,h), x1 = (x0 + delta)%w, y1 = (y + delta)%h,
36197 xc = (x0 + delta2)%w, yc = (y + delta2)%h; 40584 xc = (x0 + delta2)%w, yc = (y + delta2)%h;
36198 - const Tfloat val = (Tfloat)(0.25f*(ref(xc,y0) + ref(x0,yc) + ref(xc,y1) + ref(x1,yc)) + r*cimg::crand()); 40585 + const Tfloat val = (Tfloat)(0.25f*(ref(xc,y0) + ref(x0,yc) + ref(xc,y1) + ref(x1,yc)) +
  40586 + r*cimg::rand(-1,1));
36199 ref(xc,yc) = (T)(val<m?m:val>M?M:val); 40587 ref(xc,yc) = (T)(val<m?m:val>M?M:val);
36200 } 40588 }
36201 for (int y0 = 0; y0<h; y0+=delta) 40589 for (int y0 = 0; y0<h; y0+=delta)
36202 for (int x = -delta2; x<w; x+=delta) { 40590 for (int x = -delta2; x<w; x+=delta) {
36203 const int x0 = cimg::mod(x,w), x1 = (x + delta)%w, y1 = (y0 + delta)%h, 40591 const int x0 = cimg::mod(x,w), x1 = (x + delta)%w, y1 = (y0 + delta)%h,
36204 xc = (x + delta2)%w, yc = (y0 + delta2)%h; 40592 xc = (x + delta2)%w, yc = (y0 + delta2)%h;
36205 - const Tfloat val = (Tfloat)(0.25f*(ref(xc,y0) + ref(x0,yc) + ref(xc,y1) + ref(x1,yc)) + r*cimg::crand()); 40593 + const Tfloat val = (Tfloat)(0.25f*(ref(xc,y0) + ref(x0,yc) + ref(xc,y1) + ref(x1,yc)) +
  40594 + r*cimg::rand(-1,1));
36206 ref(xc,yc) = (T)(val<m?m:val>M?M:val); 40595 ref(xc,yc) = (T)(val<m?m:val>M?M:val);
36207 } 40596 }
36208 for (int y = -delta2; y<h; y+=delta) 40597 for (int y = -delta2; y<h; y+=delta)
36209 for (int x = -delta2; x<w; x+=delta) { 40598 for (int x = -delta2; x<w; x+=delta) {
36210 const int x0 = cimg::mod(x,w), y0 = cimg::mod(y,h), x1 = (x + delta)%w, y1 = (y + delta)%h, 40599 const int x0 = cimg::mod(x,w), y0 = cimg::mod(y,h), x1 = (x + delta)%w, y1 = (y + delta)%h,
36211 xc = (x + delta2)%w, yc = (y + delta2)%h; 40600 xc = (x + delta2)%w, yc = (y + delta2)%h;
36212 - const Tfloat val = (Tfloat)(0.25f*(ref(xc,y0) + ref(x0,yc) + ref(xc,y1) + ref(x1,yc)) + r*cimg::crand()); 40601 + const Tfloat val = (Tfloat)(0.25f*(ref(xc,y0) + ref(x0,yc) + ref(xc,y1) + ref(x1,yc)) +
  40602 + r*cimg::rand(-1,1));
36213 ref(xc,yc) = (T)(val<m?m:val>M?M:val); 40603 ref(xc,yc) = (T)(val<m?m:val>M?M:val);
36214 } 40604 }
36215 } 40605 }
@@ -36592,7 +40982,7 @@ namespace cimg_library_suffixed { @@ -36592,7 +40982,7 @@ namespace cimg_library_suffixed {
36592 const bool is_double_sided=false, const float focale=700, 40982 const bool is_double_sided=false, const float focale=700,
36593 const float lightx=0, const float lighty=0, const float lightz=-5e8, 40983 const float lightx=0, const float lighty=0, const float lightz=-5e8,
36594 const float specular_lightness=0.2f, const float specular_shininess=0.1f) { 40984 const float specular_lightness=0.2f, const float specular_shininess=0.1f) {
36595 - return draw_object3d(x0,y0,z0,vertices,primitives,colors,CImg<floatT>::empty(), 40985 + return draw_object3d(x0,y0,z0,vertices,primitives,colors,CImg<floatT>::const_empty(),
36596 render_type,is_double_sided,focale,lightx,lighty,lightz, 40986 render_type,is_double_sided,focale,lightx,lighty,lightz,
36597 specular_lightness,specular_shininess,CImg<floatT>::empty()); 40987 specular_lightness,specular_shininess,CImg<floatT>::empty());
36598 } 40988 }
@@ -36607,7 +40997,7 @@ namespace cimg_library_suffixed { @@ -36607,7 +40997,7 @@ namespace cimg_library_suffixed {
36607 const float lightx, const float lighty, const float lightz, 40997 const float lightx, const float lighty, const float lightz,
36608 const float specular_lightness, const float specular_shininess, 40998 const float specular_lightness, const float specular_shininess,
36609 CImg<tz>& zbuffer) { 40999 CImg<tz>& zbuffer) {
36610 - return draw_object3d(x0,y0,z0,vertices,primitives,colors,CImg<floatT>::empty(), 41000 + return draw_object3d(x0,y0,z0,vertices,primitives,colors,CImg<floatT>::const_empty(),
36611 render_type,is_double_sided,focale,lightx,lighty,lightz, 41001 render_type,is_double_sided,focale,lightx,lighty,lightz,
36612 specular_lightness,specular_shininess,zbuffer); 41002 specular_lightness,specular_shininess,zbuffer);
36613 } 41003 }
@@ -36622,7 +41012,7 @@ namespace cimg_library_suffixed { @@ -36622,7 +41012,7 @@ namespace cimg_library_suffixed {
36622 const bool is_double_sided=false, const float focale=700, 41012 const bool is_double_sided=false, const float focale=700,
36623 const float lightx=0, const float lighty=0, const float lightz=-5e8, 41013 const float lightx=0, const float lighty=0, const float lightz=-5e8,
36624 const float specular_lightness=0.2f, const float specular_shininess=0.1f) { 41014 const float specular_lightness=0.2f, const float specular_shininess=0.1f) {
36625 - return draw_object3d(x0,y0,z0,vertices,primitives,colors,CImg<floatT>::empty(), 41015 + return draw_object3d(x0,y0,z0,vertices,primitives,colors,CImg<floatT>::const_empty(),
36626 render_type,is_double_sided,focale,lightx,lighty,lightz, 41016 render_type,is_double_sided,focale,lightx,lighty,lightz,
36627 specular_lightness,specular_shininess,CImg<floatT>::empty()); 41017 specular_lightness,specular_shininess,CImg<floatT>::empty());
36628 } 41018 }
@@ -36637,7 +41027,7 @@ namespace cimg_library_suffixed { @@ -36637,7 +41027,7 @@ namespace cimg_library_suffixed {
36637 const float lightx, const float lighty, const float lightz, 41027 const float lightx, const float lighty, const float lightz,
36638 const float specular_lightness, const float specular_shininess, 41028 const float specular_lightness, const float specular_shininess,
36639 CImg<tz>& zbuffer) { 41029 CImg<tz>& zbuffer) {
36640 - return draw_object3d(x0,y0,z0,vertices,primitives,colors,CImg<floatT>::empty(), 41030 + return draw_object3d(x0,y0,z0,vertices,primitives,colors,CImg<floatT>::const_empty(),
36641 render_type,is_double_sided,focale,lightx,lighty,lightz, 41031 render_type,is_double_sided,focale,lightx,lighty,lightz,
36642 specular_lightness,specular_shininess,zbuffer); 41032 specular_lightness,specular_shininess,zbuffer);
36643 } 41033 }
@@ -36755,7 +41145,7 @@ namespace cimg_library_suffixed { @@ -36755,7 +41145,7 @@ namespace cimg_library_suffixed {
36755 const float absfocale = focale?cimg::abs(focale):0; 41145 const float absfocale = focale?cimg::abs(focale):0;
36756 if (absfocale) { 41146 if (absfocale) {
36757 #ifdef cimg_use_openmp 41147 #ifdef cimg_use_openmp
36758 -#pragma omp parallel for if (projections.size()>4096) 41148 +#pragma omp parallel for cimg_openmp_if(projections.size()>4096)
36759 #endif 41149 #endif
36760 cimg_forX(projections,l) { // Perspective projection 41150 cimg_forX(projections,l) { // Perspective projection
36761 const tpfloat 41151 const tpfloat
@@ -36769,7 +41159,7 @@ namespace cimg_library_suffixed { @@ -36769,7 +41159,7 @@ namespace cimg_library_suffixed {
36769 41159
36770 } else { 41160 } else {
36771 #ifdef cimg_use_openmp 41161 #ifdef cimg_use_openmp
36772 -#pragma omp parallel for if (projections.size()>4096) 41162 +#pragma omp parallel for cimg_openmp_if(projections.size()>4096)
36773 #endif 41163 #endif
36774 cimg_forX(projections,l) { // Parallel projection 41164 cimg_forX(projections,l) { // Parallel projection
36775 const tpfloat 41165 const tpfloat
@@ -36792,7 +41182,7 @@ namespace cimg_library_suffixed { @@ -36792,7 +41182,7 @@ namespace cimg_library_suffixed {
36792 bool is_forward = zbuffer?true:false; 41182 bool is_forward = zbuffer?true:false;
36793 41183
36794 #ifdef cimg_use_openmp 41184 #ifdef cimg_use_openmp
36795 -#pragma omp parallel for if (primitives.size()>4096) 41185 +#pragma omp parallel for cimg_openmp_if(primitives.size()>4096)
36796 #endif 41186 #endif
36797 cimglist_for(primitives,l) { 41187 cimglist_for(primitives,l) {
36798 const CImg<tf>& primitive = primitives[l]; 41188 const CImg<tf>& primitive = primitives[l];
@@ -36943,7 +41333,7 @@ namespace cimg_library_suffixed { @@ -36943,7 +41333,7 @@ namespace cimg_library_suffixed {
36943 case 3 : { // Flat Shading 41333 case 3 : { // Flat Shading
36944 lightprops.assign(nb_visibles); 41334 lightprops.assign(nb_visibles);
36945 #ifdef cimg_use_openmp 41335 #ifdef cimg_use_openmp
36946 -#pragma omp parallel for if (nb_visibles>4096) 41336 +#pragma omp parallel for cimg_openmp_if(nb_visibles>4096)
36947 #endif 41337 #endif
36948 cimg_forX(lightprops,l) { 41338 cimg_forX(lightprops,l) {
36949 const CImg<tf>& primitive = primitives(visibles(permutations(l))); 41339 const CImg<tf>& primitive = primitives(visibles(permutations(l)));
@@ -36977,7 +41367,7 @@ namespace cimg_library_suffixed { @@ -36977,7 +41367,7 @@ namespace cimg_library_suffixed {
36977 case 5 : { // Phong-Shading 41367 case 5 : { // Phong-Shading
36978 CImg<tpfloat> vertices_normals(vertices._width,6,1,1,0); 41368 CImg<tpfloat> vertices_normals(vertices._width,6,1,1,0);
36979 #ifdef cimg_use_openmp 41369 #ifdef cimg_use_openmp
36980 -#pragma omp parallel for if (nb_visibles>4096) 41370 +#pragma omp parallel for cimg_openmp_if(nb_visibles>4096)
36981 #endif 41371 #endif
36982 for (unsigned int l = 0; l<nb_visibles; ++l) { 41372 for (unsigned int l = 0; l<nb_visibles; ++l) {
36983 const CImg<tf>& primitive = primitives[visibles(l)]; 41373 const CImg<tf>& primitive = primitives[visibles(l)];
@@ -37030,7 +41420,7 @@ namespace cimg_library_suffixed { @@ -37030,7 +41420,7 @@ namespace cimg_library_suffixed {
37030 if (render_type==4) { 41420 if (render_type==4) {
37031 lightprops.assign(vertices._width); 41421 lightprops.assign(vertices._width);
37032 #ifdef cimg_use_openmp 41422 #ifdef cimg_use_openmp
37033 -#pragma omp parallel for if (nb_visibles>4096) 41423 +#pragma omp parallel for cimg_openmp_if(nb_visibles>4096)
37034 #endif 41424 #endif
37035 cimg_forX(lightprops,l) { 41425 cimg_forX(lightprops,l) {
37036 const tpfloat 41426 const tpfloat
@@ -37051,7 +41441,7 @@ namespace cimg_library_suffixed { @@ -37051,7 +41441,7 @@ namespace cimg_library_suffixed {
37051 lh2 = light_texture._height/2 - 1; 41441 lh2 = light_texture._height/2 - 1;
37052 lightprops.assign(vertices._width,2); 41442 lightprops.assign(vertices._width,2);
37053 #ifdef cimg_use_openmp 41443 #ifdef cimg_use_openmp
37054 -#pragma omp parallel for if (nb_visibles>4096) 41444 +#pragma omp parallel for cimg_openmp_if(nb_visibles>4096)
37055 #endif 41445 #endif
37056 cimg_forX(lightprops,l) { 41446 cimg_forX(lightprops,l) {
37057 const tpfloat 41447 const tpfloat
@@ -37864,32 +42254,37 @@ namespace cimg_library_suffixed { @@ -37864,32 +42254,37 @@ namespace cimg_library_suffixed {
37864 \param XYZ Pointer to 3 values X,Y,Z which tells about the projection point coordinates, for volumetric images. 42254 \param XYZ Pointer to 3 values X,Y,Z which tells about the projection point coordinates, for volumetric images.
37865 **/ 42255 **/
37866 CImg<T>& select(CImgDisplay &disp, 42256 CImg<T>& select(CImgDisplay &disp,
37867 - const unsigned int feature_type=2, unsigned int *const XYZ=0) {  
37868 - return get_select(disp,feature_type,XYZ).move_to(*this); 42257 + const unsigned int feature_type=2, unsigned int *const XYZ=0,
  42258 + const bool exit_on_anykey=false) {
  42259 + return get_select(disp,feature_type,XYZ,exit_on_anykey).move_to(*this);
37869 } 42260 }
37870 42261
37871 //! Simple interface to select a shape from an image \overloading. 42262 //! Simple interface to select a shape from an image \overloading.
37872 CImg<T>& select(const char *const title, 42263 CImg<T>& select(const char *const title,
37873 - const unsigned int feature_type=2, unsigned int *const XYZ=0) {  
37874 - return get_select(title,feature_type,XYZ).move_to(*this); 42264 + const unsigned int feature_type=2, unsigned int *const XYZ=0,
  42265 + const bool exit_on_anykey=false) {
  42266 + return get_select(title,feature_type,XYZ,exit_on_anykey).move_to(*this);
37875 } 42267 }
37876 42268
37877 //! Simple interface to select a shape from an image \newinstance. 42269 //! Simple interface to select a shape from an image \newinstance.
37878 CImg<intT> get_select(CImgDisplay &disp, 42270 CImg<intT> get_select(CImgDisplay &disp,
37879 - const unsigned int feature_type=2, unsigned int *const XYZ=0) const {  
37880 - return _get_select(disp,0,feature_type,XYZ,0,0,0,true,false); 42271 + const unsigned int feature_type=2, unsigned int *const XYZ=0,
  42272 + const bool exit_on_anykey=false) const {
  42273 + return _get_select(disp,0,feature_type,XYZ,0,0,0,exit_on_anykey,true,false);
37881 } 42274 }
37882 42275
37883 //! Simple interface to select a shape from an image \newinstance. 42276 //! Simple interface to select a shape from an image \newinstance.
37884 CImg<intT> get_select(const char *const title, 42277 CImg<intT> get_select(const char *const title,
37885 - const unsigned int feature_type=2, unsigned int *const XYZ=0) const { 42278 + const unsigned int feature_type=2, unsigned int *const XYZ=0,
  42279 + const bool exit_on_anykey=false) const {
37886 CImgDisplay disp; 42280 CImgDisplay disp;
37887 - return _get_select(disp,title,feature_type,XYZ,0,0,0,true,false); 42281 + return _get_select(disp,title,feature_type,XYZ,0,0,0,exit_on_anykey,true,false);
37888 } 42282 }
37889 42283
37890 CImg<intT> _get_select(CImgDisplay &disp, const char *const title, 42284 CImg<intT> _get_select(CImgDisplay &disp, const char *const title,
37891 const unsigned int feature_type, unsigned int *const XYZ, 42285 const unsigned int feature_type, unsigned int *const XYZ,
37892 const int origX, const int origY, const int origZ, 42286 const int origX, const int origY, const int origZ,
  42287 + const bool exit_on_anykey,
37893 const bool reset_view3d, 42288 const bool reset_view3d,
37894 const bool force_display_z_coord) const { 42289 const bool force_display_z_coord) const {
37895 if (is_empty()) return CImg<intT>(1,feature_type==0?3:6,1,1,-1); 42290 if (is_empty()) return CImg<intT>(1,feature_type==0?3:6,1,1,-1);
@@ -37898,13 +42293,18 @@ namespace cimg_library_suffixed { @@ -37898,13 +42293,18 @@ namespace cimg_library_suffixed {
37898 if (!title) disp.set_title("CImg<%s> (%ux%ux%ux%u)",pixel_type(),_width,_height,_depth,_spectrum); 42293 if (!title) disp.set_title("CImg<%s> (%ux%ux%ux%u)",pixel_type(),_width,_height,_depth,_spectrum);
37899 } else if (title) disp.set_title("%s",title); 42294 } else if (title) disp.set_title("%s",title);
37900 42295
  42296 + CImg<T> thumb;
  42297 + if (width()>disp.screen_width() || height()>disp.screen_height()) {
  42298 + const double ratio = cimg::min((double)disp.screen_width()/width(),(double)disp.screen_height()/height());
  42299 + get_resize(cimg::max(1,(int)(ratio*width())),cimg::max(1,(int)(ratio*height())),-100,-100).move_to(thumb);
  42300 + }
  42301 +
37901 const unsigned int old_normalization = disp.normalization(); 42302 const unsigned int old_normalization = disp.normalization();
37902 bool old_is_resized = disp.is_resized(); 42303 bool old_is_resized = disp.is_resized();
37903 disp._normalization = 0; 42304 disp._normalization = 0;
37904 disp.show().set_key(0).set_wheel().show_mouse(); 42305 disp.show().set_key(0).set_wheel().show_mouse();
37905 - disp._mouse_x = disp._mouse_y = -1;  
37906 42306
37907 - unsigned char foreground_color[] = { 255,255,255 }, background_color[] = { 0,0,0 }; 42307 + static const unsigned char foreground_color[] = { 255,255,255 }, background_color[] = { 0,0,0 };
37908 42308
37909 int area = 0, starting_area = 0, clicked_area = 0, phase = 0, 42309 int area = 0, starting_area = 0, clicked_area = 0, phase = 0,
37910 X0 = (int)((XYZ?XYZ[0]:(_width - 1)/2)%_width), 42310 X0 = (int)((XYZ?XYZ[0]:(_width - 1)/2)%_width),
@@ -37945,6 +42345,8 @@ namespace cimg_library_suffixed { @@ -37945,6 +42345,8 @@ namespace cimg_library_suffixed {
37945 if (mX>=width() && mY>=height()) area = 4; 42345 if (mX>=width() && mY>=height()) area = 4;
37946 if (disp.button()) { if (!clicked_area) clicked_area = area; } else clicked_area = 0; 42346 if (disp.button()) { if (!clicked_area) clicked_area = area; } else clicked_area = 0;
37947 42347
  42348 + CImg<charT> filename(32);
  42349 +
37948 switch (key = disp.key()) { 42350 switch (key = disp.key()) {
37949 #if cimg_OS!=2 42351 #if cimg_OS!=2
37950 case cimg::keyCTRLRIGHT : 42352 case cimg::keyCTRLRIGHT :
@@ -37982,35 +42384,33 @@ namespace cimg_library_suffixed { @@ -37982,35 +42384,33 @@ namespace cimg_library_suffixed {
37982 } break; 42384 } break;
37983 case cimg::keyS : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { 42385 case cimg::keyS : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {
37984 static unsigned int snap_number = 0; 42386 static unsigned int snap_number = 0;
37985 - char filename[32] = { 0 };  
37986 std::FILE *file; 42387 std::FILE *file;
37987 do { 42388 do {
37988 - cimg_snprintf(filename,sizeof(filename),cimg_appname "_%.4u.bmp",snap_number++); 42389 + cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.bmp",snap_number++);
37989 if ((file=std::fopen(filename,"r"))!=0) cimg::fclose(file); 42390 if ((file=std::fopen(filename,"r"))!=0) cimg::fclose(file);
37990 } while (file); 42391 } while (file);
37991 if (visu0) { 42392 if (visu0) {
37992 (+visu0).draw_text(0,0," Saving snapshot... ",foreground_color,background_color,0.7f,13).display(disp); 42393 (+visu0).draw_text(0,0," Saving snapshot... ",foreground_color,background_color,0.7f,13).display(disp);
37993 visu0.save(filename); 42394 visu0.save(filename);
37994 - (+visu0).draw_text(0,0," Snapshot '%s' saved. ",foreground_color,background_color,0.7f,13,filename). 42395 + (+visu0).draw_text(0,0," Snapshot '%s' saved. ",foreground_color,background_color,0.7f,13,filename._data).
37995 display(disp); 42396 display(disp);
37996 } 42397 }
37997 disp.set_key(key,false); key = 0; 42398 disp.set_key(key,false); key = 0;
37998 } break; 42399 } break;
37999 case cimg::keyO : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { 42400 case cimg::keyO : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {
38000 static unsigned int snap_number = 0; 42401 static unsigned int snap_number = 0;
38001 - char filename[32] = { 0 };  
38002 std::FILE *file; 42402 std::FILE *file;
38003 do { 42403 do {
38004 #ifdef cimg_use_zlib 42404 #ifdef cimg_use_zlib
38005 - cimg_snprintf(filename,sizeof(filename),cimg_appname "_%.4u.cimgz",snap_number++); 42405 + cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.cimgz",snap_number++);
38006 #else 42406 #else
38007 - cimg_snprintf(filename,sizeof(filename),cimg_appname "_%.4u.cimg",snap_number++); 42407 + cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.cimg",snap_number++);
38008 #endif 42408 #endif
38009 if ((file=std::fopen(filename,"r"))!=0) cimg::fclose(file); 42409 if ((file=std::fopen(filename,"r"))!=0) cimg::fclose(file);
38010 } while (file); 42410 } while (file);
38011 (+visu0).draw_text(0,0," Saving instance... ",foreground_color,background_color,0.7f,13).display(disp); 42411 (+visu0).draw_text(0,0," Saving instance... ",foreground_color,background_color,0.7f,13).display(disp);
38012 save(filename); 42412 save(filename);
38013 - (+visu0).draw_text(0,0," Instance '%s' saved. ",foreground_color,background_color,0.7f,13,filename). 42413 + (+visu0).draw_text(0,0," Instance '%s' saved. ",foreground_color,background_color,0.7f,13,filename._data).
38014 display(disp); 42414 display(disp);
38015 disp.set_key(key,false); key = 0; 42415 disp.set_key(key,false); key = 0;
38016 } break; 42416 } break;
@@ -38043,7 +42443,7 @@ namespace cimg_library_suffixed { @@ -38043,7 +42443,7 @@ namespace cimg_library_suffixed {
38043 X0 = (int)X; Y0 = (int)Y; Z0 = (int)Z; 42443 X0 = (int)X; Y0 = (int)Y; Z0 = (int)Z;
38044 } 42444 }
38045 } 42445 }
38046 - if (disp.button()&4) { // Reset positions. 42446 + if (disp.button()&4) {
38047 X = (float)X0; Y = (float)Y0; Z = (float)Z0; phase = area = clicked_area = starting_area = 0; 42447 X = (float)X0; Y = (float)Y0; Z = (float)Z0; phase = area = clicked_area = starting_area = 0;
38048 visu0.assign(); 42448 visu0.assign();
38049 } 42449 }
@@ -38146,7 +42546,9 @@ namespace cimg_library_suffixed { @@ -38146,7 +42546,9 @@ namespace cimg_library_suffixed {
38146 if (mx!=omx || my!=omy || !visu0 || (_depth>1 && !view3d)) { 42546 if (mx!=omx || my!=omy || !visu0 || (_depth>1 && !view3d)) {
38147 42547
38148 if (!visu0) { // Create image of projected planes. 42548 if (!visu0) { // Create image of projected planes.
38149 - __get_select(disp,old_normalization,phase?X1:X0,phase?Y1:Y0,phase?Z1:Z0).move_to(visu0).resize(disp); 42549 + if (thumb) thumb.__get_select(disp,old_normalization,phase?X1:X0,phase?Y1:Y0,phase?Z1:Z0).move_to(visu0);
  42550 + else __get_select(disp,old_normalization,phase?X1:X0,phase?Y1:Y0,phase?Z1:Z0).move_to(visu0);
  42551 + visu0.resize(disp);
38150 view3d.assign(); 42552 view3d.assign();
38151 points3d.assign(); 42553 points3d.assign();
38152 } 42554 }
@@ -38409,6 +42811,10 @@ namespace cimg_library_suffixed { @@ -38409,6 +42811,10 @@ namespace cimg_library_suffixed {
38409 } else if (!shape_selected) disp.wait(); 42811 } else if (!shape_selected) disp.wait();
38410 if (disp.is_resized()) { disp.resize(false)._is_resized = false; old_is_resized = true; visu0.assign(); } 42812 if (disp.is_resized()) { disp.resize(false)._is_resized = false; old_is_resized = true; visu0.assign(); }
38411 omx = mx; omy = my; 42813 omx = mx; omy = my;
  42814 + if (!exit_on_anykey && key && key!=cimg::keyESC &&
  42815 + (key!=cimg::keyW || (!disp.is_keyCTRLLEFT() && !disp.is_keyCTRLRIGHT()))) {
  42816 + key = 0;
  42817 + }
38412 } 42818 }
38413 42819
38414 // Return result. 42820 // Return result.
@@ -38428,7 +42834,7 @@ namespace cimg_library_suffixed { @@ -38428,7 +42834,7 @@ namespace cimg_library_suffixed {
38428 default : res[0] = X0; res[1] = Y0; res[2] = Z0; 42834 default : res[0] = X0; res[1] = Y0; res[2] = Z0;
38429 } 42835 }
38430 } 42836 }
38431 - disp.set_button(); 42837 + if (!exit_on_anykey || !(disp.button()&4)) disp.set_button();
38432 if (!visible_cursor) disp.show_mouse(); 42838 if (!visible_cursor) disp.show_mouse();
38433 disp._normalization = old_normalization; 42839 disp._normalization = old_normalization;
38434 disp._is_resized = old_is_resized; 42840 disp._is_resized = old_is_resized;
@@ -38445,9 +42851,8 @@ namespace cimg_library_suffixed { @@ -38445,9 +42851,8 @@ namespace cimg_library_suffixed {
38445 if (_depth>1) crop.get_projections2d(x,y,z).move_to(img2d); 42851 if (_depth>1) crop.get_projections2d(x,y,z).move_to(img2d);
38446 else CImg<Tuchar>(crop,false).move_to(img2d); 42852 else CImg<Tuchar>(crop,false).move_to(img2d);
38447 42853
38448 - // Check for inf and nan values.  
38449 - if (cimg::type<T>::is_float() && disp._normalization &&  
38450 - (disp._normalization!=3 || cimg::type<T>::string()!=cimg::type<unsigned char>::string())) { 42854 + // Check for inf and NaN values.
  42855 + if (cimg::type<T>::is_float() && normalization) {
38451 bool is_inf = false, is_nan = false; 42856 bool is_inf = false, is_nan = false;
38452 cimg_for(img2d,ptr,Tuchar) 42857 cimg_for(img2d,ptr,Tuchar)
38453 if (cimg::type<T>::is_inf(*ptr)) { is_inf = true; break; } 42858 if (cimg::type<T>::is_inf(*ptr)) { is_inf = true; break; }
@@ -38467,7 +42872,7 @@ namespace cimg_library_suffixed { @@ -38467,7 +42872,7 @@ namespace cimg_library_suffixed {
38467 val_pinf = (T)(normalization==1 || normalization==3?M0 + (M0 - m0)*20 + 1:M0); 42872 val_pinf = (T)(normalization==1 || normalization==3?M0 + (M0 - m0)*20 + 1:M0);
38468 if (is_nan) 42873 if (is_nan)
38469 cimg_for(img2d,ptr,Tuchar) 42874 cimg_for(img2d,ptr,Tuchar)
38470 - if (cimg::type<T>::is_nan(*ptr)) *ptr = val_minf; // Replace nan values. 42875 + if (cimg::type<T>::is_nan(*ptr)) *ptr = val_minf; // Replace NaN values.
38471 if (is_inf) 42876 if (is_inf)
38472 cimg_for(img2d,ptr,Tuchar) 42877 cimg_for(img2d,ptr,Tuchar)
38473 if (cimg::type<T>::is_inf(*ptr)) *ptr = (float)*ptr<0?val_minf:val_pinf; // Replace +-inf values. 42878 if (cimg::type<T>::is_inf(*ptr)) *ptr = (float)*ptr<0?val_minf:val_pinf; // Replace +-inf values.
@@ -38496,7 +42901,8 @@ namespace cimg_library_suffixed { @@ -38496,7 +42901,8 @@ namespace cimg_library_suffixed {
38496 CImg<intT> get_select_graph(CImgDisplay &disp, 42901 CImg<intT> get_select_graph(CImgDisplay &disp,
38497 const unsigned int plot_type=1, const unsigned int vertex_type=1, 42902 const unsigned int plot_type=1, const unsigned int vertex_type=1,
38498 const char *const labelx=0, const double xmin=0, const double xmax=0, 42903 const char *const labelx=0, const double xmin=0, const double xmax=0,
38499 - const char *const labely=0, const double ymin=0, const double ymax=0) const { 42904 + const char *const labely=0, const double ymin=0, const double ymax=0,
  42905 + const bool exit_on_anykey=false) const {
38500 if (is_empty()) 42906 if (is_empty())
38501 throw CImgInstanceException(_cimg_instance 42907 throw CImgInstanceException(_cimg_instance
38502 "select_graph(): Empty instance.", 42908 "select_graph(): Empty instance.",
@@ -38512,8 +42918,8 @@ namespace cimg_library_suffixed { @@ -38512,8 +42918,8 @@ namespace cimg_library_suffixed {
38512 if (nymin==nymax) { --nymin; ++nymax; } 42918 if (nymin==nymax) { --nymin; ++nymax; }
38513 if (nxmin==nxmax && nxmin==0) { nxmin = 0; nxmax = siz - 1.0; } 42919 if (nxmin==nxmax && nxmin==0) { nxmin = 0; nxmax = siz - 1.0; }
38514 42920
38515 - const unsigned char black[] = { 0, 0, 0 }, white[] = { 255, 255, 255 }, gray[] = { 220, 220, 220 };  
38516 - const unsigned char gray2[] = { 110, 110, 110 }, ngray[] = { 35, 35, 35 }; 42921 + static const unsigned char black[] = { 0, 0, 0 }, white[] = { 255, 255, 255 }, gray[] = { 220, 220, 220 };
  42922 + static const unsigned char gray2[] = { 110, 110, 110 }, ngray[] = { 35, 35, 35 };
38517 static unsigned int odimv = 0; 42923 static unsigned int odimv = 0;
38518 static CImg<ucharT> colormap; 42924 static CImg<ucharT> colormap;
38519 if (odimv!=_spectrum) { 42925 if (odimv!=_spectrum) {
@@ -38619,8 +43025,8 @@ namespace cimg_library_suffixed { @@ -38619,8 +43025,8 @@ namespace cimg_library_suffixed {
38619 (double)(*this)(x,0,0,_spectrum - 1)); 43025 (double)(*this)(x,0,0,_spectrum - 1));
38620 else { 43026 else {
38621 cimg_snprintf(message,message._width,"Value[%u:%g] = ( ",x,cx); 43027 cimg_snprintf(message,message._width,"Value[%u:%g] = ( ",x,cx);
38622 - cimg_forC(*this,c) std::sprintf(message._data + std::strlen(message),"%g ",(double)(*this)(x,0,0,c));  
38623 - std::sprintf(message._data + std::strlen(message),")"); 43028 + cimg_forC(*this,c) cimg_sprintf(message._data + std::strlen(message),"%g ",(double)(*this)(x,0,0,c));
  43029 + cimg_sprintf(message._data + std::strlen(message),")");
38624 } 43030 }
38625 if (x0>=0 && x1>=0) { 43031 if (x0>=0 && x1>=0) {
38626 const unsigned int 43032 const unsigned int
@@ -38634,10 +43040,10 @@ namespace cimg_library_suffixed { @@ -38634,10 +43040,10 @@ namespace cimg_library_suffixed {
38634 cy0 = nymax - ny0*(nymax - nymin)/(visu._height - 32), 43040 cy0 = nymax - ny0*(nymax - nymin)/(visu._height - 32),
38635 cy1 = nymax - ny1*(nymax - nymin)/(visu._height - 32); 43041 cy1 = nymax - ny1*(nymax - nymin)/(visu._height - 32);
38636 if (y0>=0 && y1>=0) 43042 if (y0>=0 && y1>=0)
38637 - std::sprintf(message._data + std::strlen(message)," - Range ( %u:%g, %g ) - ( %u:%g, %g )", 43043 + cimg_sprintf(message._data + std::strlen(message)," - Range ( %u:%g, %g ) - ( %u:%g, %g )",
38638 x0,cx0,cy0,x1 + one,cx1,cy1); 43044 x0,cx0,cy0,x1 + one,cx1,cy1);
38639 else 43045 else
38640 - std::sprintf(message._data + std::strlen(message)," - Range [ %u:%g - %u:%g ]", 43046 + cimg_sprintf(message._data + std::strlen(message)," - Range [ %u:%g - %u:%g ]",
38641 x0,cx0,x1 + one,cx1); 43047 x0,cx0,x1 + one,cx1);
38642 } 43048 }
38643 text.assign().draw_text(0,0,message,white,ngray,1,13).resize(-100,-100,1,3); 43049 text.assign().draw_text(0,0,message,white,ngray,1,13).resize(-100,-100,1,3);
@@ -38647,6 +43053,7 @@ namespace cimg_library_suffixed { @@ -38647,6 +43053,7 @@ namespace cimg_library_suffixed {
38647 } 43053 }
38648 43054
38649 // Test keys. 43055 // Test keys.
  43056 + CImg<charT> filename(32);
38650 switch (okey = key) { 43057 switch (okey = key) {
38651 #if cimg_OS!=2 43058 #if cimg_OS!=2
38652 case cimg::keyCTRLRIGHT : case cimg::keySHIFTRIGHT : 43059 case cimg::keyCTRLRIGHT : case cimg::keySHIFTRIGHT :
@@ -38678,15 +43085,14 @@ namespace cimg_library_suffixed { @@ -38678,15 +43085,14 @@ namespace cimg_library_suffixed {
38678 static unsigned int snap_number = 0; 43085 static unsigned int snap_number = 0;
38679 if (visu || visu0) { 43086 if (visu || visu0) {
38680 CImg<ucharT> &screen = visu?visu:visu0; 43087 CImg<ucharT> &screen = visu?visu:visu0;
38681 - char filename[32] = { 0 };  
38682 std::FILE *file; 43088 std::FILE *file;
38683 do { 43089 do {
38684 - cimg_snprintf(filename,sizeof(filename),cimg_appname "_%.4u.bmp",snap_number++); 43090 + cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.bmp",snap_number++);
38685 if ((file=std::fopen(filename,"r"))!=0) cimg::fclose(file); 43091 if ((file=std::fopen(filename,"r"))!=0) cimg::fclose(file);
38686 } while (file); 43092 } while (file);
38687 (+screen).draw_text(0,0," Saving snapshot... ",black,gray,1,13).display(disp); 43093 (+screen).draw_text(0,0," Saving snapshot... ",black,gray,1,13).display(disp);
38688 screen.save(filename); 43094 screen.save(filename);
38689 - (+screen).draw_text(0,0," Snapshot '%s' saved. ",black,gray,1,13,filename).display(disp); 43095 + (+screen).draw_text(0,0," Snapshot '%s' saved. ",black,gray,1,13,filename._data).display(disp);
38690 } 43096 }
38691 disp.set_key(key,false); okey = 0; 43097 disp.set_key(key,false); okey = 0;
38692 } break; 43098 } break;
@@ -38694,19 +43100,18 @@ namespace cimg_library_suffixed { @@ -38694,19 +43100,18 @@ namespace cimg_library_suffixed {
38694 static unsigned int snap_number = 0; 43100 static unsigned int snap_number = 0;
38695 if (visu || visu0) { 43101 if (visu || visu0) {
38696 CImg<ucharT> &screen = visu?visu:visu0; 43102 CImg<ucharT> &screen = visu?visu:visu0;
38697 - char filename[32] = { 0 };  
38698 std::FILE *file; 43103 std::FILE *file;
38699 do { 43104 do {
38700 #ifdef cimg_use_zlib 43105 #ifdef cimg_use_zlib
38701 - cimg_snprintf(filename,sizeof(filename),cimg_appname "_%.4u.cimgz",snap_number++); 43106 + cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.cimgz",snap_number++);
38702 #else 43107 #else
38703 - cimg_snprintf(filename,sizeof(filename),cimg_appname "_%.4u.cimg",snap_number++); 43108 + cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.cimg",snap_number++);
38704 #endif 43109 #endif
38705 if ((file=std::fopen(filename,"r"))!=0) cimg::fclose(file); 43110 if ((file=std::fopen(filename,"r"))!=0) cimg::fclose(file);
38706 } while (file); 43111 } while (file);
38707 (+screen).draw_text(0,0," Saving instance... ",black,gray,1,13).display(disp); 43112 (+screen).draw_text(0,0," Saving instance... ",black,gray,1,13).display(disp);
38708 save(filename); 43113 save(filename);
38709 - (+screen).draw_text(0,0," Instance '%s' saved. ",black,gray,1,13,filename).display(disp); 43114 + (+screen).draw_text(0,0," Instance '%s' saved. ",black,gray,1,13,filename._data).display(disp);
38710 } 43115 }
38711 disp.set_key(key,false); okey = 0; 43116 disp.set_key(key,false); okey = 0;
38712 } break; 43117 } break;
@@ -38733,6 +43138,11 @@ namespace cimg_library_suffixed { @@ -38733,6 +43138,11 @@ namespace cimg_library_suffixed {
38733 } 43138 }
38734 if (disp.is_resized()) { disp.resize(false); visu0.assign(); } 43139 if (disp.is_resized()) { disp.resize(false); visu0.assign(); }
38735 if (visu && visu0) disp.wait(); 43140 if (visu && visu0) disp.wait();
  43141 + if (!exit_on_anykey && okey && okey!=cimg::keyESC &&
  43142 + (okey!=cimg::keyW || (!disp.is_keyCTRLLEFT() && !disp.is_keyCTRLRIGHT()))) {
  43143 + disp.set_key(key,false);
  43144 + okey = 0;
  43145 + }
38736 } 43146 }
38737 43147
38738 disp._normalization = old_normalization; 43148 disp._normalization = old_normalization;
@@ -39067,8 +43477,8 @@ namespace cimg_library_suffixed { @@ -39067,8 +43477,8 @@ namespace cimg_library_suffixed {
39067 cimg_instance); 43477 cimg_instance);
39068 43478
39069 std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); 43479 std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
39070 - unsigned char header[64] = { 0 };  
39071 - cimg::fread(header,54,nfile); 43480 + CImg<ucharT> header(54);
  43481 + cimg::fread(header._data,54,nfile);
39072 if (*header!='B' || header[1]!='M') { 43482 if (*header!='B' || header[1]!='M') {
39073 if (!file) cimg::fclose(nfile); 43483 if (!file) cimg::fclose(nfile);
39074 throw CImgIOException(_cimg_instance 43484 throw CImgIOException(_cimg_instance
@@ -39093,7 +43503,7 @@ namespace cimg_library_suffixed { @@ -39093,7 +43503,7 @@ namespace cimg_library_suffixed {
39093 file_size = (int)std::ftell(nfile); 43503 file_size = (int)std::ftell(nfile);
39094 std::fseek(nfile,54,SEEK_SET); 43504 std::fseek(nfile,54,SEEK_SET);
39095 } 43505 }
39096 - if (header_size>40) std::fseek(nfile, header_size - 40, SEEK_CUR); 43506 + if (header_size>40) std::fseek(nfile,header_size - 40,SEEK_CUR);
39097 43507
39098 const int 43508 const int
39099 cimg_iobuffer = 24*1024*1024, 43509 cimg_iobuffer = 24*1024*1024,
@@ -40037,7 +44447,7 @@ namespace cimg_library_suffixed { @@ -40037,7 +44447,7 @@ namespace cimg_library_suffixed {
40037 - When libtiff is enabled, 2D and 3D (multipage) several 44447 - When libtiff is enabled, 2D and 3D (multipage) several
40038 channel per pixel are supported for 44448 channel per pixel are supported for
40039 <tt>char,uchar,short,ushort,float</tt> and \c double pixel types. 44449 <tt>char,uchar,short,ushort,float</tt> and \c double pixel types.
40040 - - If \c cimg_use_tif is not defined at compilation time the 44450 + - If \c cimg_use_tif is not defined at compile time the
40041 function uses CImg<T>& load_other(const char*). 44451 function uses CImg<T>& load_other(const char*).
40042 **/ 44452 **/
40043 CImg<T>& load_tiff(const char *const filename, 44453 CImg<T>& load_tiff(const char *const filename,
@@ -40243,10 +44653,13 @@ namespace cimg_library_suffixed { @@ -40243,10 +44653,13 @@ namespace cimg_library_suffixed {
40243 if (TIFFGetField(tif,TIFFTAG_IMAGEDESCRIPTION,&s_description) && s_description) 44653 if (TIFFGetField(tif,TIFFTAG_IMAGEDESCRIPTION,&s_description) && s_description)
40244 CImg<charT>::string(s_description).move_to(*description); 44654 CImg<charT>::string(s_description).move_to(*description);
40245 } 44655 }
40246 - const unsigned int spectrum = is_spp?samplesperpixel:photo==3?3:1; 44656 + const unsigned int spectrum = !is_spp || photo>=3?(photo>1?3:1):samplesperpixel;
40247 assign(nx,ny,1,spectrum); 44657 assign(nx,ny,1,spectrum);
40248 44658
40249 - if (photo>=3 && sampleformat==1 && bitspersample==8 && (samplesperpixel==3 || samplesperpixel==4)) { 44659 + if ((photo>=3 && sampleformat==1 &&
  44660 + (bitspersample==4 || bitspersample==8) &&
  44661 + (samplesperpixel==1 || samplesperpixel==3 || samplesperpixel==4)) ||
  44662 + (bitspersample==1 && samplesperpixel==1)) {
40250 // Special case for unsigned color images. 44663 // Special case for unsigned color images.
40251 uint32 *const raster = (uint32*)_TIFFmalloc(nx*ny*sizeof(uint32)); 44664 uint32 *const raster = (uint32*)_TIFFmalloc(nx*ny*sizeof(uint32));
40252 if (!raster) { 44665 if (!raster) {
@@ -40258,24 +44671,25 @@ namespace cimg_library_suffixed { @@ -40258,24 +44671,25 @@ namespace cimg_library_suffixed {
40258 } 44671 }
40259 TIFFReadRGBAImage(tif,nx,ny,raster,0); 44672 TIFFReadRGBAImage(tif,nx,ny,raster,0);
40260 switch (spectrum) { 44673 switch (spectrum) {
40261 - case 1 : {  
40262 - cimg_forXY(*this,x,y) (*this)(x,y) = (T)(float)((raster[nx*(ny - 1 - y) + x] + 128)/257);  
40263 - } break;  
40264 - case 3 : { 44674 + case 1 :
  44675 + cimg_forXY(*this,x,y)
  44676 + (*this)(x,y,0) = (T)(float)TIFFGetR(raster[nx*(ny - 1 -y) + x]);
  44677 + break;
  44678 + case 3 :
40265 cimg_forXY(*this,x,y) { 44679 cimg_forXY(*this,x,y) {
40266 (*this)(x,y,0) = (T)(float)TIFFGetR(raster[nx*(ny - 1 -y) + x]); 44680 (*this)(x,y,0) = (T)(float)TIFFGetR(raster[nx*(ny - 1 -y) + x]);
40267 (*this)(x,y,1) = (T)(float)TIFFGetG(raster[nx*(ny - 1 -y) + x]); 44681 (*this)(x,y,1) = (T)(float)TIFFGetG(raster[nx*(ny - 1 -y) + x]);
40268 (*this)(x,y,2) = (T)(float)TIFFGetB(raster[nx*(ny - 1 -y) + x]); 44682 (*this)(x,y,2) = (T)(float)TIFFGetB(raster[nx*(ny - 1 -y) + x]);
40269 } 44683 }
40270 - } break;  
40271 - case 4 : { 44684 + break;
  44685 + case 4 :
40272 cimg_forXY(*this,x,y) { 44686 cimg_forXY(*this,x,y) {
40273 (*this)(x,y,0) = (T)(float)TIFFGetR(raster[nx*(ny - 1 - y) + x]); 44687 (*this)(x,y,0) = (T)(float)TIFFGetR(raster[nx*(ny - 1 - y) + x]);
40274 (*this)(x,y,1) = (T)(float)TIFFGetG(raster[nx*(ny - 1 - y) + x]); 44688 (*this)(x,y,1) = (T)(float)TIFFGetG(raster[nx*(ny - 1 - y) + x]);
40275 (*this)(x,y,2) = (T)(float)TIFFGetB(raster[nx*(ny - 1 - y) + x]); 44689 (*this)(x,y,2) = (T)(float)TIFFGetB(raster[nx*(ny - 1 - y) + x]);
40276 (*this)(x,y,3) = (T)(float)TIFFGetA(raster[nx*(ny - 1 - y) + x]); 44690 (*this)(x,y,3) = (T)(float)TIFFGetA(raster[nx*(ny - 1 - y) + x]);
40277 } 44691 }
40278 - } break; 44692 + break;
40279 } 44693 }
40280 _TIFFfree(raster); 44694 _TIFFfree(raster);
40281 } else { // Other cases. 44695 } else { // Other cases.
@@ -40432,11 +44846,11 @@ namespace cimg_library_suffixed { @@ -40432,11 +44846,11 @@ namespace cimg_library_suffixed {
40432 const char *const ext = cimg::split_filename(filename,body); 44846 const char *const ext = cimg::split_filename(filename,body);
40433 if (!cimg::strcasecmp(ext,"hdr")) { // File is an Analyze header file. 44847 if (!cimg::strcasecmp(ext,"hdr")) { // File is an Analyze header file.
40434 nfile_header = cimg::fopen(filename,"rb"); 44848 nfile_header = cimg::fopen(filename,"rb");
40435 - std::sprintf(body._data + std::strlen(body),".img"); 44849 + cimg_sprintf(body._data + std::strlen(body),".img");
40436 nfile = cimg::fopen(body,"rb"); 44850 nfile = cimg::fopen(body,"rb");
40437 } else if (!cimg::strcasecmp(ext,"img")) { // File is an Analyze data file. 44851 } else if (!cimg::strcasecmp(ext,"img")) { // File is an Analyze data file.
40438 nfile = cimg::fopen(filename,"rb"); 44852 nfile = cimg::fopen(filename,"rb");
40439 - std::sprintf(body._data + std::strlen(body),".hdr"); 44853 + cimg_sprintf(body._data + std::strlen(body),".hdr");
40440 nfile_header = cimg::fopen(body,"rb"); 44854 nfile_header = cimg::fopen(body,"rb");
40441 } else nfile_header = nfile = cimg::fopen(filename,"rb"); // File is a Niftii file. 44855 } else nfile_header = nfile = cimg::fopen(filename,"rb"); // File is a Niftii file.
40442 } else nfile_header = nfile = file; // File is a Niftii file. 44856 } else nfile_header = nfile = file; // File is a Niftii file.
@@ -40452,7 +44866,7 @@ namespace cimg_library_suffixed { @@ -40452,7 +44866,7 @@ namespace cimg_library_suffixed {
40452 cimg::fread(&header_size,1,nfile_header); 44866 cimg::fread(&header_size,1,nfile_header);
40453 if (!header_size) 44867 if (!header_size)
40454 throw CImgIOException(_cimg_instance 44868 throw CImgIOException(_cimg_instance
40455 - "load_analyze(): Invalid zero-sized header in file '%s'.", 44869 + "load_analyze(): Invalid zero-size header in file '%s'.",
40456 cimg_instance, 44870 cimg_instance,
40457 filename?filename:"(FILE*)"); 44871 filename?filename:"(FILE*)");
40458 44872
@@ -40661,8 +45075,8 @@ namespace cimg_library_suffixed { @@ -40661,8 +45075,8 @@ namespace cimg_library_suffixed {
40661 } 45075 }
40662 45076
40663 static void _load_inr_header(std::FILE *file, int out[8], float *const voxel_size) { 45077 static void _load_inr_header(std::FILE *file, int out[8], float *const voxel_size) {
40664 - CImg<charT> item(1024); *item = 0;  
40665 - char tmp1[64] = { 0 }, tmp2[64] = { 0 }; 45078 + CImg<charT> item(1024), tmp1(64), tmp2(64);
  45079 + *item = *tmp1 = *tmp2 = 0;
40666 out[0] = std::fscanf(file,"%63s",item._data); 45080 out[0] = std::fscanf(file,"%63s",item._data);
40667 out[0] = out[1] = out[2] = out[3] = out[5] = 1; out[4] = out[6] = out[7] = -1; 45081 out[0] = out[1] = out[2] = out[3] = out[5] = 1; out[4] = out[6] = out[7] = -1;
40668 if(cimg::strncasecmp(item,"#INRIMAGE-4#{",13)!=0) 45082 if(cimg::strncasecmp(item,"#INRIMAGE-4#{",13)!=0)
@@ -40680,19 +45094,19 @@ namespace cimg_library_suffixed { @@ -40680,19 +45094,19 @@ namespace cimg_library_suffixed {
40680 cimg_sscanf(item," VY%*[^0-9.+-]%f",voxel_size + 1); 45094 cimg_sscanf(item," VY%*[^0-9.+-]%f",voxel_size + 1);
40681 cimg_sscanf(item," VZ%*[^0-9.+-]%f",voxel_size + 2); 45095 cimg_sscanf(item," VZ%*[^0-9.+-]%f",voxel_size + 2);
40682 } 45096 }
40683 - if (cimg_sscanf(item," CPU%*[ =]%s",tmp1)) out[7]=cimg::strncasecmp(tmp1,"sun",3)?0:1;  
40684 - switch (cimg_sscanf(item," TYPE%*[ =]%s %s",tmp1,tmp2)) { 45097 + if (cimg_sscanf(item," CPU%*[ =]%s",tmp1._data)) out[7] = cimg::strncasecmp(tmp1,"sun",3)?0:1;
  45098 + switch (cimg_sscanf(item," TYPE%*[ =]%s %s",tmp1._data,tmp2._data)) {
40685 case 0 : break; 45099 case 0 : break;
40686 - case 2 : out[5] = cimg::strncasecmp(tmp1,"unsigned",8)?1:0; std::strncpy(tmp1,tmp2,sizeof(tmp1) - 1); 45100 + case 2 : out[5] = cimg::strncasecmp(tmp1,"unsigned",8)?1:0; std::strncpy(tmp1,tmp2,tmp1._width - 1);
40687 case 1 : 45101 case 1 :
40688 - if (!cimg::strncasecmp(tmp1,"int",3) || !cimg::strncasecmp(tmp1,"fixed",5)) out[4] = 0; 45102 + if (!cimg::strncasecmp(tmp1,"int",3) || !cimg::strncasecmp(tmp1,"fixed",5)) out[4] = 0;
40689 if (!cimg::strncasecmp(tmp1,"float",5) || !cimg::strncasecmp(tmp1,"double",6)) out[4] = 1; 45103 if (!cimg::strncasecmp(tmp1,"float",5) || !cimg::strncasecmp(tmp1,"double",6)) out[4] = 1;
40690 - if (!cimg::strncasecmp(tmp1,"packed",6)) out[4] = 2; 45104 + if (!cimg::strncasecmp(tmp1,"packed",6)) out[4] = 2;
40691 if (out[4]>=0) break; 45105 if (out[4]>=0) break;
40692 default : 45106 default :
40693 throw CImgIOException("CImg<%s>::load_inr(): Invalid pixel type '%s' defined in header.", 45107 throw CImgIOException("CImg<%s>::load_inr(): Invalid pixel type '%s' defined in header.",
40694 pixel_type(), 45108 pixel_type(),
40695 - tmp2); 45109 + tmp2._data);
40696 } 45110 }
40697 } 45111 }
40698 if(out[0]<0 || out[1]<0 || out[2]<0 || out[3]<0) 45112 if(out[0]<0 || out[1]<0 || out[2]<0 || out[3]<0)
@@ -40846,8 +45260,8 @@ namespace cimg_library_suffixed { @@ -40846,8 +45260,8 @@ namespace cimg_library_suffixed {
40846 cimg_instance); 45260 cimg_instance);
40847 45261
40848 std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); 45262 std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
40849 - char header[32] = { 0 };  
40850 - cimg::fread(header,12,nfile); 45263 + CImg<charT> header(32);
  45264 + cimg::fread(header._data,12,nfile);
40851 if (cimg::strncasecmp("PANDORE",header,7)) { 45265 if (cimg::strncasecmp("PANDORE",header,7)) {
40852 if (!file) cimg::fclose(nfile); 45266 if (!file) cimg::fclose(nfile);
40853 throw CImgIOException(_cimg_instance 45267 throw CImgIOException(_cimg_instance
@@ -40856,10 +45270,11 @@ namespace cimg_library_suffixed { @@ -40856,10 +45270,11 @@ namespace cimg_library_suffixed {
40856 filename?filename:"(FILE*)"); 45270 filename?filename:"(FILE*)");
40857 } 45271 }
40858 unsigned int imageid, dims[8] = { 0 }; 45272 unsigned int imageid, dims[8] = { 0 };
  45273 + int ptbuf[4] = { 0 };
40859 cimg::fread(&imageid,1,nfile); 45274 cimg::fread(&imageid,1,nfile);
40860 - const bool endian = (imageid>255); 45275 + const bool endian = imageid>255;
40861 if (endian) cimg::invert_endianness(imageid); 45276 if (endian) cimg::invert_endianness(imageid);
40862 - cimg::fread(header,20,nfile); 45277 + cimg::fread(header._data,20,nfile);
40863 45278
40864 switch (imageid) { 45279 switch (imageid) {
40865 case 2 : _cimg_load_pandore_case(2,dims[1],1,1,1,unsigned char,unsigned char,unsigned char,1); break; 45280 case 2 : _cimg_load_pandore_case(2,dims[1],1,1,1,unsigned char,unsigned char,unsigned char,1); break;
@@ -40991,19 +45406,16 @@ namespace cimg_library_suffixed { @@ -40991,19 +45406,16 @@ namespace cimg_library_suffixed {
40991 break; 45406 break;
40992 case 33 : _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],dims[0],double,float,float,4); break; 45407 case 33 : _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],dims[0],double,float,float,4); break;
40993 case 34 : { // Points 1d 45408 case 34 : { // Points 1d
40994 - int ptbuf[4] = { 0 };  
40995 cimg::fread(ptbuf,1,nfile); 45409 cimg::fread(ptbuf,1,nfile);
40996 if (endian) cimg::invert_endianness(ptbuf,1); 45410 if (endian) cimg::invert_endianness(ptbuf,1);
40997 assign(1); (*this)(0) = (T)ptbuf[0]; 45411 assign(1); (*this)(0) = (T)ptbuf[0];
40998 } break; 45412 } break;
40999 case 35 : { // Points 2d 45413 case 35 : { // Points 2d
41000 - int ptbuf[4] = { 0 };  
41001 cimg::fread(ptbuf,2,nfile); 45414 cimg::fread(ptbuf,2,nfile);
41002 if (endian) cimg::invert_endianness(ptbuf,2); 45415 if (endian) cimg::invert_endianness(ptbuf,2);
41003 assign(2); (*this)(0) = (T)ptbuf[1]; (*this)(1) = (T)ptbuf[0]; 45416 assign(2); (*this)(0) = (T)ptbuf[1]; (*this)(1) = (T)ptbuf[0];
41004 } break; 45417 } break;
41005 case 36 : { // Points 3d 45418 case 36 : { // Points 3d
41006 - int ptbuf[4] = { 0 };  
41007 cimg::fread(ptbuf,3,nfile); 45419 cimg::fread(ptbuf,3,nfile);
41008 if (endian) cimg::invert_endianness(ptbuf,3); 45420 if (endian) cimg::invert_endianness(ptbuf,3);
41009 assign(3); (*this)(0) = (T)ptbuf[2]; (*this)(1) = (T)ptbuf[1]; (*this)(2) = (T)ptbuf[0]; 45421 assign(3); (*this)(0) = (T)ptbuf[2]; (*this)(1) = (T)ptbuf[1]; (*this)(2) = (T)ptbuf[0];
@@ -41886,11 +46298,11 @@ namespace cimg_library_suffixed { @@ -41886,11 +46298,11 @@ namespace cimg_library_suffixed {
41886 const unsigned long siz = size(), msiz = siz*sizeof(T), siz1 = siz - 1, 46298 const unsigned long siz = size(), msiz = siz*sizeof(T), siz1 = siz - 1,
41887 mdisp = msiz<8*1024?0U:msiz<8*1024*1024?1U:2U, width1 = _width - 1; 46299 mdisp = msiz<8*1024?0U:msiz<8*1024*1024?1U:2U, width1 = _width - 1;
41888 46300
41889 - char _title[64] = { 0 };  
41890 - if (!title) cimg_snprintf(_title,sizeof(_title),"CImg<%s>",pixel_type()); 46301 + CImg<charT> _title(64);
  46302 + if (!title) cimg_snprintf(_title,_title._width,"CImg<%s>",pixel_type());
41891 46303
41892 std::fprintf(cimg::output(),"%s%s%s%s: %sthis%s = %p, %ssize%s = (%u,%u,%u,%u) [%lu %s], %sdata%s = (%s*)%p", 46304 std::fprintf(cimg::output(),"%s%s%s%s: %sthis%s = %p, %ssize%s = (%u,%u,%u,%u) [%lu %s], %sdata%s = (%s*)%p",
41893 - cimg::t_magenta,cimg::t_bold,title?title:_title,cimg::t_normal, 46305 + cimg::t_magenta,cimg::t_bold,title?title:_title._data,cimg::t_normal,
41894 cimg::t_bold,cimg::t_normal,(void*)this, 46306 cimg::t_bold,cimg::t_normal,(void*)this,
41895 cimg::t_bold,cimg::t_normal,_width,_height,_depth,_spectrum, 46307 cimg::t_bold,cimg::t_normal,_width,_height,_depth,_spectrum,
41896 mdisp==0?msiz:(mdisp==1?(msiz>>10):(msiz>>20)), 46308 mdisp==0?msiz:(mdisp==1?(msiz>>10):(msiz>>20)),
@@ -41934,8 +46346,9 @@ namespace cimg_library_suffixed { @@ -41934,8 +46346,9 @@ namespace cimg_library_suffixed {
41934 \param disp Display window. 46346 \param disp Display window.
41935 \param display_info Tells if image information are displayed on the standard output. 46347 \param display_info Tells if image information are displayed on the standard output.
41936 **/ 46348 **/
41937 - const CImg<T>& display(CImgDisplay &disp, const bool display_info, unsigned int *const XYZ=0) const {  
41938 - return _display(disp,0,display_info,XYZ,false); 46349 + const CImg<T>& display(CImgDisplay &disp, const bool display_info, unsigned int *const XYZ=0,
  46350 + const bool exit_on_anykey=false) const {
  46351 + return _display(disp,0,display_info,XYZ,exit_on_anykey,false);
41939 } 46352 }
41940 46353
41941 //! Display image into an interactive window. 46354 //! Display image into an interactive window.
@@ -41943,16 +46356,18 @@ namespace cimg_library_suffixed { @@ -41943,16 +46356,18 @@ namespace cimg_library_suffixed {
41943 \param title Window title 46356 \param title Window title
41944 \param display_info Tells if image information are displayed on the standard output. 46357 \param display_info Tells if image information are displayed on the standard output.
41945 **/ 46358 **/
41946 - const CImg<T>& display(const char *const title=0, const bool display_info=true, unsigned int *const XYZ=0) const { 46359 + const CImg<T>& display(const char *const title=0, const bool display_info=true, unsigned int *const XYZ=0,
  46360 + const bool exit_on_anykey=false) const {
41947 CImgDisplay disp; 46361 CImgDisplay disp;
41948 - return _display(disp,title,display_info,XYZ,false); 46362 + return _display(disp,title,display_info,XYZ,exit_on_anykey,false);
41949 } 46363 }
41950 46364
41951 - const CImg<T>& _display(CImgDisplay &disp, const char *const title,  
41952 - const bool display_info, unsigned int *const XYZ, 46365 + const CImg<T>& _display(CImgDisplay &disp, const char *const title, const bool display_info,
  46366 + unsigned int *const XYZ, const bool exit_on_anykey,
41953 const bool exit_on_simpleclick) const { 46367 const bool exit_on_simpleclick) const {
41954 unsigned int oldw = 0, oldh = 0, _XYZ[3] = { 0 }, key = 0; 46368 unsigned int oldw = 0, oldh = 0, _XYZ[3] = { 0 }, key = 0;
41955 - int x0 = 0, y0 = 0, z0 = 0, x1 = width() - 1, y1 = height() - 1, z1 = depth() - 1; 46369 + int x0 = 0, y0 = 0, z0 = 0, x1 = width() - 1, y1 = height() - 1, z1 = depth() - 1,
  46370 + old_mouse_x = -1, old_mouse_y = -1;
41956 46371
41957 if (!disp) { 46372 if (!disp) {
41958 disp.assign(cimg_fitscreen(_width,_height,_depth),title?title:0,1); 46373 disp.assign(cimg_fitscreen(_width,_height,_depth),title?title:0,1);
@@ -42010,14 +46425,21 @@ namespace cimg_library_suffixed { @@ -42010,14 +46425,21 @@ namespace cimg_library_suffixed {
42010 _XYZ[1] = (unsigned int)(y1 - y0)/2; 46425 _XYZ[1] = (unsigned int)(y1 - y0)/2;
42011 _XYZ[2] = (unsigned int)(z1 - z0)/2; 46426 _XYZ[2] = (unsigned int)(z1 - z0)/2;
42012 } 46427 }
42013 - const CImg<intT> selection = visu._get_select(disp,0,2,_XYZ,x0,y0,z0,is_first_select,_depth>1); 46428 +
  46429 + disp._mouse_x = old_mouse_x; disp._mouse_y = old_mouse_y;
  46430 + const CImg<intT> selection = visu._get_select(disp,0,2,_XYZ,x0,y0,z0,true,is_first_select,_depth>1);
  46431 + old_mouse_x = disp._mouse_x; old_mouse_y = disp._mouse_y;
42014 is_first_select = false; 46432 is_first_select = false;
42015 46433
42016 if (disp.wheel()) { 46434 if (disp.wheel()) {
42017 if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { 46435 if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {
  46436 + go_down = !(go_up = disp.wheel()>0);
  46437 + } else if (disp.is_keySHIFTLEFT() || disp.is_keySHIFTRIGHT()) {
  46438 + go_left = !(go_right = disp.wheel()>0);
  46439 + }
  46440 + else if (disp.is_keyALT() || disp.is_keyALTGR() || _depth==1) {
42018 go_out = !(go_in = disp.wheel()>0); go_in_center = false; 46441 go_out = !(go_in = disp.wheel()>0); go_in_center = false;
42019 - } else if (disp.is_keySHIFTLEFT() || disp.is_keySHIFTRIGHT()) { go_left = !(go_right = disp.wheel()>0); }  
42020 - else if (disp.is_keyALT() || disp.is_keyALTGR() || _depth==1) { go_down = !(go_up = disp.wheel()>0); } 46442 + }
42021 disp.set_wheel(); 46443 disp.set_wheel();
42022 } 46444 }
42023 46445
@@ -42175,6 +46597,10 @@ namespace cimg_library_suffixed { @@ -42175,6 +46597,10 @@ namespace cimg_library_suffixed {
42175 else { z0+=(depth() - 1 - z1); z1 = depth() - 1; } 46597 else { z0+=(depth() - 1 - z1); z1 = depth() - 1; }
42176 } 46598 }
42177 disp.wait(100); 46599 disp.wait(100);
  46600 + if (!exit_on_anykey && key && key!=cimg::keyESC &&
  46601 + (key!=cimg::keyW || (!disp.is_keyCTRLLEFT() && !disp.is_keyCTRLRIGHT()))) {
  46602 + key = 0;
  46603 + }
42178 } 46604 }
42179 disp.set_key(key); 46605 disp.set_key(key);
42180 if (XYZ) { XYZ[0] = _XYZ[0]; XYZ[1] = _XYZ[1]; XYZ[2] = _XYZ[2]; } 46606 if (XYZ) { XYZ[0] = _XYZ[0]; XYZ[1] = _XYZ[1]; XYZ[2] = _XYZ[2]; }
@@ -42212,11 +46638,12 @@ namespace cimg_library_suffixed { @@ -42212,11 +46638,12 @@ namespace cimg_library_suffixed {
42212 const bool is_double_sided=true, const float focale=700, 46638 const bool is_double_sided=true, const float focale=700,
42213 const float light_x=0, const float light_y=0, const float light_z=-5e8f, 46639 const float light_x=0, const float light_y=0, const float light_z=-5e8f,
42214 const float specular_lightness=0.2f, const float specular_shininess=0.1f, 46640 const float specular_lightness=0.2f, const float specular_shininess=0.1f,
42215 - const bool display_axes=true, float *const pose_matrix=0) const { 46641 + const bool display_axes=true, float *const pose_matrix=0,
  46642 + const bool exit_on_anykey=false) const {
42216 return _display_object3d(disp,0,vertices,primitives,colors,opacities,centering,render_static, 46643 return _display_object3d(disp,0,vertices,primitives,colors,opacities,centering,render_static,
42217 render_motion,is_double_sided,focale, 46644 render_motion,is_double_sided,focale,
42218 light_x,light_y,light_z,specular_lightness,specular_shininess, 46645 light_x,light_y,light_z,specular_lightness,specular_shininess,
42219 - display_axes,pose_matrix); 46646 + display_axes,pose_matrix,exit_on_anykey);
42220 } 46647 }
42221 46648
42222 //! Display object 3d in an interactive window \simplification. 46649 //! Display object 3d in an interactive window \simplification.
@@ -42231,12 +46658,13 @@ namespace cimg_library_suffixed { @@ -42231,12 +46658,13 @@ namespace cimg_library_suffixed {
42231 const bool is_double_sided=true, const float focale=700, 46658 const bool is_double_sided=true, const float focale=700,
42232 const float light_x=0, const float light_y=0, const float light_z=-5e8f, 46659 const float light_x=0, const float light_y=0, const float light_z=-5e8f,
42233 const float specular_lightness=0.2f, const float specular_shininess=0.1f, 46660 const float specular_lightness=0.2f, const float specular_shininess=0.1f,
42234 - const bool display_axes=true, float *const pose_matrix=0) const { 46661 + const bool display_axes=true, float *const pose_matrix=0,
  46662 + const bool exit_on_anykey=false) const {
42235 CImgDisplay disp; 46663 CImgDisplay disp;
42236 return _display_object3d(disp,title,vertices,primitives,colors,opacities,centering,render_static, 46664 return _display_object3d(disp,title,vertices,primitives,colors,opacities,centering,render_static,
42237 render_motion,is_double_sided,focale, 46665 render_motion,is_double_sided,focale,
42238 light_x,light_y,light_z,specular_lightness,specular_shininess, 46666 light_x,light_y,light_z,specular_lightness,specular_shininess,
42239 - display_axes,pose_matrix); 46667 + display_axes,pose_matrix,exit_on_anykey);
42240 } 46668 }
42241 46669
42242 //! Display object 3d in an interactive window \simplification. 46670 //! Display object 3d in an interactive window \simplification.
@@ -42250,11 +46678,12 @@ namespace cimg_library_suffixed { @@ -42250,11 +46678,12 @@ namespace cimg_library_suffixed {
42250 const bool is_double_sided=true, const float focale=700, 46678 const bool is_double_sided=true, const float focale=700,
42251 const float light_x=0, const float light_y=0, const float light_z=-5e8f, 46679 const float light_x=0, const float light_y=0, const float light_z=-5e8f,
42252 const float specular_lightness=0.2f, const float specular_shininess=0.1f, 46680 const float specular_lightness=0.2f, const float specular_shininess=0.1f,
42253 - const bool display_axes=true, float *const pose_matrix=0) const { 46681 + const bool display_axes=true, float *const pose_matrix=0,
  46682 + const bool exit_on_anykey=false) const {
42254 return display_object3d(disp,vertices,primitives,colors,CImgList<floatT>(),centering, 46683 return display_object3d(disp,vertices,primitives,colors,CImgList<floatT>(),centering,
42255 render_static,render_motion,is_double_sided,focale, 46684 render_static,render_motion,is_double_sided,focale,
42256 light_x,light_y,light_z,specular_lightness,specular_shininess, 46685 light_x,light_y,light_z,specular_lightness,specular_shininess,
42257 - display_axes,pose_matrix); 46686 + display_axes,pose_matrix,exit_on_anykey);
42258 } 46687 }
42259 46688
42260 //! Display object 3d in an interactive window \simplification. 46689 //! Display object 3d in an interactive window \simplification.
@@ -42268,11 +46697,12 @@ namespace cimg_library_suffixed { @@ -42268,11 +46697,12 @@ namespace cimg_library_suffixed {
42268 const bool is_double_sided=true, const float focale=700, 46697 const bool is_double_sided=true, const float focale=700,
42269 const float light_x=0, const float light_y=0, const float light_z=-5e8f, 46698 const float light_x=0, const float light_y=0, const float light_z=-5e8f,
42270 const float specular_lightness=0.2f, const float specular_shininess=0.1f, 46699 const float specular_lightness=0.2f, const float specular_shininess=0.1f,
42271 - const bool display_axes=true, float *const pose_matrix=0) const { 46700 + const bool display_axes=true, float *const pose_matrix=0,
  46701 + const bool exit_on_anykey=false) const {
42272 return display_object3d(title,vertices,primitives,colors,CImgList<floatT>(),centering, 46702 return display_object3d(title,vertices,primitives,colors,CImgList<floatT>(),centering,
42273 render_static,render_motion,is_double_sided,focale, 46703 render_static,render_motion,is_double_sided,focale,
42274 light_x,light_y,light_z,specular_lightness,specular_shininess, 46704 light_x,light_y,light_z,specular_lightness,specular_shininess,
42275 - display_axes,pose_matrix); 46705 + display_axes,pose_matrix,exit_on_anykey);
42276 } 46706 }
42277 46707
42278 //! Display object 3d in an interactive window \simplification. 46708 //! Display object 3d in an interactive window \simplification.
@@ -42285,11 +46715,12 @@ namespace cimg_library_suffixed { @@ -42285,11 +46715,12 @@ namespace cimg_library_suffixed {
42285 const bool is_double_sided=true, const float focale=700, 46715 const bool is_double_sided=true, const float focale=700,
42286 const float light_x=0, const float light_y=0, const float light_z=-5e8f, 46716 const float light_x=0, const float light_y=0, const float light_z=-5e8f,
42287 const float specular_lightness=0.2f, const float specular_shininess=0.1f, 46717 const float specular_lightness=0.2f, const float specular_shininess=0.1f,
42288 - const bool display_axes=true, float *const pose_matrix=0) const { 46718 + const bool display_axes=true, float *const pose_matrix=0,
  46719 + const bool exit_on_anykey=false) const {
42289 return display_object3d(disp,vertices,primitives,CImgList<T>(),centering, 46720 return display_object3d(disp,vertices,primitives,CImgList<T>(),centering,
42290 render_static,render_motion,is_double_sided,focale, 46721 render_static,render_motion,is_double_sided,focale,
42291 light_x,light_y,light_z,specular_lightness,specular_shininess, 46722 light_x,light_y,light_z,specular_lightness,specular_shininess,
42292 - display_axes,pose_matrix); 46723 + display_axes,pose_matrix,exit_on_anykey);
42293 } 46724 }
42294 46725
42295 46726
@@ -42303,11 +46734,12 @@ namespace cimg_library_suffixed { @@ -42303,11 +46734,12 @@ namespace cimg_library_suffixed {
42303 const bool is_double_sided=true, const float focale=700, 46734 const bool is_double_sided=true, const float focale=700,
42304 const float light_x=0, const float light_y=0, const float light_z=-5e8f, 46735 const float light_x=0, const float light_y=0, const float light_z=-5e8f,
42305 const float specular_lightness=0.2f, const float specular_shininess=0.1f, 46736 const float specular_lightness=0.2f, const float specular_shininess=0.1f,
42306 - const bool display_axes=true, float *const pose_matrix=0) const { 46737 + const bool display_axes=true, float *const pose_matrix=0,
  46738 + const bool exit_on_anykey=false) const {
42307 return display_object3d(title,vertices,primitives,CImgList<T>(),centering, 46739 return display_object3d(title,vertices,primitives,CImgList<T>(),centering,
42308 render_static,render_motion,is_double_sided,focale, 46740 render_static,render_motion,is_double_sided,focale,
42309 light_x,light_y,light_z,specular_lightness,specular_shininess, 46741 light_x,light_y,light_z,specular_lightness,specular_shininess,
42310 - display_axes,pose_matrix); 46742 + display_axes,pose_matrix,exit_on_anykey);
42311 } 46743 }
42312 46744
42313 //! Display object 3d in an interactive window \simplification. 46745 //! Display object 3d in an interactive window \simplification.
@@ -42319,11 +46751,12 @@ namespace cimg_library_suffixed { @@ -42319,11 +46751,12 @@ namespace cimg_library_suffixed {
42319 const bool is_double_sided=true, const float focale=700, 46751 const bool is_double_sided=true, const float focale=700,
42320 const float light_x=0, const float light_y=0, const float light_z=-5e8f, 46752 const float light_x=0, const float light_y=0, const float light_z=-5e8f,
42321 const float specular_lightness=0.2f, const float specular_shininess=0.1f, 46753 const float specular_lightness=0.2f, const float specular_shininess=0.1f,
42322 - const bool display_axes=true, float *const pose_matrix=0) const { 46754 + const bool display_axes=true, float *const pose_matrix=0,
  46755 + const bool exit_on_anykey=false) const {
42323 return display_object3d(disp,vertices,CImgList<uintT>(),centering, 46756 return display_object3d(disp,vertices,CImgList<uintT>(),centering,
42324 render_static,render_motion,is_double_sided,focale, 46757 render_static,render_motion,is_double_sided,focale,
42325 light_x,light_y,light_z,specular_lightness,specular_shininess, 46758 light_x,light_y,light_z,specular_lightness,specular_shininess,
42326 - display_axes,pose_matrix); 46759 + display_axes,pose_matrix,exit_on_anykey);
42327 } 46760 }
42328 46761
42329 //! Display object 3d in an interactive window \simplification. 46762 //! Display object 3d in an interactive window \simplification.
@@ -42335,11 +46768,12 @@ namespace cimg_library_suffixed { @@ -42335,11 +46768,12 @@ namespace cimg_library_suffixed {
42335 const bool is_double_sided=true, const float focale=700, 46768 const bool is_double_sided=true, const float focale=700,
42336 const float light_x=0, const float light_y=0, const float light_z=-5e8f, 46769 const float light_x=0, const float light_y=0, const float light_z=-5e8f,
42337 const float specular_lightness=0.2f, const float specular_shininess=0.1f, 46770 const float specular_lightness=0.2f, const float specular_shininess=0.1f,
42338 - const bool display_axes=true, float *const pose_matrix=0) const { 46771 + const bool display_axes=true, float *const pose_matrix=0,
  46772 + const bool exit_on_anykey=false) const {
42339 return display_object3d(title,vertices,CImgList<uintT>(),centering, 46773 return display_object3d(title,vertices,CImgList<uintT>(),centering,
42340 render_static,render_motion,is_double_sided,focale, 46774 render_static,render_motion,is_double_sided,focale,
42341 light_x,light_y,light_z,specular_lightness,specular_shininess, 46775 light_x,light_y,light_z,specular_lightness,specular_shininess,
42342 - display_axes,pose_matrix); 46776 + display_axes,pose_matrix,exit_on_anykey);
42343 } 46777 }
42344 46778
42345 template<typename tp, typename tf, typename tc, typename to> 46779 template<typename tp, typename tf, typename tc, typename to>
@@ -42353,7 +46787,8 @@ namespace cimg_library_suffixed { @@ -42353,7 +46787,8 @@ namespace cimg_library_suffixed {
42353 const bool is_double_sided, const float focale, 46787 const bool is_double_sided, const float focale,
42354 const float light_x, const float light_y, const float light_z, 46788 const float light_x, const float light_y, const float light_z,
42355 const float specular_lightness, const float specular_shininess, 46789 const float specular_lightness, const float specular_shininess,
42356 - const bool display_axes, float *const pose_matrix) const { 46790 + const bool display_axes, float *const pose_matrix,
  46791 + const bool exit_on_anykey) const {
42357 typedef typename cimg::superset<tp,float>::type tpfloat; 46792 typedef typename cimg::superset<tp,float>::type tpfloat;
42358 46793
42359 // Check input arguments 46794 // Check input arguments
@@ -42362,14 +46797,14 @@ namespace cimg_library_suffixed { @@ -42362,14 +46797,14 @@ namespace cimg_library_suffixed {
42362 _display_object3d(disp,title,vertices,primitives,colors,opacities,centering, 46797 _display_object3d(disp,title,vertices,primitives,colors,opacities,centering,
42363 render_static,render_motion,is_double_sided,focale, 46798 render_static,render_motion,is_double_sided,focale,
42364 light_x,light_y,light_z,specular_lightness,specular_shininess, 46799 light_x,light_y,light_z,specular_lightness,specular_shininess,
42365 - display_axes,pose_matrix); 46800 + display_axes,pose_matrix,exit_on_anykey);
42366 else return CImg<T>(1,2,1,1,64,128).resize(cimg_fitscreen(CImgDisplay::screen_width()/2, 46801 else return CImg<T>(1,2,1,1,64,128).resize(cimg_fitscreen(CImgDisplay::screen_width()/2,
42367 CImgDisplay::screen_height()/2,1), 46802 CImgDisplay::screen_height()/2,1),
42368 1,(colors && colors[0].size()==1)?1:3,3). 46803 1,(colors && colors[0].size()==1)?1:3,3).
42369 _display_object3d(disp,title,vertices,primitives,colors,opacities,centering, 46804 _display_object3d(disp,title,vertices,primitives,colors,opacities,centering,
42370 render_static,render_motion,is_double_sided,focale, 46805 render_static,render_motion,is_double_sided,focale,
42371 light_x,light_y,light_z,specular_lightness,specular_shininess, 46806 light_x,light_y,light_z,specular_lightness,specular_shininess,
42372 - display_axes,pose_matrix); 46807 + display_axes,pose_matrix,exit_on_anykey);
42373 } else { if (disp) disp.resize(*this,false); } 46808 } else { if (disp) disp.resize(*this,false); }
42374 CImg<charT> error_message(1024); 46809 CImg<charT> error_message(1024);
42375 if (!vertices.is_object3d(primitives,colors,opacities,true,error_message)) 46810 if (!vertices.is_object3d(primitives,colors,opacities,true,error_message))
@@ -42382,7 +46817,7 @@ namespace cimg_library_suffixed { @@ -42382,7 +46817,7 @@ namespace cimg_library_suffixed {
42382 return _display_object3d(disp,title,vertices,nprimitives,colors,opacities,centering, 46817 return _display_object3d(disp,title,vertices,nprimitives,colors,opacities,centering,
42383 render_static,render_motion,is_double_sided,focale, 46818 render_static,render_motion,is_double_sided,focale,
42384 light_x,light_y,light_z,specular_lightness,specular_shininess, 46819 light_x,light_y,light_z,specular_lightness,specular_shininess,
42385 - display_axes,pose_matrix); 46820 + display_axes,pose_matrix,exit_on_anykey);
42386 } 46821 }
42387 if (!disp) { 46822 if (!disp) {
42388 disp.assign(cimg_fitscreen(_width,_height,_depth),title?title:0,3); 46823 disp.assign(cimg_fitscreen(_width,_height,_depth),title?title:0,3);
@@ -42583,6 +47018,7 @@ namespace cimg_library_suffixed { @@ -42583,6 +47018,7 @@ namespace cimg_library_suffixed {
42583 } 47018 }
42584 } else if (clicked) { x0 = x1; y0 = y1; clicked = false; redraw = true; } 47019 } else if (clicked) { x0 = x1; y0 = y1; clicked = false; redraw = true; }
42585 47020
  47021 + CImg<charT> filename(32);
42586 switch (key = disp.key()) { 47022 switch (key = disp.key()) {
42587 #if cimg_OS!=2 47023 #if cimg_OS!=2
42588 case cimg::keyCTRLRIGHT : 47024 case cimg::keyCTRLRIGHT :
@@ -42661,43 +47097,40 @@ namespace cimg_library_suffixed { @@ -42661,43 +47097,40 @@ namespace cimg_library_suffixed {
42661 } break; 47097 } break;
42662 case cimg::keyS : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Save snapshot 47098 case cimg::keyS : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Save snapshot
42663 static unsigned int snap_number = 0; 47099 static unsigned int snap_number = 0;
42664 - char filename[32] = { 0 };  
42665 std::FILE *file; 47100 std::FILE *file;
42666 do { 47101 do {
42667 - cimg_snprintf(filename,sizeof(filename),cimg_appname "_%.4u.bmp",snap_number++); 47102 + cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.bmp",snap_number++);
42668 if ((file=std::fopen(filename,"r"))!=0) cimg::fclose(file); 47103 if ((file=std::fopen(filename,"r"))!=0) cimg::fclose(file);
42669 } while (file); 47104 } while (file);
42670 (+visu).draw_text(0,0," Saving snapshot... ", 47105 (+visu).draw_text(0,0," Saving snapshot... ",
42671 foreground_color._data,background_color._data,0.7f,13).display(disp); 47106 foreground_color._data,background_color._data,0.7f,13).display(disp);
42672 visu.save(filename); 47107 visu.save(filename);
42673 (+visu).draw_text(0,0," Snapshot '%s' saved. ", 47108 (+visu).draw_text(0,0," Snapshot '%s' saved. ",
42674 - foreground_color._data,background_color._data,0.7f,13,filename).display(disp); 47109 + foreground_color._data,background_color._data,0.7f,13,filename._data).display(disp);
42675 disp.set_key(key,false); key = 0; 47110 disp.set_key(key,false); key = 0;
42676 } break; 47111 } break;
42677 case cimg::keyG : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Save object as a .off file 47112 case cimg::keyG : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Save object as a .off file
42678 static unsigned int snap_number = 0; 47113 static unsigned int snap_number = 0;
42679 - char filename[32] = { 0 };  
42680 std::FILE *file; 47114 std::FILE *file;
42681 do { 47115 do {
42682 - cimg_snprintf(filename,sizeof(filename),cimg_appname "_%.4u.off",snap_number++); 47116 + cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.off",snap_number++);
42683 if ((file=std::fopen(filename,"r"))!=0) cimg::fclose(file); 47117 if ((file=std::fopen(filename,"r"))!=0) cimg::fclose(file);
42684 } while (file); 47118 } while (file);
42685 (+visu).draw_text(0,0," Saving object... ", 47119 (+visu).draw_text(0,0," Saving object... ",
42686 foreground_color._data,background_color._data,0.7f,13).display(disp); 47120 foreground_color._data,background_color._data,0.7f,13).display(disp);
42687 vertices.save_off(reverse_primitives?reverse_primitives:primitives,colors,filename); 47121 vertices.save_off(reverse_primitives?reverse_primitives:primitives,colors,filename);
42688 (+visu).draw_text(0,0," Object '%s' saved. ", 47122 (+visu).draw_text(0,0," Object '%s' saved. ",
42689 - foreground_color._data,background_color._data,0.7f,13,filename).display(disp); 47123 + foreground_color._data,background_color._data,0.7f,13,filename._data).display(disp);
42690 disp.set_key(key,false); key = 0; 47124 disp.set_key(key,false); key = 0;
42691 } break; 47125 } break;
42692 case cimg::keyO : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Save object as a .cimg file 47126 case cimg::keyO : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Save object as a .cimg file
42693 static unsigned int snap_number = 0; 47127 static unsigned int snap_number = 0;
42694 - char filename[32] = { 0 };  
42695 std::FILE *file; 47128 std::FILE *file;
42696 do { 47129 do {
42697 #ifdef cimg_use_zlib 47130 #ifdef cimg_use_zlib
42698 - cimg_snprintf(filename,sizeof(filename),cimg_appname "_%.4u.cimgz",snap_number++); 47131 + cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.cimgz",snap_number++);
42699 #else 47132 #else
42700 - cimg_snprintf(filename,sizeof(filename),cimg_appname "_%.4u.cimg",snap_number++); 47133 + cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.cimg",snap_number++);
42701 #endif 47134 #endif
42702 if ((file=std::fopen(filename,"r"))!=0) cimg::fclose(file); 47135 if ((file=std::fopen(filename,"r"))!=0) cimg::fclose(file);
42703 } while (file); 47136 } while (file);
@@ -42706,16 +47139,15 @@ namespace cimg_library_suffixed { @@ -42706,16 +47139,15 @@ namespace cimg_library_suffixed {
42706 vertices.get_object3dtoCImg3d(reverse_primitives?reverse_primitives:primitives,colors,opacities). 47139 vertices.get_object3dtoCImg3d(reverse_primitives?reverse_primitives:primitives,colors,opacities).
42707 save(filename); 47140 save(filename);
42708 (+visu).draw_text(0,0," Object '%s' saved. ", 47141 (+visu).draw_text(0,0," Object '%s' saved. ",
42709 - foreground_color._data,background_color._data,0.7f,13,filename).display(disp); 47142 + foreground_color._data,background_color._data,0.7f,13,filename._data).display(disp);
42710 disp.set_key(key,false); key = 0; 47143 disp.set_key(key,false); key = 0;
42711 } break; 47144 } break;
42712 #ifdef cimg_use_board 47145 #ifdef cimg_use_board
42713 case cimg::keyP : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Save object as a .EPS file 47146 case cimg::keyP : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Save object as a .EPS file
42714 static unsigned int snap_number = 0; 47147 static unsigned int snap_number = 0;
42715 - char filename[32] = { 0 };  
42716 std::FILE *file; 47148 std::FILE *file;
42717 do { 47149 do {
42718 - cimg_snprintf(filename,sizeof(filename),cimg_appname "_%.4u.eps",snap_number++); 47150 + cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.eps",snap_number++);
42719 if ((file=std::fopen(filename,"r"))!=0) cimg::fclose(file); 47151 if ((file=std::fopen(filename,"r"))!=0) cimg::fclose(file);
42720 } while (file); 47152 } while (file);
42721 (+visu).draw_text(0,0," Saving EPS snapshot... ", 47153 (+visu).draw_text(0,0," Saving EPS snapshot... ",
@@ -42731,15 +47163,14 @@ namespace cimg_library_suffixed { @@ -42731,15 +47163,14 @@ namespace cimg_library_suffixed {
42731 sprite_scale); 47163 sprite_scale);
42732 board.saveEPS(filename); 47164 board.saveEPS(filename);
42733 (+visu).draw_text(0,0," Object '%s' saved. ", 47165 (+visu).draw_text(0,0," Object '%s' saved. ",
42734 - foreground_color._data,background_color._data,0.7f,13,filename).display(disp); 47166 + foreground_color._data,background_color._data,0.7f,13,filename._data).display(disp);
42735 disp.set_key(key,false); key = 0; 47167 disp.set_key(key,false); key = 0;
42736 } break; 47168 } break;
42737 case cimg::keyV : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Save object as a .SVG file 47169 case cimg::keyV : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Save object as a .SVG file
42738 static unsigned int snap_number = 0; 47170 static unsigned int snap_number = 0;
42739 - char filename[32] = { 0 };  
42740 std::FILE *file; 47171 std::FILE *file;
42741 do { 47172 do {
42742 - cimg_snprintf(filename,sizeof(filename),cimg_appname "_%.4u.svg",snap_number++); 47173 + cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.svg",snap_number++);
42743 if ((file=std::fopen(filename,"r"))!=0) cimg::fclose(file); 47174 if ((file=std::fopen(filename,"r"))!=0) cimg::fclose(file);
42744 } while (file); 47175 } while (file);
42745 (+visu).draw_text(0,0," Saving SVG snapshot... ", 47176 (+visu).draw_text(0,0," Saving SVG snapshot... ",
@@ -42755,7 +47186,7 @@ namespace cimg_library_suffixed { @@ -42755,7 +47186,7 @@ namespace cimg_library_suffixed {
42755 sprite_scale); 47186 sprite_scale);
42756 board.saveSVG(filename); 47187 board.saveSVG(filename);
42757 (+visu).draw_text(0,0," Object '%s' saved. ", 47188 (+visu).draw_text(0,0," Object '%s' saved. ",
42758 - foreground_color._data,background_color._data,0.7f,13,filename).display(disp); 47189 + foreground_color._data,background_color._data,0.7f,13,filename._data).display(disp);
42759 disp.set_key(key,false); key = 0; 47190 disp.set_key(key,false); key = 0;
42760 } break; 47191 } break;
42761 #endif 47192 #endif
@@ -42765,6 +47196,10 @@ namespace cimg_library_suffixed { @@ -42765,6 +47196,10 @@ namespace cimg_library_suffixed {
42765 if (zbuffer) zbuffer.assign(disp.width(),disp.height()); 47196 if (zbuffer) zbuffer.assign(disp.width(),disp.height());
42766 redraw = true; 47197 redraw = true;
42767 } 47198 }
  47199 + if (!exit_on_anykey && key && key!=cimg::keyESC &&
  47200 + (key!=cimg::keyW || (!disp.is_keyCTRLLEFT() && !disp.is_keyCTRLRIGHT()))) {
  47201 + key = 0;
  47202 + }
42768 } 47203 }
42769 if (pose_matrix) { 47204 if (pose_matrix) {
42770 std::memcpy(pose_matrix,pose._data,12*sizeof(float)); 47205 std::memcpy(pose_matrix,pose._data,12*sizeof(float));
@@ -42789,23 +47224,26 @@ namespace cimg_library_suffixed { @@ -42789,23 +47224,26 @@ namespace cimg_library_suffixed {
42789 const CImg<T>& display_graph(CImgDisplay &disp, 47224 const CImg<T>& display_graph(CImgDisplay &disp,
42790 const unsigned int plot_type=1, const unsigned int vertex_type=1, 47225 const unsigned int plot_type=1, const unsigned int vertex_type=1,
42791 const char *const labelx=0, const double xmin=0, const double xmax=0, 47226 const char *const labelx=0, const double xmin=0, const double xmax=0,
42792 - const char *const labely=0, const double ymin=0, const double ymax=0) const {  
42793 - return _display_graph(disp,0,plot_type,vertex_type,labelx,xmin,xmax,labely,ymin,ymax); 47227 + const char *const labely=0, const double ymin=0, const double ymax=0,
  47228 + const bool exit_on_anykey=false) const {
  47229 + return _display_graph(disp,0,plot_type,vertex_type,labelx,xmin,xmax,labely,ymin,ymax,exit_on_anykey);
42794 } 47230 }
42795 47231
42796 //! Display 1d graph in an interactive window \overloading. 47232 //! Display 1d graph in an interactive window \overloading.
42797 const CImg<T>& display_graph(const char *const title=0, 47233 const CImg<T>& display_graph(const char *const title=0,
42798 const unsigned int plot_type=1, const unsigned int vertex_type=1, 47234 const unsigned int plot_type=1, const unsigned int vertex_type=1,
42799 const char *const labelx=0, const double xmin=0, const double xmax=0, 47235 const char *const labelx=0, const double xmin=0, const double xmax=0,
42800 - const char *const labely=0, const double ymin=0, const double ymax=0) const { 47236 + const char *const labely=0, const double ymin=0, const double ymax=0,
  47237 + const bool exit_on_anykey=false) const {
42801 CImgDisplay disp; 47238 CImgDisplay disp;
42802 - return _display_graph(disp,title,plot_type,vertex_type,labelx,xmin,xmax,labely,ymin,ymax); 47239 + return _display_graph(disp,title,plot_type,vertex_type,labelx,xmin,xmax,labely,ymin,ymax,exit_on_anykey);
42803 } 47240 }
42804 47241
42805 const CImg<T>& _display_graph(CImgDisplay &disp, const char *const title=0, 47242 const CImg<T>& _display_graph(CImgDisplay &disp, const char *const title=0,
42806 - const unsigned int plot_type=1, const unsigned int vertex_type=1,  
42807 - const char *const labelx=0, const double xmin=0, const double xmax=0,  
42808 - const char *const labely=0, const double ymin=0, const double ymax=0) const { 47243 + const unsigned int plot_type=1, const unsigned int vertex_type=1,
  47244 + const char *const labelx=0, const double xmin=0, const double xmax=0,
  47245 + const char *const labely=0, const double ymin=0, const double ymax=0,
  47246 + const bool exit_on_anykey=false) const {
42809 if (is_empty()) 47247 if (is_empty())
42810 throw CImgInstanceException(_cimg_instance 47248 throw CImgInstanceException(_cimg_instance
42811 "display_graph(): Empty instance.", 47249 "display_graph(): Empty instance.",
@@ -42831,7 +47269,7 @@ namespace cimg_library_suffixed { @@ -42831,7 +47269,7 @@ namespace cimg_library_suffixed {
42831 labelx, 47269 labelx,
42832 nxmin + x0*(nxmax - nxmin)/siz1, 47270 nxmin + x0*(nxmax - nxmin)/siz1,
42833 nxmin + x1*(nxmax - nxmin)/siz1, 47271 nxmin + x1*(nxmax - nxmin)/siz1,
42834 - labely,y0,y1); 47272 + labely,y0,y1,true);
42835 const int mouse_x = disp.mouse_x(), mouse_y = disp.mouse_y(); 47273 const int mouse_x = disp.mouse_x(), mouse_y = disp.mouse_y();
42836 if (selection[0]>=0) { 47274 if (selection[0]>=0) {
42837 if (selection[2]<0) reset_view = true; 47275 if (selection[2]<0) reset_view = true;
@@ -42860,9 +47298,9 @@ namespace cimg_library_suffixed { @@ -42860,9 +47298,9 @@ namespace cimg_library_suffixed {
42860 case cimg::keyPAD3 : go_right = true; go_down = true; key = 0; disp.set_key(); break; 47298 case cimg::keyPAD3 : go_right = true; go_down = true; key = 0; disp.set_key(); break;
42861 } 47299 }
42862 if (disp.wheel()) { 47300 if (disp.wheel()) {
42863 - if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) go_out = !(go_in = disp.wheel()>0); 47301 + if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) go_up = !(go_down = disp.wheel()<0);
42864 else if (disp.is_keySHIFTLEFT() || disp.is_keySHIFTRIGHT()) go_left = !(go_right = disp.wheel()>0); 47302 else if (disp.is_keySHIFTLEFT() || disp.is_keySHIFTRIGHT()) go_left = !(go_right = disp.wheel()>0);
42865 - else go_up = !(go_down = disp.wheel()<0); 47303 + else go_out = !(go_in = disp.wheel()>0);
42866 key = 0; 47304 key = 0;
42867 } 47305 }
42868 47306
@@ -42915,6 +47353,11 @@ namespace cimg_library_suffixed { @@ -42915,6 +47353,11 @@ namespace cimg_library_suffixed {
42915 go_down = false; 47353 go_down = false;
42916 } 47354 }
42917 } 47355 }
  47356 + if (!exit_on_anykey && key && key!=(int)cimg::keyESC &&
  47357 + (key!=(int)cimg::keyW || (!disp.is_keyCTRLLEFT() && !disp.is_keyCTRLRIGHT()))) {
  47358 + disp.set_key(key,false);
  47359 + key = 0;
  47360 + }
42918 } 47361 }
42919 disp._normalization = old_normalization; 47362 disp._normalization = old_normalization;
42920 return *this; 47363 return *this;
@@ -43176,7 +47619,8 @@ namespace cimg_library_suffixed { @@ -43176,7 +47619,8 @@ namespace cimg_library_suffixed {
43176 filename?filename:"(FILE*)"); 47619 filename?filename:"(FILE*)");
43177 47620
43178 std::FILE *const nfile = file?file:cimg::fopen(filename,"wb"); 47621 std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
43179 - unsigned char header[54] = { 0 }, align_buf[4] = { 0 }; 47622 + CImg<ucharT> header(54,1,1,1,0);
  47623 + unsigned char align_buf[4] = { 0 };
43180 const unsigned int 47624 const unsigned int
43181 align = (4 - (3*_width)%4)%4, 47625 align = (4 - (3*_width)%4)%4,
43182 buf_size = (3*_width + align)*height(), 47626 buf_size = (3*_width + align)*height(),
@@ -43206,7 +47650,7 @@ namespace cimg_library_suffixed { @@ -43206,7 +47650,7 @@ namespace cimg_library_suffixed {
43206 header[0x25] = (buf_size>>24)&0xFF; 47650 header[0x25] = (buf_size>>24)&0xFF;
43207 header[0x27] = 0x1; 47651 header[0x27] = 0x1;
43208 header[0x2B] = 0x1; 47652 header[0x2B] = 0x1;
43209 - cimg::fwrite(header,54,nfile); 47653 + cimg::fwrite(header._data,54,nfile);
43210 47654
43211 const T 47655 const T
43212 *ptr_r = data(0,_height - 1,0,0), 47656 *ptr_r = data(0,_height - 1,0,0),
@@ -43286,7 +47730,7 @@ namespace cimg_library_suffixed { @@ -43286,7 +47730,7 @@ namespace cimg_library_suffixed {
43286 unsigned int dimbuf = 0; 47730 unsigned int dimbuf = 0;
43287 J_COLOR_SPACE colortype = JCS_RGB; 47731 J_COLOR_SPACE colortype = JCS_RGB;
43288 47732
43289 - switch(_spectrum) { 47733 + switch (_spectrum) {
43290 case 1 : dimbuf = 1; colortype = JCS_GRAYSCALE; break; 47734 case 1 : dimbuf = 1; colortype = JCS_GRAYSCALE; break;
43291 case 2 : dimbuf = 3; colortype = JCS_RGB; break; 47735 case 2 : dimbuf = 3; colortype = JCS_RGB; break;
43292 case 3 : dimbuf = 3; colortype = JCS_RGB; break; 47736 case 3 : dimbuf = 3; colortype = JCS_RGB; break;
@@ -43318,13 +47762,13 @@ namespace cimg_library_suffixed { @@ -43318,13 +47762,13 @@ namespace cimg_library_suffixed {
43318 switch (_spectrum) { 47762 switch (_spectrum) {
43319 case 1 : { // Greyscale images 47763 case 1 : { // Greyscale images
43320 const T *ptr_g = data(0, cinfo.next_scanline); 47764 const T *ptr_g = data(0, cinfo.next_scanline);
43321 - for(unsigned int b = 0; b < cinfo.image_width; b++) 47765 + for (unsigned int b = 0; b<cinfo.image_width; b++)
43322 *(ptrd++) = (unsigned char)*(ptr_g++); 47766 *(ptrd++) = (unsigned char)*(ptr_g++);
43323 } break; 47767 } break;
43324 case 2 : { // RG images 47768 case 2 : { // RG images
43325 const T *ptr_r = data(0,cinfo.next_scanline,0,0), 47769 const T *ptr_r = data(0,cinfo.next_scanline,0,0),
43326 *ptr_g = data(0,cinfo.next_scanline,0,1); 47770 *ptr_g = data(0,cinfo.next_scanline,0,1);
43327 - for(unsigned int b = 0; b < cinfo.image_width; ++b) { 47771 + for (unsigned int b = 0; b<cinfo.image_width; ++b) {
43328 *(ptrd++) = (unsigned char)*(ptr_r++); 47772 *(ptrd++) = (unsigned char)*(ptr_r++);
43329 *(ptrd++) = (unsigned char)*(ptr_g++); 47773 *(ptrd++) = (unsigned char)*(ptr_g++);
43330 *(ptrd++) = 0; 47774 *(ptrd++) = 0;
@@ -43334,7 +47778,7 @@ namespace cimg_library_suffixed { @@ -43334,7 +47778,7 @@ namespace cimg_library_suffixed {
43334 const T *ptr_r = data(0,cinfo.next_scanline,0,0), 47778 const T *ptr_r = data(0,cinfo.next_scanline,0,0),
43335 *ptr_g = data(0,cinfo.next_scanline,0,1), 47779 *ptr_g = data(0,cinfo.next_scanline,0,1),
43336 *ptr_b = data(0,cinfo.next_scanline,0,2); 47780 *ptr_b = data(0,cinfo.next_scanline,0,2);
43337 - for(unsigned int b = 0; b < cinfo.image_width; ++b) { 47781 + for (unsigned int b = 0; b<cinfo.image_width; ++b) {
43338 *(ptrd++) = (unsigned char)*(ptr_r++); 47782 *(ptrd++) = (unsigned char)*(ptr_r++);
43339 *(ptrd++) = (unsigned char)*(ptr_g++); 47783 *(ptrd++) = (unsigned char)*(ptr_g++);
43340 *(ptrd++) = (unsigned char)*(ptr_b++); 47784 *(ptrd++) = (unsigned char)*(ptr_b++);
@@ -43345,7 +47789,7 @@ namespace cimg_library_suffixed { @@ -43345,7 +47789,7 @@ namespace cimg_library_suffixed {
43345 *ptr_g = data(0,cinfo.next_scanline,0,1), 47789 *ptr_g = data(0,cinfo.next_scanline,0,1),
43346 *ptr_b = data(0,cinfo.next_scanline,0,2), 47790 *ptr_b = data(0,cinfo.next_scanline,0,2),
43347 *ptr_a = data(0,cinfo.next_scanline,0,3); 47791 *ptr_a = data(0,cinfo.next_scanline,0,3);
43348 - for(unsigned int b = 0; b < cinfo.image_width; ++b) { 47792 + for (unsigned int b = 0; b<cinfo.image_width; ++b) {
43349 *(ptrd++) = (unsigned char)*(ptr_r++); 47793 *(ptrd++) = (unsigned char)*(ptr_r++);
43350 *(ptrd++) = (unsigned char)*(ptr_g++); 47794 *(ptrd++) = (unsigned char)*(ptr_g++);
43351 *(ptrd++) = (unsigned char)*(ptr_b++); 47795 *(ptrd++) = (unsigned char)*(ptr_b++);
@@ -44087,11 +48531,12 @@ namespace cimg_library_suffixed { @@ -44087,11 +48531,12 @@ namespace cimg_library_suffixed {
44087 - When libtiff is enabled, 2D and 3D (multipage) several 48531 - When libtiff is enabled, 2D and 3D (multipage) several
44088 channel per pixel are supported for 48532 channel per pixel are supported for
44089 <tt>char,uchar,short,ushort,float</tt> and \c double pixel types. 48533 <tt>char,uchar,short,ushort,float</tt> and \c double pixel types.
44090 - - If \c cimg_use_tif is not defined at compilation time the 48534 + - If \c cimg_use_tif is not defined at compile time the
44091 function uses CImg<T>&save_other(const char*). 48535 function uses CImg<T>&save_other(const char*).
44092 **/ 48536 **/
44093 const CImg<T>& save_tiff(const char *const filename, const unsigned int compression_type=0, 48537 const CImg<T>& save_tiff(const char *const filename, const unsigned int compression_type=0,
44094 - const float *const voxel_size=0, const char *const description=0) const { 48538 + const float *const voxel_size=0, const char *const description=0,
  48539 + const bool is_bigtiff=true) const {
44095 if (!filename) 48540 if (!filename)
44096 throw CImgArgumentException(_cimg_instance 48541 throw CImgArgumentException(_cimg_instance
44097 "save_tiff(): Specified filename is (null).", 48542 "save_tiff(): Specified filename is (null).",
@@ -44099,9 +48544,9 @@ namespace cimg_library_suffixed { @@ -44099,9 +48544,9 @@ namespace cimg_library_suffixed {
44099 if (is_empty()) { cimg::fempty(0,filename); return *this; } 48544 if (is_empty()) { cimg::fempty(0,filename); return *this; }
44100 48545
44101 #ifdef cimg_use_tiff 48546 #ifdef cimg_use_tiff
44102 - TIFF *tif = TIFFOpen(filename,"w"); 48547 + TIFF *tif = TIFFOpen(filename,is_bigtiff?"w8":"w4");
44103 if (tif) { 48548 if (tif) {
44104 - cimg_forZ(*this,z) get_slice(z)._save_tiff(tif,z,compression_type,voxel_size,description); 48549 + cimg_forZ(*this,z) _save_tiff(tif,z,z,compression_type,voxel_size,description);
44105 TIFFClose(tif); 48550 TIFFClose(tif);
44106 } else throw CImgIOException(_cimg_instance 48551 } else throw CImgIOException(_cimg_instance
44107 "save_tiff(): Failed to open file '%s' for writing.", 48552 "save_tiff(): Failed to open file '%s' for writing.",
@@ -44109,7 +48554,7 @@ namespace cimg_library_suffixed { @@ -44109,7 +48554,7 @@ namespace cimg_library_suffixed {
44109 filename); 48554 filename);
44110 return *this; 48555 return *this;
44111 #else 48556 #else
44112 - cimg::unused(compression_type,voxel_size,description); 48557 + cimg::unused(compression_type,voxel_size,description,is_bigtiff);
44113 return save_other(filename); 48558 return save_other(filename);
44114 #endif 48559 #endif
44115 } 48560 }
@@ -44117,13 +48562,13 @@ namespace cimg_library_suffixed { @@ -44117,13 +48562,13 @@ namespace cimg_library_suffixed {
44117 #ifdef cimg_use_tiff 48562 #ifdef cimg_use_tiff
44118 48563
44119 #define _cimg_save_tiff(types,typed,compression_type) if (!std::strcmp(types,pixel_type())) { \ 48564 #define _cimg_save_tiff(types,typed,compression_type) if (!std::strcmp(types,pixel_type())) { \
44120 - const typed foo = (typed)0; return _save_tiff(tif,directory,foo,compression_type,voxel_size,description); } 48565 + const typed foo = (typed)0; return _save_tiff(tif,directory,z,foo,compression_type,voxel_size,description); }
44121 48566
44122 // [internal] Save a plane into a tiff file 48567 // [internal] Save a plane into a tiff file
44123 template<typename t> 48568 template<typename t>
44124 - const CImg<T>& _save_tiff(TIFF *tif, const unsigned int directory, const t& pixel_t,  
44125 - const unsigned int compression_type,  
44126 - const float *const voxel_size, const char *const description) const { 48569 + const CImg<T>& _save_tiff(TIFF *tif, const unsigned int directory, const unsigned int z, const t& pixel_t,
  48570 + const unsigned int compression_type, const float *const voxel_size,
  48571 + const char *const description) const {
44127 if (is_empty() || !tif || pixel_t) return *this; 48572 if (is_empty() || !tif || pixel_t) return *this;
44128 const char *const filename = TIFFFileName(tif); 48573 const char *const filename = TIFFFileName(tif);
44129 uint32 rowsperstrip = (uint32)-1; 48574 uint32 rowsperstrip = (uint32)-1;
@@ -44166,7 +48611,7 @@ namespace cimg_library_suffixed { @@ -44166,7 +48611,7 @@ namespace cimg_library_suffixed {
44166 for (unsigned int rr = 0; rr<nrow; ++rr) 48611 for (unsigned int rr = 0; rr<nrow; ++rr)
44167 for (unsigned int cc = 0; cc<_width; ++cc) 48612 for (unsigned int cc = 0; cc<_width; ++cc)
44168 for (unsigned int vv = 0; vv<spp; ++vv) 48613 for (unsigned int vv = 0; vv<spp; ++vv)
44169 - buf[i++] = (t)(*this)(cc,row + rr,0,vv); 48614 + buf[i++] = (t)(*this)(cc,row + rr,z,vv);
44170 if (TIFFWriteEncodedStrip(tif,strip,buf,i*sizeof(t))<0) 48615 if (TIFFWriteEncodedStrip(tif,strip,buf,i*sizeof(t))<0)
44171 throw CImgIOException(_cimg_instance 48616 throw CImgIOException(_cimg_instance
44172 "save_tiff(): Invalid strip writing when saving file '%s'.", 48617 "save_tiff(): Invalid strip writing when saving file '%s'.",
@@ -44179,8 +48624,9 @@ namespace cimg_library_suffixed { @@ -44179,8 +48624,9 @@ namespace cimg_library_suffixed {
44179 return (*this); 48624 return (*this);
44180 } 48625 }
44181 48626
44182 - const CImg<T>& _save_tiff(TIFF *tif, const unsigned int directory, const unsigned int compression_type,  
44183 - const float *const voxel_size, const char *const description) const { 48627 + const CImg<T>& _save_tiff(TIFF *tif, const unsigned int directory, const unsigned int z,
  48628 + const unsigned int compression_type, const float *const voxel_size,
  48629 + const char *const description) const {
44184 _cimg_save_tiff("bool",unsigned char,compression_type); 48630 _cimg_save_tiff("bool",unsigned char,compression_type);
44185 _cimg_save_tiff("char",char,compression_type); 48631 _cimg_save_tiff("char",char,compression_type);
44186 _cimg_save_tiff("unsigned char",unsigned char,compression_type); 48632 _cimg_save_tiff("unsigned char",unsigned char,compression_type);
@@ -44255,11 +48701,9 @@ namespace cimg_library_suffixed { @@ -44255,11 +48701,9 @@ namespace cimg_library_suffixed {
44255 if (is_empty()) { cimg::fempty(0,filename); return *this; } 48701 if (is_empty()) { cimg::fempty(0,filename); return *this; }
44256 48702
44257 std::FILE *file; 48703 std::FILE *file;
44258 - char header[348] = { 0 };  
44259 - CImg<charT> hname(1024), iname(1024); 48704 + CImg<charT> header(348,1,1,1,0), hname(1024), iname(1024);
44260 const char *const ext = cimg::split_filename(filename); 48705 const char *const ext = cimg::split_filename(filename);
44261 short datatype = -1; 48706 short datatype = -1;
44262 - std::memset(header,0,348);  
44263 if (!*ext) { 48707 if (!*ext) {
44264 cimg_snprintf(hname,hname._width,"%s.hdr",filename); 48708 cimg_snprintf(hname,hname._width,"%s.hdr",filename);
44265 cimg_snprintf(iname,iname._width,"%s.img",filename); 48709 cimg_snprintf(iname,iname._width,"%s.img",filename);
@@ -44267,27 +48711,27 @@ namespace cimg_library_suffixed { @@ -44267,27 +48711,27 @@ namespace cimg_library_suffixed {
44267 if (!cimg::strncasecmp(ext,"hdr",3)) { 48711 if (!cimg::strncasecmp(ext,"hdr",3)) {
44268 std::strcpy(hname,filename); 48712 std::strcpy(hname,filename);
44269 std::strncpy(iname,filename,iname._width - 1); 48713 std::strncpy(iname,filename,iname._width - 1);
44270 - std::sprintf(iname._data + std::strlen(iname) - 3,"img"); 48714 + cimg_sprintf(iname._data + std::strlen(iname) - 3,"img");
44271 } 48715 }
44272 if (!cimg::strncasecmp(ext,"img",3)) { 48716 if (!cimg::strncasecmp(ext,"img",3)) {
44273 std::strcpy(hname,filename); 48717 std::strcpy(hname,filename);
44274 std::strncpy(iname,filename,iname._width - 1); 48718 std::strncpy(iname,filename,iname._width - 1);
44275 - std::sprintf(hname._data + std::strlen(iname) - 3,"hdr"); 48719 + cimg_sprintf(hname._data + std::strlen(iname) - 3,"hdr");
44276 } 48720 }
44277 if (!cimg::strncasecmp(ext,"nii",3)) { 48721 if (!cimg::strncasecmp(ext,"nii",3)) {
44278 std::strncpy(hname,filename,hname._width - 1); *iname = 0; 48722 std::strncpy(hname,filename,hname._width - 1); *iname = 0;
44279 } 48723 }
44280 - int *const iheader = (int*)header; 48724 + int *const iheader = (int*)header._data;
44281 *iheader = 348; 48725 *iheader = 348;
44282 - std::strcpy(header + 4,"CImg");  
44283 - std::strcpy(header + 14," ");  
44284 - ((short*)(header + 36))[0] = 4096;  
44285 - ((char*)(header + 38))[0] = 114;  
44286 - ((short*)(header + 40))[0] = 4;  
44287 - ((short*)(header + 40))[1] = (short)_width;  
44288 - ((short*)(header + 40))[2] = (short)_height;  
44289 - ((short*)(header + 40))[3] = (short)_depth;  
44290 - ((short*)(header + 40))[4] = (short)_spectrum; 48726 + std::strcpy(header._data + 4,"CImg");
  48727 + std::strcpy(header._data + 14," ");
  48728 + ((short*)&(header[36]))[0] = 4096;
  48729 + ((char*)&(header[38]))[0] = 114;
  48730 + ((short*)&(header[40]))[0] = 4;
  48731 + ((short*)&(header[40]))[1] = (short)_width;
  48732 + ((short*)&(header[40]))[2] = (short)_height;
  48733 + ((short*)&(header[40]))[3] = (short)_depth;
  48734 + ((short*)&(header[40]))[4] = (short)_spectrum;
44291 if (!cimg::strcasecmp(pixel_type(),"bool")) datatype = 2; 48735 if (!cimg::strcasecmp(pixel_type(),"bool")) datatype = 2;
44292 if (!cimg::strcasecmp(pixel_type(),"unsigned char")) datatype = 2; 48736 if (!cimg::strcasecmp(pixel_type(),"unsigned char")) datatype = 2;
44293 if (!cimg::strcasecmp(pixel_type(),"char")) datatype = 2; 48737 if (!cimg::strcasecmp(pixel_type(),"char")) datatype = 2;
@@ -44305,17 +48749,17 @@ namespace cimg_library_suffixed { @@ -44305,17 +48749,17 @@ namespace cimg_library_suffixed {
44305 cimg_instance, 48749 cimg_instance,
44306 pixel_type(),filename); 48750 pixel_type(),filename);
44307 48751
44308 - ((short*)(header + 70))[0] = datatype;  
44309 - ((short*)(header + 72))[0] = sizeof(T);  
44310 - ((float*)(header + 112))[0] = 1;  
44311 - ((float*)(header + 76))[0] = 0; 48752 + ((short*)&(header[70]))[0] = datatype;
  48753 + ((short*)&(header[72]))[0] = sizeof(T);
  48754 + ((float*)&(header[112]))[0] = 1;
  48755 + ((float*)&(header[76]))[0] = 0;
44312 if (voxel_size) { 48756 if (voxel_size) {
44313 - ((float*)(header + 76))[1] = voxel_size[0];  
44314 - ((float*)(header + 76))[2] = voxel_size[1];  
44315 - ((float*)(header + 76))[3] = voxel_size[2];  
44316 - } else ((float*)(header + 76))[1] = ((float*)(header + 76))[2] = ((float*)(header + 76))[3] = 1; 48757 + ((float*)&(header[76]))[1] = voxel_size[0];
  48758 + ((float*)&(header[76]))[2] = voxel_size[1];
  48759 + ((float*)&(header[76]))[3] = voxel_size[2];
  48760 + } else ((float*)&(header[76]))[1] = ((float*)&(header[76]))[2] = ((float*)&(header[76]))[3] = 1;
44317 file = cimg::fopen(hname,"wb"); 48761 file = cimg::fopen(hname,"wb");
44318 - cimg::fwrite(header,348,file); 48762 + cimg::fwrite(header._data,348,file);
44319 if (*iname) { cimg::fclose(file); file = cimg::fopen(iname,"wb"); } 48763 if (*iname) { cimg::fclose(file); file = cimg::fopen(iname,"wb"); }
44320 cimg::fwrite(_data,size(),file); 48764 cimg::fwrite(_data,size(),file);
44321 cimg::fclose(file); 48765 cimg::fclose(file);
@@ -44446,14 +48890,15 @@ namespace cimg_library_suffixed { @@ -44446,14 +48890,15 @@ namespace cimg_library_suffixed {
44446 pixel_type(),filename?filename:"(FILE*)"); 48890 pixel_type(),filename?filename:"(FILE*)");
44447 48891
44448 std::FILE *const nfile = file?file:cimg::fopen(filename,"wb"); 48892 std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
44449 - char header[257] = { 0 };  
44450 - int err = cimg_snprintf(header,sizeof(header),"#INRIMAGE-4#{\nXDIM=%u\nYDIM=%u\nZDIM=%u\nVDIM=%u\n", 48893 + CImg<charT> header(257);
  48894 + int err = cimg_snprintf(header,header._width,"#INRIMAGE-4#{\nXDIM=%u\nYDIM=%u\nZDIM=%u\nVDIM=%u\n",
44451 _width,_height,_depth,_spectrum); 48895 _width,_height,_depth,_spectrum);
44452 - if (voxel_size) err+=std::sprintf(header + err,"VX=%g\nVY=%g\nVZ=%g\n",voxel_size[0],voxel_size[1],voxel_size[2]);  
44453 - err+=std::sprintf(header + err,"TYPE=%s\nCPU=%s\n",inrtype,cimg::endianness()?"sun":"decm");  
44454 - std::memset(header + err,'\n',252 - err);  
44455 - std::memcpy(header + 252,"##}\n",4);  
44456 - cimg::fwrite(header,256,nfile); 48896 + if (voxel_size) err+=cimg_sprintf(header._data + err,"VX=%g\nVY=%g\nVZ=%g\n",
  48897 + voxel_size[0],voxel_size[1],voxel_size[2]);
  48898 + err+=cimg_sprintf(header._data + err,"TYPE=%s\nCPU=%s\n",inrtype,cimg::endianness()?"sun":"decm");
  48899 + std::memset(header._data + err,'\n',252 - err);
  48900 + std::memcpy(header._data + 252,"##}\n",4);
  48901 + cimg::fwrite(header._data,256,nfile);
44457 cimg_forXYZ(*this,x,y,z) cimg_forC(*this,c) cimg::fwrite(&((*this)(x,y,z,c)),1,nfile); 48902 cimg_forXYZ(*this,x,y,z) cimg_forC(*this,c) cimg::fwrite(&((*this)(x,y,z,c)),1,nfile);
44458 if (!file) cimg::fclose(nfile); 48903 if (!file) cimg::fclose(nfile);
44459 return *this; 48904 return *this;
@@ -44552,28 +48997,28 @@ namespace cimg_library_suffixed { @@ -44552,28 +48997,28 @@ namespace cimg_library_suffixed {
44552 unsigned int _save_pandore_header_length(unsigned int id, unsigned int *dims, const unsigned int colorspace) const { 48997 unsigned int _save_pandore_header_length(unsigned int id, unsigned int *dims, const unsigned int colorspace) const {
44553 unsigned int nbdims = 0; 48998 unsigned int nbdims = 0;
44554 if (id==2 || id==3 || id==4) { 48999 if (id==2 || id==3 || id==4) {
44555 - dims[0] = 1; dims[1] = _width; nbdims = 2; 49000 + dims[0] = 1; dims[1] = _width; nbdims = 2;
44556 } 49001 }
44557 if (id==5 || id==6 || id==7) { 49002 if (id==5 || id==6 || id==7) {
44558 - dims[0] = 1; dims[1] = _height; dims[2] = _width; nbdims=3; 49003 + dims[0] = 1; dims[1] = _height; dims[2] = _width; nbdims=3;
44559 } 49004 }
44560 if (id==8 || id==9 || id==10) { 49005 if (id==8 || id==9 || id==10) {
44561 - dims[0] = _spectrum; dims[1] = _depth; dims[2] = _height; dims[3] = _width; nbdims = 4; 49006 + dims[0] = _spectrum; dims[1] = _depth; dims[2] = _height; dims[3] = _width; nbdims = 4;
44562 } 49007 }
44563 if (id==16 || id==17 || id==18) { 49008 if (id==16 || id==17 || id==18) {
44564 - dims[0] = 3; dims[1] = _height; dims[2] = _width; dims[3] = colorspace; nbdims = 4; 49009 + dims[0] = 3; dims[1] = _height; dims[2] = _width; dims[3] = colorspace; nbdims = 4;
44565 } 49010 }
44566 if (id==19 || id==20 || id==21) { 49011 if (id==19 || id==20 || id==21) {
44567 - dims[0] = 3; dims[1] = _depth; dims[2] = _height; dims[3] = _width; dims[4] = colorspace; nbdims = 5; 49012 + dims[0] = 3; dims[1] = _depth; dims[2] = _height; dims[3] = _width; dims[4] = colorspace; nbdims = 5;
44568 } 49013 }
44569 if (id==22 || id==23 || id==25) { 49014 if (id==22 || id==23 || id==25) {
44570 - dims[0] = _spectrum; dims[1] = _width; nbdims = 2; 49015 + dims[0] = _spectrum; dims[1] = _width; nbdims = 2;
44571 } 49016 }
44572 if (id==26 || id==27 || id==29) { 49017 if (id==26 || id==27 || id==29) {
44573 - dims[0] = _spectrum; dims[1] = _height; dims[2] = _width; nbdims=3; 49018 + dims[0] = _spectrum; dims[1] = _height; dims[2] = _width; nbdims=3;
44574 } 49019 }
44575 if (id==30 || id==31 || id==33) { 49020 if (id==30 || id==31 || id==33) {
44576 - dims[0] = _spectrum; dims[1] = _depth; dims[2] = _height; dims[3] = _width; nbdims = 4; 49021 + dims[0] = _spectrum; dims[1] = _depth; dims[2] = _height; dims[3] = _width; nbdims = 4;
44577 } 49022 }
44578 return nbdims; 49023 return nbdims;
44579 } 49024 }
@@ -44597,9 +49042,9 @@ namespace cimg_library_suffixed { @@ -44597,9 +49042,9 @@ namespace cimg_library_suffixed {
44597 cimg::fwrite(header,36,nfile); \ 49042 cimg::fwrite(header,36,nfile); \
44598 if (sizeof(unsigned long)==4) { CImg<ulongT> ndims(5); \ 49043 if (sizeof(unsigned long)==4) { CImg<ulongT> ndims(5); \
44599 for (int d = 0; d<5; ++d) ndims[d] = (unsigned long)dims[d]; cimg::fwrite(ndims._data,nbdims,nfile); } \ 49044 for (int d = 0; d<5; ++d) ndims[d] = (unsigned long)dims[d]; cimg::fwrite(ndims._data,nbdims,nfile); } \
44600 - else if (sizeof(unsigned int)==4) { CImg<ulongT> ndims(5); \ 49045 + else if (sizeof(unsigned int)==4) { CImg<uintT> ndims(5); \
44601 for (int d = 0; d<5; ++d) ndims[d] = (unsigned int)dims[d]; cimg::fwrite(ndims._data,nbdims,nfile); } \ 49046 for (int d = 0; d<5; ++d) ndims[d] = (unsigned int)dims[d]; cimg::fwrite(ndims._data,nbdims,nfile); } \
44602 - else if (sizeof(unsigned short)==4) { CImg<ulongT> ndims(5); \ 49047 + else if (sizeof(unsigned short)==4) { CImg<ushortT> ndims(5); \
44603 for (int d = 0; d<5; ++d) ndims[d] = (unsigned short)dims[d]; cimg::fwrite(ndims._data,nbdims,nfile); } \ 49048 for (int d = 0; d<5; ++d) ndims[d] = (unsigned short)dims[d]; cimg::fwrite(ndims._data,nbdims,nfile); } \
44604 else throw CImgIOException(_cimg_instance \ 49049 else throw CImgIOException(_cimg_instance \
44605 "save_pandore(): Unsupported datatype for file '%s'.",\ 49050 "save_pandore(): Unsupported datatype for file '%s'.",\
@@ -44633,8 +49078,9 @@ namespace cimg_library_suffixed { @@ -44633,8 +49078,9 @@ namespace cimg_library_suffixed {
44633 if (is_empty()) { cimg::fempty(file,filename); return *this; } 49078 if (is_empty()) { cimg::fempty(file,filename); return *this; }
44634 49079
44635 std::FILE *const nfile = file?file:cimg::fopen(filename,"wb"); 49080 std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
44636 - unsigned char header[36] = { 'P','A','N','D','O','R','E','0','4',0,0,0,  
44637 - 0,0,0,0,'C','I','m','g',0,0,0,0,0,'N','o',' ','d','a','t','e',0,0,0,0 }; 49081 + static const unsigned char header[36] = { 'P','A','N','D','O','R','E','0','4',0,0,0,
  49082 + 0,0,0,0,'C','I','m','g',0,0,0,0,0,
  49083 + 'N','o',' ','d','a','t','e',0,0,0,0 };
44638 unsigned int nbdims, dims[5] = { 0 }; 49084 unsigned int nbdims, dims[5] = { 0 };
44639 bool saved = false; 49085 bool saved = false;
44640 _cimg_save_pandore_case(1,1,1,"unsigned char",2); 49086 _cimg_save_pandore_case(1,1,1,"unsigned char",2);
@@ -45921,8 +50367,7 @@ namespace cimg_library_suffixed { @@ -45921,8 +50367,7 @@ namespace cimg_library_suffixed {
45921 \note Can be used to exchange the content of two lists in a fast way. 50367 \note Can be used to exchange the content of two lists in a fast way.
45922 **/ 50368 **/
45923 CImgList<T>& swap(CImgList<T>& list) { 50369 CImgList<T>& swap(CImgList<T>& list) {
45924 - cimg::swap(_width,list._width);  
45925 - cimg::swap(_allocated_width,list._allocated_width); 50370 + cimg::swap(_width,list._width,_allocated_width,list._allocated_width);
45926 cimg::swap(_data,list._data); 50371 cimg::swap(_data,list._data);
45927 return list; 50372 return list;
45928 } 50373 }
@@ -45939,6 +50384,12 @@ namespace cimg_library_suffixed { @@ -45939,6 +50384,12 @@ namespace cimg_library_suffixed {
45939 return _empty.assign(); 50384 return _empty.assign();
45940 } 50385 }
45941 50386
  50387 + //! Return a reference to an empty list \const.
  50388 + static const CImgList<T>& const_empty() {
  50389 + static const CImgList<T> _empty;
  50390 + return _empty;
  50391 + }
  50392 +
45942 //@} 50393 //@}
45943 //------------------------------------------ 50394 //------------------------------------------
45944 // 50395 //
@@ -47480,8 +51931,9 @@ namespace cimg_library_suffixed { @@ -47480,8 +51931,9 @@ namespace cimg_library_suffixed {
47480 \return A one-column vector containing the selected image indexes. 51931 \return A one-column vector containing the selected image indexes.
47481 **/ 51932 **/
47482 CImg<intT> get_select(CImgDisplay &disp, const bool feature_type=true, 51933 CImg<intT> get_select(CImgDisplay &disp, const bool feature_type=true,
47483 - const char axis='x', const float align=0) const {  
47484 - return _get_select(disp,0,feature_type,axis,align,0,false,false,false); 51934 + const char axis='x', const float align=0,
  51935 + const bool exit_on_anykey=false) const {
  51936 + return _get_select(disp,0,feature_type,axis,align,exit_on_anykey,0,false,false,false);
47485 } 51937 }
47486 51938
47487 //! Display a simple interactive interface to select images or sublists. 51939 //! Display a simple interactive interface to select images or sublists.
@@ -47493,13 +51945,14 @@ namespace cimg_library_suffixed { @@ -47493,13 +51945,14 @@ namespace cimg_library_suffixed {
47493 \return A one-column vector containing the selected image indexes. 51945 \return A one-column vector containing the selected image indexes.
47494 **/ 51946 **/
47495 CImg<intT> get_select(const char *const title, const bool feature_type=true, 51947 CImg<intT> get_select(const char *const title, const bool feature_type=true,
47496 - const char axis='x', const float align=0) const { 51948 + const char axis='x', const float align=0,
  51949 + const bool exit_on_anykey=false) const {
47497 CImgDisplay disp; 51950 CImgDisplay disp;
47498 - return _get_select(disp,title,feature_type,axis,align,0,false,false,false); 51951 + return _get_select(disp,title,feature_type,axis,align,exit_on_anykey,0,false,false,false);
47499 } 51952 }
47500 51953
47501 CImg<intT> _get_select(CImgDisplay &disp, const char *const title, const bool feature_type, 51954 CImg<intT> _get_select(CImgDisplay &disp, const char *const title, const bool feature_type,
47502 - const char axis, const float align, 51955 + const char axis, const float align, const bool exit_on_anykey,
47503 const unsigned int orig, const bool resize_disp, 51956 const unsigned int orig, const bool resize_disp,
47504 const bool exit_on_rightbutton, const bool exit_on_wheel) const { 51957 const bool exit_on_rightbutton, const bool exit_on_wheel) const {
47505 if (is_empty()) 51958 if (is_empty())
@@ -47538,7 +51991,7 @@ namespace cimg_library_suffixed { @@ -47538,7 +51991,7 @@ namespace cimg_library_suffixed {
47538 bool old_is_resized = disp.is_resized(); 51991 bool old_is_resized = disp.is_resized();
47539 disp._normalization = 0; 51992 disp._normalization = 0;
47540 disp.show().set_key(0); 51993 disp.show().set_key(0);
47541 - const unsigned char foreground_color[] = { 255,255,255 }, background_color[] = { 0,0,0 }; 51994 + static const unsigned char foreground_color[] = { 255,255,255 }, background_color[] = { 0,0,0 };
47542 51995
47543 // Enter event loop. 51996 // Enter event loop.
47544 CImg<ucharT> visu0, visu; 51997 CImg<ucharT> visu0, visu;
@@ -47547,6 +52000,7 @@ namespace cimg_library_suffixed { @@ -47547,6 +52000,7 @@ namespace cimg_library_suffixed {
47547 int oindice0 = -1, oindice1 = -1, indice0 = -1, indice1 = -1; 52000 int oindice0 = -1, oindice1 = -1, indice0 = -1, indice1 = -1;
47548 bool is_clicked = false, is_selected = false, text_down = false, update_display = true; 52001 bool is_clicked = false, is_selected = false, text_down = false, update_display = true;
47549 unsigned int key = 0; 52002 unsigned int key = 0;
  52003 +
47550 while (!is_selected && !disp.is_closed() && !key) { 52004 while (!is_selected && !disp.is_closed() && !key) {
47551 52005
47552 // Create background image. 52006 // Create background image.
@@ -47650,6 +52104,7 @@ namespace cimg_library_suffixed { @@ -47650,6 +52104,7 @@ namespace cimg_library_suffixed {
47650 if (disp.button()&2 && exit_on_rightbutton) { is_selected = true; indice1 = indice0 = -1; } 52104 if (disp.button()&2 && exit_on_rightbutton) { is_selected = true; indice1 = indice0 = -1; }
47651 if (disp.wheel() && exit_on_wheel) is_selected = true; 52105 if (disp.wheel() && exit_on_wheel) is_selected = true;
47652 52106
  52107 + CImg<charT> filename(32);
47653 switch (key = disp.key()) { 52108 switch (key = disp.key()) {
47654 #if cimg_OS!=2 52109 #if cimg_OS!=2
47655 case cimg::keyCTRLRIGHT : 52110 case cimg::keyCTRLRIGHT :
@@ -47679,10 +52134,9 @@ namespace cimg_library_suffixed { @@ -47679,10 +52134,9 @@ namespace cimg_library_suffixed {
47679 } break; 52134 } break;
47680 case cimg::keyS : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { 52135 case cimg::keyS : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {
47681 static unsigned int snap_number = 0; 52136 static unsigned int snap_number = 0;
47682 - char filename[32] = { 0 };  
47683 std::FILE *file; 52137 std::FILE *file;
47684 do { 52138 do {
47685 - cimg_snprintf(filename,sizeof(filename),cimg_appname "_%.4u.bmp",snap_number++); 52139 + cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.bmp",snap_number++);
47686 if ((file=std::fopen(filename,"r"))!=0) cimg::fclose(file); 52140 if ((file=std::fopen(filename,"r"))!=0) cimg::fclose(file);
47687 } while (file); 52141 } while (file);
47688 if (visu0) { 52142 if (visu0) {
@@ -47690,20 +52144,19 @@ namespace cimg_library_suffixed { @@ -47690,20 +52144,19 @@ namespace cimg_library_suffixed {
47690 foreground_color,background_color,0.7f,13).display(disp); 52144 foreground_color,background_color,0.7f,13).display(disp);
47691 visu0.save(filename); 52145 visu0.save(filename);
47692 (+visu0).draw_text(0,0," Snapshot '%s' saved. ", 52146 (+visu0).draw_text(0,0," Snapshot '%s' saved. ",
47693 - foreground_color,background_color,0.7f,13,filename).display(disp); 52147 + foreground_color,background_color,0.7f,13,filename._data).display(disp);
47694 } 52148 }
47695 disp.set_key(key,false).wait(); key = 0; 52149 disp.set_key(key,false).wait(); key = 0;
47696 } break; 52150 } break;
47697 case cimg::keyO : 52151 case cimg::keyO :
47698 if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { 52152 if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {
47699 static unsigned int snap_number = 0; 52153 static unsigned int snap_number = 0;
47700 - char filename[32] = { 0 };  
47701 std::FILE *file; 52154 std::FILE *file;
47702 do { 52155 do {
47703 #ifdef cimg_use_zlib 52156 #ifdef cimg_use_zlib
47704 - cimg_snprintf(filename,sizeof(filename),cimg_appname "_%.4u.cimgz",snap_number++); 52157 + cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.cimgz",snap_number++);
47705 #else 52158 #else
47706 - cimg_snprintf(filename,sizeof(filename),cimg_appname "_%.4u.cimg",snap_number++); 52159 + cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.cimg",snap_number++);
47707 #endif 52160 #endif
47708 if ((file=std::fopen(filename,"r"))!=0) cimg::fclose(file); 52161 if ((file=std::fopen(filename,"r"))!=0) cimg::fclose(file);
47709 } while (file); 52162 } while (file);
@@ -47711,13 +52164,17 @@ namespace cimg_library_suffixed { @@ -47711,13 +52164,17 @@ namespace cimg_library_suffixed {
47711 foreground_color,background_color,0.7f,13).display(disp); 52164 foreground_color,background_color,0.7f,13).display(disp);
47712 save(filename); 52165 save(filename);
47713 (+visu0).draw_text(0,0," Instance '%s' saved. ", 52166 (+visu0).draw_text(0,0," Instance '%s' saved. ",
47714 - foreground_color,background_color,0.7f,13,filename).display(disp); 52167 + foreground_color,background_color,0.7f,13,filename._data).display(disp);
47715 disp.set_key(key,false).wait(); key = 0; 52168 disp.set_key(key,false).wait(); key = 0;
47716 } break; 52169 } break;
47717 } 52170 }
47718 if (disp.is_resized()) { disp.resize(false); visu0.assign(); } 52171 if (disp.is_resized()) { disp.resize(false); visu0.assign(); }
47719 if (ym>=0 && ym<13) { if (!text_down) { visu.assign(); text_down = true; }} 52172 if (ym>=0 && ym<13) { if (!text_down) { visu.assign(); text_down = true; }}
47720 else if (ym>=visu.height() - 13) { if(text_down) { visu.assign(); text_down = false; }} 52173 else if (ym>=visu.height() - 13) { if(text_down) { visu.assign(); text_down = false; }}
  52174 + if (!exit_on_anykey && key && key!=cimg::keyESC &&
  52175 + (key!=cimg::keyW || (!disp.is_keyCTRLLEFT() && !disp.is_keyCTRLRIGHT()))) {
  52176 + key = 0;
  52177 + }
47721 } 52178 }
47722 CImg<intT> res(1,2,1,1,-1); 52179 CImg<intT> res(1,2,1,1,-1);
47723 if (is_selected) { 52180 if (is_selected) {
@@ -48422,7 +52879,7 @@ namespace cimg_library_suffixed { @@ -48422,7 +52879,7 @@ namespace cimg_library_suffixed {
48422 \param first_frame Index of the first frame to read. 52879 \param first_frame Index of the first frame to read.
48423 \param last_frame Index of the last frame to read. 52880 \param last_frame Index of the last frame to read.
48424 \param step_frame Step value for frame reading. 52881 \param step_frame Step value for frame reading.
48425 - \note If step_frame==0, the current video stream is open or released without any frames read. 52882 + \note If step_frame==0, the current video stream is forced to be released (without any frames read).
48426 **/ 52883 **/
48427 CImgList<T>& load_video(const char *const filename, 52884 CImgList<T>& load_video(const char *const filename,
48428 const unsigned int first_frame=0, const unsigned int last_frame=~0U, 52885 const unsigned int first_frame=0, const unsigned int last_frame=~0U,
@@ -48465,7 +52922,7 @@ namespace cimg_library_suffixed { @@ -48465,7 +52922,7 @@ namespace cimg_library_suffixed {
48465 } else 52922 } else
48466 if (filename) 52923 if (filename)
48467 cimg::warn(_cimglist_instance 52924 cimg::warn(_cimglist_instance
48468 - "load_video() : File '%s', opened video stream associated with filename not found.", 52925 + "load_video() : File '%s', no opened video stream associated with filename found.",
48469 cimglist_instance,filename); 52926 cimglist_instance,filename);
48470 else 52927 else
48471 cimg::warn(_cimglist_instance 52928 cimg::warn(_cimglist_instance
@@ -48864,10 +53321,10 @@ namespace cimg_library_suffixed { @@ -48864,10 +53321,10 @@ namespace cimg_library_suffixed {
48864 cimglist_for(*this,l) msiz+=_data[l].size(); 53321 cimglist_for(*this,l) msiz+=_data[l].size();
48865 msiz*=sizeof(T); 53322 msiz*=sizeof(T);
48866 const unsigned int mdisp = msiz<8*1024?0U:msiz<8*1024*1024?1U:2U; 53323 const unsigned int mdisp = msiz<8*1024?0U:msiz<8*1024*1024?1U:2U;
48867 - char _title[64] = { 0 };  
48868 - if (!title) cimg_snprintf(_title,sizeof(_title),"CImgList<%s>",pixel_type()); 53324 + CImg<charT> _title(64);
  53325 + if (!title) cimg_snprintf(_title,_title._width,"CImgList<%s>",pixel_type());
48869 std::fprintf(cimg::output(),"%s%s%s%s: %sthis%s = %p, %ssize%s = %u/%u [%u %s], %sdata%s = (CImg<%s>*)%p", 53326 std::fprintf(cimg::output(),"%s%s%s%s: %sthis%s = %p, %ssize%s = %u/%u [%u %s], %sdata%s = (CImg<%s>*)%p",
48870 - cimg::t_magenta,cimg::t_bold,title?title:_title,cimg::t_normal, 53327 + cimg::t_magenta,cimg::t_bold,title?title:_title._data,cimg::t_normal,
48871 cimg::t_bold,cimg::t_normal,(void*)this, 53328 cimg::t_bold,cimg::t_normal,(void*)this,
48872 cimg::t_bold,cimg::t_normal,_width,_allocated_width, 53329 cimg::t_bold,cimg::t_normal,_width,_allocated_width,
48873 mdisp==0?msiz:(mdisp==1?(msiz>>10):(msiz>>20)), 53330 mdisp==0?msiz:(mdisp==1?(msiz>>10):(msiz>>20)),
@@ -48915,9 +53372,9 @@ namespace cimg_library_suffixed { @@ -48915,9 +53372,9 @@ namespace cimg_library_suffixed {
48915 **/ 53372 **/
48916 const CImgList<T>& display(CImgDisplay &disp, const bool display_info, 53373 const CImgList<T>& display(CImgDisplay &disp, const bool display_info,
48917 const char axis='x', const float align=0, 53374 const char axis='x', const float align=0,
48918 - unsigned int *const XYZ=0) const { 53375 + unsigned int *const XYZ=0, const bool exit_on_anykey=false) const {
48919 bool is_exit = false; 53376 bool is_exit = false;
48920 - return _display(disp,0,display_info,axis,align,XYZ,0,true,is_exit); 53377 + return _display(disp,0,display_info,axis,align,XYZ,exit_on_anykey,0,true,is_exit);
48921 } 53378 }
48922 53379
48923 //! Display the current CImgList instance in a new display window. 53380 //! Display the current CImgList instance in a new display window.
@@ -48929,15 +53386,16 @@ namespace cimg_library_suffixed { @@ -48929,15 +53386,16 @@ namespace cimg_library_suffixed {
48929 **/ 53386 **/
48930 const CImgList<T>& display(const char *const title=0, const bool display_info=true, 53387 const CImgList<T>& display(const char *const title=0, const bool display_info=true,
48931 const char axis='x', const float align=0, 53388 const char axis='x', const float align=0,
48932 - unsigned int *const XYZ=0) const { 53389 + unsigned int *const XYZ=0, const bool exit_on_anykey=false) const {
48933 CImgDisplay disp; 53390 CImgDisplay disp;
48934 bool is_exit = false; 53391 bool is_exit = false;
48935 - return _display(disp,title,display_info,axis,align,XYZ,0,true,is_exit); 53392 + return _display(disp,title,display_info,axis,align,XYZ,exit_on_anykey,0,true,is_exit);
48936 } 53393 }
48937 53394
48938 const CImgList<T>& _display(CImgDisplay &disp, const char *const title, const bool display_info, 53395 const CImgList<T>& _display(CImgDisplay &disp, const char *const title, const bool display_info,
48939 const char axis, const float align, unsigned int *const XYZ, 53396 const char axis, const float align, unsigned int *const XYZ,
48940 - const unsigned int orig, const bool is_first_call, bool &is_exit) const { 53397 + const bool exit_on_anykey, const unsigned int orig, const bool is_first_call,
  53398 + bool &is_exit) const {
48941 if (is_empty()) 53399 if (is_empty())
48942 throw CImgInstanceException(_cimglist_instance 53400 throw CImgInstanceException(_cimglist_instance
48943 "display(): Empty instance.", 53401 "display(): Empty instance.",
@@ -48978,13 +53436,13 @@ namespace cimg_library_suffixed { @@ -48978,13 +53436,13 @@ namespace cimg_library_suffixed {
48978 disp.resize(cimg_fitscreen(_data[0]._width,_data[0]._height,_data[0]._depth),false). 53436 disp.resize(cimg_fitscreen(_data[0]._width,_data[0]._height,_data[0]._depth),false).
48979 set_title("%s (%ux%ux%ux%u)", 53437 set_title("%s (%ux%ux%ux%u)",
48980 dtitle.data(),_data[0]._width,_data[0]._height,_data[0]._depth,_data[0]._spectrum); 53438 dtitle.data(),_data[0]._width,_data[0]._height,_data[0]._depth,_data[0]._spectrum);
48981 - _data[0]._display(disp,0,false,XYZ,!is_first_call); 53439 + _data[0]._display(disp,0,false,XYZ,exit_on_anykey,!is_first_call);
48982 if (disp.key()) is_exit = true; 53440 if (disp.key()) is_exit = true;
48983 disp.resize(cimg_fitscreen(dw,dh,1),false).set_title("%s",dtitle.data()); 53441 disp.resize(cimg_fitscreen(dw,dh,1),false).set_title("%s",dtitle.data());
48984 } else { 53442 } else {
48985 bool disp_resize = !is_first_call; 53443 bool disp_resize = !is_first_call;
48986 while (!disp.is_closed() && !is_exit) { 53444 while (!disp.is_closed() && !is_exit) {
48987 - const CImg<intT> s = _get_select(disp,0,true,axis,align,orig,disp_resize,!is_first_call,true); 53445 + const CImg<intT> s = _get_select(disp,0,true,axis,align,exit_on_anykey,orig,disp_resize,!is_first_call,true);
48988 disp_resize = true; 53446 disp_resize = true;
48989 if (s[0]<0) { // No selections done. 53447 if (s[0]<0) { // No selections done.
48990 if (disp.button()&2) { disp.flush(); break; } 53448 if (disp.button()&2) { disp.flush(); break; }
@@ -48999,10 +53457,12 @@ namespace cimg_library_suffixed { @@ -48999,10 +53457,12 @@ namespace cimg_library_suffixed {
48999 ind0 = (unsigned int)cimg::max(0,s[0] - (int)delta), 53457 ind0 = (unsigned int)cimg::max(0,s[0] - (int)delta),
49000 ind1 = (unsigned int)cimg::min(width() - 1,s[0] + (int)delta); 53458 ind1 = (unsigned int)cimg::min(width() - 1,s[0] + (int)delta);
49001 if ((ind0!=0 || ind1!=_width - 1) && ind1 - ind0>=3) 53459 if ((ind0!=0 || ind1!=_width - 1) && ind1 - ind0>=3)
49002 - get_shared_images(ind0,ind1)._display(disp,0,false,axis,align,XYZ,orig + ind0,false,is_exit); 53460 + get_shared_images(ind0,ind1)._display(disp,0,false,axis,align,XYZ,exit_on_anykey,
  53461 + orig + ind0,false,is_exit);
49003 } 53462 }
49004 } else if (s[0]!=0 || s[1]!=width() - 1) 53463 } else if (s[0]!=0 || s[1]!=width() - 1)
49005 - get_shared_images(s[0],s[1])._display(disp,0,false,axis,align,XYZ,orig + s[0],false,is_exit); 53464 + get_shared_images(s[0],s[1])._display(disp,0,false,axis,align,XYZ,exit_on_anykey,
  53465 + orig + s[0],false,is_exit);
49006 } 53466 }
49007 } 53467 }
49008 return *this; 53468 return *this;
@@ -49136,7 +53596,7 @@ namespace cimg_library_suffixed { @@ -49136,7 +53596,7 @@ namespace cimg_library_suffixed {
49136 \param fps Number of desired frames per second. 53596 \param fps Number of desired frames per second.
49137 \param nb_loops Number of loops (\c 0 for infinite looping). 53597 \param nb_loops Number of loops (\c 0 for infinite looping).
49138 **/ 53598 **/
49139 - const CImgList<T>& save_gif_external(const char *const filename, const unsigned int fps=25, 53599 + const CImgList<T>& save_gif_external(const char *const filename, const float fps=25,
49140 const unsigned int nb_loops=0) { 53600 const unsigned int nb_loops=0) {
49141 CImg<charT> command(1024), filename_tmp(256), filename_tmp2(256); 53601 CImg<charT> command(1024), filename_tmp(256), filename_tmp2(256);
49142 CImgList<charT> filenames; 53602 CImgList<charT> filenames;
@@ -49162,15 +53622,15 @@ namespace cimg_library_suffixed { @@ -49162,15 +53622,15 @@ namespace cimg_library_suffixed {
49162 } 53622 }
49163 53623
49164 #if cimg_OS!=2 53624 #if cimg_OS!=2
49165 - cimg_snprintf(command,command._width,"%s -delay 1x%u -loop %u",  
49166 - cimg::imagemagick_path(),fps,nb_loops); 53625 + cimg_snprintf(command,command._width,"%s -delay %u -loop %u",
  53626 + cimg::imagemagick_path(),(unsigned int)cimg::max(0.0f,cimg::round(100/fps)),nb_loops);
49167 CImg<ucharT>::string(command).move_to(filenames,0); 53627 CImg<ucharT>::string(command).move_to(filenames,0);
49168 cimg_snprintf(command,command._width,"\"%s\" >/dev/null 2>&1", 53628 cimg_snprintf(command,command._width,"\"%s\" >/dev/null 2>&1",
49169 CImg<charT>::string(filename)._system_strescape().data()); 53629 CImg<charT>::string(filename)._system_strescape().data());
49170 CImg<ucharT>::string(command).move_to(filenames); 53630 CImg<ucharT>::string(command).move_to(filenames);
49171 #else 53631 #else
49172 - cimg_snprintf(command,command._width,"\"%s -delay 1x%u -loop %u",  
49173 - cimg::imagemagick_path(),fps,nb_loops); 53632 + cimg_snprintf(command,command._width,"\"%s -delay %u -loop %u",
  53633 + cimg::imagemagick_path(),(unsigned int)cimg::max(0.0f,cimg::round(100/fps)),nb_loops);
49174 CImg<ucharT>::string(command).move_to(filenames,0); 53634 CImg<ucharT>::string(command).move_to(filenames,0);
49175 cimg_snprintf(command,command._width,"\"%s\"\" >NUL 2>&1", 53635 cimg_snprintf(command,command._width,"\"%s\"\" >NUL 2>&1",
49176 CImg<charT>::string(filename)._system_strescape().data()); 53636 CImg<charT>::string(filename)._system_strescape().data());
@@ -49505,7 +53965,8 @@ namespace cimg_library_suffixed { @@ -49505,7 +53965,8 @@ namespace cimg_library_suffixed {
49505 \param compression_type Compression mode used to write data. 53965 \param compression_type Compression mode used to write data.
49506 **/ 53966 **/
49507 const CImgList<T>& save_tiff(const char *const filename, const unsigned int compression_type=0, 53967 const CImgList<T>& save_tiff(const char *const filename, const unsigned int compression_type=0,
49508 - const float *const voxel_size=0, const char *const description=0) const { 53968 + const float *const voxel_size=0, const char *const description=0,
  53969 + const bool is_bigtiff=true) const {
49509 if (!filename) 53970 if (!filename)
49510 throw CImgArgumentException(_cimglist_instance 53971 throw CImgArgumentException(_cimglist_instance
49511 "save_tiff(): Specified filename is (null).", 53972 "save_tiff(): Specified filename is (null).",
@@ -49513,21 +53974,18 @@ namespace cimg_library_suffixed { @@ -49513,21 +53974,18 @@ namespace cimg_library_suffixed {
49513 if (is_empty()) { cimg::fempty(0,filename); return *this; } 53974 if (is_empty()) { cimg::fempty(0,filename); return *this; }
49514 53975
49515 #ifndef cimg_use_tiff 53976 #ifndef cimg_use_tiff
49516 - if (_width==1) _data[0].save_tiff(filename,compression_type,voxel_size,description); 53977 + if (_width==1) _data[0].save_tiff(filename,compression_type,voxel_size,description,is_bigtiff);
49517 else cimglist_for(*this,l) { 53978 else cimglist_for(*this,l) {
49518 CImg<charT> nfilename(1024); 53979 CImg<charT> nfilename(1024);
49519 cimg::number_filename(filename,l,6,nfilename); 53980 cimg::number_filename(filename,l,6,nfilename);
49520 - _data[l].save_tiff(nfilename,compression_type,voxel_size,description); 53981 + _data[l].save_tiff(nfilename,compression_type,voxel_size,description,is_bigtiff);
49521 } 53982 }
49522 #else 53983 #else
49523 - TIFF *tif = TIFFOpen(filename,"w"); 53984 + TIFF *tif = TIFFOpen(filename,is_bigtiff?"w8":"w4");
49524 if (tif) { 53985 if (tif) {
49525 for (unsigned int dir = 0, l = 0; l<_width; ++l) { 53986 for (unsigned int dir = 0, l = 0; l<_width; ++l) {
49526 const CImg<T>& img = (*this)[l]; 53987 const CImg<T>& img = (*this)[l];
49527 - if (img) {  
49528 - if (img._depth==1) img._save_tiff(tif,dir++,compression_type,voxel_size,description);  
49529 - else cimg_forZ(img,z) img.get_slice(z)._save_tiff(tif,dir++,compression_type,voxel_size,description);  
49530 - } 53988 + cimg_forZ(img,z) img._save_tiff(tif,dir++,z,compression_type,voxel_size,description);
49531 } 53989 }
49532 TIFFClose(tif); 53990 TIFFClose(tif);
49533 } else 53991 } else
@@ -49588,7 +54046,7 @@ namespace cimg_library_suffixed { @@ -49588,7 +54046,7 @@ namespace cimg_library_suffixed {
49588 CImg<charT> nfilename(1024); 54046 CImg<charT> nfilename(1024);
49589 cimglist_for(*this,l) { 54047 cimglist_for(*this,l) {
49590 cimg::number_filename(body,l,6,nfilename); 54048 cimg::number_filename(body,l,6,nfilename);
49591 - if (*ext) std::sprintf(nfilename._data + std::strlen(nfilename),".%s",ext); 54049 + if (*ext) cimg_sprintf(nfilename._data + std::strlen(nfilename),".%s",ext);
49592 _data[l].save_gzip_external(nfilename); 54050 _data[l].save_gzip_external(nfilename);
49593 } 54051 }
49594 } 54052 }
@@ -49651,7 +54109,7 @@ namespace cimg_library_suffixed { @@ -49651,7 +54109,7 @@ namespace cimg_library_suffixed {
49651 54109
49652 #define _cimg_docase(x) ((x)>='a'&&(x)<='z'?(x) + 'A' - 'a':(x)) 54110 #define _cimg_docase(x) ((x)>='a'&&(x)<='z'?(x) + 'A' - 'a':(x))
49653 const char 54111 const char
49654 - *const _codec = codec?codec:"mp4v", 54112 + *const _codec = codec && *codec?codec:"mp4v",
49655 codec0 = _cimg_docase(_codec[0]), 54113 codec0 = _cimg_docase(_codec[0]),
49656 codec1 = _codec[0]?_cimg_docase(_codec[1]):0, 54114 codec1 = _codec[0]?_cimg_docase(_codec[1]):0,
49657 codec2 = _codec[1]?_cimg_docase(_codec[2]):0, 54115 codec2 = _codec[1]?_cimg_docase(_codec[2]):0,
@@ -49977,13 +54435,13 @@ namespace cimg_library_suffixed { @@ -49977,13 +54435,13 @@ namespace cimg_library_suffixed {
49977 \param is_variable_width Decide if the font has a variable (\c true) or fixed (\c false) width. 54435 \param is_variable_width Decide if the font has a variable (\c true) or fixed (\c false) width.
49978 **/ 54436 **/
49979 static const CImgList<ucharT>& font(const unsigned int font_height, const bool is_variable_width=true) { 54437 static const CImgList<ucharT>& font(const unsigned int font_height, const bool is_variable_width=true) {
49980 - if (!font_height) return CImgList<ucharT>::empty(); 54438 + if (!font_height) return CImgList<ucharT>::const_empty();
49981 cimg::mutex(11); 54439 cimg::mutex(11);
49982 54440
49983 // Decompress nearest base font data if needed. 54441 // Decompress nearest base font data if needed.
49984 - const char *data_fonts[] = { cimg::data_font12x13, cimg::data_font20x23, cimg::data_font47x53, 0 };  
49985 - const unsigned int data_widths[] = { 12,20,47,90 }, data_heights[] = { 13,23,53,103 },  
49986 - data_Ms[] = { 86,79,57,47 }; 54442 + static const char *data_fonts[] = { cimg::data_font12x13, cimg::data_font20x23, cimg::data_font47x53, 0 };
  54443 + static const unsigned int data_widths[] = { 12,20,47,90 }, data_heights[] = { 13,23,53,103 },
  54444 + data_Ms[] = { 86,79,57,47 };
49987 const unsigned int data_ind = font_height<=13U?0U:font_height<=23U?1U:font_height<=53U?2U:3U; 54445 const unsigned int data_ind = font_height<=13U?0U:font_height<=23U?1U:font_height<=53U?2U:3U;
49988 static CImg<ucharT> base_fonts[4]; 54446 static CImg<ucharT> base_fonts[4];
49989 CImg<ucharT> &base_font = base_fonts[data_ind]; 54447 CImg<ucharT> &base_font = base_fonts[data_ind];
@@ -50727,7 +55185,7 @@ namespace cimg { @@ -50727,7 +55185,7 @@ namespace cimg {
50727 char *pd = _path; 55185 char *pd = _path;
50728 for (char *ps = pd; *ps; ++ps) { if (*ps!='/' || *ps!=*(ps+1)) *(pd++) = *ps; } 55186 for (char *ps = pd; *ps; ++ps) { if (*ps!='/' || *ps!=*(ps+1)) *(pd++) = *ps; }
50729 *pd = 0; 55187 *pd = 0;
50730 - unsigned int lp = std::strlen(_path); 55188 + unsigned int lp = (unsigned int)std::strlen(_path);
50731 if (!_is_pattern && lp && _path[lp - 1]=='/') { 55189 if (!_is_pattern && lp && _path[lp - 1]=='/') {
50732 _path[lp - 1] = 0; --lp; 55190 _path[lp - 1] = 0; --lp;
50733 #if cimg_OS!=2 55191 #if cimg_OS!=2
@@ -50747,7 +55205,7 @@ namespace cimg { @@ -50747,7 +55205,7 @@ namespace cimg {
50747 } else { // No path to folder specified, assuming current folder. 55205 } else { // No path to folder specified, assuming current folder.
50748 is_current = true; *_path = 0; 55206 is_current = true; *_path = 0;
50749 } 55207 }
50750 - lp = std::strlen(_path); 55208 + lp = (unsigned int)std::strlen(_path);
50751 } 55209 }
50752 55210
50753 // Windows version. 55211 // Windows version.
@@ -50757,21 +55215,19 @@ namespace cimg { @@ -50757,21 +55215,19 @@ namespace cimg {
50757 std::memcpy(pattern,_path,lp); 55215 std::memcpy(pattern,_path,lp);
50758 pattern[lp] = '/'; pattern[lp + 1] = '*'; pattern[lp + 2] = 0; 55216 pattern[lp] = '/'; pattern[lp + 1] = '*'; pattern[lp + 2] = 0;
50759 } 55217 }
50760 -  
50761 WIN32_FIND_DATAA file_data; 55218 WIN32_FIND_DATAA file_data;
50762 const HANDLE dir = FindFirstFileA(pattern.data(),&file_data); 55219 const HANDLE dir = FindFirstFileA(pattern.data(),&file_data);
50763 - if (dir==INVALID_HANDLE_VALUE) return CImgList<char>::empty(); 55220 + if (dir==INVALID_HANDLE_VALUE) return CImgList<char>::const_empty();
50764 do { 55221 do {
50765 const char *const filename = file_data.cFileName; 55222 const char *const filename = file_data.cFileName;
50766 if (*filename!='.' || (filename[1] && (filename[1]!='.' || filename[2]))) { 55223 if (*filename!='.' || (filename[1] && (filename[1]!='.' || filename[2]))) {
50767 - const unsigned int lf = std::strlen(filename); 55224 + const unsigned int lf = (unsigned int)std::strlen(filename);
50768 const bool is_directory = (file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)!=0; 55225 const bool is_directory = (file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)!=0;
50769 if ((!mode && !is_directory) || (mode==1 && is_directory) || mode>=2) { 55226 if ((!mode && !is_directory) || (mode==1 && is_directory) || mode>=2) {
50770 if (include_path) { 55227 if (include_path) {
50771 - CImg<char> full_filename(lp + lf + 2);  
50772 - std::memcpy(full_filename,_path,lp);  
50773 - full_filename[lp] = '/';  
50774 - std::memcpy(full_filename._data + lp + 1,filename,lf + 1); 55228 + CImg<char> full_filename((lp?lp+1:0) + lf + 1);
  55229 + if (lp) { std::memcpy(full_filename,_path,lp); full_filename[lp] = '/'; }
  55230 + std::memcpy(full_filename._data + (lp?lp + 1:0),filename,lf + 1);
50775 full_filename.move_to(res); 55231 full_filename.move_to(res);
50776 } else CImg<char>(filename,lf + 1).move_to(res); 55232 } else CImg<char>(filename,lf + 1).move_to(res);
50777 } 55233 }
@@ -50782,12 +55238,12 @@ namespace cimg { @@ -50782,12 +55238,12 @@ namespace cimg {
50782 // Unix version (posix). 55238 // Unix version (posix).
50783 #else 55239 #else
50784 DIR *const dir = opendir(is_root?"/":is_current?".":_path.data()); 55240 DIR *const dir = opendir(is_root?"/":is_current?".":_path.data());
50785 - if (!dir) return CImgList<char>::empty(); 55241 + if (!dir) return CImgList<char>::const_empty();
50786 struct dirent *ent; 55242 struct dirent *ent;
50787 while ((ent=readdir(dir))!=0) { 55243 while ((ent=readdir(dir))!=0) {
50788 const char *const filename = ent->d_name; 55244 const char *const filename = ent->d_name;
50789 if (*filename!='.' || (filename[1] && (filename[1]!='.' || filename[2]))) { 55245 if (*filename!='.' || (filename[1] && (filename[1]!='.' || filename[2]))) {
50790 - const unsigned int lf = std::strlen(filename); 55246 + const unsigned int lf = (unsigned int)std::strlen(filename);
50791 CImg<char> full_filename(lp + lf + 2); 55247 CImg<char> full_filename(lp + lf + 2);
50792 55248
50793 if (!is_current) { 55249 if (!is_current) {
@@ -50886,7 +55342,8 @@ namespace cimg { @@ -50886,7 +55342,8 @@ namespace cimg {
50886 \note Use the \c libcurl library, or the external binaries \c wget or \c curl to perform the download. 55342 \note Use the \c libcurl library, or the external binaries \c wget or \c curl to perform the download.
50887 **/ 55343 **/
50888 inline char *load_network(const char *const url, char *const filename_local, 55344 inline char *load_network(const char *const url, char *const filename_local,
50889 - const unsigned int timeout, const bool try_fallback) { 55345 + const unsigned int timeout, const bool try_fallback,
  55346 + const char *const referer) {
50890 if (!url) 55347 if (!url)
50891 throw CImgArgumentException("cimg::load_network(): Specified URL is (null)."); 55348 throw CImgArgumentException("cimg::load_network(): Specified URL is (null).");
50892 if (!filename_local) 55349 if (!filename_local)
@@ -50921,6 +55378,7 @@ namespace cimg { @@ -50921,6 +55378,7 @@ namespace cimg {
50921 curl_easy_setopt(curl,CURLOPT_FOLLOWLOCATION,1L); 55378 curl_easy_setopt(curl,CURLOPT_FOLLOWLOCATION,1L);
50922 if (timeout) curl_easy_setopt(curl,CURLOPT_TIMEOUT,(long)timeout); 55379 if (timeout) curl_easy_setopt(curl,CURLOPT_TIMEOUT,(long)timeout);
50923 if (std::strchr(url,'?')) curl_easy_setopt(curl,CURLOPT_HTTPGET,1L); 55380 if (std::strchr(url,'?')) curl_easy_setopt(curl,CURLOPT_HTTPGET,1L);
  55381 + if (referer) curl_easy_setopt(curl,CURLOPT_REFERER,referer);
50924 res = curl_easy_perform(curl); 55382 res = curl_easy_perform(curl);
50925 curl_easy_cleanup(curl); 55383 curl_easy_cleanup(curl);
50926 std::fseek(file,0,SEEK_END); // Check if file size is 0. 55384 std::fseek(file,0,SEEK_END); // Check if file size is 0.
@@ -50940,23 +55398,41 @@ namespace cimg { @@ -50940,23 +55398,41 @@ namespace cimg {
50940 cimg::unused(try_fallback); 55398 cimg::unused(try_fallback);
50941 55399
50942 // Try with 'curl' first. 55400 // Try with 'curl' first.
50943 - if (timeout)  
50944 - cimg_snprintf(command,command._width,"%s -m %u -f --silent --compressed -o \"%s\" \"%s\"",  
50945 - cimg::curl_path(),timeout,filename_local,url);  
50946 - else  
50947 - cimg_snprintf(command,command._width,"%s -f --silent --compressed -o \"%s\" \"%s\"",  
50948 - cimg::curl_path(),filename_local,url); 55401 + if (timeout) {
  55402 + if (referer)
  55403 + cimg_snprintf(command,command._width,"%s -e %s -m %u -f --silent --compressed -o \"%s\" \"%s\"",
  55404 + cimg::curl_path(),referer,timeout,filename_local,url);
  55405 + else
  55406 + cimg_snprintf(command,command._width,"%s -m %u -f --silent --compressed -o \"%s\" \"%s\"",
  55407 + cimg::curl_path(),timeout,filename_local,url);
  55408 + } else {
  55409 + if (referer)
  55410 + cimg_snprintf(command,command._width,"%s -e %s -f --silent --compressed -o \"%s\" \"%s\"",
  55411 + cimg::curl_path(),referer,filename_local,url);
  55412 + else
  55413 + cimg_snprintf(command,command._width,"%s -f --silent --compressed -o \"%s\" \"%s\"",
  55414 + cimg::curl_path(),filename_local,url);
  55415 + }
50949 cimg::system(command); 55416 cimg::system(command);
50950 55417
50951 if (!(file = std::fopen(filename_local,"rb"))) { 55418 if (!(file = std::fopen(filename_local,"rb"))) {
50952 55419
50953 // Try with 'wget' otherwise. 55420 // Try with 'wget' otherwise.
50954 - if (timeout)  
50955 - cimg_snprintf(command,command._width,"%s -T %u -q -r -l 0 --no-cache -O \"%s\" \"%s\"",  
50956 - cimg::wget_path(),timeout,filename_local,url);  
50957 - else  
50958 - cimg_snprintf(command,command._width,"%s -q -r -l 0 --no-cache -O \"%s\" \"%s\"",  
50959 - cimg::wget_path(),filename_local,url); 55421 + if (timeout) {
  55422 + if (referer)
  55423 + cimg_snprintf(command,command._width,"%s --referer=%s -T %u -q -r -l 0 --no-cache -O \"%s\" \"%s\"",
  55424 + cimg::wget_path(),referer,timeout,filename_local,url);
  55425 + else
  55426 + cimg_snprintf(command,command._width,"%s -T %u -q -r -l 0 --no-cache -O \"%s\" \"%s\"",
  55427 + cimg::wget_path(),timeout,filename_local,url);
  55428 + } else {
  55429 + if (referer)
  55430 + cimg_snprintf(command,command._width,"%s --referer=%s -q -r -l 0 --no-cache -O \"%s\" \"%s\"",
  55431 + cimg::wget_path(),referer,filename_local,url);
  55432 + else
  55433 + cimg_snprintf(command,command._width,"%s -q -r -l 0 --no-cache -O \"%s\" \"%s\"",
  55434 + cimg::wget_path(),filename_local,url);
  55435 + }
50960 cimg::system(command); 55436 cimg::system(command);
50961 55437
50962 if (!(file = std::fopen(filename_local,"rb"))) 55438 if (!(file = std::fopen(filename_local,"rb")))
@@ -51079,7 +55555,7 @@ namespace cimg { @@ -51079,7 +55555,7 @@ namespace cimg {
51079 logo._data,is_centered); 55555 logo._data,is_centered);
51080 throw CImgIOException("cimg::dialog(): No display available."); 55556 throw CImgIOException("cimg::dialog(): No display available.");
51081 #else 55557 #else
51082 - const unsigned char 55558 + static const unsigned char
51083 black[] = { 0,0,0 }, white[] = { 255,255,255 }, gray[] = { 200,200,200 }, gray2[] = { 150,150,150 }; 55559 black[] = { 0,0,0 }, white[] = { 255,255,255 }, gray[] = { 200,200,200 }, gray2[] = { 150,150,150 };
51084 55560
51085 // Create buttons and canvas graphics 55561 // Create buttons and canvas graphics
@@ -51281,6 +55757,9 @@ namespace cil = cimg_library_suffixed; @@ -51281,6 +55757,9 @@ namespace cil = cimg_library_suffixed;
51281 #ifdef _cimg_redefine_PI 55757 #ifdef _cimg_redefine_PI
51282 #define PI 3.141592653589793238462643383 55758 #define PI 3.141592653589793238462643383
51283 #endif 55759 #endif
  55760 +#ifdef _MSC_VER
  55761 +#pragma warning(pop)
  55762 +#endif
51284 55763
51285 #endif 55764 #endif
51286 // Local Variables: 55765 // Local Variables:
stim/parser/filename.h
@@ -215,7 +215,7 @@ public: @@ -215,7 +215,7 @@ public:
215 hFind = FindFirstFileA((filepath.str().c_str()), &FindFileData); 215 hFind = FindFirstFileA((filepath.str().c_str()), &FindFileData);
216 216
217 if (hFind == INVALID_HANDLE_VALUE) { 217 if (hFind == INVALID_HANDLE_VALUE) {
218 - printf ("Invalid file handle. Error is %u.\n", GetLastError()); 218 + printf ("Invalid file handle. Error is %u.\n", GetLastError());
219 } 219 }
220 else { 220 else {
221 std::string file_name = FindFileData.cFileName; //get the file name 221 std::string file_name = FindFileData.cFileName; //get the file name
@@ -230,9 +230,8 @@ public: @@ -230,9 +230,8 @@ public:
230 file_list.push_back(current_file); 230 file_list.push_back(current_file);
231 } 231 }
232 FindClose(hFind); 232 FindClose(hFind);
233 - 233 + }
234 return file_list; 234 return file_list;
235 - }  
236 235
237 } 236 }
238 #endif 237 #endif