Commit 43dec7889fc305d2dab2e19da474e33c27774061

Authored by David Mayerich
1 parent b3a38641

added code for sifting BSQ files in memory, updated CImg

stim/envi/bsq.h
... ... @@ -26,7 +26,7 @@ class bsq: public binary<T> {
26 26  
27 27  
28 28 protected:
29   -
  29 +
30 30 std::vector<double> w; //band wavelengths
31 31 unsigned int offset;
32 32  
... ... @@ -51,7 +51,7 @@ public:
51 51 using binary<T>::read_line_01;
52 52 using binary<T>::read_plane_2;
53 53 //using binary<T>::getSlice;
54   -
  54 +
55 55  
56 56 /// Open a data file for reading using the class interface.
57 57  
... ... @@ -60,7 +60,7 @@ public:
60 60 /// @param Y is the number of samples (lines) along dimension 2
61 61 /// @param B is the number of samples (bands) along dimension 3
62 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 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 66 //copy the wavelengths to the BSQ file structure
... ... @@ -69,7 +69,6 @@ public:
69 69 offset = header_offset;
70 70  
71 71 return open(filename, vec<unsigned int>(X, Y, B), header_offset);
72   -
73 72 }
74 73  
75 74 /// Retrieve a single band (based on index) and stores it in pre-allocated memory.
... ... @@ -91,7 +90,7 @@ public:
91 90 return band_index(p, (unsigned int)wavelength);
92 91  
93 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 96 //get the two neighboring bands (above and below 'wavelength')
... ... @@ -165,13 +164,13 @@ public:
165 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 170 /// Perform baseline correction given a list of baseline points and stores the result in a new BSQ file.
172 171  
173 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 174 bool baseline(std::string outname, std::vector<double> wls )
176 175 {
177 176 unsigned N = wls.size(); //get the number of baseline points
... ... @@ -194,8 +193,8 @@ public:
194 193 T * c; //pointer to the current image
195 194  
196 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 199 if (a == NULL || b == NULL || c == NULL){
201 200 std::cout<<"ERROR: error allocating memory";
... ... @@ -203,13 +202,13 @@ public:
203 202 }
204 203  
205 204  
206   - //initialize lownum, highnum, low, high
  205 + //initialize lownum, highnum, low, high
207 206 ai=w[0];
208 207  
209 208 //if no baseline point is specified at band 0,
210 209 //set the baseline point at band 0 to 0
211 210 if(wls[0] != w[0]){
212   - bi = wls[control];
  211 + bi = wls[control];
213 212 memset(a, (char)0, S);
214 213 }
215 214 //else get the low band
... ... @@ -221,7 +220,7 @@ public:
221 220 //get the high band
222 221 band(b, bi);
223 222  
224   - //correct every band
  223 + //correct every band
225 224 for(unsigned cii = 0; cii < B; cii++){
226 225  
227 226 //update baseline points, if necessary
... ... @@ -253,21 +252,21 @@ public:
253 252 //get the current band
254 253 band_index(c, cii);
255 254 ci = w[cii];
256   -
  255 +
257 256 //perform the baseline correction
258 257 for(unsigned i=0; i < XY; i++){
259 258 double r = (double) (ci - ai) / (double) (bi - ai);
260 259 c[i] =(T) ( c[i] - (b[i] - a[i]) * r - a[i] );
261 260 }
262   -
  261 +
263 262 target.write(reinterpret_cast<const char*>(c), S); //write the corrected data into destination
264 263  
265 264 thread_data = (double)cii / B * 100;
266   -
267   - }
  265 +
  266 + }
268 267  
269 268 //header.save(headername); //save the new header file
270   -
  269 +
271 270 free(a);
272 271 free(b);
273 272 free(c);
... ... @@ -295,7 +294,7 @@ public:
295 294 T * c; //pointer to the current image
296 295  
297 296 b = (T*)malloc( S ); //memory allocation
298   - c = (T*)malloc( S );
  297 + c = (T*)malloc( S );
299 298  
300 299 band(b, w); //get the certain band into memory
301 300  
... ... @@ -314,17 +313,17 @@ public:
314 313 thread_data = (double)j / B * 100;
315 314 }
316 315  
317   -
  316 +
318 317  
319 318 //header.save(headername); //save the new header file
320   -
  319 +
321 320 free(b);
322 321 free(c);
323 322 target.close();
324 323 thread_data = 100; //make sure that the progress bar is full
325 324 return true;
326 325 }
327   -
  326 +
328 327 /// Convert the current BSQ file to a BIP file with the specified file name.
329 328  
330 329 /// @param outname is the name of the output BIP file to be saved to disk.
... ... @@ -356,10 +355,10 @@ public:
356 355 //simplify image resolution
357 356 unsigned int L = X() * Z() * sizeof(T); //calculate the number of bytes of a ZX slice
358 357 unsigned int jump = (Y() - 1) * X() * sizeof(T);
359   -
  358 +
360 359 std::ofstream target(outname.c_str(), std::ios::binary);
361 360 std::string headername = outname + ".hdr";
362   -
  361 +
363 362 unsigned int xz_bytes = X() * Z() * sizeof(T);
364 363 T * xz_slice; //pointer to the current spectrum
365 364 xz_slice = (T*)malloc(xz_bytes);
... ... @@ -372,16 +371,16 @@ public:
372 371 file.read((char *)(xz_slice + z * X()), sizeof(T) * X()); //read a line
373 372 file.seekg(jump, std::ios::cur); //seek to the next band
374 373  
375   -
  374 +
376 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 382 thread_data = 100;
384   -
  383 +
385 384 free(xz_slice);
386 385 target.close();
387 386  
... ... @@ -425,7 +424,7 @@ public:
425 424 rp = (T*) malloc(S);
426 425  
427 426 band(lp, lb);
428   - band(rp, rb);
  427 + band(rp, rb);
429 428  
430 429 baseline_band(lb, rb, lp, rp, bandwavelength, result);
431 430  
... ... @@ -496,7 +495,7 @@ public:
496 495 }
497 496 baseline_band(lb, rb, lp, rp, lab, cur2); //beginnning part
498 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 499 result[j] += (w[ai] - lab) * (cur[j] + cur2[j]) / 2.0;
501 500 }
502 501  
... ... @@ -507,7 +506,7 @@ public:
507 506 baseline_band(lb, rb, lp, rp, w[ai], cur2);
508 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 511 std::swap(cur,cur2); //swap the band pointers
513 512 }
... ... @@ -530,9 +529,9 @@ public:
530 529 /// @param result is a pointer to a pre-allocated array at least X * Y * sizeof(T) in size
531 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 535 //get the two peak band
537 536 height(lb1, rb1, pos1, p1);
538 537 height(lb2, rb2, pos2, p2);
... ... @@ -546,9 +545,9 @@ public:
546 545  
547 546 free(p1);
548 547 free(p2);
549   - return true;
  548 + return true;
550 549 }
551   -
  550 +
552 551 /// Compute the ratio between a peak area and peak height.
553 552  
554 553 /// @param lb1 is the label value for the left baseline point for the first peak (numerator)
... ... @@ -560,10 +559,10 @@ public:
560 559 /// @param result is a pointer to a pre-allocated array at least X * Y * sizeof(T) in size
561 560 bool pa_to_ph(double lb1, double rb1, double lab1, double rab1,
562 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 566 //get the area and the peak band
568 567 area(lb1, rb1, lab1, rab1, p1);
569 568 height(lb2, rb2, pos, p2);
... ... @@ -577,9 +576,9 @@ public:
577 576  
578 577 free(p1);
579 578 free(p2);
580   - return true;
581   - }
582   -
  579 + return true;
  580 + }
  581 +
583 582 /// Compute the ratio between two peak areas.
584 583  
585 584 /// @param lb1 is the label value for the left baseline point for the first peak (numerator)
... ... @@ -589,14 +588,14 @@ public:
589 588 /// @param lb2 is the label value for the left baseline point for the second peak (denominator)
590 589 /// @param rb2 is the label value for the right baseline point for the second peak (denominator)
591 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 592 /// @param result is a pointer to a pre-allocated array at least X * Y * sizeof(T) in size
594 593 bool pa_to_pa(double lb1, double rb1, double lab1, double rab1,
595 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 599 //get the area and the peak band
601 600 area(lb1, rb1, lab1, rab1, p1);
602 601 area(lb2, rb2, lab2, rab2, p2);
... ... @@ -610,8 +609,8 @@ public:
610 609  
611 610 free(p1);
612 611 free(p2);
613   - return true;
614   - }
  612 + return true;
  613 + }
615 614  
616 615 /// Compute the definite integral of a baseline corrected peak.
617 616  
... ... @@ -671,7 +670,7 @@ public:
671 670 }
672 671 baseline_band(lb, rb, lp, rp, lab, cur2); //beginnning part
673 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 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 681 baseline_band(lb, rb, lp, rp, w[ai], cur2);
683 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 686 std::swap(cur,cur2); //swap the band pointers
688 687 }
... ... @@ -702,9 +701,9 @@ public:
702 701 /// @param rab is the label for the end of the peak
703 702 /// @param result is a pointer to a pre-allocated array at least X * Y * sizeof(T) in size
704 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 707 //get the area and the peak band
709 708 x_area(lb, rb, lab, rab, p1);
710 709 area(lb, rb, lab, rab, p2);
... ... @@ -718,7 +717,7 @@ public:
718 717  
719 718 free(p1);
720 719 free(p2);
721   - return true;
  720 + return true;
722 721 }
723 722  
724 723 /// Create a mask based on a given band and threshold value.
... ... @@ -777,7 +776,80 @@ public:
777 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 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 853 bool sift(std::string outfile, unsigned char* p){
782 854 std::ofstream target(outfile.c_str(), std::ios::binary);
783 855 // open a band (XY plane)
... ... @@ -912,7 +984,7 @@ public:
912 984 for (unsigned j = 0; j < XY; j++){ //loop through temp, averaging valid pixels
913 985 if (mask[j] != 0){
914 986 p[i] += temp[j] / (T)count;
915   - }
  987 + }
916 988 }
917 989 }
918 990 free(temp);
... ... @@ -930,7 +1002,7 @@ public:
930 1002 unsigned int B = Z();
931 1003 T* bandi = (T*)malloc(sizeof(T) * xy);
932 1004 T* bandj = (T*)malloc(sizeof(T) * xy);
933   -
  1005 +
934 1006 //count vaild pixels in a band
935 1007 unsigned count = 0;
936 1008 for (unsigned j = 0; j < xy; j++){
... ... @@ -1004,11 +1076,11 @@ public:
1004 1076 for (unsigned y = 0; y < lines; y++)
1005 1077 {
1006 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 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 1084 file.seekg(jumpb, std::ios::cur);
1013 1085 }
1014 1086 free(temp);
... ... @@ -1030,4 +1102,4 @@ public:
1030 1102  
1031 1103 #endif
1032 1104  
1033   -
  1105 +
... ...
stim/envi/envi.h
... ... @@ -465,7 +465,26 @@ public:
465 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 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 488 bool sift(std::string outfile, unsigned char* p)
470 489 {
471 490  
... ...
stim/image/CImg.h
Changes suppressed. Click to show
... ... @@ -54,7 +54,7 @@
54 54  
55 55 // Set version number of the library.
56 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 75 #include <cstdarg>
76 76 #include <cstring>
77 77 #include <cmath>
  78 +#include <cfloat>
78 79 #include <climits>
79 80 #include <ctime>
80 81 #include <exception>
... ... @@ -122,16 +123,30 @@
122 123 #pragma warning(disable:4820)
123 124 #pragma warning(disable:4996)
124 125 #define _CRT_SECURE_NO_DEPRECATE 1
  126 +#define _CRT_SECURE_NO_WARNINGS 1
125 127 #define _CRT_NONSTDC_NO_DEPRECATE 1
126   -#define cimg_snprintf cimg::c99_snprintf
127   -#define cimg_vsnprintf cimg::c99_vsnprintf
128 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 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 146 #define cimg_snprintf snprintf
133 147 #define cimg_vsnprintf vsnprintf
134 148 #endif
  149 +#endif
135 150  
136 151 // Include OS-specific headers.
137 152 #if cimg_OS==1
... ... @@ -145,6 +160,9 @@
145 160 #ifndef NOMINMAX
146 161 #define NOMINMAX
147 162 #endif
  163 +#ifndef WIN32_LEAN_AND_MEAN
  164 +#define WIN32_LEAN_AND_MEAN
  165 +#endif
148 166 #include <windows.h>
149 167 #ifndef _WIN32_IE
150 168 #define _WIN32_IE 0x0400
... ... @@ -154,15 +172,28 @@
154 172 #include <io.h>
155 173 #endif
156 174  
157   -// Look for C++11 features
  175 +// Look for C++11 features.
158 176 #if !defined(cimg_use_cpp11) && __cplusplus>201100
159   -#define cimg_use_cpp11
  177 +#define cimg_use_cpp11 1
160 178 #endif
161   -#ifdef cimg_use_cpp11
  179 +#if defined(cimg_use_cpp11) && cimg_use_cpp11!=0
162 180 #include <initializer_list>
163 181 #include <utility>
164 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 197 // Configure filename separator.
167 198 //
168 199 // Filename separator is set by default to '/', except for Windows where it is '\'.
... ... @@ -186,7 +217,11 @@
186 217 //
187 218 // Define 'cimg_use_vt100' to allow output of color messages on VT100-compatible terminals.
188 219 #ifndef cimg_verbosity
  220 +#if cimg_OS==2
189 221 #define cimg_verbosity 2
  222 +#else
  223 +#define cimg_verbosity 1
  224 +#endif
190 225 #elif !(cimg_verbosity==0 || cimg_verbosity==1 || cimg_verbosity==2 || cimg_verbosity==3 || cimg_verbosity==4)
191 226 #error CImg Library: Configuration variable 'cimg_verbosity' is badly defined.
192 227 #error (should be { 0=quiet | 1=console | 2=dialog | 3=console+warnings | 4=dialog+warnings }).
... ... @@ -201,11 +236,7 @@
201 236 #if cimg_OS==0
202 237 #define cimg_display 0
203 238 #elif cimg_OS==1
204   -#if defined(__MACOSX__) || defined(__APPLE__)
205   -#define cimg_display 1
206   -#else
207 239 #define cimg_display 1
208   -#endif
209 240 #elif cimg_OS==2
210 241 #define cimg_display 2
211 242 #endif
... ... @@ -471,26 +502,6 @@ extern &quot;C&quot; {
471 502 #define cimg_usage(usage) cimg_library_suffixed::cimg::option((char*)0,argc,argv,(char*)0,usage,false)
472 503 #define cimg_help(str) cimg_library_suffixed::cimg::option((char*)0,argc,argv,str,(char*)0)
473 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 506 // Macros to define and manipulate local neighborhoods.
496 507 #define CImg_2x2(I,T) T I[4]; \
... ... @@ -2069,26 +2080,26 @@ namespace cimg_library_suffixed {
2069 2080  
2070 2081 // Declare cimg:: namespace.
2071 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 2084 // defined afterwards.
2074 2085 namespace cimg {
2075 2086  
2076 2087 // Define ascii sequences for colored terminal output.
2077 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 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 2103 *const t_red = cimg::t_normal,
2093 2104 *const t_green = cimg::t_normal,
2094 2105 *const t_yellow = cimg::t_normal,
... ... @@ -2114,30 +2125,68 @@ namespace cimg_library_suffixed {
2114 2125  
2115 2126 inline unsigned int& _exception_mode(const unsigned int value, const bool is_set) {
2116 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 2129 return mode;
2121 2130 }
2122 2131  
2123 2132 // Mandatory because Microsoft's _snprintf() and _vsnprintf() do not add the '\0' character
2124 2133 // at the end of the string.
2125 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 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 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 2191 #endif
2143 2192  
... ... @@ -2163,6 +2212,31 @@ namespace cimg_library_suffixed {
2163 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 2240 // Display a simple dialog box, and wait for the user's response.
2167 2241 inline int dialog(const char *const title, const char *const msg, const char *const button1_label="OK",
2168 2242 const char *const button2_label=0, const char *const button3_label=0,
... ... @@ -2172,6 +2246,7 @@ namespace cimg_library_suffixed {
2172 2246 // Evaluate math expression.
2173 2247 inline double eval(const char *const expression,
2174 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 2258 /**
2184 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 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 2268 - \b CImgArgumentException: Thrown when one argument of a called \CImg function is invalid.
2191 2269 This is probably one of the most thrown exception by \CImg.
... ... @@ -2243,28 +2321,65 @@ namespace cimg_library_suffixed {
2243 2321 **/
2244 2322 struct CImgException : public std::exception {
2245 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 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 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 2357 //! Return a C-string containing the error message associated to the thrown exception.
2261 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 2385 // The CImgArgumentException class is used to throw an exception related
... ... @@ -2273,18 +2388,24 @@ namespace cimg_library_suffixed {
2273 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 2391 // The CImgDisplayException class is used to throw an exception related
2283 2392 // to display problems encountered in a library function call.
2284 2393 struct CImgDisplayException : public CImgException {
2285 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 2409 // The CImgWarningException class is used to throw an exception for warnings
2289 2410 // encountered in a library function call.
2290 2411 struct CImgWarningException : public CImgException {
... ... @@ -2497,10 +2618,22 @@ namespace cimg_library_suffixed {
2497 2618 return !(val==val);
2498 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 2637 static double cut(const double val) { return val<min()?min():val>max()?max():val; }
2505 2638 static const char* format() { return "%.16g"; }
2506 2639 static double format(const double val) { return val; }
... ... @@ -2523,8 +2656,8 @@ namespace cimg_library_suffixed {
2523 2656 return !(val==val);
2524 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 2661 static float inf() { return (float)cimg::type<double>::inf(); }
2529 2662 static float nan() { return (float)cimg::type<double>::nan(); }
2530 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 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 2694 template<typename T, typename t> struct superset { typedef T type; };
2536 2695 template<> struct superset<bool,unsigned char> { typedef unsigned char type; };
2537 2696 template<> struct superset<bool,char> { typedef char type; };
... ... @@ -3015,7 +3174,7 @@ namespace cimg_library_suffixed {
3015 3174 const double PI = 3.14159265358979323846; //!< Value of the mathematical constant PI
3016 3175  
3017 3176 // Define a 12x13 font (small size).
3018   - const char *const data_font12x13 =
  3177 + static const char *const data_font12x13 =
3019 3178 " .wjwlwmyuw>wjwkwbwjwkwRxuwmwjwkwmyuwJwjwlx`w Fw mwlwlwuwnwuynwuwmyTwlwkwuwmwuwnwlwkwuwmwuw_wuxl"
3020 3179 "wlwkwuwnwuynwuwTwlwlwtwnwtwnw my Qw +wlw b{ \\w Wx`xTw_w[wbxawSwkw nynwky<x1w `y ,w Xwuw CxlwiwlwmyuwbwuwUwiwlwbwiwrwqw^wuwmxuwnwiwlwmy"
3021 3180 "uwJwiwlw^wnwEymymymymy1w^wkxnxtxnw<| gybwkwuwjwtwowmxswnxnwkxlxkw:wlymxlymykwn{myo{nymy2ykwqwqwm{myozn{o{mzpwrwpwkwkwswowkwqwqxswnyozlyozmzp}pwrwqwqwq"
... ... @@ -3055,7 +3214,7 @@ namespace cimg_library_suffixed {
3055 3214 "wlxm";
3056 3215  
3057 3216 // Define a 20x23 font (normal size).
3058   - const char *const data_font20x23 =
  3217 + static const char *const data_font20x23 =
3059 3218 " 9q\\q^r_rnp`qnq`plp7q\\q^q_qmqbq\\q^q_qmqHqmp_q\\q^r_rnp`qnq7q\\q^q_qmq_q \"r "
3060 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 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 3282 "r^q *q kr i";
3124 3283  
3125 3284 // Define a 47x53 font (extra-large size).
3126   - const char *const data_font47x53 =
  3285 + static const char *const data_font47x53 =
3127 3286 " "
3128 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 3288 " U]*\\2a4`V\\8^U^5a F]*\\1\\X\\4^U^=]*\\"
... ... @@ -3316,7 +3475,7 @@ namespace cimg_library_suffixed {
3316 3475 " F]']2] +]']2^ D]']3_ E]']1] \"]']2^ 8] H";
3317 3476  
3318 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 3479 // Start of first string.
3321 3480 " "
3322 3481 " "
... ... @@ -3856,7 +4015,7 @@ namespace cimg_library_suffixed {
3856 4015 " D" };
3857 4016  
3858 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 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 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 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 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 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 4044 //! Get/set default output stream for the \CImg library messages.
3903 4045 /**
3904 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 4122 return -1;
3981 4123 #else
3982 4124 #if cimg_OS==1
3983   - const unsigned int l = std::strlen(command);
  4125 + const unsigned int l = (unsigned int)std::strlen(command);
3984 4126 if (l) {
3985 4127 char *const ncommand = new char[l + 16];
3986 4128 std::strncpy(ncommand,command,l);
... ... @@ -4243,8 +4385,9 @@ namespace cimg_library_suffixed {
4243 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 4393 #else
... ... @@ -4265,19 +4408,20 @@ namespace cimg_library_suffixed {
4265 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 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 4427 //! Return a random variable following a gaussian distribution and a standard deviation of 1.
... ... @@ -4286,8 +4430,8 @@ namespace cimg_library_suffixed {
4286 4430 inline double grand() {
4287 4431 double x1, w;
4288 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 4435 w = x1*x1 + x2*x2;
4292 4436 } while (w<=0 || w>=1.0);
4293 4437 return x1*std::sqrt((-2*std::log(w))/w);
... ... @@ -4319,6 +4463,10 @@ namespace cimg_library_suffixed {
4319 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 4470 //! Bitwise-rotate value on the right.
4323 4471 template<typename T>
4324 4472 inline T ror(const T& a, const unsigned int n=1) {
... ... @@ -4333,6 +4481,10 @@ namespace cimg_library_suffixed {
4333 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 4488 //! Return absolute value of a value.
4337 4489 template<typename T>
4338 4490 inline T abs(const T& a) {
... ... @@ -4515,11 +4667,12 @@ namespace cimg_library_suffixed {
4515 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 4678 //! Convert ascii character to lower case.
... ... @@ -4575,6 +4728,51 @@ namespace cimg_library_suffixed {
4575 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 4776 //! Remove delimiters on the start and/or end of a C-string.
4579 4777 /**
4580 4778 \param[in,out] str C-string to work with (modified at output).
... ... @@ -4638,7 +4836,7 @@ namespace cimg_library_suffixed {
4638 4836 *nd = (char)val; break;
4639 4837 case 'x' :
4640 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 4840 *nd = (char)val; break;
4643 4841 default : *nd = *(ns++);
4644 4842 } else *nd = *(ns++);
... ... @@ -4650,20 +4848,20 @@ namespace cimg_library_suffixed {
4650 4848 // Return string that identifies the running OS.
4651 4849 inline const char *stros() {
4652 4850 #if defined(linux) || defined(__linux) || defined(__linux__)
4653   - const char *const str = "Linux";
  4851 + static const char *const str = "Linux";
4654 4852 #elif defined(sun) || defined(__sun)
4655   - const char *const str = "Sun OS";
  4853 + static const char *const str = "Sun OS";
4656 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 4856 #elif defined(sgi) || defined(__sgi)
4659   - const char *const str = "Irix";
  4857 + static const char *const str = "Irix";
4660 4858 #elif defined(__MACOSX__) || defined(__APPLE__)
4661   - const char *const str = "Mac OS";
  4859 + static const char *const str = "Mac OS";
4662 4860 #elif defined(unix) || defined(__unix) || defined(__unix__)
4663   - const char *const str = "Generic Unix";
  4861 + static const char *const str = "Generic Unix";
4664 4862 #elif defined(_MSC_VER) || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || \
4665 4863 defined(WIN64) || defined(_WIN64) || defined(__WIN64__)
4666   - const char *const str = "Windows";
  4864 + static const char *const str = "Windows";
4667 4865 #else
4668 4866 const char
4669 4867 *const _str1 = std::getenv("OSTYPE"),
... ... @@ -4683,11 +4881,12 @@ namespace cimg_library_suffixed {
4683 4881 // Return a random filename.
4684 4882 inline const char* filenamerand() {
4685 4883 cimg::mutex(6);
4686   - static char randomid[9] = { 0 };
  4884 + static char randomid[9];
4687 4885 cimg::srand();
4688 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 4891 cimg::mutex(6,0);
4693 4892 return randomid;
... ... @@ -4815,7 +5014,7 @@ namespace cimg_library_suffixed {
4815 5014 Can be { 0=year | 1=month | 2=day | 3=day of week | 4=hour | 5=minute | 6=second }
4816 5015 **/
4817 5016 inline int date(const unsigned int attr) {
4818   - int res = -1;
  5017 + int res;
4819 5018 cimg::mutex(6);
4820 5019 #if cimg_OS==2
4821 5020 SYSTEMTIME st;
... ... @@ -4892,7 +5091,7 @@ namespace cimg_library_suffixed {
4892 5091 const char *const ext = cimg::split_filename(filename,body);
4893 5092 if (*ext) cimg_snprintf(format,1024,"%%s_%%.%ud.%%s",digits);
4894 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 5095 delete[] format; delete[] body;
4897 5096 return str;
4898 5097 }
... ... @@ -4970,7 +5169,8 @@ namespace cimg_library_suffixed {
4970 5169  
4971 5170 // Load file from network as a local temporary file.
4972 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 5175 //! Return options specified on the command line.
4976 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 5233 const char defaut, const char *const usage=0) {
5034 5234 const char *const s = cimg::option(name,argc,argv,(char*)0);
5035 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 5238 cimg::option(name,0,0,tmp,usage);
5039 5239 return res;
5040 5240 }
... ... @@ -5061,25 +5261,6 @@ namespace cimg_library_suffixed {
5061 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 5264 //! Print information about \CImg environement variables.
5084 5265 /**
5085 5266 \note Output is done on the default output stream.
... ... @@ -5372,6 +5553,7 @@ namespace cimg_library_suffixed {
5372 5553 _cimg_create_ext_operators(long)
5373 5554 _cimg_create_ext_operators(float)
5374 5555 _cimg_create_ext_operators(double)
  5556 + _cimg_create_ext_operators(long double)
5375 5557  
5376 5558 template<typename T>
5377 5559 inline CImg<_cimg_Tfloat> operator+(const char *const expression, const CImg<T>& img) {
... ... @@ -5380,7 +5562,7 @@ namespace cimg_library_suffixed {
5380 5562  
5381 5563 template<typename T>
5382 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 5568 template<typename T>
... ... @@ -5410,12 +5592,12 @@ namespace cimg_library_suffixed {
5410 5592  
5411 5593 template<typename T>
5412 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 5598 template<typename T>
5417 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 5603 template<typename T>
... ... @@ -5528,7 +5710,7 @@ namespace cimg_library_suffixed {
5528 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 5715 CImgDisplay methods rely on a low-level graphic library to perform: it can be either \b X-Window
5534 5716 (X11, for Unix-based systems) or \b GDI32 (for Windows-based systems).
... ... @@ -5802,6 +5984,12 @@ namespace cimg_library_suffixed {
5802 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 5993 #define cimg_fitscreen(dx,dy,dz) CImgDisplay::_fitscreen(dx,dy,dz,128,-85,false), \
5806 5994 CImgDisplay::_fitscreen(dx,dy,dz,128,-85,true)
5807 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 6379 in fullscreen mode.
6192 6380 **/
6193 6381 const char *title() const {
6194   - return _title;
  6382 + return _title?_title:"";
6195 6383 }
6196 6384  
6197 6385 //! Return width of the associated window.
... ... @@ -7136,7 +7324,7 @@ namespace cimg_library_suffixed {
7136 7324 XEvent event;
7137 7325 pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,0);
7138 7326 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,0);
7139   - if (!arg) for (;;) {
  7327 + if (!arg) for ( ; ; ) {
7140 7328 cimg_lock_display();
7141 7329 bool event_flag = XCheckTypedEvent(dpy,ClientMessage,&event);
7142 7330 if (!event_flag) event_flag = XCheckMaskEvent(dpy,
... ... @@ -7397,7 +7585,7 @@ namespace cimg_library_suffixed {
7397 7585  
7398 7586 // Allocate space for window title
7399 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 7589 char *const tmp_title = s?new char[s]:0;
7402 7590 if (s) std::memcpy(tmp_title,nptitle,s*sizeof(char));
7403 7591  
... ... @@ -7535,7 +7723,7 @@ namespace cimg_library_suffixed {
7535 7723 // Remove display window from event thread list.
7536 7724 unsigned int i;
7537 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 7727 --cimg::X11_attr().nb_wins;
7540 7728  
7541 7729 // Destroy window, image, colormap and title.
... ... @@ -7630,24 +7818,27 @@ namespace cimg_library_suffixed {
7630 7818 tmpdimy = (nheight>0)?nheight:(-nheight*height()/100),
7631 7819 dimx = tmpdimx?tmpdimx:1,
7632 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 7841 _is_resized = false;
7650   - cimg_unlock_display();
7651 7842 if (_is_fullscreen) move((screen_width() - _width)/2,(screen_height() - _height)/2);
7652 7843 if (force_redraw) return paint();
7653 7844 return *this;
... ... @@ -7692,13 +7883,15 @@ namespace cimg_library_suffixed {
7692 7883  
7693 7884 CImgDisplay& move(const int posx, const int posy) {
7694 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 7894 _is_moved = false;
7701   - cimg_unlock_display();
7702 7895 return paint();
7703 7896 }
7704 7897  
... ... @@ -7715,7 +7908,7 @@ namespace cimg_library_suffixed {
7715 7908 if (is_empty()) return *this;
7716 7909 Display *const dpy = cimg::X11_attr().display;
7717 7910 cimg_lock_display();
7718   - const char pix_data[8] = { 0 };
  7911 + static const char pix_data[8] = { 0 };
7719 7912 XColor col;
7720 7913 col.red = col.green = col.blue = 0;
7721 7914 Pixmap pix = XCreateBitmapFromData(dpy,_window,pix_data,8,8);
... ... @@ -7747,7 +7940,7 @@ namespace cimg_library_suffixed {
7747 7940 va_end(ap);
7748 7941 if (!std::strcmp(_title,tmp)) { delete[] tmp; return *this; }
7749 7942 delete[] _title;
7750   - const unsigned int s = std::strlen(tmp) + 1;
  7943 + const unsigned int s = (unsigned int)std::strlen(tmp) + 1;
7751 7944 _title = new char[s];
7752 7945 std::memcpy(_title,tmp,s*sizeof(char));
7753 7946 Display *const dpy = cimg::X11_attr().display;
... ... @@ -8269,7 +8462,9 @@ namespace cimg_library_suffixed {
8269 8462 } break;
8270 8463 case WM_PAINT :
8271 8464 disp->paint();
  8465 + cimg::mutex(15);
8272 8466 if (disp->_is_cursor_visible) while (ShowCursor(TRUE)<0); else while (ShowCursor(FALSE)>=0);
  8467 + cimg::mutex(15,0);
8273 8468 break;
8274 8469 case WM_ERASEBKGND :
8275 8470 // return 0;
... ... @@ -8299,12 +8494,16 @@ namespace cimg_library_suffixed {
8299 8494 disp->_mouse_x = disp->_mouse_y = -1;
8300 8495 disp->_is_event = true;
8301 8496 SetEvent(cimg::Win32_attr().wait_event);
  8497 + cimg::mutex(15);
8302 8498 if (disp->_is_cursor_visible) while (ShowCursor(TRUE)<0); else while (ShowCursor(FALSE)>=0);
  8499 + cimg::mutex(15,0);
8303 8500 } break;
8304 8501 case WM_MOUSELEAVE : {
8305 8502 disp->_mouse_x = disp->_mouse_y = -1;
8306 8503 disp->_is_mouse_tracked = false;
  8504 + cimg::mutex(15);
8307 8505 while (ShowCursor(TRUE)<0);
  8506 + cimg::mutex(15,0);
8308 8507 } break;
8309 8508 case WM_LBUTTONDOWN :
8310 8509 disp->set_button(1);
... ... @@ -8563,24 +8762,27 @@ namespace cimg_library_suffixed {
8563 8762 tmpdimy = (nheight>0)?nheight:(-nheight*_height/100),
8564 8763 dimx = tmpdimx?tmpdimx:1,
8565 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 8786 _is_resized = false;
8585 8787 if (_is_fullscreen) move((screen_width() - width())/2,(screen_height() - height())/2);
8586 8788 if (force_redraw) return paint();
... ... @@ -8623,19 +8825,22 @@ namespace cimg_library_suffixed {
8623 8825  
8624 8826 CImgDisplay& move(const int posx, const int posy) {
8625 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 8842 _is_moved = false;
8638   - return show();
  8843 + return *this;
8639 8844 }
8640 8845  
8641 8846 CImgDisplay& show_mouse() {
... ... @@ -8651,7 +8856,7 @@ namespace cimg_library_suffixed {
8651 8856 }
8652 8857  
8653 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 8860 _update_window_pos();
8656 8861 const int res = (int)SetCursorPos(_window_x + posx,_window_y + posy);
8657 8862 if (res) { _mouse_x = posx; _mouse_y = posy; }
... ... @@ -8891,10 +9096,8 @@ namespace cimg_library_suffixed {
8891 9096 - Construct images from C-style arrays:
8892 9097 - <tt>CImg<int> img(data_buffer,256,256);</tt> constructs a 256x256 greyscale image from a \c int* buffer
8893 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 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 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 9106 The \c CImg<T> class contains a lot of functions that operates on images.
8904 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 9110 - display(): displays the image in a new window.
8908 9111 **/
8909 9112 template<typename T>
... ... @@ -8977,6 +9180,13 @@ namespace cimg_library_suffixed {
8977 9180 typedef typename cimg::last<T,long>::type longT;
8978 9181 typedef typename cimg::last<T,float>::type floatT;
8979 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 9375 *(ptrd++) = (T)a0; \
9166 9376 if (_siz--) { \
9167 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 9380 va_end(ap); \
9171 9381 } \
... ... @@ -9174,7 +9384,7 @@ namespace cimg_library_suffixed {
9174 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 9388 //! Construct image with specified size and initialize pixel values from an initializer list of integers.
9179 9389 /**
9180 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 9633 cimg::strbuffersize(sizeof(T)*size_x*size_y*size_z*size_c),
9424 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 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 9840  
9630 9841 // Constructor and assignment operator for rvalue references (c++11).
9631 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 9844 CImg(CImg<T>&& img):_width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) {
9634 9845 swap(img);
9635 9846 }
... ... @@ -9954,10 +10165,7 @@ namespace cimg_library_suffixed {
9954 10165 \endcode
9955 10166 **/
9956 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 10169 cimg::swap(_data,img._data);
9962 10170 cimg::swap(_is_shared,img._is_shared);
9963 10171 return img;
... ... @@ -9977,6 +10185,12 @@ namespace cimg_library_suffixed {
9977 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 10237 const unsigned long off = (unsigned long)offset(x,y,z,c);
10024 10238 if (!_data || off>=size()) {
10025 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 10241 cimg_instance,
10028   - x,y,z,c,off);
  10242 + (int)x,(int)y,(int)z,(int)c,off);
10029 10243 return *_data;
10030 10244 }
10031 10245 else return _data[off];
... ... @@ -10191,7 +10405,7 @@ namespace cimg_library_suffixed {
10191 10405 const unsigned int omode = cimg::exception_mode();
10192 10406 cimg::exception_mode(0);
10193 10407 try {
10194   - fill(expression,true);
  10408 + _fill(expression,true,true,0,0,"operator=",0);
10195 10409 } catch (CImgException&) {
10196 10410 cimg::exception_mode(omode);
10197 10411 load(expression);
... ... @@ -10254,7 +10468,7 @@ namespace cimg_library_suffixed {
10254 10468 CImg<T>& operator+=(const t value) {
10255 10469 if (is_empty()) return *this;
10256 10470 #ifdef cimg_use_openmp
10257   -#pragma omp parallel for if (size()>=524288)
  10471 +#pragma omp parallel for cimg_openmp_if(size()>=524288)
10258 10472 #endif
10259 10473 cimg_rof(*this,ptrd,T) *ptrd = (T)(*ptrd + value);
10260 10474 return *this;
... ... @@ -10269,37 +10483,7 @@ namespace cimg_library_suffixed {
10269 10483 instead of assigning them.
10270 10484 **/
10271 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 10489 //! In-place addition operator.
... ... @@ -10345,7 +10529,7 @@ namespace cimg_library_suffixed {
10345 10529 CImg<T>& operator++() {
10346 10530 if (is_empty()) return *this;
10347 10531 #ifdef cimg_use_openmp
10348   -#pragma omp parallel for if (size()>=524288)
  10532 +#pragma omp parallel for cimg_openmp_if(size()>=524288)
10349 10533 #endif
10350 10534 cimg_rof(*this,ptrd,T) ++*ptrd;
10351 10535 return *this;
... ... @@ -10414,7 +10598,7 @@ namespace cimg_library_suffixed {
10414 10598 CImg<T>& operator-=(const t value) {
10415 10599 if (is_empty()) return *this;
10416 10600 #ifdef cimg_use_openmp
10417   -#pragma omp parallel for if (size()>=524288)
  10601 +#pragma omp parallel for cimg_openmp_if(size()>=524288)
10418 10602 #endif
10419 10603 cimg_rof(*this,ptrd,T) *ptrd = (T)(*ptrd - value);
10420 10604 return *this;
... ... @@ -10425,37 +10609,7 @@ namespace cimg_library_suffixed {
10425 10609 Similar to operator+=(const char*), except that it performs a substraction instead of an addition.
10426 10610 **/
10427 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 10615 //! In-place substraction operator.
... ... @@ -10483,7 +10637,7 @@ namespace cimg_library_suffixed {
10483 10637 CImg<T>& operator--() {
10484 10638 if (is_empty()) return *this;
10485 10639 #ifdef cimg_use_openmp
10486   -#pragma omp parallel for if (size()>=524288)
  10640 +#pragma omp parallel for cimg_openmp_if(size()>=524288)
10487 10641 #endif
10488 10642 cimg_rof(*this,ptrd,T) *ptrd = *ptrd - (T)1;
10489 10643 return *this;
... ... @@ -10554,7 +10708,7 @@ namespace cimg_library_suffixed {
10554 10708 CImg<T>& operator*=(const t value) {
10555 10709 if (is_empty()) return *this;
10556 10710 #ifdef cimg_use_openmp
10557   -#pragma omp parallel for if (size()>=262144)
  10711 +#pragma omp parallel for cimg_openmp_if(size()>=262144)
10558 10712 #endif
10559 10713 cimg_rof(*this,ptrd,T) *ptrd = (T)(*ptrd * value);
10560 10714 return *this;
... ... @@ -10565,37 +10719,7 @@ namespace cimg_library_suffixed {
10565 10719 Similar to operator+=(const char*), except that it performs a multiplication instead of an addition.
10566 10720 **/
10567 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 10725 //! In-place multiplication operator.
... ... @@ -10654,7 +10778,7 @@ namespace cimg_library_suffixed {
10654 10778 img._width,img._height,img._depth,img._spectrum,img._data);
10655 10779 CImg<_cimg_Tt> res(img._width,_height);
10656 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 10782 cimg_forXY(res,i,j) {
10659 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 10799 CImg<T>& operator/=(const t value) {
10676 10800 if (is_empty()) return *this;
10677 10801 #ifdef cimg_use_openmp
10678   -#pragma omp parallel for if (size()>=32768)
  10802 +#pragma omp parallel for cimg_openmp_if(size()>=32768)
10679 10803 #endif
10680 10804 cimg_rof(*this,ptrd,T) *ptrd = (T)(*ptrd / value);
10681 10805 return *this;
... ... @@ -10686,37 +10810,7 @@ namespace cimg_library_suffixed {
10686 10810 Similar to operator+=(const char*), except that it performs a division instead of an addition.
10687 10811 **/
10688 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 10816 //! In-place division operator.
... ... @@ -10772,7 +10866,7 @@ namespace cimg_library_suffixed {
10772 10866 CImg<T>& operator%=(const t value) {
10773 10867 if (is_empty()) return *this;
10774 10868 #ifdef cimg_use_openmp
10775   -#pragma omp parallel for if (size()>=16384)
  10869 +#pragma omp parallel for cimg_openmp_if(size()>=16384)
10776 10870 #endif
10777 10871 cimg_rof(*this,ptrd,T) *ptrd = (T)cimg::mod(*ptrd,(T)value);
10778 10872 return *this;
... ... @@ -10783,37 +10877,7 @@ namespace cimg_library_suffixed {
10783 10877 Similar to operator+=(const char*), except that it performs a modulo operation instead of an addition.
10784 10878 **/
10785 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 10883 //! In-place modulo operator.
... ... @@ -10871,7 +10935,7 @@ namespace cimg_library_suffixed {
10871 10935 CImg<T>& operator&=(const t value) {
10872 10936 if (is_empty()) return *this;
10873 10937 #ifdef cimg_use_openmp
10874   -#pragma omp parallel for if (size()>=32768)
  10938 +#pragma omp parallel for cimg_openmp_if(size()>=32768)
10875 10939 #endif
10876 10940 cimg_rof(*this,ptrd,T) *ptrd = (T)((unsigned long)*ptrd & (unsigned long)value);
10877 10941 return *this;
... ... @@ -10882,39 +10946,7 @@ namespace cimg_library_suffixed {
10882 10946 Similar to operator+=(const char*), except that it performs a bitwise AND operation instead of an addition.
10883 10947 **/
10884 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 10952 //! In-place bitwise AND operator.
... ... @@ -10972,7 +11004,7 @@ namespace cimg_library_suffixed {
10972 11004 CImg<T>& operator|=(const t value) {
10973 11005 if (is_empty()) return *this;
10974 11006 #ifdef cimg_use_openmp
10975   -#pragma omp parallel for if (size()>=32768)
  11007 +#pragma omp parallel for cimg_openmp_if(size()>=32768)
10976 11008 #endif
10977 11009 cimg_rof(*this,ptrd,T) *ptrd = (T)((unsigned long)*ptrd | (unsigned long)value);
10978 11010 return *this;
... ... @@ -10983,39 +11015,7 @@ namespace cimg_library_suffixed {
10983 11015 Similar to operator+=(const char*), except that it performs a bitwise OR operation instead of an addition.
10984 11016 **/
10985 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 11021 //! In-place bitwise OR operator.
... ... @@ -11075,7 +11075,7 @@ namespace cimg_library_suffixed {
11075 11075 CImg<T>& operator^=(const t value) {
11076 11076 if (is_empty()) return *this;
11077 11077 #ifdef cimg_use_openmp
11078   -#pragma omp parallel for if (size()>=32768)
  11078 +#pragma omp parallel for cimg_openmp_if(size()>=32768)
11079 11079 #endif
11080 11080 cimg_rof(*this,ptrd,T) *ptrd = (T)((unsigned long)*ptrd ^ (unsigned long)value);
11081 11081 return *this;
... ... @@ -11088,39 +11088,7 @@ namespace cimg_library_suffixed {
11088 11088 - It does \e not compute the \e power of pixel values. For this purpose, use pow(const char*) instead.
11089 11089 **/
11090 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 11094 //! In-place bitwise XOR operator.
... ... @@ -11180,7 +11148,7 @@ namespace cimg_library_suffixed {
11180 11148 CImg<T>& operator<<=(const t value) {
11181 11149 if (is_empty()) return *this;
11182 11150 #ifdef cimg_use_openmp
11183   -#pragma omp parallel for if (size()>=65536)
  11151 +#pragma omp parallel for cimg_openmp_if(size()>=65536)
11184 11152 #endif
11185 11153 cimg_rof(*this,ptrd,T) *ptrd = (T)(((long)*ptrd) << (int)value);
11186 11154 return *this;
... ... @@ -11191,37 +11159,7 @@ namespace cimg_library_suffixed {
11191 11159 Similar to operator+=(const char*), except that it performs a bitwise left shift instead of an addition.
11192 11160 **/
11193 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 11165 //! In-place bitwise left shift operator.
... ... @@ -11280,7 +11218,7 @@ namespace cimg_library_suffixed {
11280 11218 CImg<T>& operator>>=(const t value) {
11281 11219 if (is_empty()) return *this;
11282 11220 #ifdef cimg_use_openmp
11283   -#pragma omp parallel for if (size()>=65536)
  11221 +#pragma omp parallel for cimg_openmp_if(size()>=65536)
11284 11222 #endif
11285 11223 cimg_rof(*this,ptrd,T) *ptrd = (T)(((long)*ptrd) >> (int)value);
11286 11224 return *this;
... ... @@ -11291,37 +11229,7 @@ namespace cimg_library_suffixed {
11291 11229 Similar to operator+=(const char*), except that it performs a bitwise right shift instead of an addition.
11292 11230 **/
11293 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 11235 //! In-place bitwise right shift operator.
... ... @@ -11403,25 +11311,7 @@ namespace cimg_library_suffixed {
11403 11311 \param expression Value string describing the way pixel values are compared.
11404 11312 **/
11405 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 11317 //! Test if two images have the same size and values.
... ... @@ -12946,6 +12836,8 @@ namespace cimg_library_suffixed {
12946 12836 of the image instance (written in base 10), separated by specified \c separator character.
12947 12837 \param separator A \c char character which specifies the separator between values in the returned C-string.
12948 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 12841 \note
12950 12842 - The returned image is never empty.
12951 12843 - For an empty image instance, the returned string is <tt>""</tt>.
... ... @@ -12953,15 +12845,18 @@ namespace cimg_library_suffixed {
12953 12845 - Otherwise, if the maximum number of string characters is exceeded, the value string is cut off
12954 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 12850 if (is_empty()) return CImg<charT>::string("");
12958 12851 CImgList<charT> items;
12959 12852 CImg<charT> s_item(256); *s_item = 0;
12960 12853 const T *ptrs = _data;
12961 12854 unsigned int string_size = 0;
  12855 + const char *const _format = format?format:cimg::type<T>::format();
  12856 +
12962 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 12860 CImg<charT> item(s_item._data,printed_size);
12966 12861 item[printed_size - 1] = separator;
12967 12862 item.move_to(items);
... ... @@ -13011,9 +12906,9 @@ namespace cimg_library_suffixed {
13011 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 12913 bool is_nan() const {
13019 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 13325 // Check consistency for the particular case of an empty 3d object.
13431 13326 if (is_empty()) {
13432 13327 if (primitives || colors || opacities) {
13433   - if (error_message) std::sprintf(error_message,
  13328 + if (error_message) cimg_sprintf(error_message,
13434 13329 "3d object (%u,%u) defines no vertices but %u primitives, "
13435 13330 "%u colors and %lu opacities",
13436 13331 _width,primitives._width,primitives._width,
... ... @@ -13442,19 +13337,19 @@ namespace cimg_library_suffixed {
13442 13337  
13443 13338 // Check consistency of vertices.
13444 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 13341 "3d object (%u,%u) has invalid vertex dimensions (%u,%u,%u,%u)",
13447 13342 _width,primitives._width,_width,_height,_depth,_spectrum);
13448 13343 return false;
13449 13344 }
13450 13345 if (colors._width>primitives._width + 1) {
13451   - if (error_message) std::sprintf(error_message,
  13346 + if (error_message) cimg_sprintf(error_message,
13452 13347 "3d object (%u,%u) defines %u colors",
13453 13348 _width,primitives._width,colors._width);
13454 13349 return false;
13455 13350 }
13456 13351 if (opacities.size()>primitives._width) {
13457   - if (error_message) std::sprintf(error_message,
  13352 + if (error_message) cimg_sprintf(error_message,
13458 13353 "3d object (%u,%u) defines %lu opacities",
13459 13354 _width,primitives._width,(unsigned long)opacities.size());
13460 13355 return false;
... ... @@ -13469,7 +13364,7 @@ namespace cimg_library_suffixed {
13469 13364 case 1 : { // Point.
13470 13365 const unsigned int i0 = (unsigned int)primitive(0);
13471 13366 if (i0>=_width) {
13472   - if (error_message) std::sprintf(error_message,
  13367 + if (error_message) cimg_sprintf(error_message,
13473 13368 "3d object (%u,%u) refers to invalid vertex indice %u in "
13474 13369 "point primitive [%u]",
13475 13370 _width,primitives._width,i0,l);
... ... @@ -13481,7 +13376,7 @@ namespace cimg_library_suffixed {
13481 13376 i0 = (unsigned int)primitive(0),
13482 13377 i1 = (unsigned int)primitive(1);
13483 13378 if (i0>=_width || i1>=_width) {
13484   - if (error_message) std::sprintf(error_message,
  13379 + if (error_message) cimg_sprintf(error_message,
13485 13380 "3d object (%u,%u) refers to invalid vertex indices (%u,%u) in "
13486 13381 "sphere primitive [%u]",
13487 13382 _width,primitives._width,i0,i1,l);
... ... @@ -13494,7 +13389,7 @@ namespace cimg_library_suffixed {
13494 13389 i0 = (unsigned int)primitive(0),
13495 13390 i1 = (unsigned int)primitive(1);
13496 13391 if (i0>=_width || i1>=_width) {
13497   - if (error_message) std::sprintf(error_message,
  13392 + if (error_message) cimg_sprintf(error_message,
13498 13393 "3d object (%u,%u) refers to invalid vertex indices (%u,%u) in "
13499 13394 "segment primitive [%u]",
13500 13395 _width,primitives._width,i0,i1,l);
... ... @@ -13508,7 +13403,7 @@ namespace cimg_library_suffixed {
13508 13403 i1 = (unsigned int)primitive(1),
13509 13404 i2 = (unsigned int)primitive(2);
13510 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 13407 "3d object (%u,%u) refers to invalid vertex indices (%u,%u,%u) in "
13513 13408 "triangle primitive [%u]",
13514 13409 _width,primitives._width,i0,i1,i2,l);
... ... @@ -13523,7 +13418,7 @@ namespace cimg_library_suffixed {
13523 13418 i2 = (unsigned int)primitive(2),
13524 13419 i3 = (unsigned int)primitive(3);
13525 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 13422 "3d object (%u,%u) refers to invalid vertex indices (%u,%u,%u,%u) in "
13528 13423 "quadrangle primitive [%u]",
13529 13424 _width,primitives._width,i0,i1,i2,i3,l);
... ... @@ -13531,7 +13426,7 @@ namespace cimg_library_suffixed {
13531 13426 }
13532 13427 } break;
13533 13428 default :
13534   - if (error_message) std::sprintf(error_message,
  13429 + if (error_message) cimg_sprintf(error_message,
13535 13430 "3d object (%u,%u) defines an invalid primitive [%u] of size %u",
13536 13431 _width,primitives._width,l,(unsigned int)psiz);
13537 13432 return false;
... ... @@ -13542,7 +13437,7 @@ namespace cimg_library_suffixed {
13542 13437 cimglist_for(colors,c) {
13543 13438 const CImg<tc>& color = colors[c];
13544 13439 if (!color) {
13545   - if (error_message) std::sprintf(error_message,
  13440 + if (error_message) cimg_sprintf(error_message,
13546 13441 "3d object (%u,%u) defines no color for primitive [%u]",
13547 13442 _width,primitives._width,c);
13548 13443 return false;
... ... @@ -13553,7 +13448,7 @@ namespace cimg_library_suffixed {
13553 13448 if (colors._width>primitives._width) {
13554 13449 const CImg<tc> &light = colors.back();
13555 13450 if (!light || light._depth>1) {
13556   - if (error_message) std::sprintf(error_message,
  13451 + if (error_message) cimg_sprintf(error_message,
13557 13452 "3d object (%u,%u) defines an invalid light texture (%u,%u,%u,%u)",
13558 13453 _width,primitives._width,light._width,
13559 13454 light._height,light._depth,light._spectrum);
... ... @@ -13579,7 +13474,7 @@ namespace cimg_library_suffixed {
13579 13474  
13580 13475 // Check instance dimension and header.
13581 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 13478 "CImg3d has invalid dimensions (%u,%u,%u,%u)",
13584 13479 _width,_height,_depth,_spectrum);
13585 13480 return false;
... ... @@ -13587,7 +13482,7 @@ namespace cimg_library_suffixed {
13587 13482 const T *ptrs = _data, *const ptre = end();
13588 13483 if (!_is_CImg3d(*(ptrs++),'C') || !_is_CImg3d(*(ptrs++),'I') || !_is_CImg3d(*(ptrs++),'m') ||
13589 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 13486 "CImg3d header not found");
13592 13487 return false;
13593 13488 }
... ... @@ -13599,7 +13494,7 @@ namespace cimg_library_suffixed {
13599 13494 if (!full_check) {
13600 13495 const unsigned long minimal_size = 8UL + 3*nb_points + 6*nb_primitives;
13601 13496 if (_data + minimal_size>ptre) {
13602   - if (error_message) std::sprintf(error_message,
  13497 + if (error_message) cimg_sprintf(error_message,
13603 13498 "CImg3d (%u,%u) has only %lu values, while at least %lu values were expected",
13604 13499 nb_points,nb_primitives,size(),minimal_size);
13605 13500 return false;
... ... @@ -13609,13 +13504,13 @@ namespace cimg_library_suffixed {
13609 13504 // Check consistency of vertex data.
13610 13505 if (!nb_points) {
13611 13506 if (nb_primitives) {
13612   - if (error_message) std::sprintf(error_message,
  13507 + if (error_message) cimg_sprintf(error_message,
13613 13508 "CImg3d (%u,%u) defines no vertices but %u primitives",
13614 13509 nb_points,nb_primitives,nb_primitives);
13615 13510 return false;
13616 13511 }
13617 13512 if (ptrs!=ptre) {
13618   - if (error_message) std::sprintf(error_message,
  13513 + if (error_message) cimg_sprintf(error_message,
13619 13514 "CImg3d (%u,%u) is an empty object but contains %u value%s "
13620 13515 "more than expected",
13621 13516 nb_points,nb_primitives,(unsigned int)(ptre - ptrs),(ptre - ptrs)>1?"s":"");
... ... @@ -13624,7 +13519,7 @@ namespace cimg_library_suffixed {
13624 13519 return true;
13625 13520 }
13626 13521 if (ptrs + 3*nb_points>ptre) {
13627   - if (error_message) std::sprintf(error_message,
  13522 + if (error_message) cimg_sprintf(error_message,
13628 13523 "CImg3d (%u,%u) defines only %u vertices data",
13629 13524 nb_points,nb_primitives,(unsigned int)(ptre - ptrs)/3);
13630 13525 return false;
... ... @@ -13633,7 +13528,7 @@ namespace cimg_library_suffixed {
13633 13528  
13634 13529 // Check consistency of primitive data.
13635 13530 if (ptrs==ptre) {
13636   - if (error_message) std::sprintf(error_message,
  13531 + if (error_message) cimg_sprintf(error_message,
13637 13532 "CImg3d (%u,%u) defines %u vertices but no primitive",
13638 13533 nb_points,nb_primitives,nb_points);
13639 13534 return false;
... ... @@ -13647,7 +13542,7 @@ namespace cimg_library_suffixed {
13647 13542 case 1 : { // Point.
13648 13543 const unsigned int i0 = cimg::float2uint((float)*(ptrs++));
13649 13544 if (i0>=nb_points) {
13650   - if (error_message) std::sprintf(error_message,
  13545 + if (error_message) cimg_sprintf(error_message,
13651 13546 "CImg3d (%u,%u) refers to invalid vertex indice %u in point primitive [%u]",
13652 13547 nb_points,nb_primitives,i0,p);
13653 13548 return false;
... ... @@ -13659,7 +13554,7 @@ namespace cimg_library_suffixed {
13659 13554 i1 = cimg::float2uint((float)*(ptrs++));
13660 13555 ptrs+=3;
13661 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 13558 "CImg3d (%u,%u) refers to invalid vertex indices (%u,%u) in "
13664 13559 "sphere primitive [%u]",
13665 13560 nb_points,nb_primitives,i0,i1,p);
... ... @@ -13672,7 +13567,7 @@ namespace cimg_library_suffixed {
13672 13567 i1 = cimg::float2uint((float)*(ptrs++));
13673 13568 if (nb_inds==6) ptrs+=4;
13674 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 13571 "CImg3d (%u,%u) refers to invalid vertex indices (%u,%u) in "
13677 13572 "segment primitive [%u]",
13678 13573 nb_points,nb_primitives,i0,i1,p);
... ... @@ -13686,7 +13581,7 @@ namespace cimg_library_suffixed {
13686 13581 i2 = cimg::float2uint((float)*(ptrs++));
13687 13582 if (nb_inds==9) ptrs+=6;
13688 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 13585 "CImg3d (%u,%u) refers to invalid vertex indices (%u,%u,%u) in "
13691 13586 "triangle primitive [%u]",
13692 13587 nb_points,nb_primitives,i0,i1,i2,p);
... ... @@ -13701,7 +13596,7 @@ namespace cimg_library_suffixed {
13701 13596 i3 = cimg::float2uint((float)*(ptrs++));
13702 13597 if (nb_inds==12) ptrs+=8;
13703 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 13600 "CImg3d (%u,%u) refers to invalid vertex indices (%u,%u,%u,%u) in "
13706 13601 "quadrangle primitive [%u]",
13707 13602 nb_points,nb_primitives,i0,i1,i2,i3,p);
... ... @@ -13709,13 +13604,13 @@ namespace cimg_library_suffixed {
13709 13604 }
13710 13605 } break;
13711 13606 default :
13712   - if (error_message) std::sprintf(error_message,
  13607 + if (error_message) cimg_sprintf(error_message,
13713 13608 "CImg3d (%u,%u) defines an invalid primitive [%u] of size %u",
13714 13609 nb_points,nb_primitives,p,nb_inds);
13715 13610 return false;
13716 13611 }
13717 13612 if (ptrs>ptre) {
13718   - if (error_message) std::sprintf(error_message,
  13613 + if (error_message) cimg_sprintf(error_message,
13719 13614 "CImg3d (%u,%u) has incomplete primitive data for primitive [%u], "
13720 13615 "%u values missing",
13721 13616 nb_points,nb_primitives,p,(unsigned int)(ptrs - ptre));
... ... @@ -13725,7 +13620,7 @@ namespace cimg_library_suffixed {
13725 13620  
13726 13621 // Check consistency of color data.
13727 13622 if (ptrs==ptre) {
13728   - if (error_message) std::sprintf(error_message,
  13623 + if (error_message) cimg_sprintf(error_message,
13729 13624 "CImg3d (%u,%u) defines no color/texture data",
13730 13625 nb_points,nb_primitives);
13731 13626 return false;
... ... @@ -13739,7 +13634,7 @@ namespace cimg_library_suffixed {
13739 13634 s = (unsigned int)*(ptrs - 1);
13740 13635 if (!h && !s) {
13741 13636 if (w>=c) {
13742   - if (error_message) std::sprintf(error_message,
  13637 + if (error_message) cimg_sprintf(error_message,
13743 13638 "CImg3d (%u,%u) refers to invalid shared sprite/texture indice %u "
13744 13639 "for primitive [%u]",
13745 13640 nb_points,nb_primitives,w,c);
... ... @@ -13748,7 +13643,7 @@ namespace cimg_library_suffixed {
13748 13643 } else ptrs+=w*h*s;
13749 13644 }
13750 13645 if (ptrs>ptre) {
13751   - if (error_message) std::sprintf(error_message,
  13646 + if (error_message) cimg_sprintf(error_message,
13752 13647 "CImg3d (%u,%u) has incomplete color/texture data for primitive [%u], "
13753 13648 "%u values missing",
13754 13649 nb_points,nb_primitives,c,(unsigned int)(ptrs - ptre));
... ... @@ -13758,7 +13653,7 @@ namespace cimg_library_suffixed {
13758 13653  
13759 13654 // Check consistency of opacity data.
13760 13655 if (ptrs==ptre) {
13761   - if (error_message) std::sprintf(error_message,
  13656 + if (error_message) cimg_sprintf(error_message,
13762 13657 "CImg3d (%u,%u) defines no opacity data",
13763 13658 nb_points,nb_primitives);
13764 13659 return false;
... ... @@ -13771,7 +13666,7 @@ namespace cimg_library_suffixed {
13771 13666 s = (unsigned int)*(ptrs - 1);
13772 13667 if (!h && !s) {
13773 13668 if (w>=o) {
13774   - if (error_message) std::sprintf(error_message,
  13669 + if (error_message) cimg_sprintf(error_message,
13775 13670 "CImg3d (%u,%u) refers to invalid shared opacity indice %u "
13776 13671 "for primitive [%u]",
13777 13672 nb_points,nb_primitives,w,o);
... ... @@ -13780,7 +13675,7 @@ namespace cimg_library_suffixed {
13780 13675 } else ptrs+=w*h*s;
13781 13676 }
13782 13677 if (ptrs>ptre) {
13783   - if (error_message) std::sprintf(error_message,
  13678 + if (error_message) cimg_sprintf(error_message,
13784 13679 "CImg3d (%u,%u) has incomplete opacity data for primitive [%u]",
13785 13680 nb_points,nb_primitives,o);
13786 13681 return false;
... ... @@ -13789,7 +13684,7 @@ namespace cimg_library_suffixed {
13789 13684  
13790 13685 // Check end of data.
13791 13686 if (ptrs<ptre) {
13792   - if (error_message) std::sprintf(error_message,
  13687 + if (error_message) cimg_sprintf(error_message,
13793 13688 "CImg3d (%u,%u) contains %u value%s more than expected",
13794 13689 nb_points,nb_primitives,(unsigned int)(ptre - ptrs),(ptre - ptrs)>1?"s":"");
13795 13690 return false;
... ... @@ -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 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 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 13730 const char *const calling_function;
13826 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 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 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 13768 if (!expression || !*expression)
13853 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 13787 level.assign(expr._width - 1);
13858   - int lv = 0; // Count parentheses/brackets level of expression.
  13788 + int lv = 0;
13859 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 13791 *(pd++) = (unsigned int)(*ps=='('||*ps=='['?lv++:*ps==')'||*ps==']'?--lv:lv);
13862 13792 if (lv!=0) {
  13793 + cimg::strellipsize(expr,64);
13863 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 13797 expr._data);
13867 13798 }
13868 13799  
13869 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 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 13954 if (se<=ss || !*ss) {
  13955 + cimg::strellipsize(expr,64);
13951 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 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 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 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 13986 const char saved_char = *se; *se = 0;
13961 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 13996 #if cimg_OS==2
13969 13997 // Check for +/-NaN and +/-inf as Microsoft's sscanf() version is not able
13970 13998 // to read those particular values.
13971 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 14045 if (*ss=='w' && *ss1=='h') _cimg_mp_return(reserved_label[0]); // wh
14007 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 17412 mp.mem[target] = _cimg_mp_defunc(mp);
14717 17413 }
14718 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 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 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 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 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 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 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 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 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 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 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 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 18907 //! Compute the square value of each pixel value.
14913 18908 /**
... ... @@ -14925,7 +18920,7 @@ namespace cimg_library_suffixed {
14925 18920 CImg<T>& sqr() {
14926 18921 if (is_empty()) return *this;
14927 18922 #ifdef cimg_use_openmp
14928   -#pragma omp parallel for if (size()>=524288)
  18923 +#pragma omp parallel for cimg_openmp_if(size()>=524288)
14929 18924 #endif
14930 18925 cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = (T)(val*val); };
14931 18926 return *this;
... ... @@ -14952,7 +18947,7 @@ namespace cimg_library_suffixed {
14952 18947 CImg<T>& sqrt() {
14953 18948 if (is_empty()) return *this;
14954 18949 #ifdef cimg_use_openmp
14955   -#pragma omp parallel for if (size()>=8192)
  18950 +#pragma omp parallel for cimg_openmp_if(size()>=8192)
14956 18951 #endif
14957 18952 cimg_rof(*this,ptrd,T) *ptrd = (T)std::sqrt((double)*ptrd);
14958 18953 return *this;
... ... @@ -14973,7 +18968,7 @@ namespace cimg_library_suffixed {
14973 18968 CImg<T>& exp() {
14974 18969 if (is_empty()) return *this;
14975 18970 #ifdef cimg_use_openmp
14976   -#pragma omp parallel for if (size()>=4096)
  18971 +#pragma omp parallel for cimg_openmp_if(size()>=4096)
14977 18972 #endif
14978 18973 cimg_rof(*this,ptrd,T) *ptrd = (T)std::exp((double)*ptrd);
14979 18974 return *this;
... ... @@ -14995,7 +18990,7 @@ namespace cimg_library_suffixed {
14995 18990 CImg<T>& log() {
14996 18991 if (is_empty()) return *this;
14997 18992 #ifdef cimg_use_openmp
14998   -#pragma omp parallel for if (size()>=262144)
  18993 +#pragma omp parallel for cimg_openmp_if(size()>=262144)
14999 18994 #endif
15000 18995 cimg_rof(*this,ptrd,T) *ptrd = (T)std::log((double)*ptrd);
15001 18996 return *this;
... ... @@ -15017,7 +19012,7 @@ namespace cimg_library_suffixed {
15017 19012 CImg<T>& log2() {
15018 19013 if (is_empty()) return *this;
15019 19014 #ifdef cimg_use_openmp
15020   -#pragma omp parallel for if (size()>=4096)
  19015 +#pragma omp parallel for cimg_openmp_if(size()>=4096)
15021 19016 #endif
15022 19017 cimg_rof(*this,ptrd,T) *ptrd = (T)cimg::log2((double)*ptrd);
15023 19018 return *this;
... ... @@ -15039,7 +19034,7 @@ namespace cimg_library_suffixed {
15039 19034 CImg<T>& log10() {
15040 19035 if (is_empty()) return *this;
15041 19036 #ifdef cimg_use_openmp
15042   -#pragma omp parallel for if (size()>=4096)
  19037 +#pragma omp parallel for cimg_openmp_if(size()>=4096)
15043 19038 #endif
15044 19039 cimg_rof(*this,ptrd,T) *ptrd = (T)std::log10((double)*ptrd);
15045 19040 return *this;
... ... @@ -15060,7 +19055,7 @@ namespace cimg_library_suffixed {
15060 19055 CImg<T>& abs() {
15061 19056 if (is_empty()) return *this;
15062 19057 #ifdef cimg_use_openmp
15063   -#pragma omp parallel for if (size()>=524288)
  19058 +#pragma omp parallel for cimg_openmp_if(size()>=524288)
15064 19059 #endif
15065 19060 cimg_rof(*this,ptrd,T) *ptrd = cimg::abs(*ptrd);
15066 19061 return *this;
... ... @@ -15086,7 +19081,7 @@ namespace cimg_library_suffixed {
15086 19081 CImg<T>& sign() {
15087 19082 if (is_empty()) return *this;
15088 19083 #ifdef cimg_use_openmp
15089   -#pragma omp parallel for if (size()>=32768)
  19084 +#pragma omp parallel for cimg_openmp_if(size()>=32768)
15090 19085 #endif
15091 19086 cimg_rof(*this,ptrd,T) *ptrd = cimg::sign(*ptrd);
15092 19087 return *this;
... ... @@ -15108,7 +19103,7 @@ namespace cimg_library_suffixed {
15108 19103 CImg<T>& cos() {
15109 19104 if (is_empty()) return *this;
15110 19105 #ifdef cimg_use_openmp
15111   -#pragma omp parallel for if (size()>=8192)
  19106 +#pragma omp parallel for cimg_openmp_if(size()>=8192)
15112 19107 #endif
15113 19108 cimg_rof(*this,ptrd,T) *ptrd = (T)std::cos((double)*ptrd);
15114 19109 return *this;
... ... @@ -15130,7 +19125,7 @@ namespace cimg_library_suffixed {
15130 19125 CImg<T>& sin() {
15131 19126 if (is_empty()) return *this;
15132 19127 #ifdef cimg_use_openmp
15133   -#pragma omp parallel for if (size()>=8192)
  19128 +#pragma omp parallel for cimg_openmp_if(size()>=8192)
15134 19129 #endif
15135 19130 cimg_rof(*this,ptrd,T) *ptrd = (T)std::sin((double)*ptrd);
15136 19131 return *this;
... ... @@ -15153,7 +19148,7 @@ namespace cimg_library_suffixed {
15153 19148 CImg<T>& sinc() {
15154 19149 if (is_empty()) return *this;
15155 19150 #ifdef cimg_use_openmp
15156   -#pragma omp parallel for if (size()>=2048)
  19151 +#pragma omp parallel for cimg_openmp_if(size()>=2048)
15157 19152 #endif
15158 19153 cimg_rof(*this,ptrd,T) *ptrd = (T)cimg::sinc((double)*ptrd);
15159 19154 return *this;
... ... @@ -15175,7 +19170,7 @@ namespace cimg_library_suffixed {
15175 19170 CImg<T>& tan() {
15176 19171 if (is_empty()) return *this;
15177 19172 #ifdef cimg_use_openmp
15178   -#pragma omp parallel for if (size()>=2048)
  19173 +#pragma omp parallel for cimg_openmp_if(size()>=2048)
15179 19174 #endif
15180 19175 cimg_rof(*this,ptrd,T) *ptrd = (T)std::tan((double)*ptrd);
15181 19176 return *this;
... ... @@ -15197,7 +19192,7 @@ namespace cimg_library_suffixed {
15197 19192 CImg<T>& cosh() {
15198 19193 if (is_empty()) return *this;
15199 19194 #ifdef cimg_use_openmp
15200   -#pragma omp parallel for if (size()>=2048)
  19195 +#pragma omp parallel for cimg_openmp_if(size()>=2048)
15201 19196 #endif
15202 19197 cimg_rof(*this,ptrd,T) *ptrd = (T)std::cosh((double)*ptrd);
15203 19198 return *this;
... ... @@ -15219,7 +19214,7 @@ namespace cimg_library_suffixed {
15219 19214 CImg<T>& sinh() {
15220 19215 if (is_empty()) return *this;
15221 19216 #ifdef cimg_use_openmp
15222   -#pragma omp parallel for if (size()>=2048)
  19217 +#pragma omp parallel for cimg_openmp_if(size()>=2048)
15223 19218 #endif
15224 19219 cimg_rof(*this,ptrd,T) *ptrd = (T)std::sinh((double)*ptrd);
15225 19220 return *this;
... ... @@ -15241,7 +19236,7 @@ namespace cimg_library_suffixed {
15241 19236 CImg<T>& tanh() {
15242 19237 if (is_empty()) return *this;
15243 19238 #ifdef cimg_use_openmp
15244   -#pragma omp parallel for if (size()>=2048)
  19239 +#pragma omp parallel for cimg_openmp_if(size()>=2048)
15245 19240 #endif
15246 19241 cimg_rof(*this,ptrd,T) *ptrd = (T)std::tanh((double)*ptrd);
15247 19242 return *this;
... ... @@ -15263,7 +19258,7 @@ namespace cimg_library_suffixed {
15263 19258 CImg<T>& acos() {
15264 19259 if (is_empty()) return *this;
15265 19260 #ifdef cimg_use_openmp
15266   -#pragma omp parallel for if (size()>=8192)
  19261 +#pragma omp parallel for cimg_openmp_if(size()>=8192)
15267 19262 #endif
15268 19263 cimg_rof(*this,ptrd,T) *ptrd = (T)std::acos((double)*ptrd);
15269 19264 return *this;
... ... @@ -15285,7 +19280,7 @@ namespace cimg_library_suffixed {
15285 19280 CImg<T>& asin() {
15286 19281 if (is_empty()) return *this;
15287 19282 #ifdef cimg_use_openmp
15288   -#pragma omp parallel for if (size()>=8192)
  19283 +#pragma omp parallel for cimg_openmp_if(size()>=8192)
15289 19284 #endif
15290 19285 cimg_rof(*this,ptrd,T) *ptrd = (T)std::asin((double)*ptrd);
15291 19286 return *this;
... ... @@ -15307,7 +19302,7 @@ namespace cimg_library_suffixed {
15307 19302 CImg<T>& atan() {
15308 19303 if (is_empty()) return *this;
15309 19304 #ifdef cimg_use_openmp
15310   -#pragma omp parallel for if (size()>=8192)
  19305 +#pragma omp parallel for cimg_openmp_if(size()>=8192)
15311 19306 #endif
15312 19307 cimg_rof(*this,ptrd,T) *ptrd = (T)std::atan((double)*ptrd);
15313 19308 return *this;
... ... @@ -15436,35 +19431,35 @@ namespace cimg_library_suffixed {
15436 19431 if (is_empty()) return *this;
15437 19432 if (p==-4) {
15438 19433 #ifdef cimg_use_openmp
15439   -#pragma omp parallel for if (size()>=32768)
  19434 +#pragma omp parallel for cimg_openmp_if(size()>=32768)
15440 19435 #endif
15441 19436 cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = (T)(1.0/(val*val*val*val)); }
15442 19437 return *this;
15443 19438 }
15444 19439 if (p==-3) {
15445 19440 #ifdef cimg_use_openmp
15446   -#pragma omp parallel for if (size()>=32768)
  19441 +#pragma omp parallel for cimg_openmp_if(size()>=32768)
15447 19442 #endif
15448 19443 cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = (T)(1.0/(val*val*val)); }
15449 19444 return *this;
15450 19445 }
15451 19446 if (p==-2) {
15452 19447 #ifdef cimg_use_openmp
15453   -#pragma omp parallel for if (size()>=32768)
  19448 +#pragma omp parallel for cimg_openmp_if(size()>=32768)
15454 19449 #endif
15455 19450 cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = (T)(1.0/(val*val)); }
15456 19451 return *this;
15457 19452 }
15458 19453 if (p==-1) {
15459 19454 #ifdef cimg_use_openmp
15460   -#pragma omp parallel for if (size()>=32768)
  19455 +#pragma omp parallel for cimg_openmp_if(size()>=32768)
15461 19456 #endif
15462 19457 cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = (T)(1.0/val); }
15463 19458 return *this;
15464 19459 }
15465 19460 if (p==-0.5) {
15466 19461 #ifdef cimg_use_openmp
15467   -#pragma omp parallel for if (size()>=8192)
  19462 +#pragma omp parallel for cimg_openmp_if(size()>=8192)
15468 19463 #endif
15469 19464 cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = (T)(1/std::sqrt((double)val)); }
15470 19465 return *this;
... ... @@ -15475,20 +19470,20 @@ namespace cimg_library_suffixed {
15475 19470 if (p==2) return sqr();
15476 19471 if (p==3) {
15477 19472 #ifdef cimg_use_openmp
15478   -#pragma omp parallel for if (size()>=262144)
  19473 +#pragma omp parallel for cimg_openmp_if(size()>=262144)
15479 19474 #endif
15480 19475 cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = val*val*val; }
15481 19476 return *this;
15482 19477 }
15483 19478 if (p==4) {
15484 19479 #ifdef cimg_use_openmp
15485   -#pragma omp parallel for if (size()>=131072)
  19480 +#pragma omp parallel for cimg_openmp_if(size()>=131072)
15486 19481 #endif
15487 19482 cimg_rof(*this,ptrd,T) { const T val = *ptrd; *ptrd = val*val*val*val; }
15488 19483 return *this;
15489 19484 }
15490 19485 #ifdef cimg_use_openmp
15491   -#pragma omp parallel for if (size()>=1024)
  19486 +#pragma omp parallel for cimg_openmp_if(size()>=1024)
15492 19487 #endif
15493 19488 cimg_rof(*this,ptrd,T) *ptrd = (T)std::pow((double)*ptrd,p);
15494 19489 return *this;
... ... @@ -15504,44 +19499,7 @@ namespace cimg_library_suffixed {
15504 19499 Similar to operator+=(const char*), except it performs a pointwise exponentiation instead of an addition.
15505 19500 **/
15506 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 19505 //! Raise each pixel value to a power, specified from an expression \newinstance.
... ... @@ -15580,7 +19538,7 @@ namespace cimg_library_suffixed {
15580 19538 CImg<T>& rol(const unsigned int n=1) {
15581 19539 if (is_empty()) return *this;
15582 19540 #ifdef cimg_use_openmp
15583   -#pragma omp parallel for if (size()>=32768)
  19541 +#pragma omp parallel for cimg_openmp_if(size()>=32768)
15584 19542 #endif
15585 19543 cimg_rof(*this,ptrd,T) *ptrd = (T)cimg::rol(*ptrd,n);
15586 19544 return *this;
... ... @@ -15596,45 +19554,7 @@ namespace cimg_library_suffixed {
15596 19554 Similar to operator<<=(const char*), except that it performs a left rotation instead of a left shift.
15597 19555 **/
15598 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 19560 //! Compute the bitwise left rotation of each pixel value \newinstance.
... ... @@ -15673,7 +19593,7 @@ namespace cimg_library_suffixed {
15673 19593 CImg<T>& ror(const unsigned int n=1) {
15674 19594 if (is_empty()) return *this;
15675 19595 #ifdef cimg_use_openmp
15676   -#pragma omp parallel for if (size()>=32768)
  19596 +#pragma omp parallel for cimg_openmp_if(size()>=32768)
15677 19597 #endif
15678 19598 cimg_rof(*this,ptrd,T) *ptrd = (T)cimg::ror(*ptrd,n);
15679 19599 return *this;
... ... @@ -15689,45 +19609,7 @@ namespace cimg_library_suffixed {
15689 19609 Similar to operator>>=(const char*), except that it performs a right rotation instead of a right shift.
15690 19610 **/
15691 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 19615 //! Compute the bitwise right rotation of each pixel value \newinstance.
... ... @@ -15768,7 +19650,7 @@ namespace cimg_library_suffixed {
15768 19650 CImg<T>& min(const T& val) {
15769 19651 if (is_empty()) return *this;
15770 19652 #ifdef cimg_use_openmp
15771   -#pragma omp parallel for if (size()>=65536)
  19653 +#pragma omp parallel for cimg_openmp_if(size()>=65536)
15772 19654 #endif
15773 19655 cimg_rof(*this,ptrd,T) *ptrd = cimg::min(*ptrd,val);
15774 19656 return *this;
... ... @@ -15812,43 +19694,7 @@ namespace cimg_library_suffixed {
15812 19694 \f$\mathrm{min}(I_{(x,y,z,c)},\mathrm{expr}_{(x,y,z,c)})\f$.
15813 19695 **/
15814 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 19700 //! Pointwise min operator between an image and an expression \newinstance.
... ... @@ -15865,7 +19711,7 @@ namespace cimg_library_suffixed {
15865 19711 CImg<T>& max(const T& val) {
15866 19712 if (is_empty()) return *this;
15867 19713 #ifdef cimg_use_openmp
15868   -#pragma omp parallel for if (size()>=65536)
  19714 +#pragma omp parallel for cimg_openmp_if(size()>=65536)
15869 19715 #endif
15870 19716 cimg_rof(*this,ptrd,T) *ptrd = cimg::max(*ptrd,val);
15871 19717 return *this;
... ... @@ -15909,43 +19755,7 @@ namespace cimg_library_suffixed {
15909 19755 \f$\mathrm{max}(I_{(x,y,z,c)},\mathrm{expr}_{(x,y,z,c)})\f$.
15910 19756 **/
15911 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 19761 //! Pointwise max operator between an image and an expression \newinstance.
... ... @@ -16094,7 +19904,7 @@ namespace cimg_library_suffixed {
16094 19904 cimg_instance);
16095 19905 CImg<T> arr(*this);
16096 19906 unsigned int l = 0, ir = size() - 1;
16097   - for (;;) {
  19907 + for ( ; ; ) {
16098 19908 if (ir<=l + 1) {
16099 19909 if (ir==l + 1 && arr[ir]<arr[l]) cimg::swap(arr[l],arr[ir]);
16100 19910 return arr[k];
... ... @@ -16106,7 +19916,7 @@ namespace cimg_library_suffixed {
16106 19916 if (arr[l]>arr[l + 1]) cimg::swap(arr[l],arr[l + 1]);
16107 19917 unsigned int i = l + 1, j = ir;
16108 19918 const T pivot = arr[l + 1];
16109   - for (;;) {
  19919 + for ( ; ; ) {
16110 19920 do ++i; while (arr[i]<pivot);
16111 19921 do --j; while (arr[j]>pivot);
16112 19922 if (j<i) break;
... ... @@ -16256,7 +20066,7 @@ namespace cimg_library_suffixed {
16256 20066 if (_depth==1) {
16257 20067 const double cste = 1.0/std::sqrt(20.0); // Depends on how the Laplacian is computed.
16258 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 20070 #endif
16261 20071 cimg_forC(*this,c) {
16262 20072 CImg_3x3(I,T);
... ... @@ -16268,7 +20078,7 @@ namespace cimg_library_suffixed {
16268 20078 } else {
16269 20079 const double cste = 1.0/std::sqrt(42.0); // Depends on how the Laplacian is computed.
16270 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 20082 #endif
16273 20083 cimg_forC(*this,c) {
16274 20084 CImg_3x3x3(I,T);
... ... @@ -16348,9 +20158,25 @@ namespace cimg_library_suffixed {
16348 20158 \param y Value of the pre-defined variable \c y.
16349 20159 \param z Value of the pre-defined variable \c z.
16350 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 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 20180 if (!expression) return 0;
16355 20181 if (!expression[1]) switch (*expression) { // Single-char optimization.
16356 20182 case 'w' : return (double)_width;
... ... @@ -16359,7 +20185,54 @@ namespace cimg_library_suffixed {
16359 20185 case 's' : return (double)_spectrum;
16360 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 20238 //! Evaluate math formula on a set of variables.
... ... @@ -16368,10 +20241,24 @@ namespace cimg_library_suffixed {
16368 20241 \param xyzc Set of values (x,y,z,c) used for the evaluation.
16369 20242 **/
16370 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 20259 CImg<doubleT> res(1,xyzc.size()/4);
16373 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 20262 #ifdef cimg_use_openmp
16376 20263 #pragma omp parallel if (res._height>=512 && std::strlen(expression)>=6)
16377 20264 {
... ... @@ -18496,36 +22383,95 @@ namespace cimg_library_suffixed {
18496 22383 \param expression C-string describing a math formula, or a list of values.
18497 22384 \param repeat_values In case a list of values is provided, tells if this list must be repeated for the filling.
18498 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 22397 if (is_empty() || !expression || !*expression) return *this;
18502 22398 const unsigned int omode = cimg::exception_mode();
18503 22399 cimg::exception_mode(0);
18504 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 22436 #ifdef cimg_use_openmp
18514   - if (_width>=512 && _height*_depth*_spectrum>=2 && std::strlen(expression)>=6)
18515 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 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 22476 // If failed, try to recognize a list of values.
18531 22477 if (!allow_formula || is_error) {
... ... @@ -18547,8 +22493,8 @@ namespace cimg_library_suffixed {
18547 22493 if (nb<siz && (sep || *nexpression)) {
18548 22494 if (is_error) throw CImgArgumentException("%s",is_error._data);
18549 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 22499 if (repeat_values && nb && nb<siz)
18554 22500 for (T *ptrs = _data, *const ptre = _data + siz; ptrd<ptre; ++ptrs) *(ptrd++) = *ptrs;
... ... @@ -18558,8 +22504,9 @@ namespace cimg_library_suffixed {
18558 22504 }
18559 22505  
18560 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 22512 //! Fill sequentially pixel values according to the values found in another image.
... ... @@ -18811,9 +22758,9 @@ namespace cimg_library_suffixed {
18811 22758  
18812 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 22765 CImg<T>& rand(const T& val_min, const T& val_max) {
18819 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 22785 CImg<T>& round(const double y=1, const int rounding_type=0) {
18839 22786 if (y>0)
18840 22787 #ifdef cimg_use_openmp
18841   -#pragma omp parallel for if (size()>=8192)
  22788 +#pragma omp parallel for cimg_openmp_if(size()>=8192)
18842 22789 #endif
18843 22790 cimg_rof(*this,ptrd,T) *ptrd = cimg::round(*ptrd,y,rounding_type);
18844 22791 return *this;
... ... @@ -18885,7 +22832,7 @@ namespace cimg_library_suffixed {
18885 22832 } break;
18886 22833 case 1 : { // Uniform noise
18887 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 22836 if (val>vmax) val = vmax;
18890 22837 if (val<vmin) val = vmin;
18891 22838 *ptrd = (T)val;
... ... @@ -18894,7 +22841,7 @@ namespace cimg_library_suffixed {
18894 22841 case 2 : { // Salt & Pepper noise
18895 22842 if (nsigma<0) nsigma = -nsigma;
18896 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 22845 } break;
18899 22846 case 3 : { // Poisson Noise
18900 22847 cimg_rof(*this,ptrd,T) *ptrd = (T)cimg::prand(*ptrd);
... ... @@ -18946,7 +22893,7 @@ namespace cimg_library_suffixed {
18946 22893 if (m==M) return fill(min_value);
18947 22894 if (m!=a || M!=b)
18948 22895 #ifdef cimg_use_openmp
18949   -#pragma omp parallel for if (size()>=65536)
  22896 +#pragma omp parallel for cimg_openmp_if(size()>=65536)
18950 22897 #endif
18951 22898 cimg_rof(*this,ptrd,T) *ptrd = (T)((*ptrd - fm)/(fM - fm)*(b - a) + a);
18952 22899 return *this;
... ... @@ -19112,7 +23059,7 @@ namespace cimg_library_suffixed {
19112 23059 if (is_empty()) return *this;
19113 23060 const T a = min_value<max_value?min_value:max_value, b = min_value<max_value?max_value:min_value;
19114 23061 #ifdef cimg_use_openmp
19115   -#pragma omp parallel for if (size()>=32768)
  23062 +#pragma omp parallel for cimg_openmp_if(size()>=32768)
19116 23063 #endif
19117 23064 cimg_rof(*this,ptrd,T) *ptrd = (*ptrd<a)?a:((*ptrd>b)?b:*ptrd);
19118 23065 return *this;
... ... @@ -19145,14 +23092,14 @@ namespace cimg_library_suffixed {
19145 23092 if (range>0) {
19146 23093 if (keep_range)
19147 23094 #ifdef cimg_use_openmp
19148   -#pragma omp parallel for if (size()>=32768)
  23095 +#pragma omp parallel for cimg_openmp_if(size()>=32768)
19149 23096 #endif
19150 23097 cimg_rof(*this,ptrd,T) {
19151 23098 const unsigned int val = (unsigned int)((*ptrd-m)*nb_levels/range);
19152 23099 *ptrd = (T)(m + cimg::min(val,nb_levels - 1)*range/nb_levels);
19153 23100 } else
19154 23101 #ifdef cimg_use_openmp
19155   -#pragma omp parallel for if (size()>=32768)
  23102 +#pragma omp parallel for cimg_openmp_if(size()>=32768)
19156 23103 #endif
19157 23104 cimg_rof(*this,ptrd,T) {
19158 23105 const unsigned int val = (unsigned int)((*ptrd-m)*nb_levels/range);
... ... @@ -19184,7 +23131,7 @@ namespace cimg_library_suffixed {
19184 23131 if (strict_threshold) {
19185 23132 if (soft_threshold)
19186 23133 #ifdef cimg_use_openmp
19187   -#pragma omp parallel for if (size()>=32768)
  23134 +#pragma omp parallel for cimg_openmp_if(size()>=32768)
19188 23135 #endif
19189 23136 cimg_rof(*this,ptrd,T) {
19190 23137 const T v = *ptrd;
... ... @@ -19192,13 +23139,13 @@ namespace cimg_library_suffixed {
19192 23139 }
19193 23140 else
19194 23141 #ifdef cimg_use_openmp
19195   -#pragma omp parallel for if (size()>=65536)
  23142 +#pragma omp parallel for cimg_openmp_if(size()>=65536)
19196 23143 #endif
19197 23144 cimg_rof(*this,ptrd,T) *ptrd = *ptrd>value?(T)1:(T)0;
19198 23145 } else {
19199 23146 if (soft_threshold)
19200 23147 #ifdef cimg_use_openmp
19201   -#pragma omp parallel for if (size()>=32768)
  23148 +#pragma omp parallel for cimg_openmp_if(size()>=32768)
19202 23149 #endif
19203 23150 cimg_rof(*this,ptrd,T) {
19204 23151 const T v = *ptrd;
... ... @@ -19206,7 +23153,7 @@ namespace cimg_library_suffixed {
19206 23153 }
19207 23154 else
19208 23155 #ifdef cimg_use_openmp
19209   -#pragma omp parallel for if (size()>=65536)
  23156 +#pragma omp parallel for cimg_openmp_if(size()>=65536)
19210 23157 #endif
19211 23158 cimg_rof(*this,ptrd,T) *ptrd = *ptrd>=value?(T)1:(T)0;
19212 23159 }
... ... @@ -19290,7 +23237,7 @@ namespace cimg_library_suffixed {
19290 23237 cimg_forX(hist,pos) { cumul+=hist[pos]; hist[pos] = cumul; }
19291 23238 if (!cumul) cumul = 1;
19292 23239 #ifdef cimg_use_openmp
19293   -#pragma omp parallel for if (size()>=1048576)
  23240 +#pragma omp parallel for cimg_openmp_if(size()>=1048576)
19294 23241 #endif
19295 23242 cimg_rof(*this,ptrd,T) {
19296 23243 const int pos = (int)((*ptrd-vmin)*(nb_levels - 1.)/(vmax-vmin));
... ... @@ -20903,7 +24850,7 @@ namespace cimg_library_suffixed {
20903 24850 cc = (int)(centering_c*((int)sc - spectrum()));
20904 24851  
20905 24852 switch (boundary_conditions) {
20906   - case 2 : { // Periodic borders.
  24853 + case 2 : { // Periodic boundary.
20907 24854 res.assign(sx,sy,sz,sc);
20908 24855 const int
20909 24856 x0 = ((int)xc%width()) - width(),
... ... @@ -20919,7 +24866,7 @@ namespace cimg_library_suffixed {
20919 24866 for (int x = x0; x<(int)sx; x+=width())
20920 24867 res.draw_image(x,y,z,c,*this);
20921 24868 } break;
20922   - case 1 : { // Neumann borders.
  24869 + case 1 : { // Neumann boundary.
20923 24870 res.assign(sx,sy,sz,sc).draw_image(xc,yc,zc,cc,*this);
20924 24871 CImg<T> sprite;
20925 24872 if (xc>0) { // X-backward
... ... @@ -20957,7 +24904,7 @@ namespace cimg_library_suffixed {
20957 24904 for (int c = cc + spectrum(); c<(int)sc; ++c) res.draw_image(0,0,0,c,sprite);
20958 24905 }
20959 24906 } break;
20960   - default : // Dirichlet borders.
  24907 + default : // Dirichlet boundary.
20961 24908 res.assign(sx,sy,sz,sc,0).draw_image(xc,yc,zc,cc,*this);
20962 24909 }
20963 24910 break;
... ... @@ -21028,17 +24975,17 @@ namespace cimg_library_suffixed {
21028 24975 cimg_forX(res,x) { *(ptrd++) = *ptrx; ptrx+=*(poff_x++); }
21029 24976 ++y;
21030 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 24979 ptry+=dy;
21033 24980 }
21034 24981 ++z;
21035 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 24984 ptrz+=dz;
21038 24985 }
21039 24986 ++c;
21040 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 24989 ptrc+=dc;
21043 24990 }
21044 24991 } break;
... ... @@ -21822,11 +25769,10 @@ namespace cimg_library_suffixed {
21822 25769 //! Resize image to half-size along XY axes, using an optimized filter \newinstance.
21823 25770 CImg<T> get_resize_halfXY() const {
21824 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 25776 T *ptrd = res._data;
21831 25777 cimg_forZC(*this,z,c) cimg_for3x3(*this,x,y,z,c,I,T)
21832 25778 if (x%2 && y%2) *(ptrd++) = (T)
... ... @@ -22895,7 +26841,7 @@ namespace cimg_library_suffixed {
22895 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 26845 if (interpolation==2) { // Cubic interpolation.
22900 26846 if (boundary_conditions==2) // Periodic boundaries.
22901 26847 #ifdef cimg_use_openmp
... ... @@ -23073,7 +27019,7 @@ namespace cimg_library_suffixed {
23073 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 27023 if (interpolation==2) { // Cubic interpolation.
23078 27024 if (boundary_conditions==2) // Periodic boundaries.
23079 27025 #ifdef cimg_use_openmp
... ... @@ -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 27096 if (mode>=3) { // Forward-relative warp.
23151 27097 res.fill(0);
23152 27098 if (interpolation>=1) // Linear interpolation.
... ... @@ -23275,7 +27221,7 @@ namespace cimg_library_suffixed {
23275 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 27225 if (interpolation==2) { // Cubic interpolation.
23280 27226 if (boundary_conditions==2) // Periodic boundaries.
23281 27227 #ifdef cimg_use_openmp
... ... @@ -23989,7 +27935,7 @@ namespace cimg_library_suffixed {
23989 27935 _cimg_math_parser *mp;
23990 27936 ~_functor4d_streamline_expr() { delete mp; }
23991 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 27940 float operator()(const float x, const float y, const float z, const unsigned int c) const {
23995 27941 return (float)(*mp)(x,y,z,c);
... ... @@ -24214,7 +28160,7 @@ namespace cimg_library_suffixed {
24214 28160 res.assign(_width/dp + (_width%dp?1:0),1,1);
24215 28161 const unsigned int pe = _width - dp;
24216 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 28164 #endif
24219 28165 for (unsigned int p = 0; p<pe; p+=dp)
24220 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 28172 res.assign(_height/dp + (_height%dp?1:0),1,1);
24227 28173 const unsigned int pe = _height - dp;
24228 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 28176 #endif
24231 28177 for (unsigned int p = 0; p<pe; p+=dp)
24232 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 28184 res.assign(_depth/dp + (_depth%dp?1:0),1,1);
24239 28185 const unsigned int pe = _depth - dp;
24240 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 28188 #endif
24243 28189 for (unsigned int p = 0; p<pe; p+=dp)
24244 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 28196 res.assign(_spectrum/dp + (_spectrum%dp?1:0),1,1);
24251 28197 const unsigned int pe = _spectrum - dp;
24252 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 28200 #endif
24255 28201 for (unsigned int p = 0; p<pe; p+=dp)
24256 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 28504 ((mask._depth==1 && mask._width<=5) || (mask._depth==mask._width && mask._width<=3))) {
24559 28505 // A special optimization is done for 2x2, 3x3, 4x4, 5x5, 2x2x2 and 3x3x3 mask (with boundary_conditions=1)
24560 28506 Ttfloat *ptrd = res._data;
  28507 + CImg<T> I;
24561 28508 switch (mask._depth) {
24562 28509 case 3 : {
24563   - T I[27] = { 0 };
  28510 + I.assign(27);
24564 28511 cimg_forC(res,c) {
  28512 + cimg_test_abort();
24565 28513 const CImg<T> _img = get_shared_channel(c%_spectrum);
24566 28514 const CImg<t> _mask = mask.get_shared_channel(c%mask._spectrum);
24567 28515 if (is_normalized) {
... ... @@ -24599,8 +28547,9 @@ namespace cimg_library_suffixed {
24599 28547 }
24600 28548 } break;
24601 28549 case 2 : {
24602   - T I[8] = { 0 };
  28550 + I.assign(8);
24603 28551 cimg_forC(res,c) {
  28552 + cimg_test_abort();
24604 28553 const CImg<T> _img = get_shared_channel(c%_spectrum);
24605 28554 const CImg<t> _mask = mask.get_shared_channel(c%mask._spectrum);
24606 28555 if (is_normalized) {
... ... @@ -24626,8 +28575,9 @@ namespace cimg_library_suffixed {
24626 28575 case 1 :
24627 28576 switch (mask._width) {
24628 28577 case 6 : {
24629   - T I[36] = { 0 };
  28578 + I.assign(36);
24630 28579 cimg_forC(res,c) {
  28580 + cimg_test_abort();
24631 28581 const CImg<T> _img = get_shared_channel(c%_spectrum);
24632 28582 const CImg<t> _mask = mask.get_shared_channel(c%mask._spectrum);
24633 28583 if (is_normalized) {
... ... @@ -24665,8 +28615,9 @@ namespace cimg_library_suffixed {
24665 28615 }
24666 28616 } break;
24667 28617 case 5 : {
24668   - T I[25] = { 0 };
  28618 + I.assign(25);
24669 28619 cimg_forC(res,c) {
  28620 + cimg_test_abort();
24670 28621 const CImg<T> _img = get_shared_channel(c%_spectrum);
24671 28622 const CImg<t> _mask = mask.get_shared_channel(c%mask._spectrum);
24672 28623 if (is_normalized) {
... ... @@ -24696,8 +28647,9 @@ namespace cimg_library_suffixed {
24696 28647 }
24697 28648 } break;
24698 28649 case 4 : {
24699   - T I[16] = { 0 };
  28650 + I.assign(16);
24700 28651 cimg_forC(res,c) {
  28652 + cimg_test_abort();
24701 28653 const CImg<T> _img = get_shared_channel(c%_spectrum);
24702 28654 const CImg<t> _mask = mask.get_shared_channel(c%mask._spectrum);
24703 28655 if (is_normalized) {
... ... @@ -24721,8 +28673,9 @@ namespace cimg_library_suffixed {
24721 28673 }
24722 28674 } break;
24723 28675 case 3 : {
24724   - T I[9] = { 0 };
  28676 + I.assign(9);
24725 28677 cimg_forC(res,c) {
  28678 + cimg_test_abort();
24726 28679 const CImg<T> _img = get_shared_channel(c%_spectrum);
24727 28680 const CImg<t> _mask = mask.get_shared_channel(c%mask._spectrum);
24728 28681 if (is_normalized) {
... ... @@ -24742,8 +28695,9 @@ namespace cimg_library_suffixed {
24742 28695 }
24743 28696 } break;
24744 28697 case 2 : {
24745   - T I[4] = { 0 };
  28698 + I.assign(4);
24746 28699 cimg_forC(res,c) {
  28700 + cimg_test_abort();
24747 28701 const CImg<T> _img = get_shared_channel(c%_spectrum);
24748 28702 const CImg<t> _mask = mask.get_shared_channel(c%mask._spectrum);
24749 28703 if (is_normalized) {
... ... @@ -24762,6 +28716,7 @@ namespace cimg_library_suffixed {
24762 28716 case 1 :
24763 28717 if (is_normalized) res.fill(1);
24764 28718 else cimg_forC(res,c) {
  28719 + cimg_test_abort();
24765 28720 const CImg<T> _img = get_shared_channel(c%_spectrum);
24766 28721 const CImg<t> _mask = mask.get_shared_channel(c%mask._spectrum);
24767 28722 res.get_shared_channel(c).assign(_img)*=_mask[0];
... ... @@ -24769,15 +28724,16 @@ namespace cimg_library_suffixed {
24769 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 28728 const int
24774 28729 mx2 = mask.width()/2, my2 = mask.height()/2, mz2 = mask.depth()/2,
24775 28730 mx1 = mx2 - 1 + (mask.width()%2), my1 = my2 - 1 + (mask.height()%2), mz1 = mz2 - 1 + (mask.depth()%2),
24776 28731 mxe = width() - mx2, mye = height() - my2, mze = depth() - mz2;
24777 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 28734 #endif
24780 28735 cimg_forC(res,c) {
  28736 + cimg_test_abort();
24781 28737 const CImg<T> _img = get_shared_channel(c%_spectrum);
24782 28738 const CImg<t> _mask = mask.get_shared_channel(c%mask._spectrum);
24783 28739 if (is_normalized) { // Normalized correlation.
... ... @@ -25009,9 +28965,10 @@ namespace cimg_library_suffixed {
25009 28965 mx1 = mx2 - 1 + (mask.width()%2), my1 = my2 - 1 + (mask.height()%2), mz1 = mz2 - 1 + (mask.depth()%2),
25010 28966 mxe = width() - mx2, mye = height() - my2, mze = depth() - mz2;
25011 28967 #ifdef cimg_use_openmp
25012   -#pragma omp parallel for if (_spectrum>=2)
  28968 +#pragma omp parallel for cimg_openmp_if(_spectrum>=2)
25013 28969 #endif
25014 28970 cimg_forC(*this,c) {
  28971 + cimg_test_abort();
25015 28972 const CImg<T> _img = get_shared_channel(c%_spectrum);
25016 28973 const CImg<t> _mask = mask.get_shared_channel(c%mask._spectrum);
25017 28974 if (is_normalized) { // Normalized erosion.
... ... @@ -25298,9 +29255,10 @@ namespace cimg_library_suffixed {
25298 29255 mx1 = mx2 - 1 + (mask.width()%2), my1 = my2 - 1 + (mask.height()%2), mz1 = mz2 - 1 + (mask.depth()%2),
25299 29256 mxe = width() - mx2, mye = height() - my2, mze = depth() - mz2;
25300 29257 #ifdef cimg_use_openmp
25301   -#pragma omp parallel for if (_spectrum>=2)
  29258 +#pragma omp parallel for cimg_openmp_if(_spectrum>=2)
25302 29259 #endif
25303 29260 cimg_forC(*this,c) {
  29261 + cimg_test_abort();
25304 29262 const CImg<T> _img = get_shared_channel(c%_spectrum);
25305 29263 const CImg<t> _mask = mask.get_shared_channel(c%mask._spectrum);
25306 29264 if (is_normalized) { // Normalized dilation.
... ... @@ -25614,44 +29572,44 @@ namespace cimg_library_suffixed {
25614 29572  
25615 29573 // Check labels of the neighbors.
25616 29574 bool is_same_label = true;
25617   - unsigned int label = 0;
  29575 + T label = 0;
25618 29576 if (x - 1>=0) {
25619 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 29579 else if (label!=(*this)(x - 1,y,z)) is_same_label = false;
25622 29580 } else Q._priority_queue_insert(is_queued,sizeQ,priority(x - 1,y,z),x - 1,y,z);
25623 29581 }
25624 29582 if (x + 1<width()) {
25625 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 29585 else if (label!=(*this)(x + 1,y,z)) is_same_label = false;
25628 29586 } else Q._priority_queue_insert(is_queued,sizeQ,priority(x + 1,y,z),x + 1,y,z);
25629 29587 }
25630 29588 if (y - 1>=0) {
25631 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 29591 else if (label!=(*this)(x,y - 1,z)) is_same_label = false;
25634 29592 } else Q._priority_queue_insert(is_queued,sizeQ,priority(x,y - 1,z),x,y - 1,z);
25635 29593 }
25636 29594 if (y + 1<height()) {
25637 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 29597 else if (label!=(*this)(x,y + 1,z)) is_same_label = false;
25640 29598 } else Q._priority_queue_insert(is_queued,sizeQ,priority(x,y + 1,z),x,y + 1,z);
25641 29599 }
25642 29600 if (z - 1>=0) {
25643 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 29603 else if (label!=(*this)(x,y,z - 1)) is_same_label = false;
25646 29604 } else Q._priority_queue_insert(is_queued,sizeQ,priority(x,y,z - 1),x,y,z - 1);
25647 29605 }
25648 29606 if (z + 1<depth()) {
25649 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 29609 else if (label!=(*this)(x,y,z + 1)) is_same_label = false;
25652 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 29615 // Fill lines.
... ... @@ -26181,6 +30139,7 @@ namespace cimg_library_suffixed {
26181 30139 Tfloat *ptrd = velocity._data, veloc_max = 0;
26182 30140 if (is_3d) // 3d version
26183 30141 cimg_forC(*this,c) {
  30142 + cimg_test_abort();
26184 30143 CImg_3x3x3(I,Tfloat);
26185 30144 cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) {
26186 30145 const Tfloat
... ... @@ -26198,6 +30157,7 @@ namespace cimg_library_suffixed {
26198 30157 }
26199 30158 else // 2d version
26200 30159 cimg_forZC(*this,z,c) {
  30160 + cimg_test_abort();
26201 30161 CImg_3x3(I,Tfloat);
26202 30162 cimg_for3x3(*this,x,y,z,c,I,Tfloat) {
26203 30163 const Tfloat
... ... @@ -26245,6 +30205,7 @@ namespace cimg_library_suffixed {
26245 30205 *(pd3++) = (Tfloat)n;
26246 30206 }
26247 30207  
  30208 + cimg_test_abort();
26248 30209 #ifdef cimg_use_openmp
26249 30210 #pragma omp parallel for collapse(2) if (_width>=256 && _height*_depth>=2) firstprivate(val)
26250 30211 #endif
... ... @@ -26338,8 +30299,9 @@ namespace cimg_library_suffixed {
26338 30299 *(pd2++) = (Tfloat)n;
26339 30300 }
26340 30301  
  30302 + cimg_test_abort();
26341 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 30305 #endif
26344 30306 cimg_forXY(*this,x,y) {
26345 30307 val.fill(0);
... ... @@ -27017,7 +30979,7 @@ namespace cimg_library_suffixed {
27017 30979 const int psize2 = (int)patch_size/2, psize1 = (int)patch_size - psize2 - 1;
27018 30980 if (is_fast_approx)
27019 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 30983 #endif
27022 30984 cimg_forXY(res,x,y) { // 2d fast approximation.
27023 30985 P = img.get_crop(x - psize1,y - psize1,x + psize2,y + psize2,true);
... ... @@ -27036,7 +30998,7 @@ namespace cimg_library_suffixed {
27036 30998 else cimg_forC(res,c) res(x,y,c) = (Tfloat)((*this)(x,y,c));
27037 30999 } else
27038 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 31002 #endif
27041 31003 cimg_forXY(res,x,y) { // 2d exact algorithm.
27042 31004 P = img.get_crop(x - psize1,y - psize1,x + psize2,y + psize2,true);
... ... @@ -27130,7 +31092,7 @@ namespace cimg_library_suffixed {
27130 31092 else switch (n) { // Without threshold.
27131 31093 case 3 : {
27132 31094 #ifdef cimg_use_openmp
27133   -#pragma omp parallel for if (_spectrum>=2)
  31095 +#pragma omp parallel for cimg_openmp_if(_spectrum>=2)
27134 31096 #endif
27135 31097 cimg_forC(*this,c) {
27136 31098 T I[9] = { 0 };
... ... @@ -27150,7 +31112,7 @@ namespace cimg_library_suffixed {
27150 31112 } break;
27151 31113 case 5 : {
27152 31114 #ifdef cimg_use_openmp
27153   -#pragma omp parallel for if (_spectrum>=2)
  31115 +#pragma omp parallel for cimg_openmp_if(_spectrum>=2)
27154 31116 #endif
27155 31117 cimg_forC(*this,c) {
27156 31118 T I[25] = { 0 };
... ... @@ -27209,9 +31171,10 @@ namespace cimg_library_suffixed {
27209 31171 }
27210 31172 } else { // 1d
27211 31173  
  31174 + CImg<T> I;
27212 31175 if (threshold>0)
27213 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 31178 #endif
27216 31179 cimg_forXC(*this,x,c) { // With threshold.
27217 31180 const int
... ... @@ -27228,26 +31191,26 @@ namespace cimg_library_suffixed {
27228 31191 else switch (n) { // Without threshold.
27229 31192 case 2 : {
27230 31193 #ifdef cimg_use_openmp
27231   -#pragma omp parallel for if (_spectrum>=2)
  31194 +#pragma omp parallel for cimg_openmp_if(_spectrum>=2)
27232 31195 #endif
27233 31196 cimg_forC(*this,c) {
27234   - T I[4] = { 0 };
  31197 + I.assign(4);
27235 31198 cimg_for2x2(*this,x,y,0,c,I,T) res(x,c) = (T)(0.5f*(I[0] + I[1]));
27236 31199 }
27237 31200 } break;
27238 31201 case 3 : {
27239 31202 #ifdef cimg_use_openmp
27240   -#pragma omp parallel for if (_spectrum>=2)
  31203 +#pragma omp parallel for cimg_openmp_if(_spectrum>=2)
27241 31204 #endif
27242 31205 cimg_forC(*this,c) {
27243   - T I[9] = { 0 };
  31206 + I.assign(9);
27244 31207 cimg_for3x3(*this,x,y,0,c,I,T)
27245 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 31210 } break;
27248 31211 default : {
27249 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 31214 #endif
27252 31215 cimg_forXC(*this,x,c) {
27253 31216 const int
... ... @@ -27300,7 +31263,7 @@ namespace cimg_library_suffixed {
27300 31263 }
27301 31264 }
27302 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 31267 #endif
27305 31268 cimg_forC(*this,c) {
27306 31269 Tfloat *ptrd = velocity.data(0,0,0,c), veloc_max = 0;
... ... @@ -27347,7 +31310,7 @@ namespace cimg_library_suffixed {
27347 31310 CImg<Tfloat> G = (alpha>0?get_blur(alpha).get_structure_tensors():get_structure_tensors());
27348 31311 if (sigma>0) G.blur(sigma);
27349 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 31314 #endif
27352 31315 cimg_forY(G,y) {
27353 31316 CImg<Tfloat> val, vec;
... ... @@ -27362,7 +31325,7 @@ namespace cimg_library_suffixed {
27362 31325 }
27363 31326 }
27364 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 31329 #endif
27367 31330 cimg_forC(*this,c) {
27368 31331 Tfloat *ptrd = velocity.data(0,0,0,c), veloc_max = 0;
... ... @@ -27444,7 +31407,7 @@ namespace cimg_library_suffixed {
27444 31407 switch (scheme) { // 3d.
27445 31408 case -1 : { // Backward finite differences.
27446 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 31411 #endif
27449 31412 cimg_forC(*this,c) {
27450 31413 const unsigned long off = c*_width*_height*_depth;
... ... @@ -27459,7 +31422,7 @@ namespace cimg_library_suffixed {
27459 31422 } break;
27460 31423 case 1 : { // Forward finite differences.
27461 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 31426 #endif
27464 31427 cimg_forC(*this,c) {
27465 31428 const unsigned long off = c*_width*_height*_depth;
... ... @@ -27484,7 +31447,7 @@ namespace cimg_library_suffixed {
27484 31447 } break;
27485 31448 default : { // Central finite differences.
27486 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 31451 #endif
27489 31452 cimg_forC(*this,c) {
27490 31453 const unsigned long off = c*_width*_height*_depth;
... ... @@ -27612,7 +31575,7 @@ namespace cimg_library_suffixed {
27612 31575 if (!cimg::strcasecmp(naxes,def_axes3d)) { // 3d
27613 31576  
27614 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 31579 #endif
27617 31580 cimg_forC(*this,c) {
27618 31581 const unsigned long off = c*_width*_height*_depth;
... ... @@ -27673,7 +31636,7 @@ namespace cimg_library_suffixed {
27673 31636 else if (axis1=='x' && axis2=='z') { // Ixz
27674 31637 valid_axis = true;
27675 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 31640 #endif
27678 31641 cimg_forC(*this,c) {
27679 31642 Tfloat *ptrd = res[l2].data(0,0,0,c);
... ... @@ -27695,7 +31658,7 @@ namespace cimg_library_suffixed {
27695 31658 else if (axis1=='y' && axis2=='z') { // Iyz
27696 31659 valid_axis = true;
27697 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 31662 #endif
27700 31663 cimg_forC(*this,c) {
27701 31664 Tfloat *ptrd = res[l2].data(0,0,0,c);
... ... @@ -27706,7 +31669,7 @@ namespace cimg_library_suffixed {
27706 31669 else if (axis1=='z' && axis2=='z') { // Izz
27707 31670 valid_axis = true;
27708 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 31673 #endif
27711 31674 cimg_forC(*this,c) {
27712 31675 Tfloat *ptrd = res[l2].data(0,0,0,c);
... ... @@ -27734,7 +31697,7 @@ namespace cimg_library_suffixed {
27734 31697 CImg<Tfloat> res(_width,_height,_depth,_spectrum);
27735 31698 if (_depth>1) { // 3d
27736 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 31701 #endif
27739 31702 cimg_forC(*this,c) {
27740 31703 Tfloat *ptrd = res.data(0,0,0,c);
... ... @@ -27743,7 +31706,7 @@ namespace cimg_library_suffixed {
27743 31706 }
27744 31707 } else if (_height>1) { // 2d
27745 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 31710 #endif
27748 31711 cimg_forC(*this,c) {
27749 31712 Tfloat *ptrd = res.data(0,0,0,c);
... ... @@ -27752,7 +31715,7 @@ namespace cimg_library_suffixed {
27752 31715 }
27753 31716 } else { // 1d
27754 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 31719 #endif
27757 31720 cimg_forC(*this,c) {
27758 31721 Tfloat *ptrd = res.data(0,0,0,c);
... ... @@ -27765,22 +31728,21 @@ namespace cimg_library_suffixed {
27765 31728  
27766 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 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 31739 if (is_empty()) return *this;
27777 31740 CImg<Tfloat> res;
27778 31741 if (_depth>1) { // 3d
27779 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 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 31746 #endif
27785 31747 cimg_forC(*this,c) {
27786 31748 Tfloat
... ... @@ -27800,33 +31762,9 @@ namespace cimg_library_suffixed {
27800 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 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 31768 #endif
27831 31769 cimg_forC(*this,c) {
27832 31770 Tfloat
... ... @@ -27846,14 +31784,12 @@ namespace cimg_library_suffixed {
27846 31784 *(ptrd5++)+=(izf*izf + izb*izb)/2;
27847 31785 }
27848 31786 }
27849   - } break;
27850 31787 }
27851 31788 } else { // 2d
27852 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 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 31793 #endif
27858 31794 cimg_forC(*this,c) {
27859 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 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 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 31809 #endif
27892 31810 cimg_forC(*this,c) {
27893 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 31819 *(ptrd2++)+=(iyf*iyf + iyb*iyb)/2;
27902 31820 }
27903 31821 }
27904   - } break;
27905 31822 }
27906 31823 }
27907 31824 return res;
... ... @@ -27992,14 +31909,15 @@ namespace cimg_library_suffixed {
27992 31909 \param nb_scales Number of scales used to estimate the displacement field.
27993 31910 \param iteration_max Maximum number of iterations allowed for one scale.
27994 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 31916 CImg<T>& displacement(const CImg<T>& source, const float smoothness=0.1f, const float precision=5.0f,
27999 31917 const unsigned int nb_scales=0, const unsigned int iteration_max=10000,
28000 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 31921 move_to(*this);
28004 31922 }
28005 31923  
... ... @@ -28008,7 +31926,7 @@ namespace cimg_library_suffixed {
28008 31926 const float smoothness=0.1f, const float precision=5.0f,
28009 31927 const unsigned int nb_scales=0, const unsigned int iteration_max=10000,
28010 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 31930 if (is_empty() || !source) return +*this;
28013 31931 if (!is_sameXYZC(source))
28014 31932 throw CImgArgumentException(_cimg_instance
... ... @@ -28022,7 +31940,18 @@ namespace cimg_library_suffixed {
28022 31940 "(should be >=0)",
28023 31941 cimg_instance,
28024 31942 precision);
  31943 +
28025 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 31955 const unsigned int
28027 31956 mins = is_3d?cimg::min(_width,_height,_depth):cimg::min(_width,_height),
28028 31957 _nb_scales = nb_scales>0?nb_scales:
... ... @@ -28032,14 +31961,7 @@ namespace cimg_library_suffixed {
28032 31961 float sm, sM = source.max_min(sm), tm, tM = max_min(tm);
28033 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 31965 floatT bound = 0;
28044 31966 for (int scale = (int)_nb_scales - 1; scale>=0; --scale) {
28045 31967 const float factor = (float)std::pow(1.5,(double)scale);
... ... @@ -28051,36 +31973,21 @@ namespace cimg_library_suffixed {
28051 31973 const CImg<Tfloat>
28052 31974 I1 = (source.get_resize(sw,sh,sd,-100,2)-=sm)/=sdelta,
28053 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 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 31984 float dt = 2, energy = cimg::type<float>::max();
28080 31985 const CImgList<Tfloat> dI = is_backward?I1.get_gradient():I2.get_gradient();
28081 31986  
28082 31987 for (unsigned int iteration = 0; iteration<iteration_max; ++iteration) {
  31988 + cimg_test_abort();
28083 31989 float _energy = 0;
  31990 +
28084 31991 if (is_3d) { // 3d version.
28085 31992 if (smoothness>=0) // Isotropic regularization.
28086 31993 #ifdef cimg_use_openmp
... ... @@ -28127,6 +32034,11 @@ namespace cimg_library_suffixed {
28127 32034 }
28128 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 32042 } else { // Anisotropic regularization.
28131 32043 const float nsmoothness = -smoothness;
28132 32044 #ifdef cimg_use_openmp
... ... @@ -28188,23 +32100,17 @@ namespace cimg_library_suffixed {
28188 32100 }
28189 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 32110 } else { // 2d version.
28205 32111 if (smoothness>=0) // Isotropic regularization.
28206 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 32114 #endif
28209 32115 cimg_forY(U,y) {
28210 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 32144 }
28239 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 32151 } else { // Anisotropic regularization.
28242 32152 const float nsmoothness = -smoothness;
28243 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 32155 #endif
28246 32156 cimg_forY(U,y) {
28247 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 32193 }
28284 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 32203 const float d_energy = (_energy - energy)/(sw*sh*sd);
28299 32204 if (d_energy<=0 && -d_energy<_precision) break;
... ... @@ -28304,6 +32209,481 @@ namespace cimg_library_suffixed {
28304 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 32687 //! Compute Euclidean distance function to a specified value.
28308 32688 /**
28309 32689 \param value Reference value.
... ... @@ -28388,7 +32768,7 @@ namespace cimg_library_suffixed {
28388 32768  
28389 32769 const unsigned long wh = (unsigned long)_width*_height;
28390 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 32772 #endif
28393 32773 cimg_forC(*this,c) {
28394 32774 CImg<longT> g(_width), dt(_width), s(_width), t(_width);
... ... @@ -28441,7 +32821,7 @@ namespace cimg_library_suffixed {
28441 32821 if (!is_value) return fill(cimg::type<T>::max());
28442 32822 const unsigned long wh = (unsigned long)_width*_height;
28443 32823 #ifdef cimg_use_openmp
28444   -#pragma omp parallel for if (_spectrum>=2)
  32824 +#pragma omp parallel for cimg_openmp_if(_spectrum>=2)
28445 32825 #endif
28446 32826 cimg_forC(*this,c) {
28447 32827 CImg<T> img = get_shared_channel(c);
... ... @@ -28491,7 +32871,7 @@ namespace cimg_library_suffixed {
28491 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 32875 template<typename t, typename to>
28496 32876 CImg<typename cimg::superset<t,long>::type>
28497 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 33075 CImg<charT> state(_width,_height,_depth); // -1=far away, 0=narrow, 1=frozen.
28696 33076  
28697 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 33079 #endif
28700 33080 cimg_forC(*this,c) {
28701 33081 const CImg<T> img = get_shared_channel(c);
... ... @@ -29645,7 +34025,7 @@ namespace cimg_library_suffixed {
29645 34025 **/
29646 34026 template<typename tp, typename tc, typename tt, typename tx>
29647 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 34029 if (is_empty()) return *this;
29650 34030 if (_height!=3)
29651 34031 throw CImgInstanceException(_cimg_instance
... ... @@ -30551,7 +34931,9 @@ namespace cimg_library_suffixed {
30551 34931  
30552 34932 struct _functor2d_expr {
30553 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 34937 ~_functor2d_expr() { delete mp; }
30556 34938 float operator()(const float x, const float y) const {
30557 34939 return (float)(*mp)(x,y,0,0);
... ... @@ -30577,7 +34959,9 @@ namespace cimg_library_suffixed {
30577 34959 struct _functor3d_expr {
30578 34960 _cimg_math_parser *mp;
30579 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 34965 float operator()(const float x, const float y, const float z) const {
30582 34966 return (float)(*mp)(x,y,z,0);
30583 34967 }
... ... @@ -35102,10 +39486,10 @@ namespace cimg_library_suffixed {
35102 39486 const t
35103 39487 *ptrs = sprite._data -
35104 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 39493 offX = (unsigned long)_width - lX,
35110 39494 soffX = (unsigned long)sprite._width - lX,
35111 39495 offY = (unsigned long)_width*(_height - lY),
... ... @@ -35146,9 +39530,9 @@ namespace cimg_library_suffixed {
35146 39530 const T
35147 39531 *ptrs = sprite._data -
35148 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 39536 const unsigned long
35153 39537 offX = (unsigned long)_width - lX,
35154 39538 soffX = (unsigned long)sprite._width - lX,
... ... @@ -35238,12 +39622,14 @@ namespace cimg_library_suffixed {
35238 39622 lY = sprite.height() - (y0 + sprite.height()>height()?y0 + sprite.height() - height():0) + (by?y0:0),
35239 39623 lZ = sprite.depth() - (z0 + sprite.depth()>depth()?z0 + sprite.depth() - depth():0) + (bz?z0:0),
35240 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 39631 const ti *ptrs = sprite._data + coff;
35246   - const tm *ptrm = mask._data + coff;
  39632 + const tm *ptrm = mask._data + coff;
35247 39633 const unsigned long
35248 39634 offX = (unsigned long)_width - lX,
35249 39635 soffX = (unsigned long)sprite._width - lX,
... ... @@ -35568,32 +39954,32 @@ namespace cimg_library_suffixed {
35568 39954 if (is_empty()) return *this;
35569 39955 const int yt = (y + 3 + font_height)<_height?y + 3:y - 2 - (int)font_height;
35570 39956 const int siz = (int)values_x.size() - 1;
35571   - char txt[32] = { 0 };
  39957 + CImg<charT> txt(32);
35572 39958 CImg<T> label;
35573 39959 if (siz<=0) { // Degenerated case.
35574 39960 draw_line(0,y,_width - 1,y,color,opacity,pattern);
35575 39961 if (!siz) {
35576   - cimg_snprintf(txt,sizeof(txt),"%g",(double)*values_x);
  39962 + cimg_snprintf(txt,txt._width,"%g",(double)*values_x);
35577 39963 label.assign().draw_text(0,0,txt,color,(tc*)0,opacity,font_height);
35578 39964 const int
35579 39965 _xt = (width() - label.width())/2,
35580 39966 xt = _xt<3?3:_xt + label.width()>=width() - 2?width() - 3 - label.width():_xt;
35581 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 39969 draw_text(xt,yt,txt,color,(tc*)0,opacity,font_height);
35584 39970 }
35585 39971 } else { // Regular case.
35586 39972 if (values_x[0]<values_x[siz]) draw_arrow(0,y,_width - 1,y,color,opacity,30,5,pattern);
35587 39973 else draw_arrow(_width - 1,y,0,y,color,opacity,30,5,pattern);
35588 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 39976 label.assign().draw_text(0,0,txt,color,(tc*)0,opacity,font_height);
35591 39977 const int
35592 39978 xi = (int)(x*(_width - 1)/siz),
35593 39979 _xt = xi - label.width()/2,
35594 39980 xt = _xt<3?3:_xt + label.width()>=width() - 2?width() - 3 - label.width():_xt;
35595 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 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 40003 const bool allow_zero=true) {
35618 40004 if (is_empty()) return *this;
35619 40005 int siz = (int)values_y.size() - 1;
35620   - char txt[32] = { 0 };
  40006 + CImg<charT> txt(32);
35621 40007 CImg<T> label;
35622 40008 if (siz<=0) { // Degenerated case.
35623 40009 draw_line(x,0,x,_height - 1,color,opacity,pattern);
35624 40010 if (!siz) {
35625   - cimg_snprintf(txt,sizeof(txt),"%g",(double)*values_y);
  40011 + cimg_snprintf(txt,txt._width,"%g",(double)*values_y);
35626 40012 label.assign().draw_text(0,0,txt,color,(tc*)0,opacity,font_height);
35627 40013 const int
35628 40014 _yt = (height() - label.height())/2,
... ... @@ -35630,14 +40016,14 @@ namespace cimg_library_suffixed {
35630 40016 _xt = x - 2 - label.width(),
35631 40017 xt = _xt>=0?_xt:x + 3;
35632 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 40020 draw_text(xt,yt,txt,color,(tc*)0,opacity,font_height);
35635 40021 }
35636 40022 } else { // Regular case.
35637 40023 if (values_y[0]<values_y[siz]) draw_arrow(x,0,x,_height - 1,color,opacity,30,5,pattern);
35638 40024 else draw_arrow(x,_height - 1,x,0,color,opacity,30,5,pattern);
35639 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 40027 label.assign().draw_text(0,0,txt,color,(tc*)0,opacity,font_height);
35642 40028 const int
35643 40029 yi = (int)(y*(_height - 1)/siz),
... ... @@ -35646,7 +40032,7 @@ namespace cimg_library_suffixed {
35646 40032 _xt = x - 2 - label.width(),
35647 40033 xt = _xt>=0?_xt:x + 3;
35648 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 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 40572 for (int y0 = 0; y0<h; y0+=delta)
36187 40573 for (int x0 = 0; x0<w; x0+=delta) {
36188 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 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 40582 for (int x0=0; x0<w; x0+=delta) {
36196 40583 const int y0 = cimg::mod(y,h), x1 = (x0 + delta)%w, y1 = (y + delta)%h,
36197 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 40587 ref(xc,yc) = (T)(val<m?m:val>M?M:val);
36200 40588 }
36201 40589 for (int y0 = 0; y0<h; y0+=delta)
36202 40590 for (int x = -delta2; x<w; x+=delta) {
36203 40591 const int x0 = cimg::mod(x,w), x1 = (x + delta)%w, y1 = (y0 + delta)%h,
36204 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 40595 ref(xc,yc) = (T)(val<m?m:val>M?M:val);
36207 40596 }
36208 40597 for (int y = -delta2; y<h; y+=delta)
36209 40598 for (int x = -delta2; x<w; x+=delta) {
36210 40599 const int x0 = cimg::mod(x,w), y0 = cimg::mod(y,h), x1 = (x + delta)%w, y1 = (y + delta)%h,
36211 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 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 40982 const bool is_double_sided=false, const float focale=700,
36593 40983 const float lightx=0, const float lighty=0, const float lightz=-5e8,
36594 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 40986 render_type,is_double_sided,focale,lightx,lighty,lightz,
36597 40987 specular_lightness,specular_shininess,CImg<floatT>::empty());
36598 40988 }
... ... @@ -36607,7 +40997,7 @@ namespace cimg_library_suffixed {
36607 40997 const float lightx, const float lighty, const float lightz,
36608 40998 const float specular_lightness, const float specular_shininess,
36609 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 41001 render_type,is_double_sided,focale,lightx,lighty,lightz,
36612 41002 specular_lightness,specular_shininess,zbuffer);
36613 41003 }
... ... @@ -36622,7 +41012,7 @@ namespace cimg_library_suffixed {
36622 41012 const bool is_double_sided=false, const float focale=700,
36623 41013 const float lightx=0, const float lighty=0, const float lightz=-5e8,
36624 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 41016 render_type,is_double_sided,focale,lightx,lighty,lightz,
36627 41017 specular_lightness,specular_shininess,CImg<floatT>::empty());
36628 41018 }
... ... @@ -36637,7 +41027,7 @@ namespace cimg_library_suffixed {
36637 41027 const float lightx, const float lighty, const float lightz,
36638 41028 const float specular_lightness, const float specular_shininess,
36639 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 41031 render_type,is_double_sided,focale,lightx,lighty,lightz,
36642 41032 specular_lightness,specular_shininess,zbuffer);
36643 41033 }
... ... @@ -36755,7 +41145,7 @@ namespace cimg_library_suffixed {
36755 41145 const float absfocale = focale?cimg::abs(focale):0;
36756 41146 if (absfocale) {
36757 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 41149 #endif
36760 41150 cimg_forX(projections,l) { // Perspective projection
36761 41151 const tpfloat
... ... @@ -36769,7 +41159,7 @@ namespace cimg_library_suffixed {
36769 41159  
36770 41160 } else {
36771 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 41163 #endif
36774 41164 cimg_forX(projections,l) { // Parallel projection
36775 41165 const tpfloat
... ... @@ -36792,7 +41182,7 @@ namespace cimg_library_suffixed {
36792 41182 bool is_forward = zbuffer?true:false;
36793 41183  
36794 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 41186 #endif
36797 41187 cimglist_for(primitives,l) {
36798 41188 const CImg<tf>& primitive = primitives[l];
... ... @@ -36943,7 +41333,7 @@ namespace cimg_library_suffixed {
36943 41333 case 3 : { // Flat Shading
36944 41334 lightprops.assign(nb_visibles);
36945 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 41337 #endif
36948 41338 cimg_forX(lightprops,l) {
36949 41339 const CImg<tf>& primitive = primitives(visibles(permutations(l)));
... ... @@ -36977,7 +41367,7 @@ namespace cimg_library_suffixed {
36977 41367 case 5 : { // Phong-Shading
36978 41368 CImg<tpfloat> vertices_normals(vertices._width,6,1,1,0);
36979 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 41371 #endif
36982 41372 for (unsigned int l = 0; l<nb_visibles; ++l) {
36983 41373 const CImg<tf>& primitive = primitives[visibles(l)];
... ... @@ -37030,7 +41420,7 @@ namespace cimg_library_suffixed {
37030 41420 if (render_type==4) {
37031 41421 lightprops.assign(vertices._width);
37032 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 41424 #endif
37035 41425 cimg_forX(lightprops,l) {
37036 41426 const tpfloat
... ... @@ -37051,7 +41441,7 @@ namespace cimg_library_suffixed {
37051 41441 lh2 = light_texture._height/2 - 1;
37052 41442 lightprops.assign(vertices._width,2);
37053 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 41445 #endif
37056 41446 cimg_forX(lightprops,l) {
37057 41447 const tpfloat
... ... @@ -37864,32 +42254,37 @@ namespace cimg_library_suffixed {
37864 42254 \param XYZ Pointer to 3 values X,Y,Z which tells about the projection point coordinates, for volumetric images.
37865 42255 **/
37866 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 42262 //! Simple interface to select a shape from an image \overloading.
37872 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 42269 //! Simple interface to select a shape from an image \newinstance.
37878 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 42276 //! Simple interface to select a shape from an image \newinstance.
37884 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 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 42284 CImg<intT> _get_select(CImgDisplay &disp, const char *const title,
37891 42285 const unsigned int feature_type, unsigned int *const XYZ,
37892 42286 const int origX, const int origY, const int origZ,
  42287 + const bool exit_on_anykey,
37893 42288 const bool reset_view3d,
37894 42289 const bool force_display_z_coord) const {
37895 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 42293 if (!title) disp.set_title("CImg<%s> (%ux%ux%ux%u)",pixel_type(),_width,_height,_depth,_spectrum);
37899 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 42302 const unsigned int old_normalization = disp.normalization();
37902 42303 bool old_is_resized = disp.is_resized();
37903 42304 disp._normalization = 0;
37904 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 42309 int area = 0, starting_area = 0, clicked_area = 0, phase = 0,
37910 42310 X0 = (int)((XYZ?XYZ[0]:(_width - 1)/2)%_width),
... ... @@ -37945,6 +42345,8 @@ namespace cimg_library_suffixed {
37945 42345 if (mX>=width() && mY>=height()) area = 4;
37946 42346 if (disp.button()) { if (!clicked_area) clicked_area = area; } else clicked_area = 0;
37947 42347  
  42348 + CImg<charT> filename(32);
  42349 +
37948 42350 switch (key = disp.key()) {
37949 42351 #if cimg_OS!=2
37950 42352 case cimg::keyCTRLRIGHT :
... ... @@ -37982,35 +42384,33 @@ namespace cimg_library_suffixed {
37982 42384 } break;
37983 42385 case cimg::keyS : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {
37984 42386 static unsigned int snap_number = 0;
37985   - char filename[32] = { 0 };
37986 42387 std::FILE *file;
37987 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 42390 if ((file=std::fopen(filename,"r"))!=0) cimg::fclose(file);
37990 42391 } while (file);
37991 42392 if (visu0) {
37992 42393 (+visu0).draw_text(0,0," Saving snapshot... ",foreground_color,background_color,0.7f,13).display(disp);
37993 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 42396 display(disp);
37996 42397 }
37997 42398 disp.set_key(key,false); key = 0;
37998 42399 } break;
37999 42400 case cimg::keyO : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {
38000 42401 static unsigned int snap_number = 0;
38001   - char filename[32] = { 0 };
38002 42402 std::FILE *file;
38003 42403 do {
38004 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 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 42408 #endif
38009 42409 if ((file=std::fopen(filename,"r"))!=0) cimg::fclose(file);
38010 42410 } while (file);
38011 42411 (+visu0).draw_text(0,0," Saving instance... ",foreground_color,background_color,0.7f,13).display(disp);
38012 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 42414 display(disp);
38015 42415 disp.set_key(key,false); key = 0;
38016 42416 } break;
... ... @@ -38043,7 +42443,7 @@ namespace cimg_library_suffixed {
38043 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 42447 X = (float)X0; Y = (float)Y0; Z = (float)Z0; phase = area = clicked_area = starting_area = 0;
38048 42448 visu0.assign();
38049 42449 }
... ... @@ -38146,7 +42546,9 @@ namespace cimg_library_suffixed {
38146 42546 if (mx!=omx || my!=omy || !visu0 || (_depth>1 && !view3d)) {
38147 42547  
38148 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 42552 view3d.assign();
38151 42553 points3d.assign();
38152 42554 }
... ... @@ -38409,6 +42811,10 @@ namespace cimg_library_suffixed {
38409 42811 } else if (!shape_selected) disp.wait();
38410 42812 if (disp.is_resized()) { disp.resize(false)._is_resized = false; old_is_resized = true; visu0.assign(); }
38411 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 42820 // Return result.
... ... @@ -38428,7 +42834,7 @@ namespace cimg_library_suffixed {
38428 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 42838 if (!visible_cursor) disp.show_mouse();
38433 42839 disp._normalization = old_normalization;
38434 42840 disp._is_resized = old_is_resized;
... ... @@ -38445,9 +42851,8 @@ namespace cimg_library_suffixed {
38445 42851 if (_depth>1) crop.get_projections2d(x,y,z).move_to(img2d);
38446 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 42856 bool is_inf = false, is_nan = false;
38452 42857 cimg_for(img2d,ptr,Tuchar)
38453 42858 if (cimg::type<T>::is_inf(*ptr)) { is_inf = true; break; }
... ... @@ -38467,7 +42872,7 @@ namespace cimg_library_suffixed {
38467 42872 val_pinf = (T)(normalization==1 || normalization==3?M0 + (M0 - m0)*20 + 1:M0);
38468 42873 if (is_nan)
38469 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 42876 if (is_inf)
38472 42877 cimg_for(img2d,ptr,Tuchar)
38473 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 42901 CImg<intT> get_select_graph(CImgDisplay &disp,
38497 42902 const unsigned int plot_type=1, const unsigned int vertex_type=1,
38498 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 42906 if (is_empty())
38501 42907 throw CImgInstanceException(_cimg_instance
38502 42908 "select_graph(): Empty instance.",
... ... @@ -38512,8 +42918,8 @@ namespace cimg_library_suffixed {
38512 42918 if (nymin==nymax) { --nymin; ++nymax; }
38513 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 42923 static unsigned int odimv = 0;
38518 42924 static CImg<ucharT> colormap;
38519 42925 if (odimv!=_spectrum) {
... ... @@ -38619,8 +43025,8 @@ namespace cimg_library_suffixed {
38619 43025 (double)(*this)(x,0,0,_spectrum - 1));
38620 43026 else {
38621 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 43031 if (x0>=0 && x1>=0) {
38626 43032 const unsigned int
... ... @@ -38634,10 +43040,10 @@ namespace cimg_library_suffixed {
38634 43040 cy0 = nymax - ny0*(nymax - nymin)/(visu._height - 32),
38635 43041 cy1 = nymax - ny1*(nymax - nymin)/(visu._height - 32);
38636 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 43044 x0,cx0,cy0,x1 + one,cx1,cy1);
38639 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 43047 x0,cx0,x1 + one,cx1);
38642 43048 }
38643 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 43053 }
38648 43054  
38649 43055 // Test keys.
  43056 + CImg<charT> filename(32);
38650 43057 switch (okey = key) {
38651 43058 #if cimg_OS!=2
38652 43059 case cimg::keyCTRLRIGHT : case cimg::keySHIFTRIGHT :
... ... @@ -38678,15 +43085,14 @@ namespace cimg_library_suffixed {
38678 43085 static unsigned int snap_number = 0;
38679 43086 if (visu || visu0) {
38680 43087 CImg<ucharT> &screen = visu?visu:visu0;
38681   - char filename[32] = { 0 };
38682 43088 std::FILE *file;
38683 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 43091 if ((file=std::fopen(filename,"r"))!=0) cimg::fclose(file);
38686 43092 } while (file);
38687 43093 (+screen).draw_text(0,0," Saving snapshot... ",black,gray,1,13).display(disp);
38688 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 43097 disp.set_key(key,false); okey = 0;
38692 43098 } break;
... ... @@ -38694,19 +43100,18 @@ namespace cimg_library_suffixed {
38694 43100 static unsigned int snap_number = 0;
38695 43101 if (visu || visu0) {
38696 43102 CImg<ucharT> &screen = visu?visu:visu0;
38697   - char filename[32] = { 0 };
38698 43103 std::FILE *file;
38699 43104 do {
38700 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 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 43109 #endif
38705 43110 if ((file=std::fopen(filename,"r"))!=0) cimg::fclose(file);
38706 43111 } while (file);
38707 43112 (+screen).draw_text(0,0," Saving instance... ",black,gray,1,13).display(disp);
38708 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 43116 disp.set_key(key,false); okey = 0;
38712 43117 } break;
... ... @@ -38733,6 +43138,11 @@ namespace cimg_library_suffixed {
38733 43138 }
38734 43139 if (disp.is_resized()) { disp.resize(false); visu0.assign(); }
38735 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 43148 disp._normalization = old_normalization;
... ... @@ -39067,8 +43477,8 @@ namespace cimg_library_suffixed {
39067 43477 cimg_instance);
39068 43478  
39069 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 43482 if (*header!='B' || header[1]!='M') {
39073 43483 if (!file) cimg::fclose(nfile);
39074 43484 throw CImgIOException(_cimg_instance
... ... @@ -39093,7 +43503,7 @@ namespace cimg_library_suffixed {
39093 43503 file_size = (int)std::ftell(nfile);
39094 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 43508 const int
39099 43509 cimg_iobuffer = 24*1024*1024,
... ... @@ -40037,7 +44447,7 @@ namespace cimg_library_suffixed {
40037 44447 - When libtiff is enabled, 2D and 3D (multipage) several
40038 44448 channel per pixel are supported for
40039 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 44451 function uses CImg<T>& load_other(const char*).
40042 44452 **/
40043 44453 CImg<T>& load_tiff(const char *const filename,
... ... @@ -40243,10 +44653,13 @@ namespace cimg_library_suffixed {
40243 44653 if (TIFFGetField(tif,TIFFTAG_IMAGEDESCRIPTION,&s_description) && s_description)
40244 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 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 44663 // Special case for unsigned color images.
40251 44664 uint32 *const raster = (uint32*)_TIFFmalloc(nx*ny*sizeof(uint32));
40252 44665 if (!raster) {
... ... @@ -40258,24 +44671,25 @@ namespace cimg_library_suffixed {
40258 44671 }
40259 44672 TIFFReadRGBAImage(tif,nx,ny,raster,0);
40260 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 44679 cimg_forXY(*this,x,y) {
40266 44680 (*this)(x,y,0) = (T)(float)TIFFGetR(raster[nx*(ny - 1 -y) + x]);
40267 44681 (*this)(x,y,1) = (T)(float)TIFFGetG(raster[nx*(ny - 1 -y) + x]);
40268 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 44686 cimg_forXY(*this,x,y) {
40273 44687 (*this)(x,y,0) = (T)(float)TIFFGetR(raster[nx*(ny - 1 - y) + x]);
40274 44688 (*this)(x,y,1) = (T)(float)TIFFGetG(raster[nx*(ny - 1 - y) + x]);
40275 44689 (*this)(x,y,2) = (T)(float)TIFFGetB(raster[nx*(ny - 1 - y) + x]);
40276 44690 (*this)(x,y,3) = (T)(float)TIFFGetA(raster[nx*(ny - 1 - y) + x]);
40277 44691 }
40278   - } break;
  44692 + break;
40279 44693 }
40280 44694 _TIFFfree(raster);
40281 44695 } else { // Other cases.
... ... @@ -40432,11 +44846,11 @@ namespace cimg_library_suffixed {
40432 44846 const char *const ext = cimg::split_filename(filename,body);
40433 44847 if (!cimg::strcasecmp(ext,"hdr")) { // File is an Analyze header file.
40434 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 44850 nfile = cimg::fopen(body,"rb");
40437 44851 } else if (!cimg::strcasecmp(ext,"img")) { // File is an Analyze data file.
40438 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 44854 nfile_header = cimg::fopen(body,"rb");
40441 44855 } else nfile_header = nfile = cimg::fopen(filename,"rb"); // File is a Niftii file.
40442 44856 } else nfile_header = nfile = file; // File is a Niftii file.
... ... @@ -40452,7 +44866,7 @@ namespace cimg_library_suffixed {
40452 44866 cimg::fread(&header_size,1,nfile_header);
40453 44867 if (!header_size)
40454 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 44870 cimg_instance,
40457 44871 filename?filename:"(FILE*)");
40458 44872  
... ... @@ -40661,8 +45075,8 @@ namespace cimg_library_suffixed {
40661 45075 }
40662 45076  
40663 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 45080 out[0] = std::fscanf(file,"%63s",item._data);
40667 45081 out[0] = out[1] = out[2] = out[3] = out[5] = 1; out[4] = out[6] = out[7] = -1;
40668 45082 if(cimg::strncasecmp(item,"#INRIMAGE-4#{",13)!=0)
... ... @@ -40680,19 +45094,19 @@ namespace cimg_library_suffixed {
40680 45094 cimg_sscanf(item," VY%*[^0-9.+-]%f",voxel_size + 1);
40681 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 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 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 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 45105 if (out[4]>=0) break;
40692 45106 default :
40693 45107 throw CImgIOException("CImg<%s>::load_inr(): Invalid pixel type '%s' defined in header.",
40694 45108 pixel_type(),
40695   - tmp2);
  45109 + tmp2._data);
40696 45110 }
40697 45111 }
40698 45112 if(out[0]<0 || out[1]<0 || out[2]<0 || out[3]<0)
... ... @@ -40846,8 +45260,8 @@ namespace cimg_library_suffixed {
40846 45260 cimg_instance);
40847 45261  
40848 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 45265 if (cimg::strncasecmp("PANDORE",header,7)) {
40852 45266 if (!file) cimg::fclose(nfile);
40853 45267 throw CImgIOException(_cimg_instance
... ... @@ -40856,10 +45270,11 @@ namespace cimg_library_suffixed {
40856 45270 filename?filename:"(FILE*)");
40857 45271 }
40858 45272 unsigned int imageid, dims[8] = { 0 };
  45273 + int ptbuf[4] = { 0 };
40859 45274 cimg::fread(&imageid,1,nfile);
40860   - const bool endian = (imageid>255);
  45275 + const bool endian = imageid>255;
40861 45276 if (endian) cimg::invert_endianness(imageid);
40862   - cimg::fread(header,20,nfile);
  45277 + cimg::fread(header._data,20,nfile);
40863 45278  
40864 45279 switch (imageid) {
40865 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 45406 break;
40992 45407 case 33 : _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],dims[0],double,float,float,4); break;
40993 45408 case 34 : { // Points 1d
40994   - int ptbuf[4] = { 0 };
40995 45409 cimg::fread(ptbuf,1,nfile);
40996 45410 if (endian) cimg::invert_endianness(ptbuf,1);
40997 45411 assign(1); (*this)(0) = (T)ptbuf[0];
40998 45412 } break;
40999 45413 case 35 : { // Points 2d
41000   - int ptbuf[4] = { 0 };
41001 45414 cimg::fread(ptbuf,2,nfile);
41002 45415 if (endian) cimg::invert_endianness(ptbuf,2);
41003 45416 assign(2); (*this)(0) = (T)ptbuf[1]; (*this)(1) = (T)ptbuf[0];
41004 45417 } break;
41005 45418 case 36 : { // Points 3d
41006   - int ptbuf[4] = { 0 };
41007 45419 cimg::fread(ptbuf,3,nfile);
41008 45420 if (endian) cimg::invert_endianness(ptbuf,3);
41009 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 46298 const unsigned long siz = size(), msiz = siz*sizeof(T), siz1 = siz - 1,
41887 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 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 46306 cimg::t_bold,cimg::t_normal,(void*)this,
41895 46307 cimg::t_bold,cimg::t_normal,_width,_height,_depth,_spectrum,
41896 46308 mdisp==0?msiz:(mdisp==1?(msiz>>10):(msiz>>20)),
... ... @@ -41934,8 +46346,9 @@ namespace cimg_library_suffixed {
41934 46346 \param disp Display window.
41935 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 46354 //! Display image into an interactive window.
... ... @@ -41943,16 +46356,18 @@ namespace cimg_library_suffixed {
41943 46356 \param title Window title
41944 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 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 46367 const bool exit_on_simpleclick) const {
41954 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 46372 if (!disp) {
41958 46373 disp.assign(cimg_fitscreen(_width,_height,_depth),title?title:0,1);
... ... @@ -42010,14 +46425,21 @@ namespace cimg_library_suffixed {
42010 46425 _XYZ[1] = (unsigned int)(y1 - y0)/2;
42011 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 46432 is_first_select = false;
42015 46433  
42016 46434 if (disp.wheel()) {
42017 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 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 46443 disp.set_wheel();
42022 46444 }
42023 46445  
... ... @@ -42175,6 +46597,10 @@ namespace cimg_library_suffixed {
42175 46597 else { z0+=(depth() - 1 - z1); z1 = depth() - 1; }
42176 46598 }
42177 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 46605 disp.set_key(key);
42180 46606 if (XYZ) { XYZ[0] = _XYZ[0]; XYZ[1] = _XYZ[1]; XYZ[2] = _XYZ[2]; }
... ... @@ -42212,11 +46638,12 @@ namespace cimg_library_suffixed {
42212 46638 const bool is_double_sided=true, const float focale=700,
42213 46639 const float light_x=0, const float light_y=0, const float light_z=-5e8f,
42214 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 46643 return _display_object3d(disp,0,vertices,primitives,colors,opacities,centering,render_static,
42217 46644 render_motion,is_double_sided,focale,
42218 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 46649 //! Display object 3d in an interactive window \simplification.
... ... @@ -42231,12 +46658,13 @@ namespace cimg_library_suffixed {
42231 46658 const bool is_double_sided=true, const float focale=700,
42232 46659 const float light_x=0, const float light_y=0, const float light_z=-5e8f,
42233 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 46663 CImgDisplay disp;
42236 46664 return _display_object3d(disp,title,vertices,primitives,colors,opacities,centering,render_static,
42237 46665 render_motion,is_double_sided,focale,
42238 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 46670 //! Display object 3d in an interactive window \simplification.
... ... @@ -42250,11 +46678,12 @@ namespace cimg_library_suffixed {
42250 46678 const bool is_double_sided=true, const float focale=700,
42251 46679 const float light_x=0, const float light_y=0, const float light_z=-5e8f,
42252 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 46683 return display_object3d(disp,vertices,primitives,colors,CImgList<floatT>(),centering,
42255 46684 render_static,render_motion,is_double_sided,focale,
42256 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 46689 //! Display object 3d in an interactive window \simplification.
... ... @@ -42268,11 +46697,12 @@ namespace cimg_library_suffixed {
42268 46697 const bool is_double_sided=true, const float focale=700,
42269 46698 const float light_x=0, const float light_y=0, const float light_z=-5e8f,
42270 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 46702 return display_object3d(title,vertices,primitives,colors,CImgList<floatT>(),centering,
42273 46703 render_static,render_motion,is_double_sided,focale,
42274 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 46708 //! Display object 3d in an interactive window \simplification.
... ... @@ -42285,11 +46715,12 @@ namespace cimg_library_suffixed {
42285 46715 const bool is_double_sided=true, const float focale=700,
42286 46716 const float light_x=0, const float light_y=0, const float light_z=-5e8f,
42287 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 46720 return display_object3d(disp,vertices,primitives,CImgList<T>(),centering,
42290 46721 render_static,render_motion,is_double_sided,focale,
42291 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 46734 const bool is_double_sided=true, const float focale=700,
42304 46735 const float light_x=0, const float light_y=0, const float light_z=-5e8f,
42305 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 46739 return display_object3d(title,vertices,primitives,CImgList<T>(),centering,
42308 46740 render_static,render_motion,is_double_sided,focale,
42309 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 46745 //! Display object 3d in an interactive window \simplification.
... ... @@ -42319,11 +46751,12 @@ namespace cimg_library_suffixed {
42319 46751 const bool is_double_sided=true, const float focale=700,
42320 46752 const float light_x=0, const float light_y=0, const float light_z=-5e8f,
42321 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 46756 return display_object3d(disp,vertices,CImgList<uintT>(),centering,
42324 46757 render_static,render_motion,is_double_sided,focale,
42325 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 46762 //! Display object 3d in an interactive window \simplification.
... ... @@ -42335,11 +46768,12 @@ namespace cimg_library_suffixed {
42335 46768 const bool is_double_sided=true, const float focale=700,
42336 46769 const float light_x=0, const float light_y=0, const float light_z=-5e8f,
42337 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 46773 return display_object3d(title,vertices,CImgList<uintT>(),centering,
42340 46774 render_static,render_motion,is_double_sided,focale,
42341 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 46779 template<typename tp, typename tf, typename tc, typename to>
... ... @@ -42353,7 +46787,8 @@ namespace cimg_library_suffixed {
42353 46787 const bool is_double_sided, const float focale,
42354 46788 const float light_x, const float light_y, const float light_z,
42355 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 46792 typedef typename cimg::superset<tp,float>::type tpfloat;
42358 46793  
42359 46794 // Check input arguments
... ... @@ -42362,14 +46797,14 @@ namespace cimg_library_suffixed {
42362 46797 _display_object3d(disp,title,vertices,primitives,colors,opacities,centering,
42363 46798 render_static,render_motion,is_double_sided,focale,
42364 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 46801 else return CImg<T>(1,2,1,1,64,128).resize(cimg_fitscreen(CImgDisplay::screen_width()/2,
42367 46802 CImgDisplay::screen_height()/2,1),
42368 46803 1,(colors && colors[0].size()==1)?1:3,3).
42369 46804 _display_object3d(disp,title,vertices,primitives,colors,opacities,centering,
42370 46805 render_static,render_motion,is_double_sided,focale,
42371 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 46808 } else { if (disp) disp.resize(*this,false); }
42374 46809 CImg<charT> error_message(1024);
42375 46810 if (!vertices.is_object3d(primitives,colors,opacities,true,error_message))
... ... @@ -42382,7 +46817,7 @@ namespace cimg_library_suffixed {
42382 46817 return _display_object3d(disp,title,vertices,nprimitives,colors,opacities,centering,
42383 46818 render_static,render_motion,is_double_sided,focale,
42384 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 46822 if (!disp) {
42388 46823 disp.assign(cimg_fitscreen(_width,_height,_depth),title?title:0,3);
... ... @@ -42583,6 +47018,7 @@ namespace cimg_library_suffixed {
42583 47018 }
42584 47019 } else if (clicked) { x0 = x1; y0 = y1; clicked = false; redraw = true; }
42585 47020  
  47021 + CImg<charT> filename(32);
42586 47022 switch (key = disp.key()) {
42587 47023 #if cimg_OS!=2
42588 47024 case cimg::keyCTRLRIGHT :
... ... @@ -42661,43 +47097,40 @@ namespace cimg_library_suffixed {
42661 47097 } break;
42662 47098 case cimg::keyS : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Save snapshot
42663 47099 static unsigned int snap_number = 0;
42664   - char filename[32] = { 0 };
42665 47100 std::FILE *file;
42666 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 47103 if ((file=std::fopen(filename,"r"))!=0) cimg::fclose(file);
42669 47104 } while (file);
42670 47105 (+visu).draw_text(0,0," Saving snapshot... ",
42671 47106 foreground_color._data,background_color._data,0.7f,13).display(disp);
42672 47107 visu.save(filename);
42673 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 47110 disp.set_key(key,false); key = 0;
42676 47111 } break;
42677 47112 case cimg::keyG : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Save object as a .off file
42678 47113 static unsigned int snap_number = 0;
42679   - char filename[32] = { 0 };
42680 47114 std::FILE *file;
42681 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 47117 if ((file=std::fopen(filename,"r"))!=0) cimg::fclose(file);
42684 47118 } while (file);
42685 47119 (+visu).draw_text(0,0," Saving object... ",
42686 47120 foreground_color._data,background_color._data,0.7f,13).display(disp);
42687 47121 vertices.save_off(reverse_primitives?reverse_primitives:primitives,colors,filename);
42688 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 47124 disp.set_key(key,false); key = 0;
42691 47125 } break;
42692 47126 case cimg::keyO : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Save object as a .cimg file
42693 47127 static unsigned int snap_number = 0;
42694   - char filename[32] = { 0 };
42695 47128 std::FILE *file;
42696 47129 do {
42697 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 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 47134 #endif
42702 47135 if ((file=std::fopen(filename,"r"))!=0) cimg::fclose(file);
42703 47136 } while (file);
... ... @@ -42706,16 +47139,15 @@ namespace cimg_library_suffixed {
42706 47139 vertices.get_object3dtoCImg3d(reverse_primitives?reverse_primitives:primitives,colors,opacities).
42707 47140 save(filename);
42708 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 47143 disp.set_key(key,false); key = 0;
42711 47144 } break;
42712 47145 #ifdef cimg_use_board
42713 47146 case cimg::keyP : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Save object as a .EPS file
42714 47147 static unsigned int snap_number = 0;
42715   - char filename[32] = { 0 };
42716 47148 std::FILE *file;
42717 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 47151 if ((file=std::fopen(filename,"r"))!=0) cimg::fclose(file);
42720 47152 } while (file);
42721 47153 (+visu).draw_text(0,0," Saving EPS snapshot... ",
... ... @@ -42731,15 +47163,14 @@ namespace cimg_library_suffixed {
42731 47163 sprite_scale);
42732 47164 board.saveEPS(filename);
42733 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 47167 disp.set_key(key,false); key = 0;
42736 47168 } break;
42737 47169 case cimg::keyV : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Save object as a .SVG file
42738 47170 static unsigned int snap_number = 0;
42739   - char filename[32] = { 0 };
42740 47171 std::FILE *file;
42741 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 47174 if ((file=std::fopen(filename,"r"))!=0) cimg::fclose(file);
42744 47175 } while (file);
42745 47176 (+visu).draw_text(0,0," Saving SVG snapshot... ",
... ... @@ -42755,7 +47186,7 @@ namespace cimg_library_suffixed {
42755 47186 sprite_scale);
42756 47187 board.saveSVG(filename);
42757 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 47190 disp.set_key(key,false); key = 0;
42760 47191 } break;
42761 47192 #endif
... ... @@ -42765,6 +47196,10 @@ namespace cimg_library_suffixed {
42765 47196 if (zbuffer) zbuffer.assign(disp.width(),disp.height());
42766 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 47204 if (pose_matrix) {
42770 47205 std::memcpy(pose_matrix,pose._data,12*sizeof(float));
... ... @@ -42789,23 +47224,26 @@ namespace cimg_library_suffixed {
42789 47224 const CImg<T>& display_graph(CImgDisplay &disp,
42790 47225 const unsigned int plot_type=1, const unsigned int vertex_type=1,
42791 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 47232 //! Display 1d graph in an interactive window \overloading.
42797 47233 const CImg<T>& display_graph(const char *const title=0,
42798 47234 const unsigned int plot_type=1, const unsigned int vertex_type=1,
42799 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 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 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 47247 if (is_empty())
42810 47248 throw CImgInstanceException(_cimg_instance
42811 47249 "display_graph(): Empty instance.",
... ... @@ -42831,7 +47269,7 @@ namespace cimg_library_suffixed {
42831 47269 labelx,
42832 47270 nxmin + x0*(nxmax - nxmin)/siz1,
42833 47271 nxmin + x1*(nxmax - nxmin)/siz1,
42834   - labely,y0,y1);
  47272 + labely,y0,y1,true);
42835 47273 const int mouse_x = disp.mouse_x(), mouse_y = disp.mouse_y();
42836 47274 if (selection[0]>=0) {
42837 47275 if (selection[2]<0) reset_view = true;
... ... @@ -42860,9 +47298,9 @@ namespace cimg_library_suffixed {
42860 47298 case cimg::keyPAD3 : go_right = true; go_down = true; key = 0; disp.set_key(); break;
42861 47299 }
42862 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 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 47304 key = 0;
42867 47305 }
42868 47306  
... ... @@ -42915,6 +47353,11 @@ namespace cimg_library_suffixed {
42915 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 47362 disp._normalization = old_normalization;
42920 47363 return *this;
... ... @@ -43176,7 +47619,8 @@ namespace cimg_library_suffixed {
43176 47619 filename?filename:"(FILE*)");
43177 47620  
43178 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 47624 const unsigned int
43181 47625 align = (4 - (3*_width)%4)%4,
43182 47626 buf_size = (3*_width + align)*height(),
... ... @@ -43206,7 +47650,7 @@ namespace cimg_library_suffixed {
43206 47650 header[0x25] = (buf_size>>24)&0xFF;
43207 47651 header[0x27] = 0x1;
43208 47652 header[0x2B] = 0x1;
43209   - cimg::fwrite(header,54,nfile);
  47653 + cimg::fwrite(header._data,54,nfile);
43210 47654  
43211 47655 const T
43212 47656 *ptr_r = data(0,_height - 1,0,0),
... ... @@ -43286,7 +47730,7 @@ namespace cimg_library_suffixed {
43286 47730 unsigned int dimbuf = 0;
43287 47731 J_COLOR_SPACE colortype = JCS_RGB;
43288 47732  
43289   - switch(_spectrum) {
  47733 + switch (_spectrum) {
43290 47734 case 1 : dimbuf = 1; colortype = JCS_GRAYSCALE; break;
43291 47735 case 2 : dimbuf = 3; colortype = JCS_RGB; break;
43292 47736 case 3 : dimbuf = 3; colortype = JCS_RGB; break;
... ... @@ -43318,13 +47762,13 @@ namespace cimg_library_suffixed {
43318 47762 switch (_spectrum) {
43319 47763 case 1 : { // Greyscale images
43320 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 47766 *(ptrd++) = (unsigned char)*(ptr_g++);
43323 47767 } break;
43324 47768 case 2 : { // RG images
43325 47769 const T *ptr_r = data(0,cinfo.next_scanline,0,0),
43326 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 47772 *(ptrd++) = (unsigned char)*(ptr_r++);
43329 47773 *(ptrd++) = (unsigned char)*(ptr_g++);
43330 47774 *(ptrd++) = 0;
... ... @@ -43334,7 +47778,7 @@ namespace cimg_library_suffixed {
43334 47778 const T *ptr_r = data(0,cinfo.next_scanline,0,0),
43335 47779 *ptr_g = data(0,cinfo.next_scanline,0,1),
43336 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 47782 *(ptrd++) = (unsigned char)*(ptr_r++);
43339 47783 *(ptrd++) = (unsigned char)*(ptr_g++);
43340 47784 *(ptrd++) = (unsigned char)*(ptr_b++);
... ... @@ -43345,7 +47789,7 @@ namespace cimg_library_suffixed {
43345 47789 *ptr_g = data(0,cinfo.next_scanline,0,1),
43346 47790 *ptr_b = data(0,cinfo.next_scanline,0,2),
43347 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 47793 *(ptrd++) = (unsigned char)*(ptr_r++);
43350 47794 *(ptrd++) = (unsigned char)*(ptr_g++);
43351 47795 *(ptrd++) = (unsigned char)*(ptr_b++);
... ... @@ -44087,11 +48531,12 @@ namespace cimg_library_suffixed {
44087 48531 - When libtiff is enabled, 2D and 3D (multipage) several
44088 48532 channel per pixel are supported for
44089 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 48535 function uses CImg<T>&save_other(const char*).
44092 48536 **/
44093 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 48540 if (!filename)
44096 48541 throw CImgArgumentException(_cimg_instance
44097 48542 "save_tiff(): Specified filename is (null).",
... ... @@ -44099,9 +48544,9 @@ namespace cimg_library_suffixed {
44099 48544 if (is_empty()) { cimg::fempty(0,filename); return *this; }
44100 48545  
44101 48546 #ifdef cimg_use_tiff
44102   - TIFF *tif = TIFFOpen(filename,"w");
  48547 + TIFF *tif = TIFFOpen(filename,is_bigtiff?"w8":"w4");
44103 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 48550 TIFFClose(tif);
44106 48551 } else throw CImgIOException(_cimg_instance
44107 48552 "save_tiff(): Failed to open file '%s' for writing.",
... ... @@ -44109,7 +48554,7 @@ namespace cimg_library_suffixed {
44109 48554 filename);
44110 48555 return *this;
44111 48556 #else
44112   - cimg::unused(compression_type,voxel_size,description);
  48557 + cimg::unused(compression_type,voxel_size,description,is_bigtiff);
44113 48558 return save_other(filename);
44114 48559 #endif
44115 48560 }
... ... @@ -44117,13 +48562,13 @@ namespace cimg_library_suffixed {
44117 48562 #ifdef cimg_use_tiff
44118 48563  
44119 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 48567 // [internal] Save a plane into a tiff file
44123 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 48572 if (is_empty() || !tif || pixel_t) return *this;
44128 48573 const char *const filename = TIFFFileName(tif);
44129 48574 uint32 rowsperstrip = (uint32)-1;
... ... @@ -44166,7 +48611,7 @@ namespace cimg_library_suffixed {
44166 48611 for (unsigned int rr = 0; rr<nrow; ++rr)
44167 48612 for (unsigned int cc = 0; cc<_width; ++cc)
44168 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 48615 if (TIFFWriteEncodedStrip(tif,strip,buf,i*sizeof(t))<0)
44171 48616 throw CImgIOException(_cimg_instance
44172 48617 "save_tiff(): Invalid strip writing when saving file '%s'.",
... ... @@ -44179,8 +48624,9 @@ namespace cimg_library_suffixed {
44179 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 48630 _cimg_save_tiff("bool",unsigned char,compression_type);
44185 48631 _cimg_save_tiff("char",char,compression_type);
44186 48632 _cimg_save_tiff("unsigned char",unsigned char,compression_type);
... ... @@ -44255,11 +48701,9 @@ namespace cimg_library_suffixed {
44255 48701 if (is_empty()) { cimg::fempty(0,filename); return *this; }
44256 48702  
44257 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 48705 const char *const ext = cimg::split_filename(filename);
44261 48706 short datatype = -1;
44262   - std::memset(header,0,348);
44263 48707 if (!*ext) {
44264 48708 cimg_snprintf(hname,hname._width,"%s.hdr",filename);
44265 48709 cimg_snprintf(iname,iname._width,"%s.img",filename);
... ... @@ -44267,27 +48711,27 @@ namespace cimg_library_suffixed {
44267 48711 if (!cimg::strncasecmp(ext,"hdr",3)) {
44268 48712 std::strcpy(hname,filename);
44269 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 48716 if (!cimg::strncasecmp(ext,"img",3)) {
44273 48717 std::strcpy(hname,filename);
44274 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 48721 if (!cimg::strncasecmp(ext,"nii",3)) {
44278 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 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 48735 if (!cimg::strcasecmp(pixel_type(),"bool")) datatype = 2;
44292 48736 if (!cimg::strcasecmp(pixel_type(),"unsigned char")) datatype = 2;
44293 48737 if (!cimg::strcasecmp(pixel_type(),"char")) datatype = 2;
... ... @@ -44305,17 +48749,17 @@ namespace cimg_library_suffixed {
44305 48749 cimg_instance,
44306 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 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 48761 file = cimg::fopen(hname,"wb");
44318   - cimg::fwrite(header,348,file);
  48762 + cimg::fwrite(header._data,348,file);
44319 48763 if (*iname) { cimg::fclose(file); file = cimg::fopen(iname,"wb"); }
44320 48764 cimg::fwrite(_data,size(),file);
44321 48765 cimg::fclose(file);
... ... @@ -44446,14 +48890,15 @@ namespace cimg_library_suffixed {
44446 48890 pixel_type(),filename?filename:"(FILE*)");
44447 48891  
44448 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 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 48902 cimg_forXYZ(*this,x,y,z) cimg_forC(*this,c) cimg::fwrite(&((*this)(x,y,z,c)),1,nfile);
44458 48903 if (!file) cimg::fclose(nfile);
44459 48904 return *this;
... ... @@ -44552,28 +48997,28 @@ namespace cimg_library_suffixed {
44552 48997 unsigned int _save_pandore_header_length(unsigned int id, unsigned int *dims, const unsigned int colorspace) const {
44553 48998 unsigned int nbdims = 0;
44554 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 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 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 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 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 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 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 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 49023 return nbdims;
44579 49024 }
... ... @@ -44597,9 +49042,9 @@ namespace cimg_library_suffixed {
44597 49042 cimg::fwrite(header,36,nfile); \
44598 49043 if (sizeof(unsigned long)==4) { CImg<ulongT> ndims(5); \
44599 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 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 49048 for (int d = 0; d<5; ++d) ndims[d] = (unsigned short)dims[d]; cimg::fwrite(ndims._data,nbdims,nfile); } \
44604 49049 else throw CImgIOException(_cimg_instance \
44605 49050 "save_pandore(): Unsupported datatype for file '%s'.",\
... ... @@ -44633,8 +49078,9 @@ namespace cimg_library_suffixed {
44633 49078 if (is_empty()) { cimg::fempty(file,filename); return *this; }
44634 49079  
44635 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 49084 unsigned int nbdims, dims[5] = { 0 };
44639 49085 bool saved = false;
44640 49086 _cimg_save_pandore_case(1,1,1,"unsigned char",2);
... ... @@ -45921,8 +50367,7 @@ namespace cimg_library_suffixed {
45921 50367 \note Can be used to exchange the content of two lists in a fast way.
45922 50368 **/
45923 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 50371 cimg::swap(_data,list._data);
45927 50372 return list;
45928 50373 }
... ... @@ -45939,6 +50384,12 @@ namespace cimg_library_suffixed {
45939 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 51931 \return A one-column vector containing the selected image indexes.
47481 51932 **/
47482 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 51939 //! Display a simple interactive interface to select images or sublists.
... ... @@ -47493,13 +51945,14 @@ namespace cimg_library_suffixed {
47493 51945 \return A one-column vector containing the selected image indexes.
47494 51946 **/
47495 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 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 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 51956 const unsigned int orig, const bool resize_disp,
47504 51957 const bool exit_on_rightbutton, const bool exit_on_wheel) const {
47505 51958 if (is_empty())
... ... @@ -47538,7 +51991,7 @@ namespace cimg_library_suffixed {
47538 51991 bool old_is_resized = disp.is_resized();
47539 51992 disp._normalization = 0;
47540 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 51996 // Enter event loop.
47544 51997 CImg<ucharT> visu0, visu;
... ... @@ -47547,6 +52000,7 @@ namespace cimg_library_suffixed {
47547 52000 int oindice0 = -1, oindice1 = -1, indice0 = -1, indice1 = -1;
47548 52001 bool is_clicked = false, is_selected = false, text_down = false, update_display = true;
47549 52002 unsigned int key = 0;
  52003 +
47550 52004 while (!is_selected && !disp.is_closed() && !key) {
47551 52005  
47552 52006 // Create background image.
... ... @@ -47650,6 +52104,7 @@ namespace cimg_library_suffixed {
47650 52104 if (disp.button()&2 && exit_on_rightbutton) { is_selected = true; indice1 = indice0 = -1; }
47651 52105 if (disp.wheel() && exit_on_wheel) is_selected = true;
47652 52106  
  52107 + CImg<charT> filename(32);
47653 52108 switch (key = disp.key()) {
47654 52109 #if cimg_OS!=2
47655 52110 case cimg::keyCTRLRIGHT :
... ... @@ -47679,10 +52134,9 @@ namespace cimg_library_suffixed {
47679 52134 } break;
47680 52135 case cimg::keyS : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {
47681 52136 static unsigned int snap_number = 0;
47682   - char filename[32] = { 0 };
47683 52137 std::FILE *file;
47684 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 52140 if ((file=std::fopen(filename,"r"))!=0) cimg::fclose(file);
47687 52141 } while (file);
47688 52142 if (visu0) {
... ... @@ -47690,20 +52144,19 @@ namespace cimg_library_suffixed {
47690 52144 foreground_color,background_color,0.7f,13).display(disp);
47691 52145 visu0.save(filename);
47692 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 52149 disp.set_key(key,false).wait(); key = 0;
47696 52150 } break;
47697 52151 case cimg::keyO :
47698 52152 if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) {
47699 52153 static unsigned int snap_number = 0;
47700   - char filename[32] = { 0 };
47701 52154 std::FILE *file;
47702 52155 do {
47703 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 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 52160 #endif
47708 52161 if ((file=std::fopen(filename,"r"))!=0) cimg::fclose(file);
47709 52162 } while (file);
... ... @@ -47711,13 +52164,17 @@ namespace cimg_library_suffixed {
47711 52164 foreground_color,background_color,0.7f,13).display(disp);
47712 52165 save(filename);
47713 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 52168 disp.set_key(key,false).wait(); key = 0;
47716 52169 } break;
47717 52170 }
47718 52171 if (disp.is_resized()) { disp.resize(false); visu0.assign(); }
47719 52172 if (ym>=0 && ym<13) { if (!text_down) { visu.assign(); text_down = true; }}
47720 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 52179 CImg<intT> res(1,2,1,1,-1);
47723 52180 if (is_selected) {
... ... @@ -48422,7 +52879,7 @@ namespace cimg_library_suffixed {
48422 52879 \param first_frame Index of the first frame to read.
48423 52880 \param last_frame Index of the last frame to read.
48424 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 52884 CImgList<T>& load_video(const char *const filename,
48428 52885 const unsigned int first_frame=0, const unsigned int last_frame=~0U,
... ... @@ -48465,7 +52922,7 @@ namespace cimg_library_suffixed {
48465 52922 } else
48466 52923 if (filename)
48467 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 52926 cimglist_instance,filename);
48470 52927 else
48471 52928 cimg::warn(_cimglist_instance
... ... @@ -48864,10 +53321,10 @@ namespace cimg_library_suffixed {
48864 53321 cimglist_for(*this,l) msiz+=_data[l].size();
48865 53322 msiz*=sizeof(T);
48866 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 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 53328 cimg::t_bold,cimg::t_normal,(void*)this,
48872 53329 cimg::t_bold,cimg::t_normal,_width,_allocated_width,
48873 53330 mdisp==0?msiz:(mdisp==1?(msiz>>10):(msiz>>20)),
... ... @@ -48915,9 +53372,9 @@ namespace cimg_library_suffixed {
48915 53372 **/
48916 53373 const CImgList<T>& display(CImgDisplay &disp, const bool display_info,
48917 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 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 53380 //! Display the current CImgList instance in a new display window.
... ... @@ -48929,15 +53386,16 @@ namespace cimg_library_suffixed {
48929 53386 **/
48930 53387 const CImgList<T>& display(const char *const title=0, const bool display_info=true,
48931 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 53390 CImgDisplay disp;
48934 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 53395 const CImgList<T>& _display(CImgDisplay &disp, const char *const title, const bool display_info,
48939 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 53399 if (is_empty())
48942 53400 throw CImgInstanceException(_cimglist_instance
48943 53401 "display(): Empty instance.",
... ... @@ -48978,13 +53436,13 @@ namespace cimg_library_suffixed {
48978 53436 disp.resize(cimg_fitscreen(_data[0]._width,_data[0]._height,_data[0]._depth),false).
48979 53437 set_title("%s (%ux%ux%ux%u)",
48980 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 53440 if (disp.key()) is_exit = true;
48983 53441 disp.resize(cimg_fitscreen(dw,dh,1),false).set_title("%s",dtitle.data());
48984 53442 } else {
48985 53443 bool disp_resize = !is_first_call;
48986 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 53446 disp_resize = true;
48989 53447 if (s[0]<0) { // No selections done.
48990 53448 if (disp.button()&2) { disp.flush(); break; }
... ... @@ -48999,10 +53457,12 @@ namespace cimg_library_suffixed {
48999 53457 ind0 = (unsigned int)cimg::max(0,s[0] - (int)delta),
49000 53458 ind1 = (unsigned int)cimg::min(width() - 1,s[0] + (int)delta);
49001 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 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 53468 return *this;
... ... @@ -49136,7 +53596,7 @@ namespace cimg_library_suffixed {
49136 53596 \param fps Number of desired frames per second.
49137 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 53600 const unsigned int nb_loops=0) {
49141 53601 CImg<charT> command(1024), filename_tmp(256), filename_tmp2(256);
49142 53602 CImgList<charT> filenames;
... ... @@ -49162,15 +53622,15 @@ namespace cimg_library_suffixed {
49162 53622 }
49163 53623  
49164 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 53627 CImg<ucharT>::string(command).move_to(filenames,0);
49168 53628 cimg_snprintf(command,command._width,"\"%s\" >/dev/null 2>&1",
49169 53629 CImg<charT>::string(filename)._system_strescape().data());
49170 53630 CImg<ucharT>::string(command).move_to(filenames);
49171 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 53634 CImg<ucharT>::string(command).move_to(filenames,0);
49175 53635 cimg_snprintf(command,command._width,"\"%s\"\" >NUL 2>&1",
49176 53636 CImg<charT>::string(filename)._system_strescape().data());
... ... @@ -49505,7 +53965,8 @@ namespace cimg_library_suffixed {
49505 53965 \param compression_type Compression mode used to write data.
49506 53966 **/
49507 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 53970 if (!filename)
49510 53971 throw CImgArgumentException(_cimglist_instance
49511 53972 "save_tiff(): Specified filename is (null).",
... ... @@ -49513,21 +53974,18 @@ namespace cimg_library_suffixed {
49513 53974 if (is_empty()) { cimg::fempty(0,filename); return *this; }
49514 53975  
49515 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 53978 else cimglist_for(*this,l) {
49518 53979 CImg<charT> nfilename(1024);
49519 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 53983 #else
49523   - TIFF *tif = TIFFOpen(filename,"w");
  53984 + TIFF *tif = TIFFOpen(filename,is_bigtiff?"w8":"w4");
49524 53985 if (tif) {
49525 53986 for (unsigned int dir = 0, l = 0; l<_width; ++l) {
49526 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 53990 TIFFClose(tif);
49533 53991 } else
... ... @@ -49588,7 +54046,7 @@ namespace cimg_library_suffixed {
49588 54046 CImg<charT> nfilename(1024);
49589 54047 cimglist_for(*this,l) {
49590 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 54050 _data[l].save_gzip_external(nfilename);
49593 54051 }
49594 54052 }
... ... @@ -49651,7 +54109,7 @@ namespace cimg_library_suffixed {
49651 54109  
49652 54110 #define _cimg_docase(x) ((x)>='a'&&(x)<='z'?(x) + 'A' - 'a':(x))
49653 54111 const char
49654   - *const _codec = codec?codec:"mp4v",
  54112 + *const _codec = codec && *codec?codec:"mp4v",
49655 54113 codec0 = _cimg_docase(_codec[0]),
49656 54114 codec1 = _codec[0]?_cimg_docase(_codec[1]):0,
49657 54115 codec2 = _codec[1]?_cimg_docase(_codec[2]):0,
... ... @@ -49977,13 +54435,13 @@ namespace cimg_library_suffixed {
49977 54435 \param is_variable_width Decide if the font has a variable (\c true) or fixed (\c false) width.
49978 54436 **/
49979 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 54439 cimg::mutex(11);
49982 54440  
49983 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 54445 const unsigned int data_ind = font_height<=13U?0U:font_height<=23U?1U:font_height<=53U?2U:3U;
49988 54446 static CImg<ucharT> base_fonts[4];
49989 54447 CImg<ucharT> &base_font = base_fonts[data_ind];
... ... @@ -50727,7 +55185,7 @@ namespace cimg {
50727 55185 char *pd = _path;
50728 55186 for (char *ps = pd; *ps; ++ps) { if (*ps!='/' || *ps!=*(ps+1)) *(pd++) = *ps; }
50729 55187 *pd = 0;
50730   - unsigned int lp = std::strlen(_path);
  55188 + unsigned int lp = (unsigned int)std::strlen(_path);
50731 55189 if (!_is_pattern && lp && _path[lp - 1]=='/') {
50732 55190 _path[lp - 1] = 0; --lp;
50733 55191 #if cimg_OS!=2
... ... @@ -50747,7 +55205,7 @@ namespace cimg {
50747 55205 } else { // No path to folder specified, assuming current folder.
50748 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 55211 // Windows version.
... ... @@ -50757,21 +55215,19 @@ namespace cimg {
50757 55215 std::memcpy(pattern,_path,lp);
50758 55216 pattern[lp] = '/'; pattern[lp + 1] = '*'; pattern[lp + 2] = 0;
50759 55217 }
50760   -
50761 55218 WIN32_FIND_DATAA file_data;
50762 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 55221 do {
50765 55222 const char *const filename = file_data.cFileName;
50766 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 55225 const bool is_directory = (file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)!=0;
50769 55226 if ((!mode && !is_directory) || (mode==1 && is_directory) || mode>=2) {
50770 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 55231 full_filename.move_to(res);
50776 55232 } else CImg<char>(filename,lf + 1).move_to(res);
50777 55233 }
... ... @@ -50782,12 +55238,12 @@ namespace cimg {
50782 55238 // Unix version (posix).
50783 55239 #else
50784 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 55242 struct dirent *ent;
50787 55243 while ((ent=readdir(dir))!=0) {
50788 55244 const char *const filename = ent->d_name;
50789 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 55247 CImg<char> full_filename(lp + lf + 2);
50792 55248  
50793 55249 if (!is_current) {
... ... @@ -50886,7 +55342,8 @@ namespace cimg {
50886 55342 \note Use the \c libcurl library, or the external binaries \c wget or \c curl to perform the download.
50887 55343 **/
50888 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 55347 if (!url)
50891 55348 throw CImgArgumentException("cimg::load_network(): Specified URL is (null).");
50892 55349 if (!filename_local)
... ... @@ -50921,6 +55378,7 @@ namespace cimg {
50921 55378 curl_easy_setopt(curl,CURLOPT_FOLLOWLOCATION,1L);
50922 55379 if (timeout) curl_easy_setopt(curl,CURLOPT_TIMEOUT,(long)timeout);
50923 55380 if (std::strchr(url,'?')) curl_easy_setopt(curl,CURLOPT_HTTPGET,1L);
  55381 + if (referer) curl_easy_setopt(curl,CURLOPT_REFERER,referer);
50924 55382 res = curl_easy_perform(curl);
50925 55383 curl_easy_cleanup(curl);
50926 55384 std::fseek(file,0,SEEK_END); // Check if file size is 0.
... ... @@ -50940,23 +55398,41 @@ namespace cimg {
50940 55398 cimg::unused(try_fallback);
50941 55399  
50942 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 55416 cimg::system(command);
50950 55417  
50951 55418 if (!(file = std::fopen(filename_local,"rb"))) {
50952 55419  
50953 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 55436 cimg::system(command);
50961 55437  
50962 55438 if (!(file = std::fopen(filename_local,"rb")))
... ... @@ -51079,7 +55555,7 @@ namespace cimg {
51079 55555 logo._data,is_centered);
51080 55556 throw CImgIOException("cimg::dialog(): No display available.");
51081 55557 #else
51082   - const unsigned char
  55558 + static const unsigned char
51083 55559 black[] = { 0,0,0 }, white[] = { 255,255,255 }, gray[] = { 200,200,200 }, gray2[] = { 150,150,150 };
51084 55560  
51085 55561 // Create buttons and canvas graphics
... ... @@ -51281,6 +55757,9 @@ namespace cil = cimg_library_suffixed;
51281 55757 #ifdef _cimg_redefine_PI
51282 55758 #define PI 3.141592653589793238462643383
51283 55759 #endif
  55760 +#ifdef _MSC_VER
  55761 +#pragma warning(pop)
  55762 +#endif
51284 55763  
51285 55764 #endif
51286 55765 // Local Variables:
... ...
stim/parser/filename.h
... ... @@ -215,7 +215,7 @@ public:
215 215 hFind = FindFirstFileA((filepath.str().c_str()), &FindFileData);
216 216  
217 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 220 else {
221 221 std::string file_name = FindFileData.cFileName; //get the file name
... ... @@ -230,9 +230,8 @@ public:
230 230 file_list.push_back(current_file);
231 231 }
232 232 FindClose(hFind);
233   -
  233 + }
234 234 return file_list;
235   - }
236 235  
237 236 }
238 237 #endif
... ...